Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set manually chart_title position? #1030

Open
rileym99 opened this issue Dec 6, 2024 · 2 comments
Open

How to set manually chart_title position? #1030

rileym99 opened this issue Dec 6, 2024 · 2 comments

Comments

@rileym99
Copy link

rileym99 commented Dec 6, 2024

Hello,

I've been using python-pptx 1.0.2 for several weeks now and find it very helpful. I've been able to do or find workarounds to everything I need to do except set manually the position of a chart title. I would like to align it to the left of the chart object.

I was trying to use something like the layout attribute that I found here: https://stackoverflow.com/questions/48325832/custom-legend-position-with-python-pptx but the chart_title element doesn't appear to have this property as I get the error: AttributeError: 'CT_Title' object has no attribute 'get_or_add_layout'.

Does anyone have any suggestions on a workaround?

Thanks,
Matthew

@scanny
Copy link
Owner

scanny commented Dec 6, 2024

@rileym99 the general gist is:

  • figure out if PowerPoint can do it and then how how it does it. This involves using the PowerPoint UI to do it and inspecting before and after XML.
  • Manipulate the XML in your document to produce the necessary elements and attributes using the best tools available.

If there is an existing property or method like .get_or_add_layout() that's of course the first choice. Where those are not available you'll need to use lower-level lxml methods to achieve the XML changes.

If you have a search around on "python-pptx workaround function" as a start you should be able to find ways folks have done that. You may want to dig into the internals that python-pptx itself uses to make methods like get_or_add_layout() like OxmlElement() and so on, many of which are in oxml/xmlchemy.py and nearby.

@rileym99
Copy link
Author

rileym99 commented Dec 9, 2024

Thank you for your help @scanny - I've been able to implement this. I've put some sample code below in case anybody else has this request.

from pptx.oxml.xmlchemy import OxmlElement

# start with an existing python-pptx chart object
chart_title = chart.chart_title
__set_chart_title_position(chart_title, 0, 0.025) # 0.025 seems to match the default position

def __set_chart_title_position(title, x, y):
    """
    Manually sets the chart title position

    :param title: a chart_title object
    :param x: value between 0 and 1 as a proportion of the chart width, from top left corner
    :param y: value between 0 and 1 as a proportion of the chart height, from top left corner
    """
    # Remove the existing layout
    cte = title._element
    cte = __remove_xml_element(cte, 'c:layout')

    # Inside layout, add manualLayout
    L = __add_xml_element(cte, 'c:layout')
    mL = __add_xml_element(L, 'c:manualLayout')

    # Add xMode and yMode and set vals to edge and x, y co-ordinates from top left corner
    xM = __add_xml_element(mL, 'c:xMode', val="edge")
    xY = __add_xml_element(mL, 'c:yMode', val="edge")
    xE = __add_xml_element(mL, 'c:x', val=str(x))
    yE = __add_xml_element(mL, 'c:y', val=str(y))

def __remove_xml_element(parent, tag_name, **kwargs):
    """
    Removes an xml element from a parent xml element

    :param parent: the parent element from which to remove the element
    :tag_name: the xml tag names, e.g. c:layout]

    Output: a reference to the parent element
    """
    tag = tag_name.split(":")[-1]
    for child in parent.getchildren():
        if tag in str(child.tag):
            parent.remove(child)

    return parent

def __add_xml_element(parent, tag_name, **kwargs):
    """
    Adds a new xml element to the presentation

    :param parent: the parent element to which to add the new element
    :tag_name: the xml tag names, e.g. c:layout

    Output: a reference to the newly created element
    """
    element = OxmlElement(tag_name)
    element.attrib.update(kwargs)
    parent.append(element)
    return element

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants