I am producing an Excel column chart from a VB macro. I added 3 horizontal reference lines and find that when the macro completes, only the first one appears (along with the column chart). However, if I save the workbook and reopen it, all 3 reference lines are visible. Alternatively, if I go to the design tab to "Select Data" and simply click on any one of the reference line names, all 3 immediately appear. Any ideas on what I can put in my macro to get them all to appear automatically when the macro completes?
The code that creates these 3 reference lines is (sc is the chart's SeriesCollection):
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "A"
.XValues = "={1,3}"
.Values = "={100,100}"
End With
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "B"
.XValues = "={1, 3}"
.Values = "={80, 80}"
End With
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "C"
.XValues = "={1, 3}"
.Values = "={50, 50}"
End With
EDIT: Here is a screenshot using the data in the answer by #axel-richter. This is what it looks like immediately after the macro ends.
I suppose this is with Excel 2010 and later.
Call Chart.ChartWizard Method without parameters after you added new series.
Example:
Suppose we have:
Then after running this macro:
Sub addChart()
Dim oChart As ChartObject
Dim sc As SeriesCollection
Set oChart = ActiveSheet.ChartObjects.Add(300, 40, 300, 200)
oChart.Chart.ChartWizard Source:=ActiveSheet.Range("A1:D4"), Gallery:=xlColumn
Set sc = oChart.Chart.SeriesCollection
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "A"
.XValues = "={1,3}"
.Values = "={100,100}"
End With
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "B"
.XValues = "={1, 3}"
.Values = "={80, 80}"
End With
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "C"
.XValues = "={1, 3}"
.Values = "={50, 50}"
End With
oChart.Chart.ChartWizard
End Sub
we have:
I still have no explanation for why those lines don't show up for me, but I've found a "solution" that coerces them into visibility. I added the following at the end of the macro to (a) add an extra series at the end, and (b) immediately delete it.
With sc.NewSeries
.ChartType = xlXYScatterLinesNoMarkers
.Name = "D"
.XValues = "={1, 3}"
.Values = "={50, 50}"
End With
sc(sc.Count).Select
Application.SendKeys "{Delete}"
Note the last line. Using Selection.Delete deletes the extra series but the lines that were invisible stay that way.
If you've got the time try not reuse your SeriesCollection object.
I ran into this with a C# app I'm writing. The only similarity I could see between our code was that we were both calling NewSeries() on the same SeriesCollection object.
It's also worth noting the Chartwizard, and quick-series-create-delete workaround methods didn't work for me.
What did work was calling seriescollection() on the chart object before each SeriesCollection.NewSeries() call.
As in:
ChartObject co = target.ChartObjects().Item(1);
Chart c = co.Chart;
SeriesCollection s = c.SeriesCollection();
Series s1 = s.NewSeries();
s1.ChartType = XlChartType.xlLine;
s = c.SeriesCollection();
Series s2 = s.NewSeries();
s2.ChartType = XlChartType.xlLine;
Total conjecture, but I suspect a defect in the SeriesCollection class; potentially some event isn't firing on subsequent NewSeries calls. Depending on the version each of us is using the workarounds were causing the event that isn't firing to fire and therefore we would see the invisible series' actually appear.
Related
I try to set a black border around the Column chart from my Vba CODE. This is what i have now. The last row where i set Border.ColorIndex obviously does not work. Currently the column looks like this.
I want it to look like this.
Here is my code.
ActiveSheet.Cells(10000, 10000).Select
ActiveSheet.Shapes.AddChart.Select
With ActiveChart ' clear SeriesCollection
Do Until .SeriesCollection.Count = 0
.SeriesCollection(1).Delete
Loop
End With
ActiveChart.ChartType = xlColumnClustered
ActiveChart.PlotVisibleOnly = True
ActiveChart.Location Where:=xlLocationAsNewSheet, Name:="Plottt" ' rename chart sheets
' create SeriesCollection for each line
ActiveChart.SeriesCollection.NewSeries
ActiveChart.SeriesCollection(1).Name = "Hallo"
ActiveChart.SeriesCollection(1).XValues = breaks
ActiveChart.SeriesCollection(1).Values = freq
ActiveChart.ChartGroups(1).GapWidth = 0
ActiveChart.ChartGroups(1).Border.ColorIndex = 3
Also i would like to reduce the step size from my code. Help with this would also be appreciated.
To set the border color for a SeriesCollection(1) use the line below:
ActiveChart.SeriesCollection(1).Format.Line.ForeColor.RGB = RGB(255, 0, 0)
Note: it's better to not use ActiveChart, and it's "relatives". Instead use referenced objects. In this case use a ChartObject.
Simple reference code:
Dim Chtobj As ChartObject
' modify "Chart_Data" Name to your Sheet, and "Chart 1" to your chart's name
Set Chtobj = Sheets("Chart_Data").ChartObjects("Chart 1")
With Chtobj
' modify the chartobject properties here...
' modify the major unit of X-axis
.Axes(xlCategory).MajorUnit = 5 '<-- modify to whatever value you want
' modify the minor unit of X-axis
.Axes(xlCategory).MinorUnit = 1
End With
I am not sure why the border isn't showing, though I suspect that there must be a property that determines its visibility or thickness.
For cleaning up your code though, try this:
Dim oChart as Object
ActiveSheet.Cells(10000, 10000).Select
Set oChart = ActiveSheet.Shapes.AddChart
With oChart' clear SeriesCollection
Do Until .SeriesCollection.Count = 0
.SeriesCollection(1).Delete
Loop
.ChartType = xlColumnClustered
.PlotVisibleOnly = True
.Location Where:=xlLocationAsNewSheet, Name:="Plottt" ' rename chart sheets
' create SeriesCollection for each line
.SeriesCollection.NewSeries
With .SeriesCollection(1)
.Name = "Hallo"
.XValues = breaks
.Values = freq
End With
With .ChartGroups(1)
.GapWidth = 0
With .Border
.ColorIndex = 3
' You may need the LineStyle property of the border
' https://msdn.microsoft.com/en-us/library/office/ff821622.aspx
.Linestyle = xlContinuous
End With
End With
End With ' Ends the with block for the entire chart
This should not only clean up your code quite a bit and make it easier to debug, but I have had cases where an object I am working with doesn't update properly if I try to update it's properties outside of a with block. I am not sure if there is a reason for this or not, but I err on the side of using the With block just in case.
My problem is that I want to make many graph in one chart but the data is from different sheets.
At the moment my code can only take multi data from one sheet, meaning I can plot 2 graph from one sheet.
My code at the moment is:
Sub ChartSheet()
Dim ChartSheet1 As Chart
Set ChartSheet1 = Charts.Add
With ChartSheet1
.SetSourceData Source:=Sheets("Sheet1").Range("E12:E6232, Y12:Y6232")
.ChartType = xlLine
.HasTitle = True
.ChartTitle.Characters.Text = "Test Chart"
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "x"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "y"
End With
End Sub
What I want is to say:
.SetSourceData Source:=Sheets("Sheet1").Range("E12:E6232, Y12:Y6232")
.SetSourceData Source:=Sheets("Sheet2").Range("D12:E23")
.SetSourceData Source:=Sheets("Sheet3").Range("Y12:Y6232, G27:G496, H3:5977")
and so on..
But when I do this my code it only print the last line from .SetSoureData
Hope some of you can help me work around this, Many thank in advarnce :)
Update:
I found abit of a work around by looping but this is not my total answer
But here is my other code:
Sub MultiSheetPlot()
Dim cht As Chart, s As Series, xRng As Range
Dim i As Long, chartName As String
Set cht = Charts.Add
cht.ChartType = xlLine
For i = 1 To 3
chartName = "Sheet" & i
Set xRng = Sheets("Sheet1").Range("A1:A20, C1:C20")
With cht.SeriesCollection.NewSeries()
.Values = xRng
.Name = chartName
End With
Next i
End Sub
the problem in this code is that it ignores the last range I define like the C10:C20
Responding to your latest update, I have a Sub that creates a series each time it's called from MultiSheetPlot Sub.
You can actually add more parameters to this Sub (as long as you remeber to pass them in the Calling).
Option Explicit
Dim cht As Chart
Sub MultiSheetPlot()
Set cht = Charts.Add
cht.ChartType = xlLine
' call the series creation chart function (each time for each series you want to add to the existing chart
Call Create_SeriesChart("Sheet1", Sheets("Sheet1").Range("E12:E6232"), 1, True, msoThemeColorText1)
Call Create_SeriesChart("Sheet1", Sheets("Sheet1").Range("Y12:Y6232"), 1, True, msoThemeColorText1)
End Sub
' ------ this Sub creates a series to the chart, it receives the following parameters: ------
' 1. seriesName - String
' 2. serValues - Range
' 3. lineWeight - Double (the weight of the line)
' 4. lineVis - Boolean (if you want to hide a certail series)
' 5. lineColor - MsoColorType (using the current's PC Theme colors
Sub Create_SeriesChart(seriesName As String, serValues As Range, lineWeight As Double, lineVis As Boolean, lineColor As MsoColorType)
Dim Ser As Series
Set Ser = cht.SeriesCollection.NewSeries
With Ser
.Name = seriesName
.Values = serValues
.Format.Line.Weight = lineWeight
If lineVis = True Then
.Format.Line.Visible = msoTrue
Else
.Format.Line.Visible = msoFalse
End If
.Format.Line.ForeColor.ObjectThemeColor = lineColor ' Line color Black
End With
End Sub
My solution is use Name of plage, you can give a name of your range
Like in my photo :
Everytime when you want to use these datas you just need call them
Like this plage i gived them name Poste_EtatDeLaDemande
When i want to use these elements i just call it like Range("Poste_EtatDeLaDemande") Excel will find it you don't need tell them where it is anymore ; )
I am trying to create a dynamic chart that will change the data set with time, but I am stuck at the first step which is creating a simple chart with a certain limited number of points.
My x values and Y values are at rows 3 and 5.
The code I am trying to run is to create the chart in the same worksheet I am using:
Sub UpdateChart()
Dim ChtObj As ChartObject
Set ChtObj = ActiveSheet.ChartObjects("Bending Moment along " & ActiveSheet.Name) 'Adjust chart name to your chart
With ChtObj.Chart
.ChartType = x1XYScatterSmooth
.SetElement msoElementLegendNone
.Axes(xlValue).MinimumScale = 0
.Axes(xlValue).MaximumScale = 5
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "Bending moment"
.SeriesCollection(1).Values = Range("D3:H3")
.SeriesCollection(1).XValues = Range("D5:H5")
End With
End Sub
I am getting error run-time 5, invalid procedure call or argument? This happens at the line of: With ChtObj.Chart
You have a typo in the first line of the With statement. Hard to see, but there is a 1 instead of an l.It should be
.ChartType = xlXYScatterSmooth
I have to create almost 200 charts of time series. So I tried to write a macro that finishes most of the work I need to do.
I generated names for the time series like this as an example:
Name:= AKB_ExampleA
The name refers to a dynamic range which I declared with this formula:
=OFFSET('sheet1'!$C$7:$C$137;0;0;COUNT('sheet1'!$C$7:$C$206))
So now to the macro I coded so far:
Sub graphik_erstellen()
Call graphik1("AKB")
End Sub
Sub graphik(Name As String)
'
Dim Ch As Chart
Dim RngToCover As Range
Set Ch = charts.Add
Set Ch = Ch.Location(Where:=xlLocationAsObject, Name:="Charts")
With Ch
.ChartType = xlLine
.SetSourceData Source:=Range(Name & "_ExampleA")
.SeriesCollection(1).XValues = Range("Datum_Volumen")
.SeriesCollection(1).Name = "SERIES1"
.FullSeriesCollection(1).Select
With Selection.Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(192, 0, 0)
.Transparency = 0
End With
.HasTitle = True
.ChartTitle.Text = Name & ", Volumen (nach Korrektur)"
.HasLegend = True
.Legend.Position = xlLegendPositionBottom
.Legend.Select
Selection.Format.TextFrame2.TextRange.Font.Size = 11
Selection.Format.TextFrame2.TextRange.Font.Bold = msoTrue
With .Parent
.top = 100
.left = 100
.height = 287.149606299
.width = 543.685039370078
.Name = Name & "_chart"
End With
End With
End Sub
My problem is, that if I do that, the dynamic range is not really considered. It takes the range of the name (which is $C$7:$C$137) but it should refer to the name itself (in order to be dynamic).
So if I click on the chart to see the series, the series values are declared as: ='sheet1'!$C$7:$C$137 instead of ='sheet1'!ExampleA.
I would be really, really grateful if somebody could help me out.
Best
Elio
I have rearranged a few lines of code and tried to place comments refering to them as well.
Let me know what works. Youjust might need to change SeriesCollection to FullSeriesCollection. Other than that the code works in my Excel 2010.
The first Sub I just get the Range size according to the data available in Column "C" from Row 7.
Let me know.
Option Explicit
Sub graphik_erstellen()
'You always want to use direct reference to a sheet/range chart
'Refering to the WorkBook they are in and the worksheet as well.
'especially if you are opening multiple WorkBooks / Sheets
Dim CurrentWorkSheet As Worksheet
Set CurrentWorkSheet = Workbooks("Book1").Worksheets("Sheet1")
'Dynamically finding the end of the data in Column C
Dim LastRow As Long
LastRow = CurrentWorkSheet.Cells(CurrentWorkSheet.Rows.Count, "C").End(xlUp).Row
'Setting the range using the document reference aswell
Dim AKB As Range
Set AKB = Workbooks("Book1").Worksheets("Sheet1").Range(Cells(7, "C"), Cells(LastRow, "C"))
Call graphik(AKB)
End Sub
Sub graphik(Name As Range)
Dim DataChart As Chart
Dim RngToCover As Range
Set DataChart = Workbooks("Book1").Charts.Add
'With Excel 2010 the line above will automatically add the chart as a sheet and not aobject in a sheet
'Set DataChart = DataChart.Location(Where:=xlLocationAsObject, Name:="Charts")
With DataChart
.Name = "Charts" ' This will be the Name of the CHart Tab
.ChartType = xlLine
.SetSourceData Source:=Name
'You can see below I avoided the Select and Selection
With .SeriesCollection(1)
'Using Offset I just used the data one cell to the left of the range
.XValues = Name.Offset(0, -1)
.Name = "SERIES1"
With .Format.Line
.Visible = msoTrue
.ForeColor.RGB = RGB(192, 0, 0)
.Transparency = 0
End With
End With
.HasTitle = True
.ChartTitle.Text = "MIDDEL TOP TEXT" 'Name & ", Volumen (nach Korrektur)"
.HasLegend = True
With .Legend
.Position = xlLegendPositionBottom
.Format.TextFrame2.TextRange.Font.Size = 11
.Format.TextFrame2.TextRange.Font.Bold = msoTrue
End With
'Not sure about this, it doesnt work in my Excel 2010
'
With .Parent
.Top = 100
.Left = 100
.Height = 287.149606299
.Width = 543.685039370078
.Name = Name & "_chart"
End With
End With
End Sub
Let me know what your intention is for the Sheet and Chart names and then I can help with getting that to what you need as well.
I am writing a code that creates a pivot chart with a variable title based on the filter criteria chosen.
I am having trouble typing a formula into the .charttitle.characters.text format and having it auto update when a new filter is chosen in the pivot table.
Here is my code. As you can see, I am trying to relate the Chart title back to a cell that formulates based off of the pivot table. If there an easier way to code this, please let me know.
The Pivot Table filter is located in Sheet("Database Pivot").Range("B1") if that wasn't particularly clear.
Set objTable = ActiveSheet.PivotTables("SA Pivot Table")
Set objPivRange = objTable.TableRange1
Sheets("SA").Range("Z1").Formula = "=IF('Database Pivot'!$B$1=""(All)"", ""Since "" & TEXT('Database'!$L$2,""MM/DD/YYYY""), IF('Database Pivot'!$B$1=""(Multiple Items)"", ""For Selected Dates"", ""On "" & TEXT('Database Pivot'!$B$1,""MM/DD/YYYY"")))"
Set objChart = Charts.Add
With objChart
.HasTitle = True
.ChartTitle.Characters.Text = "=""Average WC Adherence "" & 'SA'!$Z$1"
.ChartType = xlColumnClustered
.Location xlLocationAsNewSheet, Name:="Adherence Chart"
.PlotBy = xlColumns
.SetSourceData objPivRange
With .Axes(xlValue, xlPrimary)
.HasTitle = True
.AxisTitle.Characters.Text = "% Adherence"
End With
With .Axes(xlCategory, xlPrimary)
.HasTitle = True
.AxisTitle.Characters.Text = "Work Center"
.TickLabels.Orientation = 90
.TickLabels.Font.Size = 7.5
End With
End With
I don't know why, but it appears that certain formulas and operators cannot be used in the formula of a dynamic Chart table. We know that a simple, single cell reference in a formula will work, like "='SA'!$Z$1".
Therefore, your best option would be to create the dynamic chart title in another cell, and then have the formula in your chart title reference the single cell containing your dynamic chart title. Below the line where you set the formula of cell Z1, add the following line
' I use Z2, use whatever cell you see fit
Sheets("SA").Range("Z2") = "Average WC Adherence " & Sheets("SA").Range("Z1")
Then update the chart title formula to reference cell
.ChartTitle.Caption = "='SA'!$Z$2"
Noticed I also changed .Characters.Text to .Caption, since the Caption property can detect if it should contain text or a formula