create several charts in Excel with VBA - vba

I have a worksheet with 300 columns and would like to create one scatter plot for each column, bringing data from two other sheets that are in the same worksheet.
The problem is that I´m not familiar with VBA, and some error codes don't help at all.
Private Sub Create_Charts()
Dim sh As Worksheet
Dim chrt As Chart
For i = 1 To 300
Set sh = ActiveWorkbook.Worksheets("Graphs")
Set chrt = sh.Shapes.AddChart.Chart
With chrt
'Data
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "=""Scatter Chart"""
'With the following parameters it works:
'.SeriesCollection(1).XValues = "=OP!$c$4:$c$1588"
'.SeriesCollection(1).Values = "=PV!$c$4:$c$1588"
'But I need something like this:
.SeriesCollection(1).XValues = CStr(Worksheets("PV").Range(Cells(i, 4), Cells(i, 1588)))
.SeriesCollection(1).Values = CStr(Worksheets("OV").Range(Cells(i, 4), Cells(i, 1588)))
'Location
.ChartArea.Left = 380 * i - 380
.ChartArea.Top = 100
.ChartArea.Height = 360
.ChartArea.Width = 360
'Formatting
.Axes(xlCategory).HasMajorGridlines = True
.Axes(xlValue).HasMajorGridlines = True
.HasAxis(xlCategory, xlPrimary) = False
.HasAxis(xlValue, xlPrimary) = False
.HasLegend = False
End With
Next i
End Sub

