Python-pptx Import Slide Layout - python

I'm working with pptx to create templates based on info in existing slides. I can create a slide, define its layout, enter text, etc. I can do all the basics. I want to create a slide in a new ppt based on an input ppt and use the same amount of slides as the original, all with their original layouts, and just change some text. How can I access a specific slide's layout # without knowing beforehand? All the other answers say "new_slide_layout = prs.slides.slide_layouts[i]" where i is a number they have defined in the code (usually 0). I'm trying to get that i from the input file and use it without choosing slide type as a user. How can I do this?
Latest functional code:
inputf = pptx.Presentation(input_file)
prs = pptx.Presentation()
old_slide_list = []
slides = inputf.slides
slide_count = 0
for slide in slides:
old_slide_list.append(slide)
slide_count += 1
old_text_runs = []
new_text_runs = []
for i in range(0, slide_count):
old_slide = old_slide_list[i]
old_runs_count = 0
nl = int(input("Enter your choice for this slide's layout (0-8):"))
new_layout = prs.slide_layouts[nl]
new_slide = prs.slides.add_slide(new_layout)
I can allow the user to choose their own slide layout but if I try to rip it directly from the old slide and use it for the new slide it damages the new ppt and it will ask you to repair each time you open it. Older code that damages the presentation:
import copy
for slide in slides:
print('slide number %d' % slides.index(slide))
count += 1
tempct = 0
prs2 = pptx.Presentation()
while tempct != count:
template = prs.slides[tempct]
template_layout = template.slide_layout
new_slide = prs2.slides.add_slide(template_layout)
for shp in template.shapes:
el = shp.element
newel = copy.deepcopy(el)
new_slide.shapes._spTree.insert_element_before(newel, 'p:extLst')
tempct += 1
prs2.save(output_file)

Related

Insert blank slide with python-pptx in existing presentation

I'm working with the python-pptx library and I'm trying to insert a blank slide at a specific place (slide with the same dimensions).
I know how to delete a slide :
def delete_slides(presentation, index):
xml_slides = presentation.slides._sldIdLst
slides = list(xml_slides)
xml_slides.remove(slides[index])
But how to insert a blank slide?
Someone will probably come along with a better solution but you could just create a blank slide and then move it to the location you want.
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("test1.pptx")
layout = presentation.slide_masters[0].slide_layouts[6]
slide = presentation.slides.add_slide(layout)
slide_id = presentation.slides.index(slide)
move_slide(slide_id, 5)
presentation.save("test1.pptx")

Streamlit Session being shared with multiple users

So I am making a Stream lit web application with python. Here is the link to the app: https://jensen-holm-mlb-simapp-app-kclnz9.streamlitapp.com/
I have already deployed the app but have come across a strange problem. When I booted the app it worked great, running simulations for the two teams that I put into it. But after I do this first run, I put two other teams into it. But the simulation yields the same results from the first two teams. I know this because if i try the download play by polay button, it is always the same players from the first simulation. Very weird problem I did not forsee. Even when run on another persons computer, it still yields the same results as it did for that first test I ran on my computer.
I would really like it to re run everything when you enter two different teams and hit go again. Which I thought happens by default.
Any help is greatly appriciated, below is the main app.py file that I am running in the cloud. Here is a link to the github repo: https://github.com/Jensen-holm/MLB-Simapp
import sqlite3
import streamlit as st
from objects import Team
import game_functions
from streamlit_option_menu import option_menu
import pandas as pd
import numpy as np
def convert_df(df):
return df.to_csv().encode("utf-8")
# title and stuff
st.set_page_config(page_title = 'Ball.Sim (Beta)', page_icon = '⚾️')
st.title('Ball.Sim (Beta)')
st.write('\nCreated by Jensen Holm')
st.write('Data Source: [Sports-Reference](https://sports-reference.com)')
st.write('\n[Donate](https://www.paypal.com/donate/?business=HPLUVQJA6GFMN&no_recurring=0&currency_code=USD)')
# get rid of streamlit option menu stuff
# hide_streamlit_style = """
# <style>
# #MainMenu {visibility: hidden;}
# footer {visibility: hidden;}
# </style>
# """
# st.markdown(hide_streamlit_style, unsafe_allow_html=True)
# import the player data dict dictionaries for the keys so we can have options in the select box
sim_data_db = sqlite3.connect("Sim_Data.db")
# get list of all table names with the cursor to put into the st.select_box
all_teams_array = np.array(pd.read_sql_query("SELECT name FROM sqlite_master WHERE type='table'", sim_data_db))
# the all teams array is nested so lets unnest it
all_teams_with_year = []
for sublist in all_teams_array:
for thing in sublist:
all_teams_with_year.append(thing)
all_teams = [team[len('Year '):] for team in all_teams_with_year]
all_teams.sort()
all_teams.insert(0, "Start typing and select team")
# user unput buttons and sliders
team1 = st.selectbox(label = "Team 1", options = all_teams)
team2 = st.selectbox(label = "Team 2", options = all_teams)
number_of_simulations = st.slider("Number of Simulations", min_value = 162, max_value = 16200, step = 162)
# initialize simulation button
init_button = st.button("Go")
if init_button:
if team1 == "Start typing and select team" or team2 == "Start typing and select team":
st.error("Must select team from select boxes.")
st.stop()
# select databse tables based on user input
team1_data = pd.read_sql_query(f"SELECT * FROM 'Year {team1}'", con = sim_data_db)
team2_data = pd.read_sql_query(f"SELECT * FROM 'Year {team2}'", con = sim_data_db)
team1_year = team1[:5]
team2_year = team1[:5]
team1_name = team1[5:]
team2_name = team2[5:]
# generate teams with the data queried above
Team1 = Team(team1_name, team1_year, team1_data, lineup_settings = 'auto')
Team2 = Team(team2_name, team2_year, team2_data, lineup_settings = 'auto')
# begin simulation
pbp_df = game_functions.simulation(number_of_simulations, Team1, Team2, 0)
# make it a csv and use st.download_button()
pbp_csv = convert_df(pbp_df)
st.download_button("Download Play By Play Data", pbp_csv, file_name = "BallSimPBP.csv")
# use st.tabs to filter what to see, like a chart tab for the graph, a place where they can view stats per 162 for each player
# and download data and stuff on another one (may need to figure out the st.session state thing tho)
# footer type stuff, plugging myself.
st.write(f'\n\nFeedback and report bugs: holmj#mail.gvsu.edu')
st.write('\nSocials: [Twitter](https://twitter.com/JensenH_) [GitHub](https://github.com/Jensen-holm) [Linkedin](https://www.linkedin.com/in/jensen-holm-3584981bb/)')
st.write('[Documentation / Code](https://github.com/Jensen-holm/MLB-Simapp)')

