pythonexcelopenpyxl

openpyxl is not able to understand my 2 sub header


I have an Excel sheet with data:

when I try to create a chart like this [clustered chart]

openpyxl is not able to read the data properly

from openpyxl.chart import BarChart, Reference
from openpyxl import load_workbook, workbook

wb = load_workbook("Book1.xlsx")
ws = wb.active
data = Reference(ws, min_col=2, min_row=1, max_row=12,max_col=7)
categories = Reference(ws, min_col=1, min_row=3, max_row=12)

barChart = BarChart()

barChart.type = "col"
barChart.grouping = "clustered"
barChart.title = "XYZ"
barChart.y_axis.title = "service"
barChart.x_axis.title = "month"

barChart.add_data(data,titles_from_data=True)
barChart.set_categories(categories,labels="dasd")

barChart.style = 5
barChart.width = 20
barChart.height = 10

ws.add_chart(barChart,"k8")

wb.save("test.xlsx")

I tried to unmerge the headers, but again, if I do that, the graph I want will not be created.

I tried all the combinations but it's just openpyxl don't capture the data properly


Solution

  • You can add each row as a separate Series.
    For each row m2 to m10 add as a Series after the initial data row m1 is added.
    The categories which contains the two level Header is taken from the Rows 1 & 2. Then enable 'Multi-Level Category Labels' for the X Axis.

    The code sample below assumes your data is contained in the range A1:G12,

    Code Sample I

    from openpyxl.chart import (
        BarChart,
        Reference,
        Series
    )
    from openpyxl import load_workbook
    from openpyxl.chart.layout import Layout, ManualLayout
    
    wb = load_workbook("book1.xlsx")
    ws = wb.active
    
    ### Chart Type
    barChart = BarChart()
    
    ### Initial data Series m1 B3:G3
    data = Reference(ws, min_col=1, min_row=3, max_row=3, max_col=7)
    barChart.add_data(data, titles_from_data=True, from_rows=True)
    
    ### Data Categories (B1:G2), 2 sub header
    categories = Reference(ws, min_col=2, max_col=7, min_row=1, max_row=2)
    ### Add Categories to Chart
    barChart.set_categories(categories)
    ### Set X Axis multilevel label to enabled
    barChart.x_axis.noMultiLvlLbl = False
    
    ### Add additional Series m2 - m10
    ### Create a Series for each row from m2 (row 4) to m10 (row 12)
    for i in range(4, 13):  # 13 is ws.max_row+1
        data = Reference(ws, min_col=1, min_row=i, max_col=7, max_row=i)
        ### Use the header in Column A as the title
        series = Series(data, title_from_data=True)
        ### Add the created Series to the chart
        barChart.append(series)
    
    
    ### Chart Settings
    barChart.type = "col"
    barChart.grouping = "clustered"
    barChart.title = "XYZ"
    barChart.y_axis.title = "service"
    barChart.x_axis.title = "month"
    
    # barChart.style = 5  # Use Chart Style required. This example leaves as default
    barChart.width = 20
    barChart.height = 10
    
    ### Additional Chart Settings
    ### Set the 'Series Overlap', gap between columns 
    barChart.overlap = -10  # -10 is -10% 
    
    # Enable Axis for display
    barChart.x_axis.delete = False
    barChart.y_axis.delete = False
    
    ### Set the legend position at the bottom of the chart
    barChart.legend.position = "b"
    
    ### Adjust the layout to ensure enough space for the legends at the bottom of the chart
    barChart.layout = Layout(
        manualLayout=ManualLayout(
            x=0,  # x position of the plot area
            y=0,  # y position of the plot area
            h=0.65,  # height of the plot area
            w=0.9,  # width of the plot area
        )
    )
    
    ### Add Chart to Sheet
    ws.add_chart(barChart, "K8")
    
    ### Save workbook
    wb.save('test.xlsx')
    

    Code Sample II
    Add all Series as one data reference

    from openpyxl.chart import (
        BarChart,
        Reference
    )
    from openpyxl import load_workbook
    from openpyxl.chart.layout import Layout, ManualLayout
    
    wb = load_workbook("book1.xlsx")
    ws = wb.active
    
    ### Chart Type
    barChart = BarChart()
    
    ### Initial data Series' B3:G12
    data = Reference(ws, min_col=1, min_row=3, max_row=12, max_col=7)
    barChart.add_data(data, titles_from_data=True, from_rows=True)
    
    ### Data Categories (B1:G2), 2 sub header
    categories = Reference(ws, min_col=2, max_col=7, min_row=1, max_row=2)
    ### Add Categories to Chart
    barChart.set_categories(categories)
    ### Set X Axis multilevel label to enabled
    barChart.x_axis.noMultiLvlLbl = False
    
    ### Chart Settings
    barChart.type = "col"
    barChart.grouping = "clustered"
    barChart.title = "XYZ"
    barChart.y_axis.title = "service"
    barChart.x_axis.title = "month"
    
    # barChart.style = 5  # Use Chart Style required. This example leaves as default
    barChart.width = 20
    barChart.height = 10
    
    ### Additional Chart Settings
    ### Set the 'Series Overlap', gap between columns
    barChart.overlap = -10  # -10 is -10%
    
    # Enable Axis for display
    barChart.x_axis.delete = False
    barChart.y_axis.delete = False
    
    ### Set the legend position at the bottom of the chart
    barChart.legend.position = "b"
    
    ### Adjust the layout to ensure enough space for the legends at the bottom of the chart
    barChart.layout = Layout(
        manualLayout=ManualLayout(
            x=0,  # x position of the plot area
            y=0,  # y position of the plot area
            h=0.65,  # height of the plot area
            w=0.9,  # width of the plot area
        )
    )
    
    ### Add Chart to Sheet
    ws.add_chart(barChart, "K8")
    
    ### Save workbook
    wb.save('test.xlsx')
    

    The following is the expected Chart produced.
    Example Chart