How can I print different charts for different data with Excel or VBA? - excel

I am trying to print one graph for each row/table, the graphs should keep the same format, only the data should change among graphs. I need to do it for about 120 rows/tables so I would like to avoid doing it manually, also, I would prefer not to use the sparklines as its format is not appropriate for the purpose of the analysis.
I have tried to use a dynamic chart with the combo button but when I change the filtered line, every copied graph changes as well, making it impossible to have at the same time graphs showing different rows - one solution may be pasting it as image but it is not optimal as I would like to check the data for each graph if needed.
Below I show the example for two different "items", in the original dataset there are about 350/400 rows and about 120 "items", every 3 rows create one graph.
The graphs I have created manually are: (one for each 3 rows)
for "item" xxx:
For "item" yyy:
I need to print this type of graph for other different ~120 "items", all at once.
In terms of showing the format of the chart, see the below for the first graph:
The blank is:
The second quartile is:
The third quartile:
and the "item", which is the black point in the graph:
Same reasoning for the second graph, but considering the three rows with yyy.
I hope you can help me!
Sorry for the big amount of images, but I wanted it to be clear!
Thank you in advance!
Best,
Ema

It is easy to create a typical procedure for creating a chart and use parameters to iterate over the sheet.
Sub makeCharts()
Dim Ws As Worksheet
Dim Cht As Chart, Shp As Shape
Dim obj As ChartObject
Dim Target As Range, rngShp As Range
Dim r As Long, n As Long, i As Long
Set Ws = ActiveSheet
For Each obj In Ws.ChartObjects
obj.Delete
Next
r = Ws.Range("a" & Rows.Count).End(xlUp).Row
n = 1
For i = 3 To r Step 3
Set rngShp = Ws.Range("k" & n).Resize(10, 8)
Set Target = Ws.Range("a" & i)
Set Shp = Ws.Shapes.AddChart
With Shp
.Top = rngShp.Top
.Left = rngShp.Left
.Width = rngShp.Width
.Height = rngShp.Height
End With
Set Cht = Shp.Chart
setCharts Target, Cht
n = n + 12
Next i
End Sub
Sub setCharts(Target As Range, Cht As Chart)
Dim Srs As Series
Dim vColor
Dim i As Integer
vColor = Array(RGB(246, 246, 246), RGB(255, 224, 140), RGB(47, 157, 39), RGB(0, 0, 0))
With Cht
.ChartType = xlColumnStacked
.HasLegend = False
.HasTitle = True
.ChartTitle.Text = Target.Value
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "OCF Percentiles"
.Axes(xlValue).MajorUnit = 20
For Each Srs In .SeriesCollection
Srs.Delete
Next Srs
For i = 0 To 2
Set Srs = .SeriesCollection.NewSeries
With Srs
.Values = Target.Offset(0, 1).Resize(3).Offset(0, i)
.XValues = Array("A", "D", "I")
.Format.Fill.ForeColor.RGB = vColor(i)
If i = 0 Then
.Format.Fill.Transparency = 1 '<~~~~~ Transparency was adjusted
End If
End With
Next i
Set Srs = .SeriesCollection.NewSeries
With Srs
.ChartType = xlXYScatter
.Values = Target.Offset(0, 4).Resize(1, 3)
.MarkerStyle = xlMarkerStyleSquare
.MarkerBackgroundColor = vColor(3) 'vbBlack
End With
End With
End Sub
Result image

Related

Create multiple charts from dynamic columns in a table

I would like to create a macro that runs through a series of data in a table and is able to automatically create multiple formatted graphs from it.
Here is what I'm working with (below):
Sub MakeXYGraph()
'https://stackoverflow.com/questions/62285791/dynamically-select-cells-and-input-in-chart
Dim ws As Worksheet
Set ws = Sheet1 'This is the codename of the sheet where the data is
'For the test, deleting all the previous charts
Dim vChartObject As ChartObject
For Each vChartObject In ws.ChartObjects
vChartObject.Delete
Next vChartObject
'rngData is the range where the data are. It is assumed that nothing else is on the sheet than what you displ
Dim rngData As Range
Set rngData = ws.UsedRange.Offset(1).Resize(ws.UsedRange.Rows.Count - 1)
' Get the number of series
Dim iMaxSeries As Integer
iMaxSeries = Application.WorksheetFunction.Max(rngData.Columns(1))
' Is the actual Series, but in the sheet it called Point
Dim iPoint As Integer
'Used for setting the ranges for the series data
Dim lFirstRow As Long, lLastRow As Long, lFirstColumn As Long, lLastColumn As Long
lFirstColumn = rngData(1).Column
lLastColumn = rngData.Columns(rngData.Columns.Count).Column
'Creating the Chart
Dim cht As ChartObject
Set cht = ws.ChartObjects.Add(Left:=250, Width:=500, Top:=50, Height:=300)
With cht.Chart
.ChartType = xlXYScatterLines
'X axis name
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Vertical Displacement"
'Y-axis name
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Vertical Coordinate"
' deleting the unwanted series (Excel tries to find out the data, but no need for it.)
Do Until .SeriesCollection.Count = 0
.SeriesCollection(1).Delete
Loop
End With
For iPoint = 1 To iMaxSeries
'Search for the first occurence of the point
lFirstRow = rngData.Columns(1).Offset(-1).Find(what:=iPoint).Row
'Search for the first occurence of the second point -1 is the last of this point
If iPoint = iMaxSeries Then
lLastRow = rngData.Rows(rngData.Rows.Count).Row - 1
Else
lLastRow = rngData.Columns(1).Find(what:=iPoint + 1).Row - 1
End If
'Add the series
With cht.Chart.SeriesCollection.NewSeries
.XValues = ws.Range(Cells(lFirstRow, lFirstColumn + 1), Cells(lLastRow, lLastColumn - 1))
.Values = ws.Range(Cells(lFirstRow, lFirstColumn + 2), Cells(lLastRow, lLastColumn))
.Name = "Point " & CStr(iPoint)
End With
Next iPoint
End Sub
Which plots the vertical coordinate vs. vertical displacement columns from this table:
To create this graph:
However, as you can see from the image with the table, I have multiple columns, and I would like to like to make graphs for several columns, all with the same format as the vertical coordinate vs. vertical displacement chart above, without interfering with the previous charts created. For example, the second graph that I would like to create is vertical coordinate vs. vertical stress. There is additional data on this worksheet, so one cannot just assume that the rest of the worksheet is blank.
One issue is that as you can see there are four different point numbers (1,2,3,4) and each point number is iterated 9 times. However, these numbers can change (for example there could be 8 Point numbers with three iterations each, and thus the data is dynamic and shouldn't just consider 4 Point No.'s with 9 iterations). And the table data will always be located starting from cell "C8". The current code deals with this.
The reason why the current code doesn't satisfy this is because it assumes that there is no other data on the worksheet where the table is (but there is). I want to be able to add more columns and create more charts (all of them plotted against vertical coordinate column) without affecting the other charts. Please if there is any way to modify the code so then I could create charts for several sets of data on the same worksheet then that would be much appreciated! I'm not sure what the best way to approach this is. Thank you.
https://drive.google.com/file/d/1cuW2eWYwrkNeJ-TmatiC4-PFodflNbSN/view?usp=sharing
Here's one approach:
Sub MakeXYGraph()
Const PLOT_HEIGHT As Long = 200
Const PLOT_WIDTH As Long = 300
Dim ws As Worksheet
Dim cht As ChartObject
Dim rngData As Range, rngHeaders As Range
Dim col As Long, posTop As Long, posLeft As Long
Dim ptRanges As Object, pt, dataRows As Range, i As Long
Set ws = Sheet1 'This is the codename of the sheet where the data is
For i = ws.ChartObjects.Count To 1 Step -1
ws.ChartObjects(i).Delete
Next i
Set rngData = ws.Range("C7").CurrentRegion
Set rngHeaders = rngData.Rows(1) 'the header row
Set rngData = rngData.Offset(1, 0).Resize(rngData.Rows.Count - 1) 'just the data
Set ptRanges = PointRanges(rngData.Columns(1))
posTop = ws.Range("M2").Top
posLeft = ws.Range("M2").Left
For col = 3 To rngData.Columns.Count
'add the chart
Set cht = NewChart(ws, posLeft, PLOT_WIDTH, posTop, PLOT_HEIGHT, rngHeaders.Cells(col).Value)
'loop over the keys of the dictionary containing the point numbers and corresponding ranges
For Each pt In ptRanges
Set dataRows = ptRanges(pt).EntireRow
With cht.Chart.SeriesCollection.NewSeries
.XValues = dataRows.Columns(rngData.Columns(col).Column)
.Values = dataRows.Columns(rngData.Columns(2).Column)
.Name = "Point " & pt
End With
Next pt
posTop = posTop + PLOT_HEIGHT
Next col
End Sub
'Scan the "point No" column and collect unique values and
' corresponding ranges in a Scripting Dictionary object
' assumes data is sorted by point no
Function PointRanges(pointsRange As Range) As Object
Dim dict As Object, c As Range, p, rng As Range
Set dict = CreateObject("scripting.dictionary")
For Each c In pointsRange.Cells
p = c.Value
If Not dict.exists(p) Then
dict.Add p, c 'add the start cell
Else
Set dict(p) = dict(p).Resize(dict(p).Count + 1) 'resize to add this cell
End If
Next c
Set PointRanges = dict
End Function
'add a chart and do some initial configuration
Function NewChart(ws As Worksheet, L, W, T, H, yAxisName As String)
Dim cht As ChartObject
Set cht = ws.ChartObjects.Add(Left:=L, Width:=W, Top:=T, Height:=H)
With cht.Chart
.ChartType = xlXYScatterLines
.Axes(xlCategory, xlPrimary).HasTitle = True 'X axis name
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = yAxisName
.Axes(xlValue, xlPrimary).HasTitle = True 'Y-axis name
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Vertical Coordinate"
.Axes(xlValue, xlPrimary).ReversePlotOrder = True
Do While .SeriesCollection.Count > 0
.SeriesCollection(1).Delete
Loop
End With
Set NewChart = cht
End Function

