I would like to use a single range call within a for loop to add data series to a chart (XY line).
In my example, based on a users input to how many data series they want on a plot (1,2, or 3), ChartData(1), ChartData(2), and ChartData(3) as appropriate that would correspond to SeriesCollection(1), SeriesCollection(2), SeriesCollection(3).
Can't figure out what to use for the ranges.
Dim cb As ComboBox
Dim rge As range
Dim MyChart As Chart
Dim ChartData As range
Dim chartIndex As Integer
Dim ChartName(3) As String
Dim n As Long
Dim i As Long
Dim valid As Boolean: valid = True
m = Application.InputBox("Please enter the number of TML's to graph (1,2, or 3): ", "Select # of TML's", Type:=1)
For i = 1 To m
Set cb = TargetSheet.Shapes("ComboBox" & i).OLEFormat.Object.Object
Set rge = TargetSheet
If IsNumeric(m) And m <= 3 And m > 0 Then _
For a = 1 To m
chartIndex(a) = cb(a).ListIndex
For n = 3 To lastRowTarget2
Select Case chartIndex
Case n - 3
Set ChartData(a) = TargetSheet.range(TargetSheet.Cells(n, 5), TargetSheet.Cells(n, MyRange.Columns.Count - 2))
ChartName = TargetSheet.range("C" & n).Text
UserForm1.TextBox1.Value = TargetSheet.Cells(n, MyRange.Columns.Count).Value
UserForm1.TextBox2.Value = TargetSheet.Cells(n, MyRange.Columns.Count - 1).Value
UserForm1.TextBox3.Value = TargetSheet.Cells(n, 4)
End Select
Next n
Application.ScreenUpdating = False
Set MyChart = TargetSheet.Shapes.AddChart.Chart
With MyChart
.ChartType = xlLineMarkers
.HasTitle = True
.ChartTitle.Text = "Wall Thickness Trend based on Data Points"
.SeriesCollection.NewSeries
.SeriesCollection(a).Name = ChartName
.SeriesCollection(a).Values = ChartData
.SeriesCollection(a).XValues = TargetSheet.range(TargetSheet.Cells(1, 5), TargetSheet.Cells(1, MyRange.Columns.Count))
.SeriesCollection(a).Trendlines.Add Type:=xlLinear
.DisplayBlanksAs = xlInterpolated
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (dd-mm-yyyy)"
.Axes(xlValue).MinimumScale = 0
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Measured Wall Thickness (mm)"
.Legend.Delete
.Parent.Height = 350
.Parent.Width = 550
.Parent.Top = 100
.Parent.Left = 100
End With
Dim ser As Series
Set ser = MyChart.SeriesCollection(a)
ser.ErrorBar Direction:=xlY, Include:=xlErrorBarIncludeBoth, Type:=xlErrorBarTypeFixedValue, Amount:=1
Next a
Related
I have a VBA script that I use to generate multiple line charts in Excel. It used to include 2 series collections per chart (reading from 2 columns) but I since modified it for only one. However now I want it to do 2 series' again but want it to read both collections from the same column. Is this possible?
I've tried modifying the .SeriesCollection(2) to go to the next range further down the column. However this just returns an error 4001.
Sub CreateCharts()
Dim ws As Worksheet
Dim ch As Chart
Dim NumCharts As Integer, ChartName As String, ChartTitle As String, i As Integer
Set ws = Sheets("Charts")
NumCharts = WorksheetFunction.CountA(ws.Rows(2))
For i = 2 To NumCharts Step 1 '1 column of data per chart
ChartName = ws.Cells(2, i) '"chrt" & Range(Col1 & 2)
ChartTitle = ws.Cells(2, i) 'Range(Col1 & 2)
Set ch = Charts.Add
With ch
.ChartType = xlLine
.SetSourceData Source:=ws.Range(ws.Cells(3, i), ws.Cells(20, i)), _
PlotBy:=xlColumns 'range of data for each chart
.SeriesCollection(1).XValues = ws.Range("A3:A20") 'data range of line 1 (test data)
.SeriesCollection(2).XValues = ws.Range("A21:A38") 'data range of line 2 (Rw curve)
.Name = ChartName
.HasTitle = True
.ChartTitle.Characters.text = "#" & ws.Cells(2, i) '& " " & ws.Cells(1, i) 'remove title 'change to "ws.Cells(2, i)" to see titles
.ChartTitle.Left = 600
'HORiZONTAL X AXiS
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.text = "Frequency (Hz)"
.Axes(xlCategory).MajorTickMark = xlNone
.Axes(xlCategory).AxisBetweenCategories = False
.Axes(xlCategory).Border.LineStyle = None
'VERTiCAL Y AXiS
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.text = "Sound Reduction Index (dB)"
.Axes(xlValue).TickLabels.NumberFormat = "0"
.Axes(xlValue).MajorTickMark = xlNone
.Axes(xlValue).HasMajorGridlines = False
.Axes(xlValue).MinimumScale = 10 'minimum value on y
.Axes(xlValue).MaximumScale = 80 'maximum value on y
.Axes(xlValue).Border.LineStyle = None
'LEGEND
.HasLegend = False
'FONT SPECiFiCATiONS
.ChartArea.Format.TextFrame2.TextRange.Font.Size = 14
.ChartArea.Format.TextFrame2.TextRange.Font.Name = "Myriad Pro"
.ChartArea.Border.LineStyle = xlNone
'CHART POSiTiON, SiZE & COLOUR
.PlotArea.Format.Fill.ForeColor.RGB = RGB(242, 242, 242) 'grey background
.PlotArea.Top = 0
.PlotArea.Left = 20
.PlotArea.Height = 440
.PlotArea.Width = 420
'CHART LiNE COLOURS
.SeriesCollection(1).Border.Color = RGB(27, 117, 188) 'first line colour
'.SeriesCollection(2).Border.Color = RGB(0, 0, 0) 'second line colour
'.SeriesCollection(2).LineStyle = xlDashDot
End With
Next i
End Sub
Here is an image example of what I'm wanting to achieve.
Code is slightly modified and tested to work as far my understanding of the objective (to create one 2 series charts per column. 1st series Row 3-20 and 2nd series 21 to 38). Only issue with code was absence of SeriesCollection(2). It is modified to add necessary SeriesCollection and to delete if any automatically added series collection exist.
For i = 2 To NumCharts Step 1 '1 column of data per chart
ChartName = ws.Cells(2, i) '"chrt" & Range(Col1 & 2)
ChartTitle = ws.Cells(2, i) 'Range(Col1 & 2)
Set ch = Charts.Add
'Delete if any automatically added series exist
For x = ch.SeriesCollection.Count To 1 Step -1
ch.SeriesCollection(x).Delete
Next
With ch
.ChartType = xlLine
.SeriesCollection.Add ws.Range(ws.Cells(3, i), ws.Cells(20, i))
.SeriesCollection.Add ws.Range(ws.Cells(21, i), ws.Cells(38, i))
.SeriesCollection(1).XValues = ws.Range(ws.Cells(3, 1), ws.Cells(20, 1))
.SeriesCollection(2).XValues = ws.Range(ws.Cells(21, 1), ws.Cells(38, 1))
.Name = ChartName
I have a problem with my macro that creates chart, it works well when I step through but restarts my Excel when I run it normally. Tried various things, nothing works. It was originally part of other macro, but I isolated it to another sub, thinking it may help, but it still crashes when isolated.
Do you guys know what may be causing this?
EDIT1: There is no error information, the excel just restarts
EDIT2: The problem seems to be caused by this part of code:
.SetElement (msoElementChartTitleAboveChart)
.ChartTitle.Text = "Liczba Dni Promocji - Wykres"
.ChartTitle.Font.Bold = True
.ChartTitle.Font.Size = 16
This is the code:
Sub StworzWykres()
Application.ScreenUpdating = False
'Application.PrintCommunication = True
Dim ws As Worksheet
Dim pt As PivotTable
Dim chrt As Chart
Dim myRng As Range
Dim i As Integer
Dim j As Integer
Set ws = ThisWorkbook.Sheets("Raport_LiczbaDniPromocji")
Set pt = ws.PivotTables("LDP_Tab1")
'delete existing charts
Dim shp As Shape
For Each shp In ws.Shapes
shp.Delete
Next shp
Set shp = Nothing
'ask if make a chart
Application.ScreenUpdating = True
If MsgBox("Czy chcesz utworzyć wykres Liczby Dni Promocji?", vbYesNo, "Wykres") = vbNo Then
Exit Sub
End If
Application.ScreenUpdating = False
'adding the chart
'Set chrt = ws.Shapes.AddChart.Chart
Set myRng = ws.Range(Cells(19 + pt.RowRange.Rows.Count, 4), Cells(18 + 2 * (pt.RowRange.Rows.Count), 6))
myRng.Select
Set chrt = ws.Shapes.AddChart.Chart
'Set chrt = ws.ChartObjects.Add.Chart
'chrt.Activate
With chrt
'For j = .SeriesCollection.Count To 1 Step -1
' .SeriesCollection(j).Delete
'Next j
'.SetSourceData Source:=myRng, PlotBy:=xlColumns
.ChartType = xl3DColumnClustered
'.SetSourceData Source:=myRng, PlotBy:=xlColumns
.Parent.Name = "Wykres_LDP"
.DepthPercent = 400
.PlotArea.Format.ThreeD.RotationX = 0
.PlotArea.Format.ThreeD.RotationY = 110
.RightAngleAxes = True
.ChartArea.Left = ws.Range(Cells(1, 1), Cells(1, 6)).Width + 1 'ws.Cells(20 + pt.RowRange.Rows.Count, 8).Left - (ws.Columns(7).ColumnWidth / 1.25)
.ChartArea.Top = ws.Cells(18 + pt.RowRange.Rows.Count, 8).Top
.ChartArea.Height = ws.Range(Cells(19 + pt.RowRange.Rows.Count, 8), Cells(47 + pt.RowRange.Rows.Count, 8)).Height
.ChartArea.Width = 1000
.Parent.Placement = xlMove
.ChartColor = 10
.ChartGroups(1).GapWidth = 150
.SetElement (msoElementLegendBottom)
.Legend.Font.Size = 12
.Legend.Font.Bold = True
.SetElement (msoElementChartTitleAboveChart)
.ChartTitle.Text = "Liczba Dni Promocji - Wykres"
.ChartTitle.Font.Bold = True
.ChartTitle.Font.Size = 16
With .Axes(xlCategory, xlPrimary)
.TickLabels.Orientation = 60
'.TickLabels.Font.Bold = True
'.TickLabels.Font.Size = 11
End With
For j = .SeriesCollection.Count To 1 Step -1
.SeriesCollection(j).HasDataLabels = True
.SeriesCollection(j).DataLabels.Orientation = xlUpward
.SeriesCollection(j).DataLabels.Font.Bold = True
.SeriesCollection(j).DataLabels.Font.Size = 10
If j = 1 Then
.SeriesCollection(j).DataLabels.Font.ColorIndex = 32
Else
.SeriesCollection(j).DataLabels.Font.ColorIndex = 46
End If
Next j
'.SetSourceData Source:=myRng, PlotBy:=xlColumns
End With
'clear variables
Set ws = Nothing
Set pt = Nothing
Set myRng = Nothing
i = Empty
j = Empty
'Application.PrintCommunication = False
Application.ScreenUpdating = True
End Sub
Remove
.SetElement (msoElementChartTitleAboveChart)
and insert
.HasTitle = True
in the same place.
I have a chart that is composed of two main things.
The first is a loop that creates a bunch of series based on values. Each of these series is an XY Scatter with Lines. Each of these Lines is coloured based on conditions using the Vlookup function in Excel. The first thing I need to correct is the Case part because it doesn't like the first instance of G. This only occurs when I have added the second chart.
The next thing I want is to create an XY Scatter with another Range, then apply Custom Data Labels to only those points. I can change the type of Chart the Series plots by using the answer below, which has been updated.
Dim age1 As Variant
Dim age2 As Variant
Dim per1 As Variant
Dim per2 As Variant
Dim id as Variant
Dim mp as Range
Dim yd as Range
id = Range(Range("A2"), Range("A2").End(xlDown)).Value2
age1 = Range(Range("C2"), Range("C2").End(xlDown)).Value2
age2 = Range(Range("D2"), Range("D2").End(xlDown)).Value2
per1 = Range(Range("E2"), Range("E2").End(xlDown)).Value2
per2 = Range(Range("E2"), Range("E2").End(xlDown)).Value2
Set mp = Range(Range("J2"), Range("J2").End(xlDown))
Set yd= Range(Range("E2"), Range("E2").End(xlDown))
ln = UBound(id) - LBound(id) + 1
Set cht = ws.ChartObjects(1).Chart
With cht
.ChartArea.ClearContents 'Clears the chart so a new one can be created
.ChartType = xlXYScatterLines 'Defines the Chart as a Scatter with Lines
For i = 1 To ln 'First Thing that creates many series
xdata = Array(age1(i, 1), age2(i, 1))
ydata = Array(per1(i, 1), per2(i, 1))
.SeriesCollection.NewSeries
.SeriesCollection(i).XValues = xdata
.SeriesCollection(i).Values = ydata
.SeriesCollection(i).Name = id(i, 1)
Next i
'Orginal method: .ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(.SeriesCollection.Count).XValues = mp
.SeriesCollection(.SeriesCollection.Count).Values = yd
.SeriesCollection(.SeriesCollection.Count).Name = "Series"
'New Method
.SeriesCollection(.SeriesCollection.Count).ChartType = xlXYScatter
End With
'end of creating charts
Set drng = Range(Range("A2"), Range("B2").End(xlDown) 'For the Vlookup
With ActiveSheet
For Each xycht In .ChartObjects
For Each mysrs In xycht.Chart.SeriesCollection
mysrs.MarkerStyle = xlMarkerStyleCircle
lnum = Application.VLookup(mysrs.Name, drng, 2, 0) 'This fails the first instance with G as a Type Mismatch Error.
' Select Case lnum
' Case "G"
' lColor = RGB(255, 0, 0)
' Case "D"
' lColor = RGB(0, 255, 0)
' Case "M"
' lColor = RGB(0, 0, 255)
' Case "A"
' lColor = RGB(0, 0, 0)
' Case Else
' lColor = RGB(255, 255, 255)
' End Select
' mysrs.MarkerBackgroundColor = lColor
' mysrs.Format.Line.Visible = msoFalse
' mysrs.Format.Line.Visible = msoTrue
' mysrs.Format.Line.ForeColor.RGB = lColor
Next
Set mypts = ws.ChartObjects(1).SeriesCollection(SeriesCollection.Count).Points(1).Apply 'This fails cause it needs an Object
mypts(mypts.Count).ApplyDataLabels
With mypts(mypts.Count).DataLabel
.ShowSeriesName = False
.ShowCategoryName = False
.ShowValue = False 'I need this tonot show Values, but my own Values.
' optional parameters
.Position = xlLabelPositionAbove
.Font.Name = "Helvetica"
.Font.Size = 10
.Font.Bold = False
End With
Next
End With
Use the ChartType property of the Series object...
.SeriesCollection(.SeriesCollection.Count).ChartType = xlXYScatter
I have created a Scatter Chart using VBA in excel.
The Y-Axis has a logarithmic scaling, as the values in my data ranges (300 data ranges with a few hundred thousand data points in each one) vary from 1 to 1E-10.
Is there a way to scale the Y axis automatically? As the maximum value can vary from chart to chart from 1 to 1E-5.
If not is there a way to round up to the nearest 1E-n? So I can scale my graph using the code below.
MyChart.Axes(xlValue).MaximumScale = "round up max value from my data range"
Thanks in advance
Charlie
For cond = 2 To wb.Worksheets.Count
Set ws = wb.Sheets(cond)
wsn = ws.Name
With ws
'Includes "Title" cell
Set ttl = .Cells(.Columns(1).Find(what:="Title", after:=Cells(1, 1)).Row, 1)
Set ttl2 = .Cells(ttl.Row, .UsedRange.Columns.Count)
Set rng1 = .Range(ttl, ttl2)
Set Data = .Cells(.Columns(1).Find(what:="*Pa)*", after:=Cells(1, 1)).Row + 2, 1)
Set Data2 = .Cells(.UsedRange.Rows.Count, .UsedRange.Columns.Count)
Set rng2 = .Range(Data, Data2)
myrng = Union(rng1, rng2).Address
End With
ws.Shapes.AddChart.Name = (wsn)
ws.Shapes(wsn).Chart.ChartType = xlXYScatterLinesNoMarkers
Set MyChart = ws.Shapes(wsn).Chart
MyChart.SetSourceData Source:=ws.Range(myrng), PlotBy:=xlColumns
MyChart.ApplyLayout (1)
MyChart.ChartTitle.Text = Title & " " & wsn
MyChart.Axes(xlValue, xlPrimary).AxisTitle.Text = "Pressure "
MyChart.Axes(xlCategory, xlPrimary).AxisTitle.Text = "Output”
MyChart.Axes(xlValue).ScaleType = xlLogarithmic
MyChart.Axes(xlValue).TickLabels.NumberFormat = "0.0E+00"
MyChart.Axes(xlValue).CrossesAt = 0.000000001
MyChart.Axes(xlValue).MaximumScale = “needs automating”
MyChart.Axes(xlCategory).ScaleType = xlLogarithmic
MyChart.Axes(xlCategory).MaximumScale = 10000
ws.ChartObjects(wsn).Left = ws.Range("A1").Left
ws.ChartObjects(wsn).Top = ws.Range("A1").Top
ws.ChartObjects(wsn).Height = 400
ws.ChartObjects(wsn).Width = 1200
MyChart.Axes(xlCategory, xlPrimary).HasMajorGridlines = True
MyChart.Axes(xlCategory, xlPrimary).HasMinorGridlines = True
ws.ChartObjects(wsn).Chart.Legend.Left = 1000
ws.ChartObjects(wsn).Chart.Legend.Width = 190
ws.ChartObjects(wsn).Chart.Legend.Top = 17.5
ws.ChartObjects(wsn).Chart.Legend.Height = 360
ws.ChartObjects(wsn).Chart.PlotArea.Width = 975
Next cond
I haven't tried this, but what about:
With MyChart.Axes(xlValue)
.MinimumScaleIsAuto = True
.MaximumScaleIsAuto = True
End With
I'm trying to place two chart objects on a single sheet and encountering difficulties with Excel 2010.
My code was working fine with a single chart object but when I added an additional chart: the chart type, title and other attributes are not registering up on the second chart.
The two charts should have the same structure but reference a different column on the sheet. I've looked around but couldn’t find a solution. Please suggest how to fix this problem. I’m posting partial code only but can post the rest of the code if it's helpful. Sorry if the code is too long...
I really appreciate your help.
Function GraphMFI(Arr() As Variant, Arr2() As Variant, ChartName As String, ChartName2 As String)
Dim i As Long, l As Long
Dim rng As Range, aCell As Range
Dim MyArY() As Variant, MyArX() As Variant
Dim LastRow As Long, iVal As Long
Dim Count As Long, SumArr As Long, AvgC As Long
Application.EnableEvents = False
'***********************************************************************
'Code that calculates x and y values not shown
'**************************************************************************
On Error Resume Next
'~~~~~~~~~chart code begins
Call DeleteallCharts 'delete all existing charts from active sheet
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~add both charts~~~~~~
Set objChart = ActiveSheet.ChartObjects.Add _
(Left:=410, Width:=500, Top:=15, Height:=250)
objChart.Chart.ChartType = xlXYScatterLines
Set objChart2 = ActiveSheet.ChartObjects.Add _
(Left:=410, Width:=500, Top:=300, Height:=250)
objChart.Chart.ChartType = xlXYScatterLines
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~add both charts~~~~~~
Dim objChartSeriesColl As SeriesCollection
Dim objChartSeriesColl2 As SeriesCollection
Set objChartSeriesColl = objChart.Chart.SeriesCollection
Set objChartSeriesColl2 = objChart2.Chart.SeriesCollection
'delete all chart series
'~~~~~~~~~~~first chart
With objChartSeriesColl.NewSeries '~~~raw data
.Name = "Inner Run Variability"
.Values = Arr
.XValues = rng
.MarkerSize = 10
.
'code not shown
End With
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~First Chart
With objChartSeriesColl.NewSeries '~~~average series one
Dim nPts As Long
.Name = "Mean"
.Values = AvgArr '~~~~average of Negative control
.XValues = rng '~~~dates
'.AxisGroup = xlSecondary
.ChartType = xlXYScatterLinesNoMarkers
'With mySrs
nPts = .Points.Count
.Points(nPts).ApplyDataLabels _
Type:=xlDataLabelsShowValue, _
AutoText:=True, LegendKey:=False
.Points(nPts).DataLabel.Text = .Name
.Points(nPts).ApplyDataLabels Type:=xlDataLabelsShowValue, _
AutoText:=True, LegendKey:=False
With .DataLabels
.AutoScaleFont = False
.Font.Size = 10
.Font.ColorIndex = 3
.Position = xlLabelPositionAbove
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.Orientation = xlHorizontal
End With
'~~~~~~~~~~~~~~~~~~
End With
With objChartSeriesColl.NewSeries '~~plus two stdev series two
.Name = "plus 2 stdev"
.Values = TwoPlusSdtDevArr
.XValues = rng '~~~dates
End With
With objChartSeriesColl.NewSeries 'minus three stdev series three
.Name = "minus 2 stdev"
.Values = TwiceStdDevArr
.XValues = rng
.ChartType = xlXYScatterLinesNoMarkers
End With
'~~~~~~~~~~~Second chart
With objChartSeriesColl2.NewSeries '~~~raw data
.Name = "Inner Run Variability"
.Values = Arr2
.XValues = rng
.MarkerSize = 10
End With
'~~~~~adding series to the second chart
With objChartSeriesColl2.NewSeries '~~~average
Dim nPts2 As Long
.Name = "Mean"
.Values = AvgArr
.XValues = rng '~~~dates
.ChartType = xlXYScatterLinesNoMarkers
End With
'....more series not shown here
With objChart
.Axes(xlCategory).TickLabels.NumberFormat = "m/d/yyyy" 'changes Xaxis text format
.Axes(xlValue).TickLabels.NumberFormat = "General" 'changes Yaxis Text Format
.SetElement (msoElementChartTitleAboveChart) 'adds chart title above chart
.SetElement (msoElementPrimaryCategoryAxisTitleAdjacentToAxis) 'adds Xaxis title
.SetElement (msoElementPrimaryValueAxisTitleRotated) 'adds rotated Yaxis Title
.ChartTitle.Text = ChartName 'adds chart title above chart
.SetElement (msoElementLegendNone)
'~~~~~~~~~~~~set plot area
With .PlotArea
.Width = .Width / 2
.Height = .Height / 2
.Left = 16
.Top = 16
.Width = 450
End With
'~~~~~~~~~~~~~~~~
With .Axes(xlCategory, xlPrimary)
.AxisTitle.Text = "Run Dates" 'renames Xaxis title to "X Title"
.AxisTitle.Font.Bold = True
End With
With .Axes(xlValue, xlPrimary)
.AxisTitle.Text = "Sample Dates" 'renames Xaxis title to "X Title"
.AxisTitle.Text = "MFI Values" 'renames Yaxis title to "Y Title"
End With
.Axes(xlCategory).MinimumScale = ChartMin '~~adds min
.Axes(xlCategory).MaximumScale = ChartMax '~~ adds max
.Parent.Placement = xlFreeFloating
With .ChartArea.Format.Line
.Visible = msoCTrue
.Style = msoLineSingle
.Weight = 1
.ForeColor.RGB = RGB(255, 255, 255)
End With
End With
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'more code
End With
''''~~~~~~~~~~~~~Second Chart begins here
With objChart2
'..........
'code almost the same as 'with objChart'
Application.EnableEvents = True
End With
End Function