On occasion you will want to copy a chart in Excel and paste it into a PowerPoint presentation using VBA. This comes in handy when you want to automate a report.
Problem: assuming you are not converting the graph to an image, and depending on the size and complexity of the graph you are trying to paste, the graph does not have time to paste before VBA attempts to continue with the procedure. This is annoying when you want to manipulate the graph after it has been pasted (e.g. positioning it on the slide). What effectively happens is you end up trying to move a chart on the slide... that does not yet 'exist' as a PowerPoint shape.
This issue is annoying and in my humble opinion actually constitutes a bug. I have not yet seen a robust solution to the problem on SO, with the potential exception of this answer from John Peltier. His answer is most likely correct (and has been designated as such on the thread) but unfortunately I could not get this to work in my implementation.
The issue I lay out below.
Code (simplified for ease of reference):
Public Sub X2P()
'Copy chart and paste
ActiveChart.ChartArea.Copy
Set mySlide = myPresentation.Slides(2)
PasteChartIntoSlide mySlide
End Sub
Function PasteChartIntoSlide(theSlide As Object) As Object
CreateObject("PowerPoint.Application").CommandBars.ExecuteMso ("PasteSourceFormatting")
End Function
I see others have tried to break up the script and to copy, paste and position charts using separate functions. This is cleaner, but it has not worked for me.
The solution I have found is to count the number of shapes on the slide before the code pastes the chart, num_obj, and to set variable num_obj_final as num_obj + 1 (i.e. total number of shapes once the chart has been pasted). I then create a loop after the paste event, where I recalculate num_obj with every iteration. Only when num_obj is equal to num_obj_final does the procedure exit the loop. And then the script can resume as expected, as you can be sure that the shape now 'exists' on the slide.
Final code for PasteChartIntoSlide() function:
Function PasteChartIntoSlide(theSlide As Object) As Object
theSlide.Select
num_obj = 0
num_obj_final = theSlide.Shapes.Count + 1
CreateObject("PowerPoint.Application").CommandBars.ExecuteMso ("PasteSourceFormatting")
DoEvents
Do Until num_obj = num_obj_final
num_obj = theSlide.Shapes.Count
'Debug.Print num_obj
Loop
End Function
Related
I'm trying to animate a parametric curve in Excel by generating its ranges in an iterative loop. I'm using the code:
Public Sub playswirl()
Range([a8], [a8].End(xlDown)).Clear
Set cell = Range("a8")
Do While cell.Offset(0, 1) <> ""
cell.Offset(-1, 0).Copy cell
ActiveSheet.ChartObjects(2).Chart.Refresh
DoEvents
Sleep (50)
Set cell = cell.Offset(1, 0)
Loop
End Sub
The chart is cleared in the first instruction, then rebuilt one item at a time in the loop. While the code is running, I see the values in the spreadsheet changing one at a time, but the chart never updates (I see the full curve, i.e. the state before the first line of code is executed). When I ctrl-break and put the code in debug state, the chart updates to the point where the code was interrupted.
I thought that the chart.refresh would have done the trick - and added the doevents in for good measure when that didn't work - but no luck. Changing the sleep call to the Excel-native Application.Wait call doesn't help either (and is too slow in any case).
Any ideas?
I think it may not be a problem with the chart; it may be a problem with the updating system. If Application.ScreenUpdating = True (which it is by default), then here are some things you can try:
Try adding the "DoEvents" to your loop like explained here.
Try adding "Calculate" to the function. For example, write the code ActiveSheet.Calculate.
Let me know how those go.
Question overview:
I am using Excel VBA histogram function from 'Analysis Toolpak' to generate approximately 25 histograms automatically. When Histogram graph is generated, it is placed on top of cells that have values in it, effectively hiding them (Which is OK with me). Therefore a following message is generated "Histogram - some data will be hidden by embedded chart(s)" with "OK" & "Help" buttons. I don't want to press "OK" 25 times whenever I am running this macro.
What I have tried:
Application.DisplayAlerts = False/True is not working out for me. I have tried placing this in variaty of location in my code
Application.ScreenUpdating = False/True
Also tried playing with SetWarning function
Code (1/25):
Dim binrng As Range
Set binrng = Sheets("PSDreport").Range("P4:P64")
Dim outputrng As Range
Set outputrng = Sheets("PSDreport").Range("Q3")
Application.Run "Histogram", inprng, outputrng, binrng, False, False, True, False
My partial solution:
With Application
//CODE GOES HERE//
.SendKeys "{ENTER}"
End With
Problem with my current solution:
Note that all Histogram generating segments of code (1/25) are wrapped around the 'With'. For some reason the first Histogram generated still produces the pop-out (Not good). the remaining 24 successfully skip the pop-outs but the noise of the pop-outs is still produced (slight annoyance).
I am looking for a more elegant way to solve this problem
I had this warning too when I tried to output my embedded chart on the same worksheet that I had my source data (your "imprng"). Once I moved my output range (outputrng) to a different worksheet, the warning stopped.
Bit late to the party but anyone else looking at this should try
With Application
.SendKeys "{ENTER}"
//CODE GOES HERE//
End With
I have a worksheet where I create graphs in VBA and then place them according to named ranges in the worksheet.
graph3.Height = gRange.Height
graph3.Width = gRange.Width
graph3.Top = gRange.Cells(1, 1).Top
graph3.Left = gRange.Cells(1, 1).Left
It used to work fine but for some reason the graph no longer is positioned in the correct location. When I set a a stop point on any of the four lines and then continue to run the procedure, the graph returns to the correct position. Has anyone ever experienced this and how can I correct it?
I Know similar questions have been asked, but I still can't figure out this error.
I am working in Access, exporting to excel and used some excel macros to format the data and create charts. I am now trying to put those charts into a Powerpoint, and I am having trouble pasting only one of the four charts I am trying to copy over.
My code to export the third and fourth charts is as follows:
xl.Sheets("Sheet with chart 3").Select
Set rng = xl.ActiveChart
rng.CopyPicture
mySlide.Shapes.PasteSpecial DataType:=ppPasteEnhancedMetafile
Set myShapeRange = mySlide.Shapes(mySlide.Shapes.Count)
myShapeRange.Left = 365
myShapeRange.Top = 200
myShapeRange.Width = 345
xl.Sheets("Sheet with chart 4").Select
Set rng = xl.ActiveChart
rng.CopyPicture
mySlide.Shapes.PasteSpecial DataType:=ppPasteEnhancedMetafile
Set myShapeRange = mySlide.Shapes(mySlide.Shapes.Count)
myShapeRange.Left = 365
myShapeRange.Top = 200
myShapeRange.Width = 345
I get the error "Object variable or With block variable not set (Error 91)" on the second occurrence of the line
rng.CopyPicture
So why would this code fail after running three times prior? I believe I qualified everything correctly, and this code isn't running inside a with block either. Also, The excel sheet it is pulling from is practically identical to the others.
I had been stuck on this for awhile, the problem was caused by this line:
xlSheet.Range("G7").Select
which was the last line during the formatting on the excel book. I had recorded macros in excel to make the charts and pasted the resulting code in Access. I guess having this cell selected was preventing the chart from being set to active, so I couldn't copy it. Hopefully this helps someone having the same silly problem I was!
I am quite new to VBA. I have written a macro which creates about 10 pivot charts and some normal charts after filtering and cutting some data from a database spreadsheet. I now want to write a sub which goes through applying the same formatting to each one. The sub is as follows:
Sub FormatChart(Cht As ChartObject, title As String)
Cht.Activate
MsgBox ActiveChart.SeriesCollection.Count
With ActiveChart
.HasTitle = True
.ChartTitle.Text = title
.Axes(xlValue).HasMajorGridlines = False
End With
ActiveChart.SeriesCollection(1).Select
With Selection.Format.Fill
.Visible = msoTrue
.ForeColor.RGB = RGB(255, 182, 0)
End With
End Sub
I originally didn't include all the activates and selects, but couldn't get the macro to work without them and don't see it as the end of the world - the datasets are never going to be massive so speed isn't so much of a concern, and I disable screenupdating so that users can't click on cells/other objects and disrupt the macro as it runs.
Here's my problem. If I take out the second With loop, everything proceeds perfectly and the gridlines are removed and the title is added. However, whenever I try to edit the colours of columns with the above I get Run time error '1004': Invalid parameter. I've also tried keeping the content of the second with loop inside the first but then moved it out to try using selection to see if it made a difference.
I've fiddled around quite a bit and recorded various macros changing the colour of the chart in question, but I think the problem might be to do with referencing SeriesCollection as when I try to debug with
MsgBox ActiveChart.SeriesCollection.Count
I get "0".
Please let me know if I'm missing the point - as I said I am new to VBA and am trying to learn as much as possible :)
EDIT: The solution was that I was passing each chart to the above sub after I had created the chart, but before I had set a data source for the chart. Doh!
This obviously meant that there were no seriesCollections for that chart, hence the error I was getting.
I marked Joehannah as answering the question (even though it isn't technically the solution) because it made me check my code and notice that the above could be causing the problem - if I shouldn't do that someone please tell me and I'll try to fix it!
You are better off using Set cht = (create chart object) for each chart and then Immediately calling the format method passing in cht.
I have been told to post my own answer since I figured out the issue.
I was passing each chart to this function just after creating it, as follows:
Set ptr1 = Sheets("withinBRSPivots").PivotTables("UniqueClicks").TableRange1
Set cht1 = Sheets("BRS Overview").ChartObjects.Add(Left:=950, Top:=500, _
Width:=400, Height:=300)
cht1.Name = "UCChart"
Charter.FormatChart cht1, "Average Number of Unqique Clicks"
I then set the source data for the chart after doing the above. This meant that when the chart was passed to my chartformat sub, it had no source data. This is what resulted in being able to edit the title and gridlines, but not the seriesCollection. The fix was to just move the FormatChart sub line to after I had set the source data.
Many thanks to everyone who posted answers!