Filling a variant array with charts in Excel VBA - vba

I am working on a file that creates up to 120 charts based on data, variables, and format selections from the user. To do this I create a variant array to hold the charts which allows me to easily reference them for adding data, formatting, etc. This method has worked well for me so far.
Now I would like to let users make small tweaks to formatting (adjust the min and max on the axis, add or remove legend entries, etc.). To do this I would like to continue referencing the charts from an array, but I can't seem to add the existing charts to the variant array.
When I initially create the charts I use this line to add the chart to the array when it is created. I fill in appropriate parameters to place and size the chart and this seems to work fine.
Set charts(graphIndex) = activeSheet.ChartObjects.Add(...)
After creating all the charts, I think the non Global variables used are cleared from the cache (at least that is my current understanding). This means that in order to make these tweaks I need to reinitialize and redefine the variant array that I use to reference the charts. This is what I am struggling with. This is my current attempt to add the existing chart to the variant array.
charts(graphIndex) = Worksheets(activeSheetName).ChartObjects("chart name").Chart
When I run the code I am getting a "Run-time error '438': Object doesn't support property or method."
Hopefully I provided enough context, but any help on this would be greatly appreciated. This feels like it should be fairly easy, but I couldn't find any information online.

I am just guessing that in your code if you had the Set word it would have worked (However, I am not seeing the whole code, thus not sure).
This works, if you make sure to have 3 charts named "Diagramm 1", "Diagramm 2" and "Diagramm 3" on the first worksheet:
Option Explicit
Sub TestMe()
Dim cht2 As Chart
Dim varArray As Variant
With Worksheets(1)
Set cht2 = .ChartObjects("Diagramm 2").Chart
varArray = Array(.ChartObjects("Diagramm 1").Chart, cht2)
ReDim Preserve varArray(2)
Set varArray(2) = .ChartObjects("Diagramm 3").Chart
Dim cnt As Long
For cnt = LBound(varArray) To UBound(varArray)
Debug.Print varArray(cnt).Name
Next cnt
End With
End Sub
The Reedim Preserve increases the array units with one additional, while it keeps what it already has. Thus, at the end this is what we have in the locals:

Related

VBA extend range of chart by a variable stored in a cell

This is proper basic but I'm struggling here. I need the range of rows of a data source in a graph to extend or retract by a value I have in "J5". "J5" changes dynamically and I can use a call function for it to work in the graph. Because of the way the charts are set up it has to be this way. My code so far is:
Sub Updatecodelengh()
Dim i As Integer
Dim G As Worksheet
Set G = Sheet1
i = G.Range("J5")
ActiveSheet.ChartObjects("GanttChart").Activate
ActiveChart.SeriesCollection(16).Values = "='Gantt'!$L$3:$L$4"
End Sub
Where it says "='Gantt'!$L$3:$L$4" I need the range of the chart data to start on $L$3 and extend downwards by the value obtained in J5. Thanks for any help
Do you mean simply
ActiveChart.SeriesCollection(16).Values = "='Gantt'!$L$3:$L$" & i
However, you should check if J5 contains a valid number to prevent runtime errors.
A small hint: When dealing with row and column numbers in VBA, always use datatype long.

PivotCache Refresh from Access

I am automating some Excel file creation from Access. I need help with dynamically resetting the pivotcache for all the pivot tables. The first set of code is me testing working code in Excel. Now I want to translate this so that it runs from Access module.
Sub Update_PTSource()
With Sheets("Pivot")
.PivotTables(1).ChangePivotCache ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=Sheets("Data").Range("data"))
End With
End Sub
Function pivot_refresh_test()
Dim pt As Variant
Dim wb, ws As Object
Dim strWBName As String
Dim strTabName As String
strWBName = "C:\Users\...\Packaged SKU.xlsb"
strTabName = "Pivot"
Set wb = GetObject(strWBName)
For Each pt In wb.Sheets(strTabName).Pivottables
pt.ChangePivotCache wb.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=wb.Sheets("Data").Range("data"))
pt.RefreshTable
Next pt
End Function
I'm getting error on pt.ChangePivotCache line with error
invalid procedure call or argument
As far as I can see, you've only made one simple error:
xlDatabase is an Excel enum, and since you're using late bindings, you don't have access to it. You can use it's integer value, 1, instead:
For Each pt In wb.Sheets(strTabName).Pivottables
pt.ChangePivotCache wb.PivotCaches.Create(SourceType:=1, SourceData:=wb.Sheets("Data").Range("data"))
pt.RefreshTable
Next pt
I'm anal about using the least code possible when designing solutions so I found a much easier method to what I wanted to do.
My task was to update and refresh the source data of all my pivot tables. There was one source, multiple pivot tables. I created a dynamic named range for my source for this purpose in my template Excel book that Access was writing into. I never save over the template I just used saveas vba to create the filled copy.
However, since I had created a named range and am modifying always the same template file with Access, I don't need to write a program to change my pivotcache. I can just use 'Change Data Source' in Excel ribbon. The vba code gets much easier. It is just a variation of: ThisWorkbook.RefreshAll. No code loops required!
The whole power of my strategy is the formula that creates my named range. =Data!$A$5:OFFSET(Data!$A$5,COUNTA(Data!$A:$A)-1,52). You just set the first cell of your data, and set how many columns there are for your fields, the rows are automatically adjusted.
I hope this little rant help whoever navigates here. I've been searching a lot for good dynamic pivot table automation but most of the internet has crap info on this.

