VBA - Creating a chart where each series represents a data point - vba

I am trying to write a bit of VBA that will automatically populate a scatter chart such that each row (x,y) in a table represents a series i.e. one point per series. I attach below my code so far. But when I come to run it it fails with the following run time error
"Run-time error '438':
Object doesn't support this property or method.
Sub CreateChart()
Dim NPOINTS As Integer
Dim NVAL(1000) As Range, XVAL(1000) As Range, YVAL(1000) As Range
Sheets("Scenario").Select
Range("B4").Select
NPOINTS = Worksheets("Scenario").Range(Selection, Selection.End(xlDown)).Rows.Count
Set Scenario = Worksheets("Scenario")
ActiveSheet.Shapes.AddChart2(240, xlXYScatter).Select
NVAL0 = "B3"
XVAL0 = "C3"
YVAL0 = "D3"
For i = 1 To NPOINTS
Set NVAL(i) = Cells(Range(NVAL0).Offset(i, 0).Row, Range(NVAL0).Column)
Set XVAL(i) = Cells(Range(XVAL0).Offset(i, 0).Row, Range(XVAL0).Column)
Set YVAL(i) = Cells(Range(YVAL0).Offset(i, 0).Row, Range(YVAL0).Column)
ActiveChart.SeriesCollection.NewSeries
ActiveChart.FullSeriesCollection(i).Name = NVAL(i)
ActiveChart.FullSeriesCollection(i).XValues = XVAL(i)
ActiveChart.FullSeriesCollection(i).YValues = YVAL(i)
Next
End Sub
Where am I going wrong?

The y-values in a scatter plot are stored in Values, not YValues, so you need to change the last line accordingly.

Related

Excel Chart - How to draw discontinuous series in VBA without range reference

Excel 2010.
Issue : I need to plot a *single* *discontinuous* series in a XY-scatter chart *via VBA* without referencing a range in the sheet.
It is easy to achieve that when the Yvalues are laid-out in a sheet range, by inserting blank values at the discontinuities ; as long as one selects 'Show empty cells as: Gaps' in Select Data > Hidden and Empty Cells. Here is an example (the Series2 in red is the one that matters) :
So I was trying to reproduce the same via VBA :
Sub addDiscountinuousSingleSeries()
Dim vx As Variant, vy As Variant
Dim chrtObj As ChartObject, chrt As Chart, ser As Series
Set chrtObj = ActiveSheet.ChartObjects("MyChart"): Set chrt = chrtObj.Chart
Set ser = chrt.SeriesCollection.NewSeries
vx = Array(0.3, 0.3, 0.3, 0.7, 0.7, 0.7)
vy = Array(-1, 1, vbNullString, -1, 1, vbNullString)
'vy = Array(-1, 1, CVErr(xlErrNA), -1, 1, CVErr(xlErrNA)) 'doesn't work either
'vy = Range(RANGE_YVALUES_WITH_BLANK) 'this would work, but I do not want to reference a range
chrt.DisplayBlanksAs = xlNotPlotted 'VBA equivalent to 'Show empty cells as: Gaps'
With ser
ser.Name = "VBA Series"
.XValues = vx
.Values = vy
End With
End Sub
But the blank values in the vy array seems to be ignored and the two vertical bars are now connected, which I am trying to avoid (green series).
I know that I could delete the middle line programmatically, but in the real-life problem I am trying to solve it would not be the right solution (too complex, too slow).
My question : is there a way to specify the series' .Values array to get the expected behavior and get a gap between the two vertical green segments in vba (with only one series and no reference to a sheet range)?
You could just format the lines you don't want. Maybe not the prettiest way, but it'd achieve what your after.
ser.Points(3).Format.Line.Visible = msoFalse
ser.Points(4).Format.Line.Visible = msoFalse
ser.Points(6).Format.Line.Visible = msoFalse
Or:
For i = 1 To ser.Points.Count
If i <> 1 Then k = i - 1 Else k = i
If ser.Values(i) = 0 Or ser.Values(k) = 0 Then
ser.Points(i).Format.Line.Visible = msoFalse
End If
Next

VBA Excel: Different colors in one line diagram depending on value