Missing portion of the graph in VBA when 2 or more separate graphs are plotted when same data are used

When I plot my chart using one set of data(current 1), the graph shows the correct output. However when I plot 2 sets of data concurrently(current 1 and current 2), part of the graph is missing(circled in red) for both data consisting of current 1 and current 2. Btw the data are the same for both scenarios and no data are missing. As my data for them is huge, I can only show you the part of my data sample which looks like this as shown below for current 1 and current 2. I know the code for plotting graph of current1 only contains a lot of variables that you all might deem as the one that causes problem so let me clarify that totalsample1 and myarray values should be correct as they are the ones responsible for the data(Like the one shown in data sample for current1) for plotting the graph for current and all data for plotting are present in this case. So what could be the code that causes this problem and how to remedy it?
Data sample for current 1
Data sample for current 2
1st update:add wsf to range and cells
2nd update: replaced activechart with cht1
3rd update: Remove from For i = 2 To totalsample1 Step 1 till all the cht1.series collection
4th update: I make a simpler version of my code to plot graph for current 1.
5th update: And using the code suggested by #Dy.Lee, the ideal graph for current 1 is as shown.
Private Sub addgraph_Vramp1()
Application.ScreenUpdating = False
Dim i As Long
Dim wf As Workbook
Set wf = ActiveWorkbook
Dim wsf As Worksheet
Set wsf = wf.Worksheets("current1")
Dim shp1 As Shape
Dim Cht1 As Chart
Set shp1 = wsf.Shapes.AddChart
Set Cht1 = shp1.Chart
wsf.Activate
With Cht1
Cht1.SetSourceData Source:=wsf.Range("A1:BQ750")
Cht1.ChartType = xlXYScatterSmoothNoMarkers
Cht1.Axes(xlValue).ScaleType = xlLogarithmic
Cht1.Axes(xlValue).MaximumScale = 0.001
Cht1.Axes(xlValue).MinimumScale = 0.000000000000001
End With
With Cht1
.Legend.Delete
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Voltage"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Current"
End With
changes to the graph for the current 1 after using updated codes
changes to the graph after removing cht1.series collection(it still remains in the updated code just to let other knows what is being removed here)
Ideal graph :))))
Caught wrong range
Cht1.SeriesCollection(i).XValues = wsf.Range(Cells(2, 2 * i - 1), wsf.Cells(myarray(i + 1), 2 * i - 1))
To
Cht1.SeriesCollection(i).XValues = wsf.Range(wsf.Cells(2, 2 * i - 1), wsf.Cells(myarray(i + 1), 2 * i - 1))
This is an example of creating a chart using a parameterized procedure.
Sub test()
Dim Ws As Worksheet
Dim Ws2 As Worksheet
Set Ws = Sheets("current1")
Set Ws2 = Sheets("current2")
addgraph_Vramp1 Ws
addgraph_Vramp1 Ws2
End Sub
Private Sub addgraph_Vramp1(Ws As Worksheet)
Dim i As Long, c As Long
Dim shp As Shape
Dim Cht As Chart
Dim rngDB As Range, rngX As Range, rngY As Range
Dim Srs As Series
Set rngDB = Ws.UsedRange
c = rngDB.Columns.Count
Set shp = Ws.Shapes.AddChart
Set Cht = shp.Chart
With Cht
.ChartType = xlXYScatterSmoothNoMarkers
.HasLegend = False
For Each Srs In .SeriesCollection
Srs.Delete
Next Srs
For i = 1 To c Step 2
With Ws
Set rngX = Ws.Range(.Cells(2, i), .Cells(2, i).End(xlDown))
Set rngY = rngX.Offset(, 1)
End With
Set Srs = .SeriesCollection.NewSeries
With Srs
.XValues = rngX
.Values = rngY
End With
Next i
.Axes(xlValue).ScaleType = xlLogarithmic
.Axes(xlValue).MaximumScale = 0.001
.Axes(xlValue).MinimumScale = 0.000000000000001
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Voltage"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Current"
End With
End Sub