Powerpoint VBA - Set DataRange for DataLabels

I have no idea how to set DataRange for DataLabels using VBA.
Powerpoint does not have recording capabilities as well.
Can anybody tell me to do this using VBA please?
The code to accomplish this is as follows:
Dim myChart As Chart
Dim mySerCol As SeriesCollection
Dim strRange As String
strRange = "=Sheet1!$F$2:$F$5" 'To hold the range for the new labels
Set myChart = ....[put in code to get the appropriate chart]
Set mySerCol = myChart.SeriesCollection(i)
mySerCol.ApplyDataLabels 'Turn on the datalabels for this series
'The next line sets the range to get the values from
mySerCol.Format.TextFrame2.TextRange.InsertChartField msoChartFieldRange _
, strRange, 0
mySerCol.ShowRange = True 'Show the values from the range
mySerCol.ShowValue = False 'Do not show the actual values of the points
Note that this will only do this for one of the series. To do the other ones, loop through i in the myChart.SeriesCollections(i) line.
****EDIT**** See other answer. I am leaving this here because it provides some information about several objects that could be used, but doesn't actually solve the problem.
This is not a complete answer to the issue, but this is too long for a comment.
I've searched through the documentation for the Datalabels and was unable to figure out how to do this (I assume that you want to be able to define the range that the labels come from using VBA). I was able to "check" the checkbox, but couldn't figure out where the range that is attached to it is. The appropriate code to check.
To check the checkbox, use this code:
myChart.SeriesCollection(i).ApplyDataLabels
where i is the series in question and myChart is a Chart object referencing your chart. There are a bunch of parameters to this method that will allow you to show different items (percentages, values, etc.), but none of the parameters is a range.
This defaults to the values of the series if you do not enter any of the optional parameters
It is then possible to turn this on and off using:
myChart.SeriesCollection(i).DataLabels.ShowRange = True/False
It is possible to change the caption of the Datalabels using:
myChart.SeriesCollection(i).DataLabels(j).Caption = "MY CAPTION"
This will change the caption one at a time, and it will replace the value that the "ApplyDataLabels" method puts in there. It would be possible to loop through the range to set the values, but this is likely not what you are looking for.
There's also this:
myChart.SeriesCollection(i).HasDataLabels = True
but this just seems to turn them on and off and resets the captions that you may have put in there.
MSDN link uses both the hasdatalabels property and the applydatalabels method, but it is not clear why they are using both: https://msdn.microsoft.com/EN-US/library/office/ff745965.aspx
Hopefully this can at least give you something to start with.

VBA Error 1004 - PasteSpecial method of Range class

