Thought provoking problem (for me at least). Normally when creating a chart you have your data and then use it to create the chart. If you then copy the chart to another workbook, the values on the chart stay the same but there is "no available" data source in the new workbook. I want to create a new chart which is the average of multiple copied charts. Is this possible in excel/vba?
I can't even try recording a macro and going from there as I don't know if its possible to "average" multiple charts.
EDIT : Been doing some more thinking and am thinking if it is possible to instead of extract data into a new sheet for each chart, is it possible to average data upon extraction. If on the chart you Right click -> select data, you can see the reference to the data in the original worksheet. Is it possible to average this and print just the outcome without having to store all the data? Would still be easier to directly average charts if possible!
EDIT 2: I have reworked my data template so that matching time series data ranges is no longer an issue. Also as per the comment on averages-of-averages, the data is all of equal weight and quantity so this should not be a problem. It literally just comes down to: is there a way to take the face values of multiple charts (or graphs), and average them to form a new chart (or graph) without massive data manipulation in the original (or new) workbook?
Bounty Summary (with round numbers): Looking for a quick'ish way in VBA to create a chart which is the average of multiple charts. I have 10 types of chart on 50 separate worksheets. I'm looking to create a summary sheet with 10 charts that average the data from the same respective chart on the other 50 sheets. The key difficulty is that this is a 'presentation Workbook that all charts are copied into, all the data for each chart is in a different workbook.
EDIT 4: Data is stored in multiple time series tables that are all side by side in a main data sheet. It appears to be at the moment (as per Scott's comment) that there is no way to directly manipulate and the most likely solution will be that of data extraction/manipulation. Search still continues though :)
I want to create a new chart which is the average of multiple copied charts. Is this possible in excel/vba?
It is possible but there is no magic formula for this task.
I would first iterate each workbook, each worksheet, each shape and aggregate the values in an array, with one array for each type of chart.
To avoid storing all the data, the averages will have to be computed upon each extraction like this:
Average = ((PreviousAverage * N) + Value) / (N + 1)
Next, to expose the data in your dashboard, I would duplicate the missing charts from the aggregated workbooks and reuse the one already present.
This way, the customisation of the dashboard will remain untouched if all the charts are already there.
Finally, I would directly insert the aggregated values in the charts without storing them in a sheet.
I've assemble a working example that aggregates all the charts from the current workbook and displays the results in the sheet "Dashboard":
Sub AgregateCharts()
Dim ws As Worksheet, wsDashboard As Worksheet, sh As Shape, ch As chart
Dim xValues(), yValues(), yAverages(), weight&, key
Dim items As Scripting.dictionary, item As Scripting.dictionary
Set items = CreateObject("Scripting.Dictionary")
' define the dashboard sheet
Set wsDashboard = ThisWorkbook.sheets("Dashboard")
' disable events
Application.ScreenUpdating = False
Application.EnableEvents = False
' iterate worksheets '
For Each ws In ThisWorkbook.Worksheets
' if not dashboard '
If Not ws Is wsDashboard Then
' iterate shapes '
For Each sh In ws.Shapes
If sh.type = msoChart Then ' if type is chart '
Debug.Print "Agregate " & ws.name & "!" & sh.name
' check if that type of chart was previously handled
If Not items.Exists(sh.chart.chartType) Then
' extract the values from the first serie
xValues = sh.chart.SeriesCollection(1).xValues
yValues = sh.chart.SeriesCollection(1).values
' duplicate the chart if it doesn't exists in the dashboard
Set ch = FindChart(wsDashboard, sh.chart.chartType)
If ch Is Nothing Then
Set ch = DuplicateChart(sh.chart, wsDashboard)
End If
' store the data in a new item '
Set item = New Scripting.dictionary
item.Add "Chart", ch
item.Add "Weight", 1 ' number of charts used to compute the averages
item.Add "XValues", xValues
item.Add "YAverages", yValues
items.Add ch.chartType, item ' add the item to the collection '
Else
' retreive the item for the type of chart '
Set item = items(sh.chart.chartType)
weight = item("Weight")
yAverages = item("YAverages")
' update the averages : ((previous * count) + value) / (count + 1) '
yValues = sh.chart.SeriesCollection(1).values
UpdateAverages yAverages, weight, yValues
' save the results '
item("YAverages") = yAverages
item("Weight") = weight + 1
End If
End If
Next
End If
Next
' Fill the data for each chart in the dashboard
For Each key In items
Set item = items(key)
Set ch = item("Chart")
' Add the computed averages to the chart
ch.SeriesCollection(1).xValues = "={" & Join(item("XValues"), ";") & "}"
ch.SeriesCollection(1).values = "={" & Join(item("YAverages"), ";") & "}"
Next
' restore events
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Private Sub UpdateAverages(averages(), weight&, values())
Dim i&
For i = LBound(averages) To UBound(averages)
averages(i) = (averages(i) * weight + values(i)) / (weight + 1)
Next
End Sub
Private Function DuplicateChart(ByVal source As chart, target As Worksheet) As chart
' clone the chart to the target
source.Parent.Copy
target.Paste
Application.CutCopyMode = 0
' clear the data '
With target.Shapes(target.Shapes.count).chart.SeriesCollection(1)
Set DuplicateChart = .Parent.Parent
.name = CStr(.name)
.xValues = "={0}"
.values = "={0}"
End With
End Function
Private Function FindChart(source As Worksheet, chartType As XlChartType) As chart
' iterate each shape in the worksheet to fin the corresponding type
Dim sh As Shape
For Each sh In source.Shapes
If sh.type = msoChart Then
If sh.chart.chartType = chartType Then
Set FindChart = sh.chart
Exit Function
End If
End If
Next
End Function
Some data manipulation will probably be necessary. However, you can do it all in memory (or in a hidden worksheet if you prefer).
To extract data from a chart, example code:
Sub chartTest()
Dim ch As ChartObject
Set ch = Worksheets(1).ChartObjects(1)
Dim nr As Variant, var As Variant, var 2 As Variant
nr = UBound(ch.Chart.SeriesCollection(1).Values)
' Paste the values back onto the sheet
Range(Cells(1, 1), Cells(nr, 1)) = Application.Transpose(ch.Chart.SeriesCollection(1).XValues)
Range(Cells(1, 2), Cells(nr, 2)) = Application.Transpose(ch.Chart.SeriesCollection(1).Values)
' Pull the values into a variable (will be in array format)
var = ch.Chart.SeriesCollection(1).XValues
var2 = ch.Chart.SeriesCollection(1).Values
' Retrieval example
For i = 1 To UBound(var)
Range("A" & i).Value = var(i)
Range("B" & i).Value = var2(i)
Next i
End Sub
Whether you use Chart or ChartObjects as a first stop seems to depend on how the chart is created. The code in this example worked for a chart created by right-clicking some data in a sheet and inserting the chart.
See the Chart.SeriesCollection and the Series Properties pages on MSDN for more information.
So basically, extract all the data from the charts using code similar to the above, compare them, and create a new chart based on this data.
Related
I have an Access Database with VBA that populates the series for simple chart objects and pastes them into a table into a table in a Word document.
Whenever a chart-object series contains more that five points, the paste fails with a 4065 error.
This error is:
This method or property is not available because the Clipboard is empty or not valid.
Charts with five or fewer points are successfully pasted into the Word document table with no error.
The chart object is required in the Word document. An image will not suffice. The client needs the ability to inspect and edit the chart data from Word.
The error always occurs when the Paste command is executed.
The source of the error is probably one of the following:
A corrupt Chart object
Something amiss with the destination cell in the Word table.
Incorrect usage of the Paste or PasteSpecial commands.
A combination of two or more of the above items.
An alternative to Paste or PasteSpecial should be used to add charts to a cell in a Word Table.
I can silence the 4065 error by placing an On Error Resume Next above the call to Paste.
On Error Resume Next
.Cell(TblRow, 2).Range.PasteSpecial Link:=False, _
DataType:=wdPasteEnhancedMetafile, _
Placement:=wdInLine, _
DisplayAsIcon:=False
This allows the Word document generation to complete.
Charts with 1 to 5 data points are pasted into the Word table without any problem.
Charts with more than 6 data points are not. The paste generates a 4065 error.
I am not sure why charts with six or more data points cause a 4065 error on the Paste.
What I am trying:
Inspected and queried the series in the Chart.ChartData.Workbook.ActiveSheet for charts with six or more data points. The series seem to be in good shape and no data is missing.
Adding some API calls to VBA to programmatically get the clipboard contents following the Paste. If the chart object from the clipboard is in tact, the problem lies with the Word table cell.
What I have tried thus far:
I tried a 3-second pause and a 5-second pause followed by a DoEvents after the Copy. This had no effect. Charts with 5 or fewer data points are pasted into the Word Table. Charts with more than 5 data points throw the 4065 error.
Added a method to inspect the data being added to the chart. Nothing looks suspicious. The data looks good.
I am interested to hear any recommendations or suggestions on this problem.
Source Code
The MS Word Document being generated uses another MS Word Document as a template. The template Word document contains a table that has ten charts. The ten charts are clustered bar (xlBarClustered) charts. The first template chart has a data series with 1 data point, the second template chart has a data series with 2 data points, etc. The tenth chart has a data series with ten data points.
The template charts are loaded into an array: chtArray.
' This sub initializes ChtArray. Each index corresponds to the number of rows in the chart
'------------------------------------------------------------------------------------------
Sub InitCharts()
Dim ProgCnt As Integer, ChrtCnt As Integer
ProgCnt = 0
ChrtCnt = 0
' Initialize an array of chart references to each chart in ChartTemplate.docx
'----------------------------------------------------------------------------
Do While ProgCnt < SrcDoc.InlineShapes.Count And ChrtCnt < MAXCHARTS
ProgCnt = ProgCnt + 1
If SrcDoc.InlineShapes(ProgCnt).Type = wdInlineShapeChart Then
ChrtCnt = ChrtCnt + 1
Set ChtArray(ChrtCnt) = SrcDoc.InlineShapes(ProgCnt).Chart
End If
Loop
End Sub
As the target Word Document is generated, the following code adds a copy of a chart from the template for the number of data points from the ChtArray and adds it to the target Word Document.
' This sub adds the charts and WrkGrp percentages to the table
'-------------------------------------------------------------
Sub AddChartsToTable(TblRowCnt)
Dim TblRow As Integer, DesTblRowCnt As Integer, clipFormats As Integer
Dim currentWorkGroup As Double
currentWorkGroup = rstFiltered.Fields("Work Group").Value
With tbl
For TblRow = 3 To TblRowCnt ' Header and column heads are in rows 1 and 2
' WorkGroup column formatting and value
'--------------------------------------
With .Cell(TblRow, 1).Range
'========================================================
' TODO: Remove the Q and WG
'========================================================
.Text = Format(rstFiltered![WrkGrpPct].Value, "##0%") & _
" Q" & CStr(rstFiltered![QNum].Value) & _
" WG:" & CStr(rstFiltered.Fields("Work Group").Value)
Select Case rstFiltered![WrkGrpPct].Value
Case Is >= 0.75
.Font.TextColor = ColorGreen
Case Is >= 0.6
.Font.TextColor = ColorGold
Case Else
.Font.TextColor = ColorRed
End Select
End With
currentWorkGroup = rstFiltered.Fields("Work Group").Value
DesTblRowCnt = GetNumChtPoints(rstFiltered![Work Group])
' Set reference to the only chart we're updating,
' the one in SrcDoc with the correct number of rows
'--------------------------------------------------
If ChtArray(DesTblRowCnt) Is Nothing Then
' TODO: Log the instance...
Else
Set Cht = ChtArray(DesTblRowCnt)
' Set Cht = NewChart()
Set Pts = Cht.SeriesCollection(1).Points
Set sht = Cht.ChartData.Workbook.ActiveSheet
' Inspect the chart series before setting the points.
InspectChartSeries
UpdateChartForWrkGrp DesTblRowCnt, TblRow
' Inspect the chart series after setting the points.
InspectChartSeries
' Paste the chart object into the Word table.
Cht.Copy
Pause 2
' Check the clipboard contents (Did the copy move the chart to the clipboard?)
On Error Resume Next
.Cell(TblRow, 2).Range.PasteSpecial Link:=False, _
DataType:=wdPasteEnhancedMetafile, _
Placement:=wdInLine, _
DisplayAsIcon:=False
End If
If TblRow < TblRowCnt Then tbl.Rows.Add
Next TblRow
End With
End Sub
The UpdateChartForGrp method sets the data for the newly added chart ad sets the color for each bar.
' This sub's purpose is to update the chart with the appropriate data point name and color.
' Called from AddChartsToTable
'------------------------------------------------------------------------------------------
Sub UpdateChartForWrkGrp(TotChtPts As Integer, TblRow As Integer)
Dim i As Integer
Dim ptCount As Integer
' Update the chart data itself
'-----------------------------
For i = 2 To TotChtPts + 1
sht.Range("A" & i) = rstFiltered!Department.Value
sht.Range("B" & i) = rstFiltered![DeptPct].Value ' Chart template cells formatted as a percentage already
' While we are updating chart, add Change data to the Word table
'---------------------------------------------------------------
tbl.Cell(TblRow, 3).Range.InsertBefore rstFiltered!Change.Value & IIf(i = 2, "", vbCr)
rstFiltered.MoveNext
Next i
Cht.Refresh
ptCount = 0
For Each Pt In Pts
Select Case Val(Pt.DataLabel.Caption) / 100
Case Is >= 0.75
Pt.Interior.Color = ColorGreen
Case Is >= 0.6
Pt.Interior.Color = ColorGold
Case Else
Pt.Interior.Color = ColorRed
End Select
ptCount = ptCount + 1
Next Pt
Debug.Print "UpdateChartForWrkGrp:ptCount = " & ptCount
Cht.Refresh ' just to be on the safe side
End Sub
Example Data
Data for the referenced `rstFiltered` Recordset are below.
Work Group
Department
DeptPct
Change
1
A
0.7
0.05
1
B
0.6
0.07
1
C
0.8
0.00
1
D
0.4
0.00
1
E
0.9
0.10
1
F
0.8
0.05
I'm trying to combine a Excel Pivot Table Slicer to control multiple pivot tables form different data tables.
I've found a function do detect and record the Slicer's active selection:
Public Function SlicerSelections(Slicer_Name As String)
FblSlicerSelections = ""
Dim i As Integer
With ActiveWorkbook.SlicerCaches(Slicer_Name)
For i = 1 To .SlicerItems.Count
If .SlicerItems(i).Selected Then
SlicerSelections = SlicerSelections & " " & .SlicerItems(i).Value
End If
Next i
End With
End Function
Now I want to use the results of these function to alter the pivot fields of others pivot tables.
All the pivot tables shares a number of common fields, like primaries keys.
I've already tried to create a single query to combine all the data into a single table, so I could use Slicers to navigate trough the data in different pivot tables, but, as the unique queries has different number of registers for a single set of primary keys, the end result was messy.
How can I use the results of SlicerSelections function to alter the filter parameters (pivot fields) of a Pivot Table and refresh it, so I can use the first pivot table slicer and a macro to command all the pivot tables within a spreadsheet?
Thank you all.
Well, things didn't go as smooth as I imagine.
The procedure works very well with a static data base. I mean, of I don't change the original data sets.
But the data sets have to change, because the data tables will be fulfilled by a query.
First error that apear was the Run Time Error 5.
So I've researched a little bit and understood that the pivotcaches should be reseted in order to run the procedure multiple times.
I've found a code to do that, but now I'm facing the following error: Run time error 1004 - Application Defined or Objected Defined error.
Here is the codes:
Sub Atualiza_Din()
'Dim pvtf As PivotField
Call PivotCacheReset
' Definição das variáveis de controle
Set pvtf_Dias_cen = ActiveSheet.PivotTables("TDDias").PivotFields("Número")
Set pvtf_Dias_per = ActiveSheet.PivotTables("TDDias").PivotFields("PER_Nome")
Set pvtf_Dias_ref = ActiveSheet.PivotTables("TDDias").PivotFields("REF_Nome")
Set pvtf_Dias_tpu = ActiveSheet.PivotTables("TDDias").PivotFields("TPU_Nome")
Set pvtf_Dias_upr = ActiveSheet.PivotTables("TDDias").PivotFields("UPR_Nome")
Set pvtf_Prod_cen = ActiveSheet.PivotTables("TDProd").PivotFields("Número")
Set pvtf_Prod_per = ActiveSheet.PivotTables("TDProd").PivotFields("PER_Nome")
Set pvtf_Prod_ref = ActiveSheet.PivotTables("TDProd").PivotFields("REF_Nome")
Set pvtf_Prod_tpu = ActiveSheet.PivotTables("TDProd").PivotFields("TPU_Nome")
Set pvtf_Prod_upr = ActiveSheet.PivotTables("TDProd").PivotFields("UPR_Nome")
cen = SlicerSelections("SegmentaçãodeDados_Número1") 'Identifica o cenário selecionado
per = SlicerSelections("SegmentaçãodeDados_PER_Nome1") 'Identifica o período selecionado
ref = SlicerSelections("SegmentaçãodeDados_REF_Nome1") 'Identifica a refinaria selecionada
tpu = SlicerSelections("SegmentaçãodeDados_TPU_Nome1") 'Identifica o processo selecionado
upr = SlicerSelections("SegmentaçãodeDados_UPR_Nome1") 'Identifica a unidade selecionada
'MsgBox (ref)
pvtf_Dias_cen.CurrentPage = cen
pvtf_Dias_per.CurrentPage = per
pvtf_Dias_ref.CurrentPage = ref
pvtf_Dias_tpu.CurrentPage = tpu
pvtf_Dias_upr.CurrentPage = upr
pvtf_Prod_cen.CurrentPage = cen
pvtf_Prod_per.CurrentPage = per
pvtf_Prod_ref.CurrentPage = ref
pvtf_Prod_tpu.CurrentPage = tpu
pvtf_Prod_upr.CurrentPage = upr
End Sub
And here is the pivot cache reset:
Sub PivotCacheReset()
' When a data set is pivoted and then some of the underlying data is
' removed, even after a refresh old removed values can still remain in the
' pivot filter. This macro changes the properties of all pivot tables in
' the active workbook, to prevent missing items from appearing, or clear
' items that have appeared. It also resets all pivot table caches in the
' active workbook.
Dim wb As Workbook
Set wb = ActiveWorkbook
Dim iWs As Worksheet
Dim pvt As PivotTable
Dim iProtectState As Boolean
' Loop through each worksheet.
For Each iWs In wb.Worksheets
' If the worksheet is protected, unprotect it. Remember
' it was protected so that it can be re-protected later.
iProtectState = False ' Reset variable that remembers if each sheet is protected.
If iWs.ProtectContents = True Then
' Worksheet is protected.
iWs.Unprotect ' Unprotect the worksheet.
iProtectState = True ' Remember that this worksheet was protected.
End If
' Loop through each pivot table in the sheet.
For Each pvt In iWs.PivotTables
pvt.PivotCache.MissingItemsLimit = xlMissingItemsNone ' Don't allow missing items in the pivot table filters.
pvt.PivotCache.Refresh ' Reset the pivot table cache including any missing items.
Next pvt
' If the worksheet was originally protected, re-protect it.
If iProtectState = True Then iWs.Protect
Next iWs
End Sub
Where I'm making the mistake?
These are two different codes I am using to generate chart and do the calculation using two different buttons.
Code1: To generate charts, works okay
Private Sub CommandButton1_Click()
'PURPOSE: Create a chart (chart dimensions are required)
Dim rng As Range
Dim cht As ChartObject
'Your data range for the chart
Set rng = ActiveSheet.Range("A27:B113")
'Create a chart
Set cht = ActiveSheet.ChartObjects.Add( _
Left:=ActiveCell.Left, _
Width:=650, _
Top:=ActiveCell.Top, _
Height:=250)
'Give chart some data
cht.Chart.SetSourceData Source:=rng
'Determine the chart type
cht.Chart.ChartType = xlColumnClustered
End Sub
Code 2: To do the calculations
Sub GenerateCharts()
[D32].Value = "AA"
Range("D31").Formula = Application.WorksheetFunction.SumIf(Range("B27:B113"), ">=56") / Application.WorksheetFunction.Sum(Range("B27:B113"))
[H35].Value = "All Defects"
Range("I35").Formula = "=SUM(B27:B113)"
[H36].Value = "Percentage(%)"
Range("I36").Formula = "=(1-(I28/I29))*100"
[H28].Value = "Non Kaizens"
**Range("I28").Formula = Application.WorksheetFunction.SumIf(Range("'Machine 4th QTR’!V:V", "'Machine 4th QTR'!B:B","", "'Machine 4th QTR’!V:V'"), "<56"**)
End Sub
I have got two issues here.
1. Code 1 runs fine, coming to Code 2, all it does is it calculates the values.
When I run the Code 2, error is shown in the part in BOLD. The BOLD part translates the formula shown below into VBA code.
=SUMIFS('Machine 4th QTR'!V:V,'Machine 4th QTR'!B:B,"",'Machine 4th QTR'!V:V,"<56")
This is the error message displayed:
Wrong number of arguments or invalid propert assigment
I cannot figure out what is going wrong in the last piece (highlighted one).
Can I embed both the codes into one so that I can perform both the operations with only one click.
Change "" to """" or TEXT(,) and change "<56" to ""<56"". You need to double up quotes within quoted strings or use an alternative.
If you want the formula in the cell, use a string representing the formula, not an evaluation (aka result) of the WorksheetFunction.SumIfs formula.
You needed a SUMIFS, not a SUMIF.
You were using back-quotes (e.g. ’) not tick quotes (e.g. ') in some places.
Range("D31").Formula = "=SUMIF(B27:B113, "">=56"")/SUM(B27:B113)"
...
Range("I28").Formula = "=SUMIFS('Machine 4th QTR'!V:V, 'Machine 4th QTR'!B:B, TEXT(,), 'Machine 4th QTR'!V:V, ""<56"")"
I have data in excel sheet like this
Country Product Price
America A 43
China B 13
Germany C 21
Turkey D 12
In excel i select this data and make a chart out of it that seems like this
But the problem is when i select the same data with vba and draw the chart from vba then it results into
Now i want the vba chart to display to category axis as same as we select data from excel and draw the chart.
In short i want the vba chart to automatically adjust according to the data.
Here is the code.
Sub CreateChart()
Range("a1").Select
Selection.CurrentRegion.Select
myrange = Selection.Address
mysheetname = ActiveSheet.Name
Worksheets(1).Activate
'ActiveWindow.DisplayGridlines = False
' Add a chart to the active sheet.
ActiveSheet.ChartObjects.Add(125.25, 60, 301.5, 155.25).Select
Application.CutCopyMode = False
ActiveChart.ChartWizard _
Source:=Sheets(mysheetname).Range(myrange), _
Gallery:=xlColumnStacked, Format:=10, PlotBy:=xlRows, _
CategoryLabels:=1, SeriesLabels:=1, HasLegend:=1, _
Title:=charttitle, CategoryTitle:=chartcategory, _
ValueTitle:=chartvalue, ExtraTitle:=""
End Sub
It's very simple in Excel. Record a macro while inserting the chart and selecting the data for the chart. The recorder records the VBA steps and gives you the neat code which can do the same whenever you execute. For instance, the recorder gave me this 2 lines of code:
Sub Macro1()
ActiveSheet.Shapes.AddChart2(201, xlColumnClustered).Select
ActiveChart.SetSourceData Source:=Range("A2:C5"), PlotBy:=xlColumns
End Sub
Pretty simple, isn't it?
If you just wana to update data in already existing chart, better solution can be to update them. Basicaly create chart which you desire and assign some name to it. (for example myLovelyChart)
Sub updateChartSO()
Dim chartSheet As Worksheet
Set chartSheet = Sheets("testSheet")
Dim chtSerie As Series
With chartSheet
For Each chtSerie In .ChartObjects("myLovelyChart").SeriesCollection
'specify your values, can be specified by array or even from sheet'
chtSerie.Values = ""
chtSerie.XValues = ""
Next
End With
End Sub
Or if you really wana to create new chart, take a closer look at chartType property (https://msdn.microsoft.com/en-us/library/office/ff820803.aspx) and its enumeration (https://msdn.microsoft.com/en-us/library/office/ff838409.aspx)
In VBA, it auto define the format based on data range.
However, You can using below code to control it
Chart(1).PlotBy = xlRows
OR
Chart(1).PlotBy = xlColumns
I'm creating a ProcessBook display that populates an embedded Microsoft Office 11.0 Spreadsheet object (Office 2003) with a set of entries. I'm then calculating aggregate data about them; this aggregate data should not be visible in spreadsheet form onscreen, but does need to be used to generate a bar chart. The data is currently being used to populate a separate Microsoft Office 11.0 Spreadsheet object. It's organized such that the title of each bar chart is in column A and the corresponding value is in column B.
Since this is ProcessBook, I've had some difficulty even gaining access to embedded objects, but I've managed to embed and gain access to a ChartSpace object, as well as a child ChChart object. Unfortunately, I can't figure out how to either manually set the values of the bars or how to use the .SetData or .SetSpreadsheetData methods to point it to an object that I've populated.
Accessing the ChartSpace object is pretty straightforward: ThisDisplay.ChartSpace1
I can then add a Chart and access it fairly easily:
Dim objChart as ChChart
Set objChart = ThisDisplay.ChartSpace1.Charts.Add(0)
I can access my spreadsheet values pretty easily as well:
strBarName = ThisDisplay.sstChartData.Range("A2").Value
intBarVal = ThisDisplay.sstChartData.Range("B2").Value
How do I actually set the data source or manually set the values of the bars in the ChChart object? Alternatively, how do I use a different object to accomplish the same goal?
Apparently persistence is the key here. I managed to determine how to both add values manually and how to refer to the existing spreadsheet object. Both examples take heavily from the online ChChart documentation; I guess I was just tired when I attempted it in the first place and must have mistyped something somewhere.
Public Sub AddValuesToChartManually()
Dim objChart As ChChart
With ThisDisplay.ChartSpace1
Do While .Charts.Count > 0
ThisDisplay.ChartSpace1.Charts.Delete (0)
Loop
Set objChart = .Charts.Add
objChart.HasTitle = True
objChart.Title.Caption = "Chart Title"
objChart.Axes.Item(0).HasTitle = True
objChart.Axes.Item(1).HasTitle = True
objChart.Axes.Item(0).Title.Caption = "Axis 0"
objChart.Axes.Item(1).Title.Caption = "Axis 1"
objChart.HasLegend = False
Dim astrHeaders(0 To 4) As String
Dim aintValues1(0 To 4) As String
Dim aintValues2(0 To 4) As String
Dim astrSeries1(0) As String
Dim astrSeries2(0) As String
astrHeaders(0) = "AL1"
astrHeaders(1) = "AL2"
astrHeaders(2) = "AL3"
astrHeaders(3) = "AL4"
astrHeaders(4) = "AL5"
astrSeries(0) = "Series Name"
aintValues(0) = 1
aintValues(1) = 3
aintValues(2) = 17
aintValues(3) = 1
aintValues(4) = 7
objChart.Type = .Constants.chChartTypeColumnClustered
Call objChart.SetData(chDimSeriesName, .Constants.chDataLiteral, astrSeries)
Call objChart.SetData(chDimCategories, .Constants.chDataLiteral, astrHeaders)
Call objChart.SeriesCollection(0).SetData(.Constants.chDimValues, .Constants.chDataLiteral, aintValues)
End With
End Sub
Public Sub AddValuesFromSpreadsheet()
Dim objChart1 As ChChart
With ThisDisplay.ChartSpace1
Do While .Charts.Count > 0
ThisDisplay.ChartSpace1.Charts.Delete (0)
Loop
Set .DataSource = ThisDisplay.sstChartData
Set objChart1 = .Charts.Add
' Set the chart type.
objChart1.Type = .Constants.chChartTypeColumnClustered
' Display titles
objChart1.HasTitle = True
objChart1.Title.Caption = "Chart Title"
' Bind the series name to cell B1 in the first sheet of the spreadsheet
objChart1.SetData chDimSeriesNames, .Constants.chDataBound, "B1"
' Bind the category axis to cell A2:A28 in the first sheet of the spreadsheet.
objChart1.SetData chDimCategories, .Constants.chDataBound, "A2:A6"
' Bind the values of the data series to cells B2:B28 in the first sheet of the spreadsheet.
objChart1.SeriesCollection(0).SetData chDimValues, .Constants.chDataBound, "B2:B6"
End With
End Sub