0
votes

I have the following code:

import pptx
from pptx.util import Cm
from pptx.enum.chart import XL_CHART_TYPE
from pptx.chart.data import ChartData
from random import randrange

## Select path from which the deck will be imported
path_import = r"XXX.pptx"
## Select layout
SLD_LAYOUT_TITLE_AND_CONTENT = 6 #Empty template
## Create presentation
prs = pptx.Presentation(path_import)
slide_layout = prs.slide_layouts[SLD_LAYOUT_TITLE_AND_CONTENT]
slide = prs.slides.add_slide(slide_layout)
## Create chart data
chart_data1 = ChartData()
chart_data1.categories = [f"TM {i}" for i in range(1,21)]
chart_data1.add_series('Series 1', [randrange(10) for x in range(20)])
## Add chart
chart1 = slide.shapes.add_chart(chart_type=XL_CHART_TYPE.COLUMN_CLUSTERED,
                                x=Cm(0.75),
                                y=Cm(4.71),
                                cx=Cm(32.12),
                                cy=Cm(1.76),
                                chart_data=chart_data1)
## Save deck to path
path_export = r"YYY.pptx"
prs.save(path_export)

So I now have a slide with a graph on it, the "chart area" dimensions are 32.12 cm long and 1.76 cm wide. However, the "plot area" dimensions are fairly small comparatively and I'd like to increase them so that they take up a bigger proportion of the graph. I can't find any reference to this in the documentation, is this possible?

2

2 Answers

1
votes

python-pptx has no API support for overriding the automatic sizing of the chart plot area. It would be possible to patch something in by writing some low-level lxml code, because the PPTX format supports this sort of resizing. But it doesn't come up much. In fact I think this is the first time I've heard someone ask for it.

The downside of using "hard" resizing here or on other chart components is you lose some of the automatic "internal component" resizing that charts do.

In general the preferred approach is to work within that auto-resizing behavior, perhaps by removing the legend and/or chart title, removing axis tick-labels or reducing their font size, etc. Each of those other components you remove makes room that an unadjusted chart area will automatically expand into.

I can't say which approach is right for your application of course, so that decision is up to you. But this latter approach is most common and can be accomplished without resorting to low-level XML manipulation.

0
votes

My solution:

from pptx.oxml.xmlchemy import OxmlElement

def SubElement(parent, tagname, **kwargs):
        element = OxmlElement(tagname)
        element.attrib.update(kwargs)
        parent.append(element)
        return element

def alterChartPlotAreaSize(
        chart,
        x,
        y,
        w,
        h
        ):
    ## Get layout
    plotArea = chart.chart_part._element.chart.plotArea
    plotAreaChildren = plotArea.getchildren()
    pacLayout = [x
                 for x in plotAreaChildren
                 if isinstance(x,pptx.oxml.chart.shared.CT_Layout)]
    if len(pacLayout) == 1:
        layout = pacLayout[0]
    else:
        layout = SubElement(plotArea, 'c:layout', val='inner')
    ## Get manualLayout
    mL = layout.get_or_add_manualLayout()
    ## Remove the current values
    mL.remove_if_present(*['c:layoutTarget',
                          'c:xMode',
                          'c:yMode',
                          'c:x',
                          'c:y',
                          'c:w',
                          'c:h'])
    ## Add layoutTarget and set val to inner
    _ = SubElement(mL, 'c:layoutTarget', val='inner')
    ## Add xMode and yMode and set vals to edge
    _ = SubElement(mL, 'c:xMode', val="edge")
    _ = SubElement(mL, 'c:yMode', val="edge")
    ## Add x, value is between 0 and 1, where 0 is far left of chart area
    ##    and 1 is far right of chart area
    _ = SubElement(mL, 'c:x', val=str(x))
    ## Add y, same concept as above
    _ = SubElement(mL, 'c:y', val=str(y))
    ## Add x, value is between 0 and 1, where 0 is very top of chart area
    ##    and 1 is very bottom of chart area
    _ = SubElement(mL, 'c:w', val=str(w))
    ## Add h, same concept as above
    _ = SubElement(mL, 'c:h', val=str(h))