Python PPTX workaround function for rotating chart data labels - python

I intend to create the following chart using Python PPTX.
Below code achieve the color setting, font size and number format. However, I am not yet able to rotate the data label, as I believe this API is not yet available in python-pptx 0.6.5
lbl = plot.data_labels
lbl.font.size = config["DATA_LABEL_FONT_SIZE"]
lbl.font.color.rgb = config["DATA_LABEL_FONT_COLOR"]
lbl.number_format = config["DATA_LABEL_NUMBER_FORMAT"]
lbl.position = config["DATA_LABEL_POSITION"]
To get started, I have created two minimal slides before and after rotating, and use opc-diag tool to find the diff.
<a:bodyPr rot="-5400000" spcFirstLastPara="1" vertOverflow="ellipsis"
vert="horz" wrap="square" lIns="38100" tIns="19050" rIns="38100"
bIns="19050" anchor="ctr" anchorCtr="1">\n
<a:spAutoFit/>\n </a:bodyPr>\n
I believe I need to add rot="-5400000" XML element to lbl (plot.data_labels), but not clear on how to achieve this. I have used dir(), ._element and .xml on the chart and its children but not able to find <a:bodyPr> tag.

I tried below and it works.
if config["DATA_LABEL_VERTICAL"]:
txPr = lbl._element.get_or_add_txPr()
txPr.bodyPr.set('rot','-5400000')

Related

Using local images as markers in Bokeh for Python graphs

I want to use local images as the markers on a figure rather than the provided shapes.
Like this
image source So instead of:
slider_renderer = plt.square(x='x_mercator', y='y_mercator', source=payload_at_timestamp, size=20, color='lightskyblue')
Something like:
slider_renderer = plt.image(image='path/to/image', x='x_mercator', y='y_mercator', source=payload_at_timestamp, size=20, color='lightskyblue')
I've tried a few ways of doing this without success. In particular, using the Bokeh image object didn't work as intended, with the interpreter complaining that the image was not part of the source dataframe:
quad_icon = skimage.io.imread('analysis_icons/quad.png')
slider_renderer = Image(image=[quad_icon], x='x_mercator', y='y_mercator', source=payload_at_timestamp)
I'm currently outputting the resulting figure in an HTML file, so hosting it locally with bokeh serve isn't a good option.

change all fonts in powerpoint without opening the file

