Working with Charts

Overview

Aspose.Cells FOSS uses a method-per-chart-type API. Instead of a generic add(ChartType.X, ...) call, each chart type has its own dedicated method on the worksheet’s charts collection:

MethodChart type
ws.charts.add_bar(top_row, left_col, bottom_row, right_col)Clustered column
ws.charts.add_line(top_row, left_col, bottom_row, right_col)Line
ws.charts.add_bar(top_row, left_col, bottom_row, right_col)Horizontal bar
ws.charts.add_pie(top_row, left_col, bottom_row, right_col)Pie

All four positional parameters describe the rectangular area in the sheet where the chart will be embedded. Row and column indices are zero-based. Each method returns a Chart object that you configure further before saving.


Adding a Column Chart

The example below writes a small revenue-by-product dataset and then adds a column chart positioned below the data.

from aspose.cells_foss import Workbook, Cell

workbook = Workbook()
ws = workbook.worksheets[0]

##--- Data ---
ws.cells["A1"].value = "Product"
ws.cells["B1"].value = "Revenue"

products = ["Widget A", "Widget B", "Widget C", "Widget D", "Widget E"]
revenues = [12_500, 18_200, 9_800, 21_400, 15_600]

for i, (product, revenue) in enumerate(zip(products, revenues), start=2):
    ws.cells[f"A{i}"].value = product
    ws.cells[f"B{i}"].value = revenue

##--- Chart (rows 7–22, columns A–H, all zero-based) ---
##top_row=6, left_col=0, bottom_row=22, right_col=7
chart = ws.charts.add_bar(6, 0, 22, 7)

chart.title = "Revenue by Product"
chart.n_series.add("B2:B6", category_data="A2:A6", name="Revenue (USD)")
chart.show_legend = True
chart.legend_position = "bottom"

workbook.save("column_chart.xlsx")
print("Saved column_chart.xlsx")

The data occupies rows 1–6 (zero-based rows 0–5), so top_row=6 places the chart immediately below without overlapping the data.


Adding a Line Chart

Line charts work well for showing trends over time. The call signature is identical to add_bar — only the method name changes.

from aspose.cells_foss import Workbook, Cell

workbook = Workbook()
ws = workbook.worksheets[0]

##--- Monthly trend data ---
ws.cells["A1"].value = "Month"
ws.cells["B1"].value = "Page Views"
ws.cells["C1"].value = "Conversions"

months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
page_views   = [4_200, 5_100, 4_800, 6_300, 7_100, 6_800]
conversions  = [  210,   255,   230,   340,   390,   360]

for i, (month, pv, cv) in enumerate(zip(months, page_views, conversions), start=2):
    ws.cells[f"A{i}"].value = month
    ws.cells[f"B{i}"].value = pv
    ws.cells[f"C{i}"].value = cv

##--- Line chart below the data ---
chart = ws.charts.add_line(8, 0, 24, 8)

chart.title = "Monthly Website Metrics"
chart.n_series.add("B2:B7", category_data="A2:A7", name="Page Views")
chart.n_series.add("C2:C7", category_data="A2:A7", name="Conversions")
chart.show_legend = True
chart.legend_position = "bottom"

workbook.save("line_chart.xlsx")
print("Saved line_chart.xlsx")

Chart Title and Legend

Set the chart title by assigning a plain string directly to chart.title. The property accepts a str — do not attempt to access a sub-property such as .title.text, which does not exist in this library.

##Correct
chart.title = "Quarterly Sales"

##Wrong — raises AttributeError
##chart.title.text = "Quarterly Sales"

Legend visibility and position are controlled by two properties:

chart.show_legend = True          # display the legend
chart.legend_position = "bottom"  # "bottom", "top", "left", "right"

To hide the legend entirely, set chart.show_legend = False. The legend_position value is ignored when the legend is hidden.


Data Series Configuration

Use chart.n_series.add() to attach data ranges to a chart. Pass all arguments as keyword arguments to avoid positional-order confusion:

chart.n_series.add("B2:B6", category_data="A2:A6", name="Revenue")

You can add multiple series to a single chart by calling n_series.add more than once. Each call appends a new series:

from aspose.cells_foss import Workbook, Cell

