Skip to main content
Charts visualize data in PowerPoint presentations. python-pptx supports most PowerPoint chart types including column, bar, line, pie, XY (scatter), and bubble charts.

Adding a chart

Create charts using chart data objects and the add_chart() method:
from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[5])

# Define chart data
chart_data = CategoryChartData()
chart_data.categories = ['East', 'West', 'Midwest']
chart_data.add_series('Series 1', (19.2, 21.4, 16.7))

# Add chart to slide
x, y, cx, cy = Inches(2), Inches(2), Inches(6), Inches(4.5)
graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)

# Access the chart object
chart = graphic_frame.chart

prs.save('chart-01.pptx')
add_chart() returns a GraphicFrame shape containing the chart. Access the chart via the chart property.

Category charts

Category charts use discrete categories for the X-axis (column, bar, line, pie, etc.).

Single series chart

from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE

chart_data = CategoryChartData()
chart_data.categories = ['Q1', 'Q2', 'Q3', 'Q4']
chart_data.add_series('Revenue', (125.3, 142.7, 156.2, 178.9))

graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)

Multi-series chart

chart_data = CategoryChartData()
chart_data.categories = ['East', 'West', 'Midwest']
chart_data.add_series('Q1 Sales', (19.2, 21.4, 16.7))
chart_data.add_series('Q2 Sales', (22.3, 28.6, 15.2))
chart_data.add_series('Q3 Sales', (20.4, 26.3, 14.2))

graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)

Chart types

from pptx.enum.chart import XL_CHART_TYPE

chart_data = CategoryChartData()
chart_data.categories = ['A', 'B', 'C']
chart_data.add_series('Series 1', (10, 20, 30))

graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED,
    x, y, cx, cy, chart_data
)

XY and bubble charts

XY (scatter) charts use continuous values for both axes. Bubble charts add a third dimension via marker size.

XY scatter chart

from pptx.chart.data import XyChartData
from pptx.enum.chart import XL_CHART_TYPE

chart_data = XyChartData()

series_1 = chart_data.add_series('Model 1')
series_1.add_data_point(0.7, 2.7)
series_1.add_data_point(1.8, 3.2)
series_1.add_data_point(2.6, 0.8)

series_2 = chart_data.add_series('Model 2')
series_2.add_data_point(1.3, 3.7)
series_2.add_data_point(2.7, 2.3)
series_2.add_data_point(1.6, 1.8)

chart = slide.shapes.add_chart(
    XL_CHART_TYPE.XY_SCATTER, x, y, cx, cy, chart_data
).chart

Bubble chart

from pptx.chart.data import BubbleChartData

chart_data = BubbleChartData()

series_1 = chart_data.add_series('Series 1')
series_1.add_data_point(0.7, 2.7, 10)  # x, y, bubble_size
series_1.add_data_point(1.8, 3.2, 4)
series_1.add_data_point(2.6, 0.8, 8)

chart = slide.shapes.add_chart(
    XL_CHART_TYPE.BUBBLE, x, y, cx, cy, chart_data
).chart

Formatting charts

Axes

Customize category and value axes:
from pptx.enum.chart import XL_TICK_MARK
from pptx.util import Pt

chart = graphic_frame.chart

# Category axis
category_axis = chart.category_axis
category_axis.has_major_gridlines = True
category_axis.minor_tick_mark = XL_TICK_MARK.OUTSIDE
category_axis.tick_labels.font.italic = True
category_axis.tick_labels.font.size = Pt(24)

# Value axis
value_axis = chart.value_axis
value_axis.maximum_scale = 50.0
value_axis.minimum_scale = 0.0
value_axis.minor_tick_mark = XL_TICK_MARK.OUTSIDE
value_axis.has_minor_gridlines = True

# Format tick labels
tick_labels = value_axis.tick_labels
tick_labels.number_format = '0"%"'  # Format as percentage
tick_labels.font.bold = True
tick_labels.font.size = Pt(14)

Data labels

Add and format data labels:
from pptx.dml.color import RGBColor
from pptx.enum.chart import XL_LABEL_POSITION
from pptx.util import Pt

plot = chart.plots[0]
plot.has_data_labels = True
data_labels = plot.data_labels

data_labels.font.size = Pt(13)
data_labels.font.color.rgb = RGBColor(0x0A, 0x42, 0x80)
data_labels.position = XL_LABEL_POSITION.INSIDE_END
data_labels.number_format = '0.0'  # One decimal place

Legend

Add and position a legend:
from pptx.enum.chart import XL_LEGEND_POSITION

chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.RIGHT
chart.legend.include_in_layout = False
Legend position options:
  • XL_LEGEND_POSITION.BOTTOM
  • XL_LEGEND_POSITION.LEFT
  • XL_LEGEND_POSITION.RIGHT
  • XL_LEGEND_POSITION.TOP
  • XL_LEGEND_POSITION.CORNER

Complete examples

from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LEGEND_POSITION
from pptx.util import Inches

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[5])

# Create chart data
chart_data = CategoryChartData()
chart_data.categories = ['Q1', 'Q2', 'Q3', 'Q4']
chart_data.add_series('Revenue', (125.3, 142.7, 156.2, 178.9))
chart_data.add_series('Costs', (95.2, 105.8, 112.3, 125.6))
chart_data.add_series('Profit', (30.1, 36.9, 43.9, 53.3))

# Add chart
x, y, cx, cy = Inches(0.5), Inches(1), Inches(9), Inches(5)
graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)

chart = graphic_frame.chart

# Add legend
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
chart.legend.include_in_layout = False

# Format value axis
value_axis = chart.value_axis
value_axis.maximum_scale = 200
value_axis.has_major_gridlines = True

prs.save('revenue-chart.pptx')

Understanding plots

A plot (called ChartGroup in the Microsoft API) is a sub-chart containing one or more series. Most charts have a single plot, but combination charts can have multiple plots.
# Access the first plot
plot = chart.plots[0]

# Set data labels on the plot
plot.has_data_labels = True

# Access series through the plot
for series in plot.series:
    print(series.name)

Working with series

Access and customize individual series:
# Access series by index
series = chart.series[0]

# Series properties
print(series.name)
print(len(series.values))

# Format series (line charts)
series.smooth = True  # Smooth the line

# Access data points
for point in series.points:
    # Customize individual points
    pass

Chart colors

By default, charts use theme colors (Accent 1 through Accent 6). To customize colors:
  1. Use theme colors: Modify the theme colors in your template presentation
  2. Set data point colors: Customize individual data points programmatically (support varies by chart type)
Color customization support varies by chart type. The most reliable approach is to use theme colors in your template.

Best practices

  • Use CategoryChartData for column, bar, line, and pie charts
  • Use XyChartData for scatter charts
  • Use BubbleChartData for bubble charts
  • Set include_in_layout = False for legends to prevent chart resizing
  • Format tick labels with appropriate number formats ('0%', '$#,##0', etc.)
  • Enable gridlines for easier data reading
  • Keep legends concise and position them appropriately
  • Use consistent chart dimensions across slides for professional appearance

Build docs developers (and LLMs) love