Recently I started getting the error 1004: PasteSpecial method of Range class failed. I know people have said before that it might be that it is trying to paste to the active sheet when there is none, however, as you can see, everything is based on ThisWorkbook so that shouldn't be the problem. It happens extra much when Excel doesn't have the focus.
'references the Microsoft Forms Object Library
Sub SetGlobals()
Set hwb = ThisWorkbook' home workbook
Set mws = hwb.Worksheets("Code Numbers") ' main worksheet
Set hws = hwb.Worksheets("Sheet3") ' home worksheet (Scratch pad)
Set sws = hwb.Worksheets("Status") ' Status sheet
Set aws = hwb.Worksheets("Addresses") ' Addresses sheet
End Sub
Sub Import()
Call SetGlobals
hws.Select
'a bunch of code to do other stuff here.
For Each itm In itms
Set mitm = itm
body = Replace(mitm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
Call Buf.SetText(body)
Call Buf.PutInClipboard
Call hws.Cells(k, 1).Select
Call hws.Cells(k, 1).PasteSpecial
For Each shape In hws.Shapes
shape.Delete
Next shape
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub
Update: mitm and itm have two different types, so I did it for intellisense and who knows what else. This code takes a list of emails and pastes them into excel so that excel parses the html (which contains tables) and pastes it directly into excel. Thus the data goes directly into the sheet and I can sort it and parse it and whatever else I want.
I guess I'm basically asking for anyone who knows another way to do this besides putting it in an html file to post it. Thanks
This probably will not exactly answer your problem - but I noticed a few things in your source code that are too long to place in a comment, so here it is. Some of it is certainly because you omitted it for the example, but I'll mention it anyway, just in case:
Use Option Explicit - this will avoid a lot of errors as it forces you to declare every variable
Call SetGlobals can be simplified to SetGlobals - same for Call Buf.SetText(body) = Bof.SetText Body, etc.
No need to '.Select' anything - your accessing everything directly through the worksheet/range/shape objects (which is best practice), so don't select (hws.Select, hws.Cells(k,1).Select)
Why Set mitm = itm? mitm will therefore be the same object as itm - so you can simply use itm
You're deleteing all shapes in hwsmultiple times - for each element in itms. However, once is enough, so move the delete loop outside of the For Each loop
Instead of putting something in the clipboard and then pasting it to a cell, just assign it directly: hws.Cells(k, 1).Value = body - this should solve your error!
Instead of using global variables for worksheets that you assign in 'SetGlobals', simply use the sheet objects provided by Excel natively: If you look at the right window in the VBE with the project tree, you see worksheet nodes Sheet1 (sheetname), Sheet2 (sheetname), etc.. You can rename these objects - go to their properties (F4) and change it to meaningful names - or your current names (hwb, mws, ...) if you want. Then you can access them throughout your code without any assignment! And it'll work later, even if you change the name of Sheet3to something meaningful! ;-)
Thus, taking it all into account, I end up with the following code, doing the same thing:
Option Explicit
Sub Import()
'a bunch of code to do other stuff here.
For Each shape In hws.Shapes
shape.Delete
Next shape
For Each itm In itms
Call hws.Cells(k, 1) = Replace(itm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub

Get Source Range of a PivotTable

I am building a set of reports to be updated daily for some users who are not super savvy when it comes to pivot charts and pivot tables in Excel (2010). I have data from an already automated data pull from our db, but to make that information useful (and more simple to use), I want to generate the pivots using VBA.
I have already generated the pivot tables just fine and can manually manipulate them to create the relevant charts. As I create the tables (all on one sheet), I am labeling them (if that helps solve my problem). Where I am running into trouble is creating the pivot charts, and specifically, setting the data source.
Since the charts are based on pivots that may change in size depending on the data present, I can't just assign a fixed range as the source. Same problem with a named range, as I still don't know what range to assign a name, unless I can assign a PT as a range.
I've tried something like this, but that didn't work, since I'm not looking at an actual 'Range' object:
Dim MyChartObject As ChartObject
Dim MyChart As Chart
'These variables are assigned elsewhere in the code.
Set MyChartObject = wksMainCharts.ChartObjects.Add( _
iChartLeft, iChartTop, iChartWidth, iChartHeight)
Set MyChart = MyChartObject.Chart
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).SourceData 'Fails; requires Range object
'More code to follow...
I do know that this is a string representation of the wrong range, but I was playing with what I could figure on my own.
Essentially what I want is the opposite of this question, which seeks to find the pivot table at a specified range. I also reviewed this question, but it's not quite what I'm looking for (there are also no answers provided).
Also: I'm asking here for a way to get the range of a PT, which I think would be interesting to know, but ultimately, I just want to create the pivot chart, so if anyone wants to offer a better method than what I've started on, I'm completely open to that as well.
Is this what you are trying to achieve?
Sub Sample()
Dim Chrt As Chart, pvtTbl As PivotTable
Set pvtTbl = ActiveSheet.PivotTables(1)
Set Chrt = ActiveSheet.ChartObjects(1).Chart
Chrt.SetSourceData Source:=pvtTbl.TableRange1
End Sub
So your this line
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).SourceData
becomes
MyChart.SetSourceData wksMainPivot.PivotTables(PivotName).TableRange1