Change the Chart Style from a Line Chart in Excel with Openpyxl

Question:

I have this following code to export a set of dataframes and then convert them to tables in excel and applying a color format, then it creates Line Graphs for every table, everything works but I’m having trouble with the following:

  • Apply Style 12
  • Place Data Labels to "Above"
  • Remove Major Gridlines

This is what I'm getting

This is what I’m getting

This is what I need

This is what I need! Style 12 with no Major Gridlines and Data Labels Avobe

        # Load the existing workbook
        workbook = openpyxl.load_workbook(output_path + '\' + output_file)

        # Get the 'USA (TM)' sheet or create it if it doesn't exist
        sheet_name = s
        if sheet_name not in workbook.sheetnames:
            workbook.create_sheet(sheet_name)
        sheet = workbook[sheet_name]

        # Assuming 'df' is your DataFrame

        # Write headers to the specified sheet starting from column F, row 1
        headers = merged_cc.columns.tolist()
        for idx, header in enumerate(headers, start=1):
            sheet.cell(row=1, column=idx + columns_position[e] - 1, value=header)

        # Write the DataFrame values to the specified sheet starting from column F, row 2
        for r_idx, row in enumerate(merged_cc.iterrows(), start=2):
            for c_idx, value in enumerate(row[1], start=1):
                sheet.cell(row=r_idx, column=c_idx + columns_position[e] -1 , value=value)
                if isinstance(value, (int, float)):
                    sheet.cell(row=r_idx, column=c_idx + columns_position[e] -1).number_format = '0%'

        # Adjust cell width of the table to specific width
        for idx, column_width in enumerate([10.71, 10.71,10.71, 10.71, 10.71], start=columns_position[e]):  # Example widths
            column_letter = openpyxl.utils.get_column_letter(idx)
            sheet.column_dimensions[column_letter].width = column_width


        # Replace 'A1:B10' with the range you want to convert
        table_range = w

        # Check if the table name already exists
        existing_tables = sheet.tables
        if table_name in existing_tables:
            del sheet._tables[table_name]
        
        # Format the range as a table
        table = openpyxl.worksheet.table.Table(displayName=table_name, ref=table_range)
        table.tableStyleInfo = TableStyleInfo(name="TableStyleMedium13", showFirstColumn=False,
               showLastColumn=False, showRowStripes=True, showColumnStripes=False)
        # Add the table to the worksheet
        sheet.add_table(table)

        # Create Graph *

        # Create a new LineChart object
        chart = LineChart()

        # Add data to the chart
        data = Reference(sheet, min_col=columns_position[e]+2, min_row=1, max_col=columns_position[e] + 4, max_row=sheet.max_row)
        chart.add_data(data, titles_from_data=True)

        # Set the categories (X-axis labels)
        categories = Reference(sheet, min_col=columns_position[e] + 1, min_row=2, max_row=len(merged_cc)+1)
        chart.set_categories(categories)

        # Set the title of the chart
        chart.title = companies[e]
        chart.style = 12
        '''
        # Create a DataLabelList object
        data_labels = DataLabelList()
        data_labels.showVal = True  # Show the values of the data points

        # Set the data labels for the chart
        chart.dLbls = data_labels

        # Iterate through each series in the chart
        for series in chart.series:
            # Set data labels for each data point in the series
            for point in series:
                data_label = DataLabel(idx=point.index, showVal=True, position='above')  # Position data label above the data point
                point.dataLabel = data_label

        # Add the chart to the worksheet
        '''
        sheet.add_chart(chart, graph_coordenades[e])  # Adjust the cell reference as needed
        # Save the workbook
        workbook.save(output_path + '\' + output_file)
Asked By: Berny

||

Answers:

Not sure what you are looking for when you state style 12 but to duplicate what I assume is your required view in the second screen-shot you can specify most of the requirements.

Given your code is not runable I have included a standalone sample that sets the required Chart properties so you can add to your code as you need.

from openpyxl import Workbook
from openpyxl.chart.label import DataLabelList
from openpyxl.drawing.text import ParagraphProperties, CharacterProperties
from openpyxl.chart import (
    LineChart,
    Reference,
    Series,
)

wb = Workbook()
ws = wb.active

### Some constants
min_col = 2
max_col = 5
marker_size = 8
marker_symb = "circle"

"""
This section just adds some data to the Sheet in the format of that used from the screen shot
"""
rows = [
    ('Quarter', 'FQ2 2022', 'FQ4 2022', 'FQ2 2023', 'FQ4 2023'),
    ('R1', 0.51, 0.53, 0.56, 0.58),
    ('R2', 0.26, 0.27, 0.28, 0.31),
    ('R3', 0.07, 0.08, 0.08, 0.1),
]
for r in rows:
    ws.append(r)

for row in ws.iter_rows(min_row=2, min_col=min_col, max_row=4, max_col=max_col):
    for cell in row:
        cell.number_format = '0%'
# ----------------------------------------------------------------- #


def chart_series(s_clr, s_title, s_row):
    # Function to create the series for each plot line
    
    data = Reference(ws, min_col=min_col, min_row=s_row, max_col=max_col, max_row=s_row)
    series = Series(data, title=s_title)  # or have Title reference a cell
    series.graphicalProperties.line.solidFill = s_clr  # Colour of the plotted line
    series.marker.symbol = marker_symb
    series.marker.size = marker_size  # Size of the Marker symbol
    series.marker.graphicalProperties.solidFill = s_clr  # Marker filling
    series.marker.graphicalProperties.line.solidFill = s_clr  # Marker outline

    return series


### Create Line chart
l_chart1 = LineChart()

### Set data and line colour and markers for first row data
s1_line_colour = "0000FF"  # Colour of series plot line
s1_title = 'Unaided Awareness'  # or reference a cell
s1_row = 2  # Row data for this series exists on
### Add Series1 to the chart
l_chart1.append(chart_series(s1_line_colour, s1_title, s1_row))

### Set data and line colour and markers for second row data
s2_line_colour = "FF0000"
s2_title = 'Unaided Consideration'
s2_row = 3
### Add Series2 to the chart
l_chart1.append(chart_series(s2_line_colour, s2_title, s2_row))

### Set data and line colour and markers for third row data
s3_line_colour = "00FF00"
s3_title = 'Unaided Preference'
s3_row = 4
### Add Series3 to the chart
l_chart1.append(chart_series(s3_line_colour, s3_title, s3_row))

### Set Chart Style
# l_chart1.style = 12  # Can be set but will not affect chart

### Set x-axis names
## Get the names from the Excel Range off Sheet
x_values = Reference(ws, min_col=min_col, min_row=1, max_col=max_col, max_row=1)
l_chart1.set_categories(x_values)

### Set y-axis Gridlines and number format
l_chart1.y_axis.minorGridlines = None  # Disable minor gridlines
l_chart1.y_axis.majorGridlines = None  # Disable major gridlines
l_chart1.y_axis.number_format = '0%'   # Set the number format for the Y axis

### Set Chart title
l_chart1.title = 'Store 1'
## Remove Bolding from the Title Text
l_chart1.title.text.rich.paragraphs[0].pPr = ParagraphProperties(defRPr=CharacterProperties(b=False))

### Set position for the Legend
l_chart1.legend.position = 'b'  # Place legend at the bottom of the chart

### Set Datalables above the markers
l_chart1.dataLabels = DataLabelList()
l_chart1.dataLabels.showVal = True
l_chart1.dataLabels.position = 't'  # Put the label above the marker

### Set the Chart size, height and width
l_chart1.height = 15  # default height is 7.5
l_chart1.width = 40  # default width is 15
### Add Chart to Excel Sheet
ws.add_chart(l_chart1, "F1")

### Save Sheet
wb.save("LineChart.xlsx")

This would result in the chart like
enter image description here

You also mention that you want to have "no Major Gridlines" however the Chart in screenshot in your post has Major Gridlines but no X or Y axis lines.
The example above removes the Major and Minor Gridlines, if that is what you require. Removing the X and Y axis lines is probably possible but would need to check further on that.

Answered By: moken