Chart not showing data when selecting data with vba

I'm using VBA to update my chart. With VBA I select the data that should be shown in the chart. My code does select the data, but somehow my chart doesn't show anything. When I click on my chart end select "Select data" it does show selected data, bu somehow my chart is still empty. Because my chart is empty, the rest of my code doesn't work
My chart is a combo chart with both dataranges as bars, absolute on the primary axis and relative on the secondary axis.
Dim DataSite As Range
Dim DataAbsolute As Range
Dim DataRelative As Range
Set DataSite = Range(Cells(7, 1), Cells(7, 1).End(xlDown))
Set DataAbsolute = Range(Cells(7, 4), Cells(7, 4).End(xlDown))
Set DataRelative = Range(Cells(7, 5), Cells(7, 5).End(xlDown))
GraphsFrames.Select
For Each serie In cht.Chart.SeriesCollection
serie.Select
serie.Delete
Next serie
With cht.Chart
With .SeriesCollection.NewSeries
.XValues = DataSite
.Values = DataAbsolute
.Name = "Absolute"
.AxisGroup = 1
End With
With .SeriesCollection.NewSeries
.Values = DataRelative
.Name = "Relative"
.AxisGroup = 2
End With
.ChartGroups(1).GapWidth = 50
.ChartGroups(2).GapWidth = 300
.Refresh
End With
What can I do to make sure my chart shows the data selected?
Well, I don't know what GraphFrames is, so I ignored it. I made only minor adjustments to your code, below, and it worked just fine. I assume the data is on the active sheet, and so is the chart object you're adding data to.
Sub DoChartData()
Dim DataSite As Range
Dim DataAbsolute As Range
Dim DataRelative As Range
With ActiveSheet
Set DataSite = .Range(.Cells(7, 1), .Cells(7, 1).End(xlDown))
Set DataAbsolute = .Range(.Cells(7, 4), .Cells(7, 4).End(xlDown))
Set DataRelative = .Range(.Cells(7, 5), .Cells(7, 5).End(xlDown))
End With
Dim cht As ChartObject
Set cht = ActiveSheet.ChartObjects(1)
Dim serie As Series
For Each serie In cht.Chart.SeriesCollection
serie.Delete
Next serie
With cht.Chart
With .SeriesCollection.NewSeries
.XValues = DataSite
.Values = DataAbsolute
.Name = "Absolute"
.AxisGroup = 1
End With
With .SeriesCollection.NewSeries
.Values = DataRelative
.Name = "Relative"
.AxisGroup = 2
End With
.ChartGroups(1).GapWidth = 50
.ChartGroups(2).GapWidth = 300
End With
End Sub

