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))
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 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
I wrote the following code to add a chart and position it on a worksheet with data on it:
Dim sh As Worksheet
Dim chrteit As Chart
lastrows = Range("A2").End(xlDown).Row
Set sh = ActiveWorkbook.Worksheets("TraceTable")
Set chrteit = sh.Shapes.AddChart.Chart
With chrteit
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).XValues = sh.Range(Cells(2, 6), Cells(lastrows, 6))
.SeriesCollection(1).Values = sh.Range(Cells(2, 7), Cells(lastrows, 7))
.HasTitle = True
.ChartTitle.Text = "EIT"
.Parent.Height = Range("N2:N14").Height
.Parent.Width = Range("N2:T2").Width
.Parent.top = Range("N2").top
.Parent.Left = Range("N2").Left
End With
The problem is, later in my module I have a macro that will an entire row between two data points if the two data points are different, and it is as follows:
Private Sub Dividers()
Dim DividerRange As Range, lastrow As Long, k As Integer, counter As Integer
lastrow = Range("C2").End(xlDown).Row
Set DividerRange = Range(Cells(2, 3), Cells(lastrow, 3))
counter = 0
For k = 2 To DividerRange.Count
If DividerRange(k + counter).Value <> DividerRange(k + counter - 1).Value Then
DividerRange(k + counter).EntireRow.Insert
counter = counter + 1
Else
End If
Next k
End Sub
By adding the entire row, it changes the height of my graph and it's position. I want it to be a fixed position, how can I do this? I would PREFER not to change the second code, but rather the first but let me know any solutions you guys have, Thanks!
Add this line to the first procedure:
chrteit.Placement = xlFreeFloating
This is the same as right-click, format chart area, properties: Don't move or size with cells.
|
Or you could place that method inside the With block, thusly:
With chrteit
.ChartType = xlXYScatter
.SeriesCollection.NewSeries
.SeriesCollection(1).XValues = sh.Range(Cells(2, 6), Cells(lastrows, 6))
.SeriesCollection(1).Values = sh.Range(Cells(2, 7), Cells(lastrows, 7))
.HasTitle = True
.ChartTitle.Text = "EIT"
.Parent.Height = Range("N2:N14").Height
.Parent.Width = Range("N2:T2").Width
.Parent.top = Range("N2").top
.Parent.Left = Range("N2").Left
.Placement = xlFreeFloating
End With
I'm attempting to create a chart using VBA in Excel 2010. I'm attempting to select data from another sheet in the same workbook. The data, however, is horizontal (and has to be kept that way), so I need to use the Cells() function to select the data for the chart.
However, it doesn't seem to be working, and I can't really find out why. I keep getting the error "Application-Defined or Object-Defined error" on any line that uses the Cells() function to define a range. However, if Cells() is used to reference a single cell, it works fine.
Can Range(Cells(x, y), Cells(z, w)) not be used in this case?
Here is the relevant code:
BinNumber = 2048
Worksheets("Graph One").Activate
Range("A1").Select
'Setting the range the chart will cover
Set rngChart = ActiveSheet.Range("H2:U26")
'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
'Graphing Data
With cht.SeriesCollection.NewSeries
.Name = Worksheets("Transposed Data").Cells(3, 1)
.XValues = Worksheets("Transposed Data").Range(Cells(2, 5), Cells(2, BinNumber + 4))
.Values = Worksheets("Transposed Data").Range(Cells(3, 5), Cells(3, BinNumber + 4))
.MarkerSize = 4
.MarkerStyle = xlMarkerStyleCircle
End With
'Setting chart labels
With cht
.HasTitle = True
.ChartTitle.Characters.Text = "Counts per energy level"
.Axes(xlCategory, xlPrimary).HasTitle = True
.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Energy (keV)"
.Axes(xlValue, xlPrimary).HasTitle = True
.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Counts"
.Axes(xlCategory).HasMajorGridlines = True
.Axes(xlCategory).HasMinorGridlines = True
End With
The code stops when it tries to set the x and y values under the Graphing Data header.
Just to single it out, I'll include it again below.
'Graphing Data
With cht.SeriesCollection.NewSeries
.Name = Worksheets("Transposed Data").Cells(3, 1)
.XValues = Worksheets("Transposed Data").Range(Cells(2, 5), Cells(2, BinNumber + 4))
.Values = Worksheets("Transposed Data").Range(Cells(3, 5), Cells(3, BinNumber + 4))
.MarkerSize = 4
.MarkerStyle = xlMarkerStyleCircle
The data for the x-values is in range E2 to BZX2 and the data for the y-values is in range E3 to BZX3. Cell A3 just has the title for the chart.
However, if Cells() is used to reference a single cell, it works fine.
This is not exactly true.
The problem is that Cells(2, 5) always refers to the active worksheet, unless it is fully qualified. So in this line, the Cells method is qualified to an explicit worksheet reference, and no error should occur. This might be what you were seeing that it is a "single cell", but the distinction here is that it's fully qualified.
.Name = Worksheets("Transposed Data").Cells(3, 1)
This line will fail unless the "Transposed Data" sheet is active (not recommended) or you fully qualify the range.
.XValues = Worksheets("Transposed Data").Range(Cells(2, 5), Cells(2, BinNumber + 4))
This is equivalent to:
.XValues = Worksheets("Transposed Data").Range(ActiveSheet.Cells(2, 5), ActiveSheet.Cells(2, BinNumber + 4))
When we put it that way, it becomes more clearly a potential for error :)
Here is your code, restructured slightly. I will use a With block for the worksheet itself, and create a variable to represent the series:
Dim srs as Series
Set srs = cht.SeriesCollection.NewSeries
With Worksheets("Transposed Data")
srs.Name = .Cells(3, 1)
srs.XValues = .Range(.Cells(2, 5), .Cells(2, BinNumber + 4))
srs.Values = .Range(.Cells(3, 5), .Cells(3, BinNumber + 4))
srs.MarkerSize = 4
srs.MarkerStyle = xlMarkerStyleCircle
End With
So note the . preceding .Range and .Cells(... this makes these methods relate to the With Worksheets("Transposed Data").
I am trying to create a macro in VBA that will take a large data set in Sheet1 (called Raw Data) and create a XY scatter plot for every 8000 data points in another worksheet. The macro will also need to label each graph with what range it represents (ie 1-8000, 8001-16000 etc).
The large data set consists of temperature readings from 8 different thermocouples which record data every second. The number of data points will vary based on how long the experiment was run. The temperature values are stored in columns C through J and the time parameter is in column T.
What I have right now is a "batch" approach where the macro is set up to graph data in chunks of 8000 up to 32000 (4 different plots). This approach is not practical because the data set will almost always be significantly larger than 32000 points.
What I would like the macro to do is automatically graph and label every 8000 data points until there is no more data to graph.
I have been looking into using a loop but I am new to writing code and not sure how.
Any suggestions or help is greatly appreciated!
Here's some of my batch code:
'creates graph for first 8000 seconds in TC 1
Sheets("TC 1").Select
ActiveSheet.Shapes.AddChart.Select
ActiveChart.ChartType = xlXYScatterSmoothNoMarkers
ActiveChart.SeriesCollection.NewSeries
ActiveChart.SeriesCollection(1).Name = "='Raw Data'!$C$1"
ActiveChart.SeriesCollection(1).XValues = "='Raw Data'!$t$2:$t$8000"
ActiveChart.SeriesCollection(1).Values = "='Raw Data'!$C$2:$C$8000"
With ActiveChart
'X axis name
.axes(xlCategory, xlPrimary).HasTitle = True
.axes(xlCategory, xlPrimary).AxisTitle.Characters.Text = "Time (seconds)"
'y-axis name
.axes(xlValue, xlPrimary).HasTitle = True
.axes(xlValue, xlPrimary).AxisTitle.Characters.Text = "Temperature (F)"
'chart title
.HasTitle = True
.ChartTitle.Text = ("1-8000 seconds")
'adjusts the size/placement of graph and x-axis values
Set RngToCover = ActiveSheet.Range("A1:T25")
Set ChtOb = ActiveChart.Parent
ChtOb.Height = RngToCover.Height ' resize
ChtOb.Width = RngToCover.Width ' resize
ChtOb.Top = RngToCover.Top ' repositon
ChtOb.Left = RngToCover.Left ' reposition
ActiveChart.axes(xlCategory).Select
ActiveChart.axes(xlCategory).MinimumScale = 0
ActiveChart.axes(xlCategory).MaximumScale = 8000
End With
Here is what I came up with.
The macro calculates the total number of used rows, then divides that number by 8000.
The For...Next loop runs from 0 to the total rows divided by 8000.
Dim i As Integer
Dim j As Variant
Dim p As Integer
Dim start_row As Long
Dim end_row As Long
Dim RngToCover As Range
Dim ChtOb As ChartObject
i = Worksheets("Raw Data").UsedRange.Rows.Count
j = i / 8000
Sheets("TC 1").Activate
For p = 0 To j
start_row = (p * 8000) + 2
end_row = ((p + 1) * 8000) + 1
Set ChtOb = ActiveSheet.ChartObjects.Add(Left:=20, Width:=800, Top:=20, Height:=250)
ChtOb.Chart.ChartType = xlXYScatterSmoothNoMarkers
ChtOb.Activate
With ActiveChart.SeriesCollection.NewSeries
.Name = Worksheets("Raw Data").Cells(1, 3)
.XValues = Worksheets("Raw Data").Range(Worksheets("Raw Data").Cells(start_row, 20), Worksheets("Raw Data").Cells(end_row, 20))
.Values = Worksheets("Raw Data").Range(Worksheets("Raw Data").Cells(start_row, 3), Worksheets("Raw Data").Cells(end_row, 3))
End With
Next
It sounds like you already understand how to generate the charts for a given 8000 records. Below is a WHILE loop to keep running your export code until it finds an empty cell in the source column for the X-axis (column T).
Dim i As Integer
Dim ws As Worksheet
i = 2
Set ws = ThisWorkbook.Worksheets("Raw Data")
While ws.Cells(i, 20).Value <> ""
''' Create Chart for Next Data Set Starting at Row i (up to 8000 records)
i = i + 8000
Wend