Forum Discussion
I am trying to make a separate charts for each row on the same sheet.
I wrote a little VBA routine to take a chart that uses Y values in one row, and make a copy of the chart, use the next row for the Y values (and name if it uses a cell for the name), and repeat until the next row has no numeric values. Here's how it looks at the start:
Here is the code:
Sub DuplicateActiveChartOncePerRow()
If ActiveChart Is Nothing Then
MsgBox "Select a chart and try again!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
Dim nCharts As Long
nCharts = ActiveSheet.ChartObjects.Count
Dim OriginalChart As Chart
Set OriginalChart = ActiveChart
' SERIES formula
Dim sFormula As String
sFormula = OriginalChart.SeriesCollection(1).Formula
' formula arguments only
sFormula = Mid$(Left$(sFormula, Len(sFormula) - 1), InStr(sFormula, "(") + 1)
' array of arguments
Dim vFormula As Variant
vFormula = Split(sFormula, ",")
' series name - first argument
Dim sName As String
sName = vFormula(LBound(vFormula))
Dim rName As Range
On Error Resume Next
Set rName = Range(sName)
On Error GoTo 0
Dim bNameIsRange As Boolean
bNameIsRange = Not rName Is Nothing
' y values - third argument
Dim sYVals As String
sYVals = vFormula(LBound(vFormula) + 2)
Dim rYVals As Range
On Error Resume Next
Set rYVals = Range(sYVals)
On Error GoTo 0
If rYVals Is Nothing Then
MsgBox "Y Values Are Not in a Range!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
Dim iChart As Long
iChart = 1
Do
' loop until we run out of Y values
If WorksheetFunction.Count(rYVals.Offset(iChart)) = 0 Then
MsgBox "Finished!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
' make copy of original chart
OriginalChart.Parent.Copy
Do
' loop to avoid error because sometimes clipboard isn't ready to paste
DoEvents
On Error Resume Next
ActiveSheet.Paste
On Error GoTo 0
If ActiveSheet.ChartObjects.Count >= nCharts + iChart Then Exit Do
Loop
Dim NewChart As Chart
Set NewChart = ActiveSheet.ChartObjects(ActiveSheet.ChartObjects.Count).Chart
NewChart.Parent.Left = OriginalChart.Parent.Left
NewChart.Parent.Top = OriginalChart.Parent.Top + iChart * rYVals.Height
' change Y values and name in new chart
With NewChart.SeriesCollection(1)
.Values = rYVals.Offset(iChart)
If bNameIsRange Then
.Name = "=" & rName.Offset(iChart).Address(, , , True)
End If
End With
iChart = iChart + 1
Loop
ExitSub:
End Sub
And here is the end result:
Hello- I found this code very very helpful so thank you very much for sharing. I have modified it to include two data series. However, I am now struggling with adding a chart title. How can I make the chart title link to a column and change with each new chart generated per row? (As your posted code does but for two data series.) I can post my attempt below -
Sub DuplicateActiveChartOncePerRow()
If ActiveChart Is Nothing Then
MsgBox "Select a chart and try again!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
Dim nCharts As Long
nCharts = ActiveSheet.ChartObjects.Count
Dim OriginalChart As Chart
Set OriginalChart = ActiveChart
' SERIES formula
Dim sFormula As String
Dim sFormula2 As String
sFormula = OriginalChart.SeriesCollection(1).Formula
sFormula2 = OriginalChart.SeriesCollection(2).Formula
' formula arguments only
sFormula = Mid$(Left$(sFormula, Len(sFormula) - 1), InStr(sFormula, "(") + 1)
sFormula2 = Mid$(Left$(sFormula2, Len(sFormula2) - 1), InStr(sFormula2, "(") + 1)
' array of arguments
Dim vFormula As Variant
Dim vFormula2 As Variant
vFormula = Split(sFormula, ",")
vFormula2 = Split(sFormula2, ",")
' series name - first argument
Dim sName As String
sName = vFormula(LBound(vFormula))
Dim rName As Range
On Error Resume Next
Set rName = Range(sName)
On Error GoTo 0
Dim bNameIsRange As Boolean
bNameIsRange = Not rName Is Nothing
Dim sName2 As String
sName2 = vFormula2(LBound(vFormula2))
Dim rName2 As Range
On Error Resume Next
Set rName2 = Range(sName2)
On Error GoTo 0
Dim bNameIsRange2 As Boolean
bNameIsRange2 = Not rName2 Is Nothing
' y values - third argument
Dim sYVals As String
sYVals = vFormula(LBound(vFormula) + 2)
Dim rYVals As Range
On Error Resume Next
Set rYVals = Range(sYVals)
On Error GoTo 0
If rYVals Is Nothing Then
MsgBox "Y Values Are Not in a Range!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
Dim sYVals2 As String
sYVals2 = vFormula2(LBound(vFormula2) + 2)
Dim rYVals2 As Range
On Error Resume Next
Set rYVals2 = Range(sYVals2)
On Error GoTo 0
If rYVals2 Is Nothing Then
MsgBox "Y Values Are Not in a Range!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
Dim iChart As Long
iChart = 1
Do
' loop until we run out of Y values
If WorksheetFunction.Count(rYVals.Offset(iChart)) = 0 Then
MsgBox "Finished!", vbExclamation + vbOKOnly
GoTo ExitSub
End If
' make copy of original chart
OriginalChart.Parent.Copy
Do
' loop to avoid error because sometimes clipboard isn't ready to paste
DoEvents
On Error Resume Next
ActiveSheet.Paste
On Error GoTo 0
If ActiveSheet.ChartObjects.Count >= nCharts + iChart Then Exit Do
Loop
Dim NewChart As Chart
Set NewChart = ActiveSheet.ChartObjects(ActiveSheet.ChartObjects.Count).Chart
NewChart.Parent.Left = OriginalChart.Parent.Left
NewChart.Parent.Top = OriginalChart.Parent.Top + iChart * rYVals.Height
' change Y values and name in new chart
With NewChart.SeriesCollection(1)
.Values = rYVals.Offset(iChart)
If bNameIsRange Then
.Name = "=" & rName.Offset(iChart).Address(, , , True) & "!" & Cells(iChart, 3).Address(, , , True)
End If
End With
With NewChart.SeriesCollection(2)
.Values = rYVals2.Offset(iChart)
End With
iChart = iChart + 1
Loop
ExitSub:
End Sub
- JonPeltierMar 21, 2022MVP
Before
Dim iChart As Long
insert this block of code:
' chart title Dim sTitle As String sTitle = OriginalChart.ChartTitle.Formula sTitle = Mid$(sTitle, 2) ' trim leading = Dim rTitle As Range On Error Resume Next Set rTitle = Range(sTitle) On Error GoTo 0 Dim bTitleIsRange As Boolean bTitleIsRange = Not rTitle Is Nothing
then before
iChart = iChart + 1
insert this code:
If bTitleIsRange Then NewChart.ChartTitle.Formula = "=" & rTitle(Offset(iChart).Address(, , , True) End If
- jasper1984Mar 22, 2022Copper Contributor
JonPeltier - Thank you so much. I truly appreciate your help. Works perfectly, take care. Final code:
Sub DuplicateActiveChartOncePerRow() If ActiveChart Is Nothing Then MsgBox "Select a chart and try again!", vbExclamation + vbOKOnly GoTo ExitSub End If Dim nCharts As Long nCharts = ActiveSheet.ChartObjects.Count Dim OriginalChart As Chart Set OriginalChart = ActiveChart ' SERIES formula Dim sFormula As String Dim sFormula2 As String sFormula = OriginalChart.SeriesCollection(1).Formula sFormula2 = OriginalChart.SeriesCollection(2).Formula ' formula arguments only sFormula = Mid$(Left$(sFormula, Len(sFormula) - 1), InStr(sFormula, "(") + 1) sFormula2 = Mid$(Left$(sFormula2, Len(sFormula2) - 1), InStr(sFormula2, "(") + 1) ' array of arguments Dim vFormula As Variant Dim vFormula2 As Variant vFormula = Split(sFormula, ",") vFormula2 = Split(sFormula2, ",") ' y values - third argument Dim sYVals As String sYVals = vFormula(LBound(vFormula) + 2) Dim rYVals As Range On Error Resume Next Set rYVals = Range(sYVals) On Error GoTo 0 If rYVals Is Nothing Then MsgBox "Y Values Are Not in a Range!", vbExclamation + vbOKOnly GoTo ExitSub End If Dim sYVals2 As String sYVals2 = vFormula2(LBound(vFormula2) + 2) Dim rYVals2 As Range On Error Resume Next Set rYVals2 = Range(sYVals2) On Error GoTo 0 If rYVals2 Is Nothing Then MsgBox "Y Values Are Not in a Range!", vbExclamation + vbOKOnly GoTo ExitSub End If ' chart title Dim sTitle As String sTitle = OriginalChart.ChartTitle.Formula sTitle = Mid$(sTitle, 2) ' trim leading Dim rTitle As Range On Error Resume Next Set rTitle = Range(sTitle) On Error GoTo 0 Dim bTitleIsRange As Boolean bTitleIsRange = Not rTitle Is Nothing Dim iChart As Long iChart = 1 Do ' loop until we run out of Y values If WorksheetFunction.Count(rYVals.Offset(iChart)) = 0 Then MsgBox "Finished!", vbExclamation + vbOKOnly GoTo ExitSub End If ' make copy of original chart OriginalChart.Parent.Copy Do ' loop to avoid error because sometimes clipboard isn't ready to paste DoEvents On Error Resume Next ActiveSheet.Paste On Error GoTo 0 If ActiveSheet.ChartObjects.Count >= nCharts + iChart Then Exit Do Loop Dim NewChart As Chart Set NewChart = ActiveSheet.ChartObjects(ActiveSheet.ChartObjects.Count).Chart NewChart.Parent.Left = OriginalChart.Parent.Left NewChart.Parent.Top = OriginalChart.Parent.Top + iChart * rYVals.Height ' change Y values and name in new chart With NewChart.SeriesCollection(1) .Values = rYVals.Offset(iChart) End With With NewChart.SeriesCollection(2) .Values = rYVals2.Offset(iChart) End With If bTitleIsRange Then NewChart.ChartTitle.Formula = "=" & rTitle.Offset(iChart).Address(, , , True) End If iChart = iChart + 1 Loop ExitSub: End Sub