Error in script which copies charts from Excel to PowerPoint - vba

I am attempting to call the below Sub in order to copy given chart to a specified PowerPoint presentation. However, when I run the macro which calls this Sub, the line indicated below returns the following error: "Object doesn't support this property or method." What's odd is that both Shapes and Slide do contain the methods which are called. As well, the bitmap is correctly copied to my clipboard and pastes into the slide before the error is called. You will find the Sub() below.
Sub copyChart(chrt As Chart, pres As PowerPoint.Presentation)
Dim curSlide As Slide, dummySlide As Slide
Set dummySlide= pres.Slides(2) 'Second slide is dummy slide.
Set curSlide = dummySlide.Duplicate(1) 'Duplicate dummy, set as current slide.
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap 'Copy the chart as a picture.
curSlide.Shapes.Paste '<-----------Error here.
End Sub
As well, I was hoping to provide a .txt file of my entire script, but was unsure how (it is a little lengthy to paste here). Thanks for your help.
(Note that this implementation is very similar to that at Paste Excel Chart into Powerpoint using VBA, further confusing me.)

I have had a lot of trouble in recent versions of Office. 2003 and earlier didn't have this problem, 2007 and 2010 had it a bit, and 2013 and 2016 have it in spades.
When you step through the code it works fine, but when you run it at full speed, it errors on the paste.
It's as if the copy doesn't have time to finish finish, so when you paste the clipboard doesn't have anything in it yet to paste.
Sometimes this helps:
chrt.CopyPicture Appearance:=xlScreen, Format:=xlBitmap
DoEvents
curSlide.Shapes.Paste
DoEvents tells VBA to wait while background operations have a chance to finish up.

It looks like the error can be attributed to how VBA handles variables across different references. (In particular, how PPT VBA handles them.) I was able to get the macro to work by actively selecting/copying the charts. I will need to do a little more research to get why variables cause problems, but at least I know how tackle the problem.
Sub copyChart(curSlide As Slide)
Dim chr as ChartObject
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
Sheets("CHARTSHEET").Select
ActiveChart.CopyPicture
curSlide.Shapes.PasteSpecial
End Sub

I like to use another method, I like to define an Object, then set it to the pasted Chart. Afterwards, it's much easier modifying the pasted Chart object's parameters inside PowerPoint (from Excel).
See code below:
Sub copyChart(curSlide As Slide)
Dim chr As ChartObject
Dim myChart As Object
Set chr = Sheets("CHARTSHEET").ChartObjects(1)
chr.Copy
' setting myChart object to the pasted chart (let's me later an easy way to modify it's parameters)
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse) ' can change first parameter to other avaialabe formats : ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.
' set different parameters for the pasted chart in PowerPoint slide
With myChart
.Left = 200
.Top = 200
End With
End Sub
In the code line:
Set myChart = curSlide.Shapes.PasteSpecial(ppPasteBitmap, msoFalse)
You can change the first parameter in brackets: ppPasteBitmap to many other avaialble formats (test them and see which one gives you the best result), such as: ppPasteGIF, ppPasteEnhancedMetafile, ppPasteOLEObject, etc.

Related

VBA deleting a duplicate copy of chart object fails in Excel 2013

I have a VBA code that is intended to copy the contents of a range into a chart, to be able to export it to a PNG file (+some post-processing using an external command). Here is the relevant part:
Sub GenererImage() ' Entry point
getparams ' Collect parameters and define global variables
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen,Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
.Delete
End With
Application.DisplayAlerts = True
End Sub
The getparams procedure called in there is just collecting some parameters from another worksheet to define:
"MiseEnPage": reference to the worksheet object where the range I want to copy exists,
"ZoneImage" is set to the "B4:F11" string (refers to the range address),
"ObjetGraphique" is a reference to a ChartObject inside the "MiseEnPage" sheet. This ChartObject is an empty container (I am mainly using it to easily set the width and height).
"CheminImage" is a string containing the path to the picture filename on disk.
This code used to work perfectly in Excel 2010. Now my company has deployed Excel 2013 and my code now fails on the .Delete line, leaving the copy of the ChartObject (with the range picture pasted inside it) on the sheet and stopping macro execution.
I have tried activating the worksheet first, selecting the duplicate prior to deleting it and other things, to no avail. When tracing the execution in the debugger it chokes on the delete line with error 1004.
I am frustratingly stuck. Any clue?
If this works
With ObjetGraphique.Duplicate
.Chart.Paste
.Chart.Export Filename:=CheminImage, Filtername:="PNG"
.Select
End With
Selection.Delete
we have to assume that either the With is holding a reference and preventing the delete, or that the delete routine called by the selection object is not the same delete that's called by ObjetGraphique.Duplicate.delete, or that it's a subtle timing bug and that the extra time it takes to retrieve the selected object is enough to fix it.
OK after fiddling a lot with the object model, here is (the relevant part of) my final solution. Many thanks to HarassedDad for the clues.
Sub GenererImage() ' Point d'entrée
getparams
MiseEnPage.Range(ZoneImage).CopyPicture Appearance:=xlScreen, Format:=xlPicture
Application.DisplayAlerts = False
With ObjetGraphique
.Chart.Paste
.Chart.Export filename:=CheminImage, Filtername:="PNG"
.Chart.Shapes(1).Delete
End With
Application.DisplayAlerts = True
End Sub
What seems to happen is that the .Paste method of the Chart object creates a Shape in the .Shapes collection of this object. I can delete this Shape, but not the Chart itself or the ChartObject. Excel 2010 would allow that, but not Excel 2013.
I still do not understand the reasons, but at least I have something that works (until the next excel update probably...).

