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?
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.
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')
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