Python PPTX Bar Chart negative values

2019-03-02 04:35发布

问题:

I use the following code to give specific color for the bars, for a bar chart generated by python-pptx.

chart.series[0].format.fill.solid()
chart.series[0].format.fill.fore_color.rgb = RGBColor(160,190,230)

This looks fine most of time. However, then the bar charts have negative values, the bars, several issues occur.

  • The negative bars have no colors and is transparent
  • The bars overlap with the category names

I've tried both of below options to no effect.

chart.series[0].invert_if_negative = True
chart.series[0].invert_if_negative = False

Is there a way to make the chart renders properly, with color and not overlapping with category names?

回答1:

Well, this is two questions. But as far as the category names overlapping, you can fix that by setting the tick label position to LOW:

from pptx.enum.chart import XL_TICK_LABEL_POSITION

category_axis = chart.category_axis
category_axis.tick_label_position = XL_TICK_LABEL_POSITION.LOW

On the transparent (or perhaps white) colored bars, I suspect you might be seeing a PowerPoint version-dependent non-conformance with the spec that's cropped up elsewhere. I'd open it in PowerPoint and see what you can see on the properties dialog, whether the invert if negative option is appearing the way you set it and whether it operates when you set it manually using the PowerPoint UI.

If the "Invert if negative" checkbox is not checked in the Data Series > Fill (format) dialog when you've set it to True using python-pptx AND clicking that checkbox on solves the display issue, you can open a case on the python-pptx GitHub issues list and we'll get a fix into the next release.

Basically, certain versions of PowerPoint interpret a boolean element type such as this inconsistently, depending on the element (<c:invertIfNegative> in this case), so while it passes the tests, it doesn't behave as expected in all PowerPoint versions. It could be that's what you're seeing.



回答2:

try to dig a little into the xml:

    ccaxis = chart.category_axis
    ticklblPos = ccaxis._element.find('{http://schemas.openxmlformats.org/drawingml/2006/chart}tickLblPos')
    ticklblPos.set('val','low')


回答3:

Replacing fill.solid() by fill.patterned() worked for me :

color_red = RGBColor(254, 98, 94)
color_green = RGBColor(1, 194, 170)

for idx, point in enumerate(series.points):
    fill = point.format.fill
    fill.patterned()
    if data[idx]<0 :
        fill.fore_color.rgb = color_red   
    else:
        fill.back_color.rgb = color_green