I wanted change the all fonts in about 100 powerpoint files, without opening the files. There are several shape types in each slide and each might have a different font. I used python-pptx package and wrote the following code to change the fonts of all texts in a powerpoint presentation. Although it does not give any error, it does not work, and the fonts in the file are still whatever they were, for example Arial. I also added print(shape.text) to make sure that it has found all texts, and it seems that there is no issue there. Is it a bug? Or am I missing anything?
prs = Presentation('f10.pptx')
for i, slide in enumerate(prs.slides):
for shape in slide.shapes:
print (shape.has_text_frame)
if shape.has_text_frame:
print(shape.text)
for p in shape.text_frame.paragraphs:
for r in p.runs:
print(r.font.name)
r.font.name = 'Tahoma'
print(r.font.name)
prs.save('f10_tahoma.pptx')
Besides, it seems that the package does not work for utf-8 characters. I added a text-box on the last slide by adding:
text_frame = shape.text_frame
text_frame.clear() # not necessary for newly-created shape
p = text_frame.paragraphs[0]
run = p.add_run()
run.text = 'سلام '
font = run.font
font.name = 'Andalus'
font.size = Pt(18)
before saving the file to add a textbox with utf-8 characters. It adds it there, and when I check the font it shows that it is set to Andalus, but actually it is not Andalus.
With Aspose.Slides for Python via .NET, you can easily change all fonts for all texts in your presentations. The following code example shows you how to do this:
import aspose.slides as slides
with slides.Presentation('example.pptx') as presentation:
for slide in presentation.slides:
for shape in slide.shapes:
if isinstance(shape, slides.AutoShape):
for paragraph in shape.text_frame.paragraphs:
for portion in paragraph.portions:
portion.portion_format.latin_font = slides.FontData('Tahoma')
You can also evaluate Aspose.Slides Cloud SDK for Python for presentation manipulating. This REST-based API allows you to make 150 free API calls per month for API learning and presentation processing.
Aspose Slides Online Viewer can be used to view presentations without PowerPoint installed.
I work at Aspose.
What language is the text of the file? Run.font properties work fine for UTF-8, but there is a separate font for cursive scripts like Arabic. Access to that secondary font is not implemented in python-pptx unfortunately, but that could explain at least part of the behavior you're seeing.
For roman character text (like that we're using here), there are a couple things to check.
The font in question needs to be installed on the machine PowerPoint is running on when the document is opened. Otherwise PowerPoint will substitute a font.
The font (typeface) name used in the XML will not always exactly match what appears in the PowerPoint drop-down selection box. You need to give that name to python-pptx in the exact form it should appear in the XML. You may need to make an example file that works by hand, perhaps containing a single slide with a single textbox for simplicity, and then inspect the XML of that file to find the "spelling" used for that typeface by PowerPoint.
You could do that with code like this:
prs = Presentation("example.pptx")
shape = prs.slides[0].shapes[0]
print(shape._element.xml)
You should be able to locate the typeface name somewhere in an element like <p:rPr> or <p:defRPr>.

Python PPTX: Adding Entire Slide from Another Presentation

It seems this issue was brought up and requested back in 2015 but I cannot find any updates on it. I'm trying to copy an entire slide (including its text and images) from another presentation into my working presentation by doing something like the following:
prs = Presentation('CurrentPresentation.pptx')
prs1 = Presentation('OtherPresentation.pptx')
# Wanted_Slide = prs1.slides[0]
New_Slide = prs.slides.add_slide(prs1.slide_layout[0])
But all this does is add a totally blank slide (with the wanted slide's background) with slide layout 0, which totally makes sense. I know that's not the right way to do it. I tried the below and it did add a slide, but it was just a duplicate one of what was already in the prs presentation (I guess I found a way to duplicate a slide already in the presentation inadvertently):
def Add_Slide(self):
xml_slides = prs.slides._sldIdLst
xml_slides1 = prs1.slides._sldIdLst
slides = list(xml_slides)
slides1 = list(xml_slides1)
xml_slides.append(slides1[0])
The above code is a manipulation of a slide delete method I found online.
Or does anyone have any sort of recommendation on how to completely copy a slide and all of its contents over to a working presentation?
I apologize if no developments have been made and this post is a rehash. Thank you in advance.
There's an issue in the library's repo that has some code to do this, but it's rough, it doesn't work for all cases.
from pptx.parts.chart import ChartPart
from pptx.parts.embeddedpackage import EmbeddedXlsxPart
from pptx import Presentation
import copy
def _get_blank_slide_layout(pres):
layout_items_count = [len(layout.placeholders) for layout in pres.slide_layouts]
min_items = min(layout_items_count)
blank_layout_id = layout_items_count.index(min_items)
return pres.slide_layouts[blank_layout_id]
def move_slide(pres1, pres, index):
"""Duplicate the slide with the given index in pres1 and "moves" it into pres.
Adds slide to the end of the presentation"""
source = pres1.slides[index]
blank_slide_layout = _get_blank_slide_layout(pres)
dest = pres.slides.add_slide(blank_slide_layout)
for shape in source.shapes:
newel = copy.deepcopy(shape.element)
dest.shapes._spTree.insert_element_before(newel, 'p:extLst')
for key, value in source.part.rels.items():
# Make sure we don't copy a notesSlide relation as that won't exist
if "notesSlide" not in value.reltype:
target = value._target
# if the relationship was a chart, we need to duplicate the embedded chart part and xlsx
if "chart" in value.reltype:
partname = target.package.next_partname(
ChartPart.partname_template)
xlsx_blob = target.chart_workbook.xlsx_part.blob
target = ChartPart(partname, target.content_type,
copy.deepcopy(target._element), package=target.package)
target.chart_workbook.xlsx_part = EmbeddedXlsxPart.new(
xlsx_blob, target.package)
dest.part.rels.add_relationship(value.reltype, target,value.rId)
This function is an alteration of what is on the github comments at the location cited above. It works well for me, haven't tested it with charts or anything. It's slightly altered from what was posted on the site, because there was the rough example noted by the original answer, and there was a more thorough answer for duplicating within a presentation. Figured I'd post since it took me a while to get this all put together.
This solution has mainly worked with one exception. After copying the slide over to the destination presentation when I open the destination presentation I get the following warning:
PowerPoint couldn't read some content in xxx.pptx and removed it. Please check your presentation to see if the rest of it looks ok.
The rest of the presentation does look fine and after saving and reopening the warning goes away. Do you know of a way to make it so this warning doesn't appear or if there is a way to resolve it with Python (saving/closing again?).

Need help to format text in charts created using openpyxl

Long time lurker, first time asker. If I'm missing something let me know.
I'm using python 35 and openpyxl 2.4.0. I've generated a number of charts in an xlsx file. Snippet below:
# create chart for summary graph
myChart = BarChart()
myChart.type = 'col'
myChart.style = 10
myChart.title = chartTitle # 'chartTitle' is passed to the function
myChart.y_axis.title = 'No. of WRs'
myChart.x_axis.title = 'WR assignee'
# some lines here omitted (related to charted data)
myChart.shape = 4
newSheet.add_chart(myChart, 'F1')
All works well, but the chart title and axis titles are 18 and 16 pt font - much too big for the chart size. I don't want to work on the chart size because I don't know in advance how many columns will be graphed - the script reads a weekly ERP dump and graphs specific results.
The openpyxl doc provides guidance on formatting cells, but none (that I can find) on text size within charts. Any help would be appreciated.
I hope it won't get you too late. After a lot of research I was able to find a way to change the font and its size from a chart segment using Openpyxl.
The size of the font is defined at the sz=1500 and this means the usual 15 font size. Using that logic 1200 is 12. The minimum is 100 and the maximum is 400000.
from openpyxl.chart.text import RichText
from openpyxl.drawing.text import Paragraph, ParagraphProperties, CharacterProperties, Font
font_test = Font(typeface='Calibri')
cp = CharacterProperties(latin=font_test, sz=1500)
chart.x_axis.txPr = RichText(p=[Paragraph(pPr=ParagraphProperties(defRPr=cp), endParaRPr=cp)])

Custom Artist In Matplotlib Legend

I have a program using PtQt that utilizes matplotlib to do some plot rendering. For saving images, I would like to make use of the legend to render a custom image (additionally the built-in draggable feature makes this very appealing). I'm reading up on the legend, but I can't seem to figure out how to make a legend that calls my own paintEvent() method for Qt in which I can render custom images.
In case this approach is terrible, here's my goal: I want to put a image (rendered inside the program by Qt) either inside the plot window or find a way to append this image on top of the exported figure.
Here's a screenshot of what the output looks like now:
I'd like to take the DAIP... sequence at the top and have that exported with the figure.
Hopefully someone has tackled a similar problem before.
I solved it by using the OffsetImage and AnnotationBBox features of matplotlib after saving the image to a temporary png file. For some reason keeping it as a temporary file didn't work well.
Briefly:
#draw stuff onto QPixmap named pix
byteArray = QByteArray()
buffer = QBuffer(byteArray)
buffer.open(QIODevice.WriteOnly)
pix.save(buffer, 'PNG')
stringIO = StringIO(byteArray)
stringIO.seek(0)
tfile = tempfile.NamedTemporaryFile(suffix=".png", mode="wb", delete=False)
tfile.write(stringIO.buf)
tfile.close()
imagebox = mpl.offsetbox.OffsetImage(mpl._png.read_png(tfile.name),zoom=zlvl)
ab = mpl.offsetbox.AnnotationBbox(imagebox, [w/2,0],frameon=False)
ab.set_figure(self.canvas.figure)
ab.draggable()
self.subplot.axes.add_artist(ab)
os.remove(tfile.name)

Categories

Resources