I'm looking for a way to have three different colors in the same line chart of a diagram in Excel, depending on the values themselves or where they are from (from which sheet f.e).
Till now, I have the following code:
Sub ChangeColor()
Dim i As Integer
Dim IntRow As Integer
Dim r As Range
ActiveSheet.ChartObjects("Cash").Activate
ActiveChart.SeriesCollection(1).Select
IntRow = ActiveChart.ChartObjects("Cash").Count
For i = 2 To IntRow
Set r = Cells(2, i)
If r.Value < 3000 Then
Selection.Border.ColorIndex = 5
Else
Selection.Border.ColorIndex = 9
End If
Next
End Sub
However, the if statement is not considered and the color of the whole line changes only whenever I change the first ColorIndex. I have no idea, how to color parts of the line depending on the values in the underlying table.
Moreover, by defining IntRow as ActiveChart.ChartObjects("Cash").Count I'm not able to get the length of my array. This problem can be solved by manual counting and declaring IntRow as an Integer, however, the version above seems nicer (if that is possible of course).
I appreciate any help! Thank you.
Alexandra
You can read the values directly from the chart series:
Sub ChangeColor()
Dim cht As Chart, p As Point, s As Series
Dim i As Integer
Dim numPts As Long
'access the chart directly - no select/activate required
Set cht = ActiveSheet.ChartObjects("Cash").Chart
'reference the first series
Set s = cht.SeriesCollection(1)
'how many points in the first series?
numPts = s.Points.Count
'loop over the series points
For i = 1 To numPts
Set p = cht.SeriesCollection(1).Points(i)
p.Border.ColorIndex = IIf(s.Values(i) < 3000, 5, 9)
Next
End Sub

Conditionally Coloring a Graph in Excel

Hi there!
I am trying to color a graph (a task tracker) via VBA, in excel. The idea is to color all "categories" a certain color -- visually, it would mean making all bars on each "row" a particular color. I'm using the following code, which I copied from http://peltiertech.com/vba-conditional-formatting-of-charts-by-category-label/:
Sub ColorByCategoryLabel()
Dim rPatterns As Range
Dim iCategory As Long
Dim vCategories As Variant
Dim rCategory As Range
Set rPatterns = ActiveSheet.Range("A1:A5")
With ActiveChart.SeriesCollection(2)
vCategories = .XValues
For iCategory = 1 To UBound(vCategories)
Set rCategory = rPatterns.Find(What:=vCategories(iCategory))
.Points(iCategory).Format.Fill.ForeColor.RGB = rCategory.Interior.Color
Next
End With
End Sub
and I can't figure out what is wrong.
Basically, I have a series (series2), with horizontal (category) axis labels consisting of integers from 1-5. This category determines the vertical position of the bar, but I also want to color each bar in this series according to this vertical position, according to the color in the range(a1:a5) -- which is exactly what this code seems to be doing.
Any suggestions, as to the code, or perhaps, any alternative way to color bar graphs based on the value of the "horizontal (category) axis"?
Thanks!
Well, I found an answer to my problem by stepping through it. I can't imagine this to be the easiest way to horizontal bar graphs according to their height but it works.
Sub ColorByCategoryLabel()
Dim iCategory As Long
Dim vCategories As Variant
Dim rCategory As Range
Dim CurColor As Double
Dim CurColorIndex As Long
Dim CurHeight As Double
CurHeight = 0
CurColorIndex = 1
CurColor = ActiveSheet.Cells(CurColorIndex + 1, 10).Interior.Color
ActiveSheet.ChartObjects("Chart 1").Select
With ActiveChart.SeriesCollection(2)
vCategories = .XValues
For iCategory = 1 To UBound(vCategories)
If .Points(iCategory).Top > CurHeight Then
CurColorIndex = CurColorIndex + 1
CurColor = ActiveSheet.Cells(CurColorIndex + 1, 10).Interior.Color
CurHeight = .Points(iCategory).Top
End If
.Points(iCategory).Format.Fill.ForeColor.RGB = CurColor
Next
End With
End Sub
You would need to modify the line
Curcolor = ActiveSheet.Cells(CurColorIndex+1,10).Interior.Color
To properly specify the cells whose background color you wish to copy.
By the way, if anyone is interested in the timetracker, it is hosted here: https://drive.google.com/file/d/0B85fvjQDbl3lUVpPNmdGT1VkWW8/view?usp=sharing

How to assign XValues for excel chart using VBA