Using win32com to combine powerpoint presentations by copying slides

I'm trying to write a python script that combines slides from different powerpoint presentations into a new standalone presentation.
The following code copies a single slide (in this case slide 11) from an existing presentation and pastes it into a new presentation at the insert_index:
import win32com.client
source_path = "source_path"
target_path = "target_path"
ppt_instance = win32com.client.Dispatch('PowerPoint.Application')
read_only = True
has_title = False
window = False
source_prs = ppt_instance.Presentations.open(source_path, read_only, has_title, window)
target_prs = ppt_instance.Presentations.Add()
nr_slide = 11
insert_index = 1
source_prs.Slides(nr_slide).Copy()
target_prs.Slides.Paste(Index=insert_index)
target_prs.SaveAs(target_path)
target_prs.Close()
source_prs.Close()
ppt_instance.Quit()
del ppt_instance
However, this unfortunately changes the colors of some objekts.
How can I get around this?
I appreciate your help.

How to remove the blank text boxes from python pptx generated slides?

from pptx import Presentation
from pptx.util import Inches
prs = Presentation("my_pptfile_begin.pptx")
left = Inches(0.6)
top = Inches(1.7)
blank_slide_1 = prs.slide_layouts[6]
add_the_slide = prs.slides.add_slide(blank_slide_1)
img_path1 = 'Three_Part_Set_Difference_excel_printout.png'
slide1=prs.slides[1]
pic = slide1.shapes.add_picture(img_path1, left, top)
blank_slide_2 = prs.slide_layouts[6]
add_the_slide = prs.slides.add_slide(blank_slide_2)
img_path2 = 'my_image.png'
slide2=prs.slides[2]
pic = slide2.shapes.add_picture(img_path2, left, top)
logoleft = Inches(4.7)
logotop = Inches(1.8)
blank_slide_3 = prs.slide_layouts[6]
add_the_slide = prs.slides.add_slide(blank_slide_3)
img_path3 = 'logo_slide.png'
slide3=prs.slides[3]
pic = slide3.shapes.add_picture(img_path3, logoleft, logotop)
prs.save('my_pptfile_Final.pptx')
How to remove the blank text boxes (or as a matter of fact all textboxes)?
I do not need any text boxes in my Powerpoint output file
If you're talking about empty placeholder shapes, just use a slide layout that has no placeholders.
In the default template used when you call Presentation() by itself (without an argument), that is the seventh layout I believe (prs.slide_layouts[6]).
But you need to adjust that for whatever starting .pptx file you're using ("my_pptfile_begin.pptx" in your case) by looking at it in slide-master view and counting down to the blank layout (or adding one if it doesn't have one).
blank_slide_3 = prs.slide_layouts[x] where x the slide number of the default template of your pptx application or your company's default template.
Therefore you need to know the default template and know the blank slide with no textboxes of that template based on the defaults of your ppt application

Generating consecutive bitmaps with wxPython trouble