Error in Code to Paste / Copy Shapes from Excel to PowerPoint VBA

I created a code in VBA to copy shapes from a sheet in Excel to an existing PowerPoint file, these shapes are added to existing slides. In Excel I have a table that indicates which slide and in which position to paste each shape (I named all shapes so that I can reference them by name). My code loops through this table to get the shape and paste it to the designated slide. This is my code:
Dim nombrePic As String, auxi As String, i As Integer
Dim PPT As Object
Dim PPSlide As PowerPoint.Slide
Dim numSlide As Integer, posVertical As Double, posHorizontal As Double
'Abrir PPT
Set PPT = CreateObject("PowerPoint.Application")
PPT.Visible = True
PPT.Presentations.Open "c:\prueba.pptx"
auxi = Sheets("FigurasResumen_RangPD").Cells(2, 5)
i = 2
Do
Sheets("FigurasResumen_RangPD").Shapes(auxi).Copy
'Get paste information about shape
numSlide = Sheets("FigurasResumen_RangPD").Cells(i, 8)
posHorizontal = Sheets("FigurasResumen_RangPD").Cells(i, 9)
posVertical = Sheets("FigurasResumen_RangPD").Cells(i, 10)
PPT.ActiveWindow.View.GotoSlide (numSlide)
PPT.ActiveWindow.View.PasteSpecial DataType:=ppPasteDefault
PPT.ActiveWindow.Selection.ShapeRange.Left = Format(Application.CentimetersToPoints(posHorizontal), "0.00")
PPT.ActiveWindow.Selection.ShapeRange.Top = Format(Application.CentimetersToPoints(posVertical), "0.00")
PPT.ActiveWindow.Selection.ShapeRange.ZOrder msoSendToBack
i = i + 1
auxi = Sheets("FigurasResumen_RangPD").Cells(i, 5)
Loop Until auxi = ""
End Sub
When I first tried it, it work fine. I created a sample PPT and everything went great.
Once I changed the path to use the official PPT (which weights around 120MB) it shows the following error:
View.PasteSpecial : Invalid Request.
Clipboard is empty or contains data which may not be pasted here.
[Answer replaced: I wrote an answer yesterday but I think this one is better.]
VBA sees "copy" and "paste" operations as unrelated to each other. It also executes asynchronously - it starts executing an instruction, and then it may move on to executing the next one while the previous instruction is still being executed. It shouldn't do so if the second instruction depends on the first, but "paste" just takes ANYTHING from the clipboard, it is not aware of how things got on the clipboard. In particular, it doesn't relate specifically to the "copy" command right before it. Then, copying to the clipboard is a slow process; program execution gets to "paste" before anything is on the clipboard (or only partial, incomplete data is on it).
There are two ways to address the problem. One is to add a Sleep xxx instruction before the paste command. xxx is a number of milliseconds - and for Sleep to work, you need to declare it properly at the top of your module (it is a Windows function, not a VBA function). Google "VBA Sleep function" or something similar. With this solution, you have to experiment with xxx, sometimes 2 ms will suffice and sometimes 50 ms will not be enough. Not a good solution.
The better solution in your case would be to declare a Shape variable, assign to it the shape you were copying, and then add it to your target slide. This should work, because the shape (saved as the Shape variable) cannot be added to the new slide until the variable assignment completes. ASSUMING, of course, that VBA has a method for adding a shape to a slide...

Refresh all charts without blinking

