Search code examples
pythonbar-chartpython-pptx

Python PPTX suppress zero values in a stacked Bar Chart


Is there a possibility to suppress zero values in a stacked Bar Chart like the following.

stacked_bar_chart

Manually, it's at least possible to remove the zero values in the Excel workbook while keeping the order (bad, medium, good). I tried to replace the zeros in the numpy array by NaN and then adding it by using add_series. As soon as I want to replace the data, I get the following error:

{TypeError} NAN/INF not supported in write_number() without 'nan_inf_to_errors' Workbook() option

My code snippet looks like:

chart_data = ChartData()
chart_data.categories = labels
chart = graphic_frame.chart

for index, row in df.iterrows():
    values = row.values
    values[values == 0] = np.nan
    chart_data.add_series(index, (values))

chart.replace_data(chart_data)

Or is there an alternative going deeper in the xml code to hide specifically zero labels?


Solution

  • This worked out for clustered bars.

    You need to look for the particular point in the series with a value of 0 and set for that point's data_label the has_text_frame property to True.

    It may seem counterintuitive to set it to True and not to False. The thing is that this property is already set to False, and the one rendering the numbers is PowerPoint using the value in the data set. By setting it to True and not providing any text, it will leave it empty.

    Next, you need to set show_values to True for each series. This will tell PowerPoint to show the numeric value of the datapoint. You will have to do this series by series.

    The last thing to do is to give format to your labels. Since they were removed and rendered when you do show_values = True, the format is reset so you need to set it again.

    Here is a sample code:

    for series in chart.plots[0].series:
        for i, val in enumerate(series.values):
            if val == 0:
                series.points[i].data_label.has_text_frame = True
        series.data_labels.show_value = True
        series.data_labels.font.size = YOUR_FONT_SIZE
        series.data_labels.font.name = YOUR_FONT
        series.data_labels.font.color.rgb = YOUR_COLOR
        series.data_labels.number_format = YOUR_NUMBER_FORMAT
    

    Here is an example of how this looks, before and after

    Before

    Clustered bar chart showing data labels for series with a value of 0

    After

    Clustered bar chart hiding data labels which have a value of 0