workbook = Workbook()
ws = workbook.worksheets[0]

##Headers
ws.cells["A1"].value = "Quarter"
ws.cells["B1"].value = "North"
ws.cells["C1"].value = "South"
ws.cells["D1"].value = "East"

data = [
    ("Q1", 8_400, 6_100, 7_200),
    ("Q2", 9_200, 7_400, 8_100),
    ("Q3", 10_500, 8_900, 9_600),
    ("Q4", 11_800, 9_300, 10_200),
]

for i, row in enumerate(data, start=2):
    ws.cells[f"A{i}"].value = row[0]
    ws.cells[f"B{i}"].value = row[1]
    ws.cells[f"C{i}"].value = row[2]
    ws.cells[f"D{i}"].value = row[3]

chart = ws.charts.add_bar(6, 0, 22, 8)
chart.title = "Regional Sales by Quarter"

chart.n_series.add("B2:B5", category_data="A2:A5", name="North")
chart.n_series.add("C2:C5", category_data="A2:A5", name="South")
chart.n_series.add("D2:D5", category_data="A2:A5", name="East")

chart.show_legend = True
chart.legend_position = "bottom"

workbook.save("multi_series_chart.xlsx")
print("Saved multi_series_chart.xlsx")

Category Data

Category labels can be set at the chart level or at the individual series level.

Chart-level category data applies to all series as a default:

chart.category_data = "A2:A5"

Series-level category data (via the category_data keyword argument to n_series.add) overrides the chart-level setting for that specific series:

chart.n_series.add("B2:B5", category_data="A2:A5", name="Revenue")

When every series shares the same category range, setting chart.category_data once is more concise. When series have different category ranges — for example, two datasets with different time periods — use the per-series keyword argument instead.


Chart Positioning

The four positional parameters to every add_* method define a bounding rectangle in the sheet, measured in zero-based row and column indices:

add_bar(top_row, left_col, bottom_row, right_col)
ParameterMeaning
top_rowZero-based index of the first row occupied by the chart
left_colZero-based index of the leftmost column
bottom_rowZero-based index of the last row occupied by the chart
right_colZero-based index of the rightmost column

A common pattern is to place the chart directly below the data. If your data ends at Excel row 6 (zero-based row index 5), start the chart at top_row=6:

from aspose.cells_foss import Workbook, Cell

workbook = Workbook()
ws = workbook.worksheets[0]

##Data in rows 1–5 (zero-based 0–4)
labels = ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]
values = [30, 45, 28, 60, 52]

ws.cells["A1"].value = "Category"
ws.cells["B1"].value = "Score"

for i, (label, val) in enumerate(zip(labels, values), start=2):
    ws.cells[f"A{i}"].value = label
    ws.cells[f"B{i}"].value = val

##Data ends at zero-based row 5 (Excel row 6).
##Place chart from row 6 to row 22, columns A–H (0–7).
chart = ws.charts.add_bar(6, 0, 22, 7)
chart.title = "Category Scores"
chart.n_series.add("B2:B6", category_data="A2:A6", name="Score")
chart.show_legend = False

workbook.save("positioned_chart.xlsx")
print("Saved positioned_chart.xlsx")

Make the chart tall enough to be readable: a height of at least 15 rows (bottom_row - top_row >= 15) and a width of at least 6 columns is a reasonable starting point.


Common Mistakes

WrongRightWhy
ws.charts.add(ChartType.COLUMN, ...)ws.charts.add_bar(...)There is no generic add method; use the dedicated method for each chart type.
chart.title.text = "My Chart"chart.title = "My Chart"chart.title is a plain string property, not an object with a .text sub-property.
chart.n_series.add("B2:B5", "A2:A5", "Revenue")chart.n_series.add("B2:B5", category_data="A2:A5", name="Revenue")The second and third parameters must be passed as keyword arguments to avoid ambiguity.
chart = ws.charts.add_bar(0, 0, 15, 7) (overlaps data)Place top_row below last data rowA chart that overlaps data obscures values and causes confusing layouts.
chart.legend_position = "bottom" without chart.show_legend = TrueSet chart.show_legend = True firstlegend_position has no effect when show_legend is False.

See Also