This line references a column:
.SeriesCollection(1).XValues = "=OP!$c$4:$c$1588"
This references a row, row i from column 4 to column 1588:
.SeriesCollection(1).XValues = CStr(Worksheets("PV").Range(Cells(i, 4), Cells(i, 1588)))
But you also need to reference not only Range but Cells. And if you pass in a string address, you need the leading "="; it's easier to pass in a range. So try this:
Dim wsPV As Worksheet, wsOV As Worksheet
Dim rngX As Range, rngY As Range
Set wsPV = ActiveWorkbook.Worksheets("PV")
Set wsOV = ActiveWorkbook.Worksheets("OV")
Set rngX = wsPV.Range(wsPV.Cells(4, i), wsPV.Cells(1588, i)
Set rngY = wsOV.Range(wsOV.Cells(4, i), wsOV.Cells(1588, i)
chrt.SeriesCollection(1).XValues = rngX
chrt.SeriesCollection(1).Values = rngY

Related

Creating Chart with data from another sheet and different number of columns

My code should create one chart for every row of a data base. This data base is in a different sheet. Since that data base should change the number of columns I'm counting how many columns and changing the data source. Every time I run the code it comes with an error in the SetSourceData.
I couldn't find what am I doing wrong.
Can someone help me find a solution?
Sub createColumnChartMatriz12()
Dim ChartName As String
Dim Row As Integer
Dim ChartRow As Integer
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Matriz 1")
Dim k As Long
Dim z As Long
k = sh.Range("A1", sh.Range("A1").End(xlDown)).Rows.Count
z = sh.Cells(1, sh.Columns.Count).End(xlToLeft).Column - 4
ThisWorkbook.Sheets("Matriz1Chart").Select
Cells.Select
Selection.RowHeight = 15.5
Cells(1, 1).Select
ChartRow = 49
Row = 2
For Row = 2 To k
ChartName = "Utilização no Período " & sh.Cells(Row, 1).Value
ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
With ActiveChart
.SetSourceData Source:=sh.Range(Cells(Row, 4), Cells(Row, z)), _
PlotBy:=xlRows
.FullSeriesCollection(1).XValues = "='Matriz 1'!$D$1:$AM$1"
.Parent.Height = Range("A1:A15").Height
.Parent.Width = Range("A1:J1").Width
.Parent.Top = Range("A" & ChartRow).Top
.Parent.Left = Range("A" & ChartRow).Left
.HasTitle = True
.ChartTitle.Text = ChartName
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Meses"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Utilização"
.Axes(xlCategory, xlPrimary).TickLabels.NumberFormat = "mm-yyyy"
End With
ChartRow = ChartRow + 16
Next
End Sub
Not sure if this is your only problem, but when you access a Range by providing two cells (Cells are in fact also Ranges), you have to qualify these cells also.
Your statement sh.Range(Cells(Row, 4), Cells(Row, z)) tries to define a Range object of sheet "Matriz 1" (saved in variable sh), but Cells(Row, 4) refers to the active sheet. That makes the range itself invalid and causes the failure of the .SetSourceData command.
You should write sh.Range(sh.Cells(Row, 4), sh.Cells(Row, z)) instead. As a general advice: split the logic of such complicated command - it is much easier to debug and figure out what fails. In your case, first define the range, write it into a variable and after that assign it to the chart:
With ActiveChart
dim chartRange as Range
set chartRange = sh.Range(sh.Cells(Row, 4), sh.Cells(Row, z))
.SetSourceData Source:=chartRange, PlotBy:=xlRows
...
end with
or, if you prefer (but note the leading .)
With ActiveChart
dim chartRange as Range
with sh
set chartRange = .Range(.Cells(Row, 4), .Cells(Row, z))
end with
.SetSourceData Source:=chartRange, PlotBy:=xlRows
...
end with

Setting line on XY scatter without having a marker line

So I am trying to format a XY scatter chart in Excel using VBA and I would like to have lines connecting the markers, but for both the markers and the marker lines I would like for them to be invisible.
For some reason both the marker line and the line that connects the markers both use the same code to change their visibility property.
chart.SeriesCollection(1).Format.Line.Visible = msoFalse
I can change the colours independently using the MarkerBackGroundColor property, but I can't seem to figure out how to make one visible without making the other visible as well.
Any help on this would be very much appreciated.
You can use
FullSeriesCollection(1).Border.LineStyle = xlNone
or
FullSeriesCollection(1).Border.LineStyle = xlSolid
to format the line only.
The code seems to set point. Bellow code is sample of setting points.
Sub ScatterChart_setPoint()
Dim Ws As Worksheet
Dim DB As Range, myCell As Range
Dim Ch As Chart
Dim i As Integer, n As Long, r As Integer, g As Integer, b As Integer
Dim vX(), vY(), vLable(), vMarker
Dim pnt As Point
Dim Shp As Shape
Dim h As Single, w As Single, l As Single, t As Single, fs As Single
Application.DisplayAlerts = False
Set Ws = ActiveSheet 'Sheets("Current Account")
Ws.Activate
Ws.Range("a65536").Select
vMarker = Array(xlMarkerStyleCircle, xlMarkerStyleDash, xlMarkerStyleDiamond, xlMarkerStyleDot, _
xlMarkerStylePlus, xlMarkerStyleSquare, xlMarkerStyleStar, _
xlMarkerStyleTriangle, xlMarkerStyleX)
Set DB = Ws.Range("h3", Ws.Range("h3").End(xlDown)) '<~~ range of data
For Each myCell In DB
If myCell = 0 Or myCell.Offset(, 10) = "" Then
Else
n = n + 1
ReDim Preserve vX(1 To n)
ReDim Preserve vY(1 To n)
ReDim Preserve vLable(1 To n)
vX(n) = myCell
vY(n) = myCell.Offset(, 10)
vLable(n) = myCell.Offset(, -7)
End If
Next myCell
Charts.Add
With ActiveChart
.HasTitle = True
.ChartType = xlXYScatter
.Legend.Position = xlLegendPositionRight
With .ChartTitle
.Characters.Text = Ws.Range("a1").Value
.Characters.Font.Size = 12
End With
.SeriesCollection.NewSeries
With .SeriesCollection(1)
.Name = "OECD"
.XValues = vX
.Values = vY
.Trendlines.Add
With .Trendlines(1)
.DisplayRSquared = True
.DisplayEquation = True
End With
End With
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = Ws.Range("r2")
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = Ws.Range("h2")
For i = 1 To n
Set pnt = .SeriesCollection(1).Points(i)
With pnt
.ApplyDataLabels
.DataLabel.Text = vLable(i)
.DataLabel.ShowValue = False
.DataLabel.ShowCategoryName = True
.MarkerStyle = vMarker(WorksheetFunction.RandBetween(0, 8))
With WorksheetFunction
r = .RandBetween(0, 240)
g = .RandBetween(0, 240)
b = .RandBetween(0, 240)
End With
.MarkerForegroundColor = RGB(r, g, b)
.MarkerBackgroundColor = RGB(r, g, b)
End With
.ApplyDataLabels
Next i
Application.DisplayAlerts = True
End Sub

series deletion in chart

I have an table and would like to generate an chart out of it. the problem is I would like to have only the column Values of A, F, G, and H.
I tried seriescollection(1).deletion method,. but I am still getting the column B and C series in my chart.
Could anyone tell me how I can do it.
Any lead would be helpful
Sub chartstatus()
Dim Rng As Range
Dim cht As Object
Set Rng = ActiveSheet.Range("A2:H53")
ThisWorkbook.Sheets("Status").ChartObjects.delete
Set Sh = ActiveSheet.ChartObjects.Add(Left:=650, _
Width:=600, _
Top:=80, _
Height:=250)
Sh.Select
Set cht = ActiveChart
With cht
.SetSourceData Source:=Rng
.ChartType = xlColumnClustered
cht.Axes(xlSecondary).TickLabels.NumberFormat = "0.%"
End With
cht.SeriesCollection(6).Name = " % Missing "
cht.SeriesCollection(7).Name = " % OnTime"
cht.SeriesCollection(8).Name = " % Delayed"
cht.SeriesCollection(6).HasDataLabels = True
cht.SeriesCollection(7).HasDataLabels = True
cht.SeriesCollection(8).HasDataLabels = True
cht.SeriesCollection(1).Format.Fill.ForeColor.RGB = RGB(255, 255, 255) '<~~ Red
cht.HasTitle = True
cht.ChartTitle.Text = "Result "
End Sub
You can combine 2 range into 1 range
Dim Rng As Range
Dim Rng_A As Range
Dim Rng_FH As Range
Set Rng_A = ActiveSheet.Range("A2:A52")
Set Rng_FH = ActiveSheet.Range("F2:H52")
Set Rng = Union(Rng_A, Rng_FH)

VBA Excel: Find row in which more than 5 columns are being used

I'm working on a program that will compile multiple excel workbooks into one and plot the data. One problem I have run into is that the rows prior to the actual data varies and I want the code to be able to find the starting point by itself. On top of that, I would like it to use a range that starts from that row and continues all of the way down the spreadsheet until data ceases. Data File Example
Here is my code so far:
Private Sub runHPO_Click()
Dim FolderPath As String
Dim FileName As String
Dim WorkBk As Workbook
Dim SourceRange As range
Dim DestRange As range
Dim DataSheet As Worksheet
Dim cht As Chart
Application.ScreenUpdating = False
'Test specific section - directory, chart title
FolderPath = "I:\SHARED\Marshall Test Compiler\Performance Tests\3.2.1.7 HPO\"
FileName = Dir(FolderPath & "*.*")
ThisWorkbook.Charts.Add.Name = "HPO"
Set cht = ActiveChart
With cht
.ChartType = xlXYScatterLinesNoMarkers
.HasTitle = True
.ChartTitle.Text = "3.2.1.7 Hot Pump Out"
.Axes(xlCategory).HasTitle = True
.Axes(xlCategory).AxisTitle.Text = "Time [min:sec]"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Text = "Fan Speed [rpm]"
End With
Do While FileName <> ""
ThisWorkbook.Sheets.Add(After:=Sheets(Sheets.Count)).Name = FileName
Set DataSheet = ActiveSheet
Set WorkBk = Workbooks.Open(FolderPath & FileName)
Set SourceRange = WorkBk.Worksheets(1).range("A1:Z2045")
Set DestRange = DataSheet.range("A1:Z2045")
DestRange.Value = SourceRange.Value
'Change legend name to serial number
Dim LName As String
LName = DataSheet.range("A14").Characters(8, 9).Text
'Add plotting
Dim profTime As range
Dim profInSpeed As range
Dim profSpDemand As range
Dim profLoLimit
Dim xrange As range
Dim fsrange As range
Dim pwmrange As range
Dim btrange As range
Dim sdrange As range
Set profTime = ThisWorkbook.Worksheets("Profiles").range("H4:H13")
Set profInSpeed = ThisWorkbook.Worksheets("Profiles").range("I4:I13")
Set profSpDemand = ThisWorkbook.Worksheets("Profiles").range("J4:J13")
Set profUpLimit = ThisWorkbook.Worksheets("Profiles").range("K4:K13")
Set xrange = DataSheet.range("A797:A2045")
Set fsrange = DataSheet.range("D797:D2045")
Set pwmrange = DataSheet.range("J797:J2045")
Set btrange = DataSheet.range("F797:F2045")
Set sdrange = DataSheet.range("K797:K2045")
xrange.NumberFormat = "mm:ss"
profTime.NumberFormat = "mm:ss"
'Profile
With cht.SeriesCollection.NewSeries
.Name = "Input Speed"
.AxisGroup = xlPrimary
.Values = profInSpeed
.XValues = profTime
End With
With cht.SeriesCollection.NewSeries
.Name = "Speed Demand"
.AxisGroup = xlPrimary
.Values = profSpDemand
.XValues = profTime
End With
With cht.SeriesCollection.NewSeries
.Name = "Fan Speed Upper Limit"
.AxisGroup = xlPrimary
.Values = profUpLimit
.XValues = profTime
End With
'Fan Speed
With cht.SeriesCollection.NewSeries
.Name = LName & " Fan Speed"
.AxisGroup = xlPrimary
.Values = fsrange
.XValues = xrange
End With
'PWM
With cht.SeriesCollection.NewSeries
.Name = LName & " PWM"
.AxisGroup = xlSecondary
.Values = pwmrange
.XValues = xrange
End With
'Box Temp
With cht.SeriesCollection.NewSeries
.Name = LName & " Box Temp"
.AxisGroup = xlSecondary
.Values = btrange
.XValues = xrange
End With
'Speed Demand
With cht.SeriesCollection.NewSeries
.Name = LName & " Speed Demand"
.AxisGroup = xlSecondary
.Values = sdrange
.XValues = xrange
End With
WorkBk.Close savechanges:=False
FileName = Dir()
Loop
With cht
.HasAxis(xlValue, xlSecondary) = True
.Axes(xlValue, xlSecondary).HasTitle = True
.Axes(xlValue, xlSecondary).AxisTitle.Select
.Axes(xlValue, xlSecondary).AxisTitle.Text = "PWM [%] / Box Temp [degC]"
.Axes(xlValue, xlPrimary).MaximumScale = 2400
.Axes(xlValue, xlSecondary).MaximumScale = 120
.Axes(xlValue, xlSecondary).MinimumScale = -800
.SeriesCollection(1).Delete
End With
ThisWorkbook.Worksheets("Compiler").Select
Application.ScreenUpdating = True
End Sub
In your example, your data is obstructed by a lot of header information on the far left. If this is always the case, you can select a column that will never have data in front of it and find the first row by using:
FirstRow = Sheets("Your Sheet Name").Cells(1, 20).end(xlDown).Row
(This assumes that column 20 is clear of all header data). You can find the last row of contiguous data by using:
LastRow = Sheets("Your Sheet Name").Cells(FirstRow, 20).end(xlDown).Row
The last column:
LastColumn = Sheets("Your Sheet Name").Cells(FirstRow, Columns.Count).end(xltoLeft).Column
If it is not the case that there is an unobstructed column, I recommend you use the .Find function to find a unique number or alpha format.

VBA chart position changes when rows inserted

I wrote the following code to add a chart and position it on a worksheet with data on it:
Dim sh As Worksheet
Dim chrteit As Chart
lastrows = Range("A2").End(xlDown).Row
Set sh = ActiveWorkbook.Worksheets("TraceTable")
Set chrteit = sh.Shapes.AddChart.Chart
With chrteit
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).XValues = sh.Range(Cells(2, 6), Cells(lastrows, 6))
.SeriesCollection(1).Values = sh.Range(Cells(2, 7), Cells(lastrows, 7))
.HasTitle = True
.ChartTitle.Text = "EIT"
.Parent.Height = Range("N2:N14").Height
.Parent.Width = Range("N2:T2").Width
.Parent.top = Range("N2").top
.Parent.Left = Range("N2").Left
End With
The problem is, later in my module I have a macro that will an entire row between two data points if the two data points are different, and it is as follows:
Private Sub Dividers()
Dim DividerRange As Range, lastrow As Long, k As Integer, counter As Integer
lastrow = Range("C2").End(xlDown).Row
Set DividerRange = Range(Cells(2, 3), Cells(lastrow, 3))
counter = 0
For k = 2 To DividerRange.Count
If DividerRange(k + counter).Value <> DividerRange(k + counter - 1).Value Then
DividerRange(k + counter).EntireRow.Insert
counter = counter + 1
Else
End If
Next k
End Sub
By adding the entire row, it changes the height of my graph and it's position. I want it to be a fixed position, how can I do this? I would PREFER not to change the second code, but rather the first but let me know any solutions you guys have, Thanks!
Add this line to the first procedure:
chrteit.Placement = xlFreeFloating
This is the same as right-click, format chart area, properties: Don't move or size with cells.
|
Or you could place that method inside the With block, thusly:
With chrteit
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).XValues = sh.Range(Cells(2, 6), Cells(lastrows, 6))
.SeriesCollection(1).Values = sh.Range(Cells(2, 7), Cells(lastrows, 7))
.HasTitle = True
.ChartTitle.Text = "EIT"
.Parent.Height = Range("N2:N14").Height
.Parent.Width = Range("N2:T2").Width
.Parent.top = Range("N2").top
.Parent.Left = Range("N2").Left
.Placement = xlFreeFloating
End With