The aim is to refresh all charts in Excel after cells recalculation.
I work with Microsoft Excel 2010.
As we know, there is a bug? in Excel so that Excel does not update charts even after
Application.CalculateFullRebuild
A known hack is to do something like this:
Application.ScreenUpdating = False
Temp = ActiveCell.ColumnWidth
ActiveCell.Columns.AutoFit
ActiveCell.ColumnWidth = Temp
Application.ScreenUpdating = True
This does work. However, all Excel charts blink (they become white for a moment while updating). Could you advise, please, is there any way to avoid such blinking?
I tried to call
.Refresh
on all charts (https://msdn.microsoft.com/en-us/library/office/ff198180(v=office.14).aspx):
For Each ChartObject In ActiveSheet.ChartObjects
ChartObject.Refresh
Next
but for some reason my Excel (2010) shows error #438 "Object doesn't support this property or method".
Could you advise, please, do I miss something important?
Untested But the .Refresh may work with this:
Sub ChangeCharts()
Application.ScreenUpdating = False 'This line disable the on screen update for better performance, the blink you see, you could delete both lanes but it will run slower
Dim myChart As ChartObject
For Each myChart In ActiveSheet.ChartObjects
myChart.Chart.Refresh
Next myChart
Application.ScreenUpdating = True'This line reenable the on screen update for better performance, the blink you see, you could delete both lanes but it will run slower
End Sub
And that's because (as the link you provide shows) .Refresh only works with the object Chart and not with the object ChartObjects as you have been trying to apply it. Hope it'll guide you in the right direction. (also added quotes for the blink/flicker on screen in the code)
Happy Pi Day!
I just did some experiments with animating charts, using VBA to change a counter in a cell, and worksheet formulas to recalculate chart data based on this counter.
I used to do a lot of chart animations, back in the days of Excel 97-2003, and those ran pretty well. When Excel 2007 came out, the animations really degraded, and nothing seemed to help. But just now I did these tesst in the latest build of Office 365 (Version 1904, Build 11504). And it turns out, sometime in the past few years or so, Microsoft has made it work better.
Sub ChartAnimation1()
Dim i As Double
For i = 0 To 1000 Step 50
ActiveSheet.Range("Stepper") = i
Next
End Sub
The animation didn't animate, that is, the chart didn't change despite the data changing.
My experience told me I should put something like DoEvents in the code after I change the cell's value.
Sub ChartAnimation2()
Dim i As Double
For i = 0 To 1000 Step 50
ActiveSheet.Range("Stepper") = i
DoEvents
Next
End Sub
This helped a little, the chart changed, but the animation was not smooth. Some steps were missed, and the effect was a herky-jerky animation.
Sub ChartAnimation3()
Dim i As Double
For i = 0 To 1000 Step 50
ActiveSheet.Range("Stepper") = i
DoEvents
DoEvents
Next
End Sub
This ran a bit more slowly than with one DoEvents, but it was a lot smoother; still not perfect, but pretty good.
More than two DoEvents was overkill: the code took the same length of time, and the animation was not any smoother.
I also tried various combinations of Chart.Refresh, Chart.Activate, and ScreenUpdating. Two takeaways:
Without a couple DoEvents, the animation didn't work regardless of what other things I tried.
With a couple DoEvents, none of these extra steps made the animation any smoother, but they could make it significantly slower.
This was pretty interesting, so I'll blog about it some day. When I do I'll come back and post a link.
As is often the case I was sent to this VBA post following a VB.NET query regarding blinking or flashing Excel Charts after turning on Excel ScreenUpdating. Blinking Charts is something that has been driving me mad for a long time now and I have seen no solutions that work including the above solution that looks like it should work but doesn't. I have now found a solution that works 100% for all of my programs. As this is a VBA post I have shown a VBA solution to the flashing charts but my VB.NET solution is for anyone else who is sent to this post looking for a VB.NET solution. My solution is based on the answer by Zegad above but it has a couple of essential additions that are not documented and which to me are not obvious. Use the following sub as a replacement for "MyXLApp.ScreenUpdating = True". If you find it works for you please do not ask me to explain why it works. I'm sure there are many here who could probably explain this but for me it is the result of luck and dogged determination. An odd addition here is that you actually only need to activate and refresh then deactivate any one chart and all of the charts will update without flashing when re-enabled, See 'VB.NET CODE-2 sub below.
Sub ScrUpdateEnableNoFlicker()'VBA CODE
Dim myChartObj As ChartObject
For Each myChartObj In ActiveSheet.ChartObjects
myChartObj.Activate 'IMPORTANT ADDITION
myChartObj.Chart.Refresh
Next
Cells.Range("A1").Select 'IMPORTANT ADDITION
Application.ScreenUpdating = True
End Sub
Private Sub ScrUpdateEnableNoFlicker() 'VB.NET CODE-1
'BEFORE TURNING SCREEN UPDATING BACK ON...
'ACTIVATE and refresh the chart objects on the sheet with the charts.
Dim aSheet As Excel.Worksheet = CType(mXLWrkbk.Sheets("Sheet1"), Excel.Worksheet)
Dim aChartObjects As Excel.ChartObjects = CType(aSheet.ChartObjects, Excel.ChartObjects)
For Each achartobject As Excel.ChartObject In aChartObjects
achartobject.Activate() 'IMPORTANT - Will not work without activating first
Dim achart As Excel.Chart = achartobject.Chart
achart.Refresh()
Next
'Now deactivate the current activated chart object by selecting any cell
'THIS IS IMPORTANT - It will not work without doing this
Dim selRange As Excel.Range = aSheet.Range("A1")
selRange.Select()
'Now turn Screen Updating back on...
'All of the Charts will have updated and will not flicker
mXLApp.ScreenUpdating = True
End Sub
Private Sub ScrUpdateEnableNoFlicker() 'VB.NET CODE-2
'BEFORE TURNING SCREEN UPDATING BACK ON...
'ACTIVATE ANY ONE of the chart objects on the sheet with the charts.
Dim aSheet As Excel.Worksheet = CType(mXLWrkbk.Sheets("Sheet1"), Excel.Worksheet)
Dim aChartObject As Excel.ChartObject = CType(aSheet.ChartObjects("Chart 9"), Excel.ChartObject)
aChartObject.Activate() 'IMPORTANT - Will not work without activating first
'Refresh just the ONE activated chart.
Dim aChart As Excel.Chart = aChartObject.Chart
aChart.Refresh()
'Now deactivate the current activated chart object by selecting any cell
'THIS IS IMPORTANT - It will not work without doing this
Dim selRange As Excel.Range = aSheet.Range("A1")
selRange.Select()
'Now turn Screen Updating back on...
'You only need to activate/deactivate any one chart and all of the Charts will have updated and will not flicker
mXLApp.ScreenUpdating = True
End Sub
I was having this issue when hiding or showing a series in my chart. The change would not be apparent until I would scroll away then back again to the chart, which was really a pain. I tried all the above solutions with no luck until I realized unselecting and selecting again the chart before doing the change would work.
myChart.TopLeftCell.Select
myChart.Select
...
Good luck in your research for a solution ;)
Thanks to those who have posted here before! Without your successes, I would not have smooth animation of a dynamic simulation. In my case, it is an xlXYScatterLinesNoMarkers type chart. Running in VBA.
This works for me when changing the series programmatically. The chart is animated smoothly. Running Excel 2016 64 bit
Public Sub ShowOneAnimationFrame(worksheetName As String, chartName As String, _
xvals() As Double, yvals() As Double)
'update chart series programmatically
'Excel 2016 64bit
'Dec 21, 2020
'Author: S^3
Dim theChart As chart
Dim chrtObj As ChartObject
Dim oneSeries As Series
Set chrtObj = Sheets(worksheetName).ChartObjects(chartName)
Set theChart = chrtObj.chart
If theChart.SeriesCollection.Count = 0 Then
theChart.SeriesCollection.NewSeries
End If
Set oneSeries = theChart.SeriesCollection(1)
'update the series with new values
oneSeries.XValues = xvals
oneSeries.Values = yvals
theChart.Refresh 'required (this and the next line are required but the order doesn't matter)
chrtObj.Select 'required
Cells.Range("A1") = Cells.Range("A1").value 'something like this is required
End Sub