I have this VBA function for drawing charts in Excel 2013:
Sub DrawChart2(obj_worksheetTgt As Worksheet, ByVal XLabels As Range, ByVal DataValues As Range, ByVal chartTitle As String, a As Integer, b As Integer)
'
'obj_worksheetTgt - Object worksheet on which to be placed the chart
'XLabels - Data range for X labels
'DataValues - Data range for Y values
'chartTitle - Chart title
'a - left border position of chart in pixels
'b - top border position of chart in pixels
With obj_worksheetTgt.ChartObjects.Add(a, b, 900, 300) ' Left, Top, Width, Height
With .Chart
.ChartType = xlBarClustered
Set .SeriesCollection(1).XValues = XLabels ' Here is the error
Set .SeriesCollection(1).Values = DataValues
.Legend.Position = -4107
.HasTitle = True
.chartTitle.Text = chartTitle
.chartTitle.Font.Size = 12
With .Axes(1).TickLabels
.Font.Size = 8
.Orientation = 90
End With
End With
End With
End Sub
I call the function this way:
ChartsWorksheet = "Summary"
Queryname = "query1"
chartTitle = "Values"
With .Worksheets("LastDayData").ListObjects(Queryname)
Set chart_labels = .ListColumns(2).DataBodyRange
Set chart_values = .ListColumns(6).DataBodyRange
End With
Call DrawChart2(.Worksheets(ChartsWorksheet), chart_labels, chart_values, chartTitle, 10, 10)
And I receive an error:
Runtime Error '1004':
Invalid Parameter
When I click debug it marks the row "Set .SeriesCollection(1).XValues = XLabels" in the function above.
In the documentation is written:
The XValues property can be set to a range on a worksheet or to an
array of values, but it cannot be a combination of both
So it should be able to take the given range as values for XValues, but I can't understand why this error appears.
Before you can set the Values and XValues of a series, you will need to add the series first. This is simple to do using the SeriesCollection.NewSeries method as show below:
With ActiveSheet.ChartObjects.Add(a, b, 900, 300) ' Left, Top, Width, Height
With .Chart
.ChartType = xlBarClustered
' need to add the series before you can assign the values/xvalues
' calling the "NewSeries" method add one series each time you call it.
.SeriesCollection.NewSeries
' now that the series is added, you may assign (not set) the values/xvalues
.SeriesCollection(1).XValues = XLabels
.SeriesCollection(1).Values = DataValues
End With
End With
You cannot use named ranges for .XValues or .Values, but you can change the .Formula property by replacing the series formula
For more information on editing the series formula see http://peltiertech.com/change-series-formula-improved-routines/
Note of caution, there is a bug in Excel 2013 that prevents you from using named ranges starting with "R" or "C" when using VBA to change the series formula; see http://answers.microsoft.com/en-us/office/forum/office_2013_release-excel/named-range-use-in-chart-series-formulas-causes/c5a40317-c33f-4a83-84db-0eeee5c8827f/?auth=1&rtAction=1466703182593

Read Chart Properties using VBA

I'm using VBA to create some graphics I need to do.
Basically, what I want to do is to create the 1st series automatically and then, the 2nd series, copy the color and format from the 1st series.
I'm trying to do this code but with no success:
ActiveChart.SeriesCollection(a - 1).Select
ActiveChart.SeriesCollection(a).Border.ColorIndex = ActiveChart.SeriesCollection(a - 1).Border.ColorIndex
ActiveChart.SeriesCollection(a).MarkerBackgroundColorIndex = ActiveChart.SeriesCollection(a - 1).MarkerBackgroundColorIndex
ActiveChart.SeriesCollection(a).MarkerForegroundColorIndex = ActiveChart.SeriesCollection(a - 1).MarkerForegroundColorIndex
ActiveChart.SeriesCollection(a).MarkerStyle = ActiveChart.SeriesCollection(a - 1).MarkerStyle
Can someone please help me on how to read the properties from the previous series and apply them to the next?
Thanks.
In general something like this could work:
Sub Tester()
Dim Cht as Chart
Dim a As Series, b As Series, x As Long
Set cht = ActiveChart
Set a = cht.SeriesCollection(1)
For x = 2 To cht.SeriesCollection.Count
Set b = cht.SeriesCollection(x)
b.Border.Color = a.Border.Color
b.MarkerBackgroundColor = a.MarkerBackgroundColor
b.MarkerForegroundColor = a.MarkerForegroundColor
b.MarkerStyle = a.MarkerStyle
Next x
End Sub
Note however that some properties will not be read unless the first series was manually formatted, and is not just the "default" format.
Eg: see Fill and Border color property of data point marker (scatter or line) Excel VBA for similar problem.