How can I plot charts in excel at a predefined location, everytime I run a macro to plot the charts?

I need to plot charts at a predefined position in my worksheet when I run the macro to plot the charts. The problem is that the charts are automatically plotted in a weird manner and I don't like that. I want to make sure I can predefine the exact positions at which I want the charts to be plotted on running the macro. I have attached 2 images here, 1 image shows how it's currently plotted and the other shows how I want the charts to be plotted. Any kind of help would be highly appreciated.
This is how I want the charts to be shown on the sheet:
This is how it's currently showing up, with one pie chart overlapping the other and the line chart obscuring the macro buttons as well
This is the code I used, starting with the line chart, followed by the pie charts. I'm new to VBA and coding so please excuse the code structure.
' CHART Code
Dim chart As chart
Dim k As Integer
Dim p As Integer
Dim j As Integer
Dim arrDEM() As Long
Dim arrDATE() As Integer
ReDim arrDEM(1 To 65) As Long
ReDim arrDATE(1 To 65) As Integer
Dim DEM As Integer
j = findcell.Select
ActiveCell.Offset(0, 1).Select
For DEM = 1 To 65
arrDEM(DEM) = ActiveCell.Value
ActiveCell.Offset(0, 1).Select
Next DEM
Debug.Print arrDEM(65)
Range("B1").Activate
For p = 1 To 65
arrDATE(p) = ActiveCell.Value
ActiveCell.Offset(0, 1).Select
Next p
Debug.Print arrDATE(65)
Range("B31:B031") = arrDEM
Range("B31:B031").Select
Set cht1 = ActiveSheet.ChartObjects.Add(Left:=200, Width:=4500, Top:=200, Height:=4000)
ActiveSheet.Shapes.AddChart.Select
Set chart = ActiveChart
chart.ChartType = 4
chart.SeriesCollection(1).Name = x
chart.SeriesCollection(1).XValues = arrDATE
chart.SeriesCollection(1).Values = arrDEM
With ActiveChart
'chart name
.HasTitle = True
.ChartTitle.Characters.Text = "Demand Distribution"
'X axis name
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Weeks"
'y-axis name
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Demand"
'Copy chart from Original file
ActiveChart.ChartArea.Copy
'Paste chart in destination file
Worksheets("Model Calculations").Paste
'Deleting Charts
Worksheets("Sheet1").ChartObjects.Delete
'Activating destination chart
Worksheets("Model Calculations").Activate
Application.DisplayAlerts = False
End With
' PieC Macro
Range("C10:D11").Select
ActiveSheet.Shapes.AddChart2(262, xl3DPie).Select
ActiveChart.SetSourceData Source:=Range("'Model Calculations'!$C$10:$D$11")
With ActiveChart
'chart name
.HasTitle = True
.ChartTitle.Characters.Text = "Continuous Review"
' .Name = "Continuous Chart"
End With
' PieP Macro
'
Range("C10,D10,C12,D12").Select
ActiveSheet.Shapes.AddChart2(262, xl3DPie).Select
ActiveChart.SetSourceData Source:=Range("'Model Calculations'!$C$10,'Model Calculations'!$D$10,'Model Calculations'!$C$12,'Model Calculations'!$D$12")
With ActiveChart
'chart name
.HasTitle = True
.ChartTitle.Characters.Text = "Periodic Review"
'.Name = "Periodic Chart"
End With
End Sub
Your code could use some help in a number of ways. To answer your question, I'll ignore all that, and fix one piece of code. Here is what I'm replacing:
' PieC Macro
Range("C10:D11").Select
ActiveSheet.Shapes.AddChart2(262, xl3DPie).Select
ActiveChart.SetSourceData Source:=Range("'Model Calculations'!$C$10:$D$11")
With ActiveChart
'chart name
.HasTitle = True
.ChartTitle.Characters.Text = "Continuous Review"
' .Name = "Continuous Chart"
End With
I'll start by declaring and assigning a few variables, then create, populate, and position a chart.
Dim WkSht As Worksheet
Set WkSht = Worksheets("Model Calculations")
WkSht.Activate
Dim rChartData As Range
Set rChartData = WkSht.Range("C10:D11")
Dim rChartCover As Range
Set rChartCover = WkSht.Range("F10:K18")
Dim NewChart As Chart
Set NewChart = WkSht.Shapes.AddChart2(262, xl3DPie).Chart
With NewChart
.SetSourceData rChartData
With .Parent
.Left = rChartCover.Left
.Top = rChartCover.Top
.Width = rChartCover.Width
.Height = rChartCover.Height
End With
End With
You could replace this:
Set WkSht = Worksheets("Model Calculations")
WkSht.Activate
with this:
Set WkSht = ActiveSheet
to make it more general, and if you know the position and size of the resulting chart, you can plug those in instead of using the position and size of a given range (like I used rChartCover above).