Recorded macro for data labels does not work

So, I'm a novice at using VBA but not so new that I know not to use .select and the likes wherever possible but I will still record macros to find out how to call certain objects. I am working on a large piece of code to do various things before manipulating a chart at the end, it wasn't working so breaking it down into a new spreadsheet I found that some of my lines for manipulating chart labels were giving me an error. I recorded a macro to make sure I hadn't mis-typed anything, but could not fix it, then tried to run the recorded macro, but couldn't get it to work.
Heres the aim of my code:
1. Apply data labels to one point in a series.
2. Delete the label I just applied
(in the final code there will be "if" functions ect)
Here is the macro code, straight from the recorder:
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveChart.SeriesCollection(2).Select
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveChart.SeriesCollection(2).Points(1).Select
ActiveChart.SeriesCollection(2).Points(1).ApplyDataLabels
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveChart.SeriesCollection(2).Points(1).DataLabel.Select
Selection.ShowValue = 0
Selection.ShowCategoryName = -1
' this line ^ gives error 438, object does not support this property or method
ActiveSheet.ChartObjects("Chart 1").Activate
ActiveChart.SeriesCollection(2).Points(1).DataLabel.Select
Selection.Delete
What's also very curious is that sometimes rather than Selection.ShowValue = 0 it will use Selection.ShowValue = False
Anyone know why the recorded code for this is so jumpy? Also if anyone could suggest simpler code for manipulating data labels that would be very useful.
I am using excel 07 on windows 7.
Charts in VBA have always been a pain in the rear for me. That being said, here's some code that tosses a few of the more common objects into variables (so you can break the code on a line and see what's going on in the "locals" window). This will iterate through all of the points on your chart and add a datalabel containing the "Value".
Sub test()
Dim myChart As ChartObject 'A "ChartObject" contains a Chart, in which the "SeriesCollection" resides
Dim chartSeries As Series 'Multiple "Series" can be found in a "SeriesCollection"
Dim scPoint As Point
Set myChart = ActiveSheet.ChartObjects("Chart 1")
Set chartSeries = myChart.Chart.SeriesCollection(1) 'Get the first "Series" in the "SeriesCollection" for this chart
'loop through the points in this Series. As it loops the point will be available in the "scPoint" variable.
For Each scPoint In chartSeries.Points
With scPoint.DataLabel 'Finally the "DataLabel" is part of the "Point"
.ShowValue = True 'Just show the value. There are other options here, just create a new line and start typing with a period to see what other options are available for a "DataLabel"
End With
Next scPoint
'Instead of iterating, if you just want to address a single point's datalabel then:
chartSeries.Points(2).DataLabel.ShowValue
End Sub