Well, while I don't consider myself an experienced programmer, especially when it comes to multimedia applications, I had to do this image viewer sort of a program that displays images fullscreen, and the images change when the users press <- or -> arrows.
The general idea was to make a listbox where all the images contained in a certain folder (imgs) are shown, and when someone does double click or hits RETURN a new, fullscreen frame is generated containing, at first, the image selected in the listbox but after the user hits the arrows the images change in conecutive order, just like in a regular image viewer.
At the beginning, when the first 15 - 20 images are generated, everything goes well, after that, although the program still works an intermediary, very unpleasant and highly unwanted, effect appears between image generations, where basically some images that got generated previously are displayed quickly on the screen and after this the right, consecutive image appears. On the first apparitions the effect is barelly noticeble, but after a while it takes longer and longer between generations.
Here's the code that runs when someone does double click on a listbox entry:
def lbclick(self, eve):
frm = wx.Frame(None, -1, '')
frm.ShowFullScreen(True)
self.sel = self.lstb.GetSelection() # getting the selection from the listbox
def pressk(eve):
keys = eve.GetKeyCode()
if keys == wx.WXK_LEFT:
self.sel = self.sel - 1
if self.sel < 0:
self.sel = len(self.chk) - 1
imgs() # invocking the function made for displaying fullscreen images when left arrow key is pressed
elif keys == wx.WXK_RIGHT:
self.sel = self.sel + 1
if self.sel > len(self.chk) - 1:
self.sel = 0
imgs() # doing the same for the right arrow
elif keys == wx.WXK_ESCAPE:
frm.Destroy()
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, pressk)
def imgs(): # building the function
imgsl = self.chk[self.sel]
itm = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).ConvertToBitmap() # obtaining the name of the image stored in the list self.chk
mar = itm.Size # Because not all images are landscaped I had to figure a method to rescale them after height dimension, which is common to all images
frsz = frm.GetSize()
marx = float(mar[0])
mary = float(mar[1])
val = frsz[1] / mary
vsize = int(mary * val)
hsize = int(marx * val)
panl = wx.Panel(frm, -1, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0)) # making a panel container
panl.SetBackgroundColour('#000000')
imag = wx.Image(str('imgs/{0}'.format(imgsl)), wx.BITMAP_TYPE_JPEG).Scale(hsize, vsize, quality = wx.IMAGE_QUALITY_NORMAL).ConvertToBitmap()
def destr(eve): # unprofessionaly trying to destroy the panel container when a new image is generated hopeing the unvanted effect, with previous generated images will disappear. But it doesn't.
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
panl.Destroy()
except:
pass
eve.Skip()
panl.Bind(wx.EVT_CHAR_HOOK, destr) # the end of my futile tries
if vsize > hsize: # if the image is portrait instead of landscaped I have to put a black image as a container, otherwise in the background the previous image will remain, even if I use Refresh() on the container (the black bitmap named fundal)
intermed = wx.Image('./res/null.jpg', wx.BITMAP_TYPE_JPEG).Scale(frsz[0], frsz[1]).ConvertToBitmap()
fundal = wx.StaticBitmap(frm, 101, intermed)
stimag = wx.StaticBitmap(fundal, -1, imag, size = (hsize, vsize), pos = (frsz[0] / 2 - hsize / 2, 0))
fundal.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
def destr(eve): # the same lame attempt to destroy the container in the portarit images situation
keycd = eve.GetKeyCode()
if keycd == wx.WXK_LEFT or keycd == wx.WXK_RIGHT:
try:
fundal.Destroy()
except:
pass
eve.Skip()
frm.Bind(wx.EVT_CHAR_HOOK, destr)
else: # the case when the images are landscape
stimag = wx.StaticBitmap(panl, -1, imag)
stimag.Refresh()
stimag.SetToolTip(wx.ToolTip('Esc = exits fullscreen\n<- -> arrows = quick navigation'))
imgs() # invocking the function imgs for the situation when someone does double click
frm.Center()
frm.Show(True)
Thanks for any advice in advance.
Added later:
The catch is I'm trying to do an autorun presentation for a DVD with lots of images on it. Anyway it's not necessarely to make the above piece of code work properly if there are any other options. I've already tried to use windows image viewer, but strangely enough it doesn't recognizes relative paths and when I do this
path = os.getcwd() # getting the path of the current working directory
sel = listbox.GetSelection() # geting the value of the current selection from the list box
imgname = memlist[sel] # retrieving the name of the images stored in a list, using the listbox selection, that uses as choices the same list
os.popen(str('rundll32.exe C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen {0}/imgsdir/{1}'.format(path, imgname))) # oepning the images up with bloody windows image viewer
it opens the images only when my program is on the hard disk, if it's on a CD / image drive it doesn't do anything.
There's an image viewer included with the wxPython demo package. I also wrote a really simple one here. Either one should help you in your journey. I suspect that you're not reusing your panels/frames and instead you're seeing old ones that were never properly destroyed.

Categories