scanny / python-pptx

Create Open XML PowerPoint documents in Python
MIT License
2.39k stars 518 forks source link

Connector between shape doesn't match how powerpoint would draw it manually #946

Open jwhendy opened 7 months ago

jwhendy commented 7 months ago

Caveat: I'm pretty new to python-pptx and could be easily messing up.

I approached connecting shapes naively, per the approach in this SO post answered by @scanny .

I have this image saved as box.png: box

Here is my code:

import pptx
from pptx.enum.shapes import MSO_CONNECTOR_TYPE
from pptx.util import Cm

prs = pptx.Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6]) # this yields a blank slide in my default template

s1 = slide.shapes.add_picture('./box.png', left=Cm(2), top=Cm(2), height=pptx.util.Inches(1))
s2 = slide.shapes.add_picture('./box.png', left=Cm(4), top=Cm(5), height=pptx.util.Inches(1))

line = slide.shapes.add_connector(MSO_CONNECTOR_TYPE.ELBOW, Cm(2), Cm(2), Cm(2), Cm(2))
line.begin_connect(s1, 3)
line.end_connect(s2, 0)

prs.save('test.pptx')

I'm getting the right connection points, but I don't understand why the connector comes in from the right vs. down? image

If I go to re-connect the line manually, it does the expected thing, and I'm not sure how I could force the as-is behavior from within powerpoint even if I wanted to? image

Is this a bug or user error on my part? I admit I just put in dummy coordinates; it was not clear to me why I need to initialize the coordinates of a connector when we'll just be accessing shape built-ins to accomplish this. I did play with them a bit, but saw no effect. Just in case, I implemented the method of also determining the connection points from that same SO post and tried this with the same result:

cx1 = s1.left + s1.width
cy1 = s1.top + int(s1.height/2)
cx2 = s2.left + int(s2.width/2)
cy2 = s2.top

line = slide.shapes.add_connector(MSO_CONNECTOR_TYPE.ELBOW, cx1, cy1, cx2, cy2)
line.begin_connect(s1, 3)
line.end_connect(s2, 0)

I do see that connectors are experimental, so if that's why this isn't perfect, could the docs be updated to say what, exactly, isn't working how you want? At the moment, it just seems like it only works with certain shapes, and I believe I'm using ones that ShouldWork. Thanks for any input!

scanny commented 7 months ago

Hmm, dunno. I think you'd have to analyze the change to the XML that happened between the before and after XML for the connector.

Might be worth trying it for two rectangles where it comes out of a side and goes into a side of the other or out of the bottom of one and into the top of the other, just to see if that works. I think you're right the initial location of the connector endpoints is arbitrary if you're going to connect it.

I don't recall much about this feature, I expect it was sponsored and this was good enough behavior for the sponsor and better-than-nothing behavior for everyone else :)

I kind of suppose there is some "egress vector/angle/orientation" attribute that appears on either the connector or the shape and is not or cannot reliably be computed by python-pptx. It's possible it depends on the connector type, that would explain some things. Definitely analysis of the XML would be the next step if you wanted to understand it.

jwhendy commented 7 months ago

I've tried a bunch of entry ids (0 through 3) and the end always wants to go down, then bend right. Not sure.

Forgive the formatting, but here's the extracted connector info (I ditched the