plotting the wanted ranges in xyscatter graph with VBA

I am trying to create a xy plot where the x values is the time axis (column A) and the y values are in the other columns. (in the example only C and D)
When I try my code from below, I get a graph with time axis (so column A) and y values all the other columns (B, C, D, E,...) which is unwanted.
I can see that the .seriescollection(1) and (2) overwrite the default y-values (because my range is smaller), but all the others (column B, D, E,...) still remains in the graph.
Any thoughts why? Thanks in advance!
Sub grafieken()
'
' grafieken Macro
'
Dim sh As Worksheet
Dim chrt As Chart
Dim naaaam As String
naaam = ActiveWorkbook.ActiveSheet.Name
Set sh = ActiveWorkbook.Worksheets(naaam)
Set chrt = sh.Shapes.AddChart.Chart
With chrt
'Data?
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = sh.Range("$C$1")
.SeriesCollection(1).XValues = sh.Range("$A$2:$A$11")
.SeriesCollection(1).Values = sh.Range("$C$2:$C$11")
.SeriesCollection(2).Name = sh.Range("$D$1")
.SeriesCollection(2).XValues = sh.Range("$A$2:$A$11")
.SeriesCollection(2).Values = sh.Range("$D$2:$D$11")
'Titles?
.HasTitle = True
.ChartTitle.Characters.Text = naaam
End With
End Sub
Sub grafieken()
Dim MySh As Worksheet
Dim chrt As Chart
Dim naaaam As String
naaam = ActiveWorkbook.ActiveSheet.Name
Set MySh = ActiveWorkbook.Worksheets(naaam)
Set chrt = MySh.Shapes.AddChart.Chart
With chrt
'Data?
.SetSourceData Source:=Sheets(naaam).Range("A1:B11")
.ChartType = xlXYScatter
.SeriesCollection.Add Source:=ActiveSheet.Range("E1:E11")
'.SeriesCollection.NewSeries
.SeriesCollection(1).Name = ActiveSheet.Range("$C$1")
.SeriesCollection(1).XValues = ActiveSheet.Range("$A$2:$A$11")
.SeriesCollection(1).Values = ActiveSheet.Range("$C$2:$C$11")
'Titles?
.HasTitle = True
.ChartTitle.Characters.Text = naaam
End With
End Sub
I found a way, I first needed to define the source data for the first series, and change them later into the one I want, this way no unwanted series appears.

Resources