I am using Python3 and the win32com package to automatically copy charts from an excel file and paste them into a powerpoint presentation. The charts do not all fit on one slide unless they are resized, so I scale their width by 0.85. However, I am not sure how to paste them at specific locations so they are all pasted atop one another. I think I have found a solution in visual basic (here: https://www.mrexcel.com/board/threads/vba-positioning-chart-in-powerpoint-after-copy-pasting-from-excel.1107603/ and here: VBA: Copy + Paste Selected Charts from Excel to Powerpoint) but I don't know any VBA so am not sure how to translate it to python. Thank you for your help!
import os
import win32com.client as client
from win32com.client import constants
xl = client.gencache.EnsureDispatch('Excel.Application')
ppt = client.gencache.EnsureDispatch('PowerPoint.Application')
wb = xl.Workbooks.Open(os.path.abspath("desiredFile.xlsx"))
prs = ppt.Presentations.Open(os.path.abspath("sample00.pptx"))
sheet = wb.Sheets('TheSheetINeed')
Slide = prs.Slides.Add(prs.Slides.Count,constants.ppLayoutBlank)
for ch in sheet.ChartObjects():
ch.Activate()
ch.Copy()
Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
#Here is where I need help
prs.Save()
prs.Close()
wb.Close(False)
ppt.Quit()
xl.Quit()
I don't know how Python3 declares variables or otherwise works, but I would try something like the following. Instead of
Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
I would try
shp = Slide.Shapes.PasteSpecial(constants.ppPasteShape).ScaleWidth(.85,0)
shp.Left = LeftValue
shp.Top = TopValue
where shp is a variable that represents the pasted shape.
Related
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
Before saying this has been answered numerous times, don't please. I have looked at every link I could find. I still am having trouble figuring it out because most answers talk about VBA IN Excel not VB.Net in Visual Studio.
I am trying this:
Dim Charts As Excel.ChartObjects = CType(sheet.ChartObjects(Type.Missing), Excel.ChartObjects)
Dim myChart As Excel.ChartObject = CType(Charts.Add(10, pos * 20, 600, 400), Excel.ChartObject)
Dim chart As Excel.Chart = myChart.Chart
chart.ChartType = Excel.XlChartType.xlLineStacked
chart.SetSourceData(sheet.Range("B4:B10, E4:E10"))
chart.SetSourceData(sheet.Range("H4:H10, J4:J10"))
It plots 1 series perfectly, but I can't get the second series on there.
The chart displays like this:
I tried creating a Macro in Excel and then pasting/editing the code and I couldn't get that to work either. Working with VB.Net and Excel is all new to me. How can I plot multiple series to an Excel sheet from VB.Net? Thanks!!
UPDATE:
I was able to FINALLY figure this out. I wasn't creating a separate series individually. Now I feel like this was a really dumb question... Thanks everyone.
This is what I did to get it working.
Dim ds As Excel.Series
ds = chart.SeriesCollection.NewSeries()
ds.XValues = sheet.Range("B4:B6")
ds.Values = sheet.Range("E4:E6")
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 have a template.pptx , having 10 slides in total. I want to copy a slide/layout of slide 2 and add new slide after 2, between 2 and 3.
what I can do currently is copy and add the slide at the end of presentation.
prs = Presentation('C:\Documents\template.pptx')
slide = prs.slides.add_slide(prs.slide_layouts[1])
prs.save('C:\Documents\template_save.pptx')
Can I do this using java apache-poi?
I have tried the hybrid approach and it works well.
Copy and add slide at the end of presentation with python-pptx
Reorder slides with Apache POI
ppt.setSlideOrder(slides.length-1, 4); // Bring last slide to 5th position
from pptx import Presentation
def move_slide(old_index, new_index):
xml_slides = presentation.slides._sldIdLst
slides = list(xml_slides)
xml_slides.remove(slides[old_index])
xml_slides.insert(new_index, slides[old_index])
presentation = Presentation(pptpath)
layout = presentation.slide_masters[0].slide_layouts[6]
slide = presentation.slides.add_slide(layout)
slide_id = presentation.slides.index(slide)
move_slide(slide_id, 3)
presentation.save(pptpath)
Couldn't find answers I can understand. So I've decided to ask.
I'm learning Python. And now I'm trying to solve a problem with collecting data from active spreadsheet in one excel file and paste it to another excel file. The first file contains table and a few cells with information to the right of it. I'm trying to fully copy the spreadsheet data.
import openpyxl, os
from openpyxl.cell import get_column_letter
os.chdir('D:\\Python')
wb = openpyxl.load_workbook('auto.xlsx')
ws = wb.active
# Create new workbook and chose active worksheet.
wbNew = openpyxl.Workbook()
wsNew = wbNew.active
# Loop through all cells (rows, then columns) in the first file
# and fill in the second one.
for allObj in ws['A1':get_column_letter(ws.max_column) + str(ws.max_row)]:
for cellObj in allObj:
for allNewObj in wsNew:
for newCellObj in allNewObj:
wsNew[cellObj.coordinate].value = cellObj.value
wbNew.save('example.xlsx')
Finally it works.