I am trying to create a chart that changes the data with time. The Y data are the same but only the X data are changed. I am using Application.Wait to allow for some time between each change in X values (So I can see it with my eye). However when I run the code its very laggy and I am not sure if I am using the Application.Wait function properly but I want between each change a time of 0.5 seconds. Is there a way to make it more smooth so that I can see the graph as it changes with time (as the code loops through the rows)
Here is my code:
Sub UpdateChart()
Dim ChtObj As ChartObject
Dim counter As Integer
Dim timecount As Double
Set ChtObj = ActiveSheet.ChartObjects.Add(200, 50, 500, 500)
'Creating intial graph
With ChtObj.Chart
'Chart Type
.ChartType = xlXYScatterSmooth
'Datainput
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "Bending moment"
.SeriesCollection(1).Values = Range("D3:H3")
.SeriesCollection(1).XValues = Application.Union(Cells(5, 4), Cells(5, 5), Cells(5, 6), Cells(5, 7), Cells(5, 8))
.HasLegend = False
'Title
.HasTitle = True
.ChartTitle.Text = "Bending moment along pile " & ActiveSheet.Name & " at time 0 seconds"
'X-Axis
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Bending moment (kN.m)"
'Y-Axis
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Length along pile (m)"
End With
'Loopingthrough data to be done**
counter = 6
timecount = 0
While (Not IsEmpty(Cells(counter, 4)))
'Pausing for half a second and recording cumulative time
timecount = timecount + 0.5
Application.Wait (Now() + TimeValue("0:00:005"))
'Updating Chart data
With ChtObj.Chart
.SeriesCollection(1).XValues = Application.Union(Cells(counter, 4), Cells(counter, 5), Cells(counter, 6), Cells(counter, 7), Cells(counter, 8))
.ChartTitle.Text = "Bending moment along pile " & ActiveSheet.Name & " at time " & timecount & " s"
End With
'Next row
counter = counter + 1
Wend
End Sub
This seemed to solve my problem:
Public Function PauseEvent(ByVal Delay As Double)
Dim dblEndTime As Double
dblEndTime = Timer + Delay
Do While Timer < dblEndTime
DoEvents
Loop
End Function
Related
My code should create one chart for every row of a data base. This data base is in a different sheet. Since that data base should change the number of columns I'm counting how many columns and changing the data source. Every time I run the code it comes with an error in the SetSourceData.
I couldn't find what am I doing wrong.
Can someone help me find a solution?
Sub createColumnChartMatriz12()
Dim ChartName As String
Dim Row As Integer
Dim ChartRow As Integer
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Matriz 1")
Dim k As Long
Dim z As Long
k = sh.Range("A1", sh.Range("A1").End(xlDown)).Rows.Count
z = sh.Cells(1, sh.Columns.Count).End(xlToLeft).Column - 4
ThisWorkbook.Sheets("Matriz1Chart").Select
Cells.Select
Selection.RowHeight = 15.5
Cells(1, 1).Select
ChartRow = 49
Row = 2
For Row = 2 To k
ChartName = "Utilização no Período " & sh.Cells(Row, 1).Value
ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
With ActiveChart
.SetSourceData Source:=sh.Range(Cells(Row, 4), Cells(Row, z)), _
PlotBy:=xlRows
.FullSeriesCollection(1).XValues = "='Matriz 1'!$D$1:$AM$1"
.Parent.Height = Range("A1:A15").Height
.Parent.Width = Range("A1:J1").Width
.Parent.Top = Range("A" & ChartRow).Top
.Parent.Left = Range("A" & ChartRow).Left
.HasTitle = True
.ChartTitle.Text = ChartName
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Meses"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Utilização"
.Axes(xlCategory, xlPrimary).TickLabels.NumberFormat = "mm-yyyy"
End With
ChartRow = ChartRow + 16
Next
End Sub
Not sure if this is your only problem, but when you access a Range by providing two cells (Cells are in fact also Ranges), you have to qualify these cells also.
Your statement sh.Range(Cells(Row, 4), Cells(Row, z)) tries to define a Range object of sheet "Matriz 1" (saved in variable sh), but Cells(Row, 4) refers to the active sheet. That makes the range itself invalid and causes the failure of the .SetSourceData command.
You should write sh.Range(sh.Cells(Row, 4), sh.Cells(Row, z)) instead. As a general advice: split the logic of such complicated command - it is much easier to debug and figure out what fails. In your case, first define the range, write it into a variable and after that assign it to the chart:
With ActiveChart
dim chartRange as Range
set chartRange = sh.Range(sh.Cells(Row, 4), sh.Cells(Row, z))
.SetSourceData Source:=chartRange, PlotBy:=xlRows
...
end with
or, if you prefer (but note the leading .)
With ActiveChart
dim chartRange as Range
with sh
set chartRange = .Range(.Cells(Row, 4), .Cells(Row, z))
end with
.SetSourceData Source:=chartRange, PlotBy:=xlRows
...
end with
I am trying to create a chart that will update its values automatically as time goes. The Y values of the data are constant while the X values are changing with time. My data is as follows:
Y data = 1 1.5 2 2.5 3
At time = 0 X data = 10 10 10 10 10
At time = 0.5 X data = 20 20 20 20 20
At time = 1.0 X data = 30 30 30 30 30
At time = 1.5 X data = 40 40 40 40 40
*NOTE MY X DATA ARE NOT CONSECUTIVE, THEY ARE IN 5 COLUMNS AS SHOWN ABOVE BUT NOT CONSECUTIVE COLUMNS.
This is what I have reached until now
Sub UpdateChart()
Dim ChtObj As ChartObject
Dim BM1 As Range, BM2 As Range, BM3 As Range, BM4 As Range, BM5 As Range
Set ChtObj = ActiveSheet.ChartObjects.Add(200, 150, 500, 500)
'Creating intial graph
With ChtObj.Chart
'Chart Type
.ChartType = xlXYScatterSmooth
'Datainput
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "Bending moment"
.SeriesCollection(1).Values = Range("D3:H3")
''How to do this .SeriesCollection(1).XValues = Range((Cells(5, 4), Cells(5, 6), Cells(5, 8), Cells(5, 10), Cells(5, 12))
.HasLegend = False
'Title
.HasTitle = True
.ChartTitle.Text = "Bending moment along pile " & ActiveSheet.Name
'X-Axis
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Bending moment (kN.m)"
'Y-Axis
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Length along pile (m)"
End With
'Loopingthrough data to be done**
End Sub
How can I enter the X data using Cells() function so I can incorporate that into the loop?
Your help is greatly appreciated!
My X data are not in continuous
To add a discontinuous range from the active sheet use
.SeriesCollection(1).XValues = Application.Union(Cells(5, 4), Cells(5, 6), Cells(5, 8), Cells(5, 10), Cells(5, 12))
I'm using VBA to graph data in a program I created in Excel 2010. I sent it to another computer, which has Excel 2013 instead, and I found that everything worked perfectly except for this graphing issue.
My code will create the graphs, and size them perfectly, but it won't actually graph any of the data points. In my code, I also add and delete series, and I notice that the number of series is correct on the side, but that the series didn't retain the custom names I gave them.
But here's the twist. When I right click on the chart and click "select data", all of the data immediately pops up, including all of my custom names for the series. I don't even go into select data or anything. The moment I click it, all of the values just pop up immediately.
Here is an imgur album of what it looks like before/after. Note that I do absolutely nothing other than right click and select the option "select data". It's like the data is already selected, but just doesn't show up until I click 'select data".
Why would Excel 2013 be doing this? How do I make these values actually show up via VBA methods? I'll add a sample of the graphing code I use below.
'Setting the range the chart will cover
Set rngChart = ActiveSheet.Range(Cells(Counter + 3, 4), Cells(Counter + 27, 10))
'Dimensioning the chart and choosing chart type
Set co = ActiveSheet.Shapes.AddChart(xlXYScatter, rngChart.Cells(1).Left, rngChart.Cells(1).Top, rngChart.Width, rngChart.Height)
Set cht = co.Chart
Set sc = cht.SeriesCollection
'Remove any default series
Do While sc.Count > 0
sc(1).Delete
Loop
'Setting chart data
'Series 1
With sc.NewSeries
.Name = "=Sheet1!$C$1"
.XValues = "=Sheet2!$A$2:$A$" & SimpleTracker + 1
.Values = "=Sheet2!$B$2:$B$" & SimpleTracker + 1
.MarkerSize = 3
.MarkerStyle = xlMarkerStyleCircle
End With
'Series 2
With sc.NewSeries
.Name = "=Sheet1!$B$1"
.XValues = "=Sheet1!$A$2:$A$" & Counter + 1
.Values = "=Sheet1!$B$2:$B$" & Counter + 1
.MarkerSize = 5
.MarkerStyle = xlMarkerStyleCircle
.MarkerBackgroundColorIndex = 10
.MarkerForegroundColorIndex = 10
End With
'Setting chart labels
With cht
.HasTitle = True
If n = 0 Then
.ChartTitle.Characters.Text = "Simple Fit - CFL Over Time"
ElseIf Range("I" & n) = "Regression Title" Then
.ChartTitle.Characters.Text = Range("J" & n).Text
Else
.ChartTitle.Characters.Text = "Simple Fit - CFL Over Time"
End If
.Axes(xlCategory, xlPrimary).HasTitle = True
If DayTracker = 1 Then
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Days)"
ElseIf HourTracker = 1 Then
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Hours)"
Else
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Minutes)"
End If
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "CFL"
.Axes(xlCategory).HasMajorGridlines = True
.Axes(xlCategory).HasMinorGridlines = True
End With
I also want to note that this code still works perfectly in Excel 2010, and that the graphing still works there. It just doesn't work in Excel 2013.
Thank you for reading! If you have any questions or need any clarification, just let me know.
Replace
With sc.NewSeries
with
With cht.SeriesCollection.NewSeries
I had the same issue in Excel 2013. I don't know why, but this solution works for me.
The short story is I wasn't able to replicate the misbehavior.
The long story: I assumed that your code was the body of a Sub, so I created a module that contained the following:
Sub DoItOriginal()
'Setting the range the chart will cover
Set rngChart = ActiveSheet.Range(Cells(Counter + 3, 4), Cells(Counter + 27, 10))
'Dimensioning the chart and choosing chart type
Set co = ActiveSheet.Shapes.AddChart(xlXYScatter, rngChart.Cells(1).Left, rngChart.Cells(1).Top, rngChart.Width, rngChart.Height)
Set cht = co.Chart
Set sc = cht.SeriesCollection
'Remove any default series
Do While sc.Count > 0
sc(1).Delete
Loop
'Setting chart data
'Series 1
With sc.NewSeries
.Name = "=Sheet1!$B$1"
.XValues = "=Sheet2!$A$2:$A$" & SimpleTracker + 1
.Values = "=Sheet2!$B$2:$B$" & SimpleTracker + 1
.MarkerSize = 3
.MarkerStyle = xlMarkerStyleCircle
End With
'Series 2
With sc.NewSeries
.Name = "=Sheet1!$B$1"
.XValues = "=Sheet1!$A$2:$A$" & Counter + 1
.Values = "=Sheet1!$B$2:$B$" & Counter + 1
.MarkerSize = 5
.MarkerStyle = xlMarkerStyleCircle
.MarkerBackgroundColorIndex = 10
.MarkerForegroundColorIndex = 10
End With
'Setting chart labels
With cht
.HasTitle = True
If n = 0 Then
.ChartTitle.Characters.Text = "Simple Fit - CFL Over Time"
ElseIf Range("I" & n) = "Regression Title" Then
.ChartTitle.Characters.Text = Range("J" & n).Text
Else
.ChartTitle.Characters.Text = "Simple Fit - CFL Over Time"
End If
.Axes(xlCategory, xlPrimary).HasTitle = True
If DayTracker = 1 Then
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Days)"
ElseIf HourTracker = 1 Then
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Hours)"
Else
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (Minutes)"
End If
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "CFL"
.Axes(xlCategory).HasMajorGridlines = True
.Axes(xlCategory).HasMinorGridlines = True
End With
End Sub
Next, I needed some data to work with, so in another module I wrote a data generator that populated Sheet1 and Sheet2. Here is the content of that module:
Option Explicit
Sub Setup()
SetupSheet "Sheet1", 5
SetupSheet "Sheet2", 2.5
End Sub
Sub SetupSheet(nm As String, divisor As Double)
Dim i As Long
With ThisWorkbook.Worksheets(nm)
.[A2].CurrentRegion.ClearContents
.[B1].Value = "Chart" & Right(nm, 1)
With .[A1]
For i = 1 To SimpleTracker
.Offset(i).Value = i
.Offset(i, 1).FormulaR1C1 = "=1-EXP(-RC[-1]/" & divisor & ")"
Next i
End With
End With
End Sub
I then executed Setup() from the VB Editor, and created a third worksheet and activated it.
Then I ran DoItOriginal() from the VB editor, and I did not observe the issue you described. It occurred to me that one possible explanation is that switching back to the Excel user interface from the VBE did something to hide the misbehavior, so I installed a button on the sheet and executed DoItOriginal from there, and still did not observe the behavior in 2010, 2011, or 2013.
On thing I noticed is the line
.Name = "=Sheet1!$B$1"
in the setup for Series 1 probably wants to refer to Sheet2.
Try the code above and see if you still observe the misbehavior. If you do and I don't that might be interesting. If you don't, then the puzzle is how does this arrangement differ from the context in which you do see the misbehavior. Since you didn't post that, I'll wait in suspense. -hth
Try adding
DoEvents
After adding each chart element, especially after adding each series.
This is my first time learning and working with VBA so bear with me please.
I've worked out this makeshift code to plot xvalues vs. y values and everything's great so far (I think). Now I'd like to create something that makes a second, third, fourth (and so on) graph using data that simply needs to shift down by 4 rows. Can someone help?!
Sub VOCChartMaker()
Sheets("HousevGarageCharts").Select
With ActiveSheet
.Shapes.AddChart.Select
With ActiveChart
.ChartType = xlXYScatter
.HasTitle = True
.ChartTitle.Text = "='Data'!$C$2"
Do Until ActiveChart.SeriesCollection.Count = 0
ActiveChart.SeriesCollection(1).Delete
Loop
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "='Data'!$A$2"
.SeriesCollection(1).XValues = "='Data'!$D$2:$BB$2"
.SeriesCollection(1).Values = "='Data'!$D$3:$BB$3"
.SeriesCollection(1).MarkerSize = 5
.SeriesCollection.NewSeries
.SeriesCollection(2).Name = "='Data'!$A$4"
.SeriesCollection(2).XValues = "='Data'!$D$4:$BB$4"
.SeriesCollection(2).Values = "='Data'!$D$5:$BB$5"
.SeriesCollection(2).MarkerSize = 5
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Garage"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "House"
End With
End With
End Sub
Thanks a bunch!
Megan
Instead of providing complete solution I add some key point+comments to part of your code. I think the rest will go easy after that.
Sub VOCChartMaker()
Sheets("HousevGarageCharts").Select
'>> we need a simple loop which will star here
Dim i As Byte '>>required declaration
For i=1 To 4 '>>for four charts
With ActiveSheet
.Shapes.AddChart.Select
With ActiveChart
.ChartType = xlXYScatter
.HasTitle = True
'>> title for every fourth row starting from 2nd
.ChartTitle.Text = "='Data'!$C$" & 2 + (i-1)*4
'>> as far as you create new chart you don't need it _
as there is nothing to delete
'Do Until ActiveChart.SeriesCollection.Count = 0
'ActiveChart.SeriesCollection(1).Delete
'Loop
'changes made to create chart series for every fourth row starting from 2nd
.SeriesCollection.NewSeries
.SeriesCollection(1).Name = "='Data'!$A$" & 2 + (i-1)*4
.SeriesCollection(1).XValues = "='Data'!$D$" & 2 + (i-1)*4 & ":$BB$" & 2 + (i-1)*4
.SeriesCollection(1).Values = "='Data'!$D$" & 3 + (i-1)*4 & ":$BB$" & 3 + (i-1)*4
.SeriesCollection(1).MarkerSize = 5
'>> change the second series accordingly on your own!!!!!
.SeriesCollection.NewSeries
.SeriesCollection(2).Name = "='Data'!$A$4"
.SeriesCollection(2).XValues = "='Data'!$D$4:$BB$4"
.SeriesCollection(2).Values = "='Data'!$D$5:$BB$5"
.SeriesCollection(2).MarkerSize = 5
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Garage"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "House"
End With
End With
Next i '>> the end of the loop
End Sub
I used Excel VBA to create a chart and I want to adjust the line color and x-axis interval.
Below is the code:
Sub add_cpu_chart(server_hostname, site)
On Error Resume Next
Dim rpt_site As String
rpt_site = site
Set tbl = ThisWorkbook.Sheets(server_hostname).ListObjects(1)
strTableName = tbl.Name
strTableRange = tbl.Range.Address
Dim m_s_name, m_e_name As Date
m_s_name = CDate(fromDateStr)
m_e_name = CDate(toDateStr)
'Create new embedded chart
Set shp = ThisWorkbook.Sheets(server_hostname).Shapes.AddChart
'Position Shape over range
shp.Top = 100
shp.Left = 200
With shp
With .Chart
'Specify source data and orientation
'.SetSourceData Source:=ActiveSheets.Range(Table1 & "[#All]"), _
'PlotBy:=xlRows
.SetSourceData Source:=ThisWorkbook.Sheets(server_hostname).Range(strTableName & "[#All]")
.ChartType = xlLineMarkers
.SetElement (msoElementChartTitleAboveChart)
.HasTitle = True
.ChartTitle.Text = "CPU Utilization of " & server_hostname & " in " & _
rpt_site & " (" & Format(m_s_name, "dd-Mmm") & " to " & Format(m_e_name, "dd-Mmm yyyy") & ")"
.ChartTitle.Font.Size = 14
'.ChartArea.Font.Size = 14
.Legend.Delete
.SetElement (msoElementPrimaryValueAxisTitleRotated)
.Axes(xlValue, xlPrimary).AxisTitle.Text = "CPU Utlization (%)"
.Axes(xlValue, xlPrimary).AxisTitle.Font.Size = 10
.Axes(xlValue).MinimumScale = 0
.Axes(xlValue).MinorUnit = 2
.Axes(xlValue).MaximumScale = 100
.Axes(xlValue).MajorUnit = 20
.Axes(xlValue).TickLabels.NumberFormat = "General"
.SetElement (msoElementPrimaryCategoryAxisTitleAdjacentToAxis)
.Axes(xlCategory, xlPrimary).AxisTitle.Text = "Date of the Month"
.Axes(xlCategory, xlPrimary).AxisTitle.Font.Size = 10
'.Axes(xlCategory).MajorUnit = 1
.Axes(xlCategory).TickLabels.NumberFormat = "d"
With .PlotArea.Format.Fill
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.150000006
.Transparency = 0
.Solid
End With
End With
End With
End Sub
I want to change the line color to red - as in excel 2003 - as well as change the data in interval separated by 2 days. Currently, the data is in the form 1,2,3,4... I want to display the data in the form 1,3 ,5....
In a line chart, the X axis' minimumscale, maximum scale, majorunit, and minorunit are meaningless. The X values are merely categories which have no interpreted numerical values even if the labels show numerals.
You should probably change to an XY chart, which will allow full control over the axis scale using minimumscale, maximum scale, majorunit, and minorunit. Of course, an XY chart allows the same formatting of series markers and lines as in a line chart, but the confusing terminology will live on forever.
If for some reason you decide to stick with a line chart, you can use
ActiveChart.Axes(xlCategory).TickLabelSpacing = 2