PowerPoint VBA - Paste Special (Enhanced Metafile) bug

I am using a macro in PowerPoint 2003 SP3 to find a specified chart in an Excel workbook, copy it, and then paste it into the current slide as an Enhanced Metafile with, ultimately, the following line of code:
Application.ActiveWindow.View.PasteSpecial DataType:=ppPasteEnhancedMetafile
As often as it works, I also receive the following error:
Run-time error '-2147188160 (80048240)':
View (unknown member) : Invalid request. The specified data type is unavailable.
If I end the macro and attempt to manually Paste Special as Enhanced Metafile, I have no problem, so it's not as though the clipboard object or the pastespecialtype is invalid.
Has anyone else experienced this? Do you have a solution or a workaround? There are few results and no solutions in a Google search on this error.
Update
The general code is as follows:
Set presPPTCurrent = ActivePresentation
Set objXLApp = GetObject(, "Excel.Application")
''#Find the target chart and copy it to the clipboard
With objXLApp
''#This part works - if I go to Excel, I can see that the chart is copied
End With
''#Now paste in the chart as an Enhanced Metafile
presPPTCurrent.Application.Activate
Application.ActiveWindow.View.PasteSpecial DataType:=ppPasteEnhancedMetafile
Note that this is in a Sub to which a Shape is passed (the Shape being passed is used as a reference to find the chart in Excel). I've realized that it only bugs when I attempt to reuse this sub on multiple shapes passed from a For Next loop in another Sub.
However, if I pass a single Shape to this Sub with via another Sub and then re-run the Sub that passes multiple Shapes, it runs fine.
Solution
Per Otaku's mention, the macro was losing its focus on the Slide Pane. Telling it to re-select the Slide Pane solved the issue.
Application.ActiveWindow.Panes(2).Activate
This is likely a loss of focus where switching between Excel and PowerPoint is causing PowerPoint to lose focus and therefore there is no ActiveWindow for PowerPoint to paste in to or the ActiveWindow becomes a different Pane in PowerPoint, such as the Slide Sorter or the Notes pane.
I was experiencing the same issue. I have macro which exports a lot of graphs to the PowerPoint. But some copy-paste actions end with the same error as above (Run-time error '-2147188160 (80048240)':)
I realized that the PasteSpecial error was not due to the loss of focus, but due to the loss of clipboard.
The solution is therefore recopying the area to the clipboard again like:
On Error GoTo paste_error
ppSlide.Shapes.PasteSpecial(2, link:=RangeLink).Select
...
paste_error:
Worksheets(SheetName).Range(RangeName).copy
Resume
Maybe this help somebody...
I was getting the same errors and experimented with many of the solutions on here. What ended up working for me was something very simple. I think it works because of the first line that saves a reference to the slide. The paste option could be EnhancedMetaFile instead of Bitmap.
Sub Macro()
Set sld = Application.ActiveWindow.View.Slide
With GetObject(, "Excel.Application")
.Workbooks(1).Sheets(1).Shapes(1).Copy
End With
sld.Shapes.PasteSpecial DataType:=ppPasteBitmap
End Sub