Skip to main content
Shapes are the building blocks of slides in PowerPoint. Nearly everything visible on a slide is a shape, from text boxes and images to tables and charts.

Shape types

PowerPoint supports several fundamental shape types:

Auto shape

Regular shapes like rectangles, circles, arrows, and text boxes:
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE
from pptx.util import Inches

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

# Add an auto shape
left = top = Inches(1)
width = height = Inches(2)
shape = slide.shapes.add_shape(
    MSO_SHAPE.ROUNDED_RECTANGLE,
    left, top, width, height
)
shape.text = "Rounded Rectangle"
Auto shapes can have fill, outline, and text. Text boxes are auto shapes with no fill or outline by default.

Picture

Raster images like photographs or clip art:
from pptx import Presentation
from pptx.util import Inches

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

# Add picture
img_path = 'logo.png'
left = top = Inches(1)
pic = slide.shapes.add_picture(img_path, left, top)

# Or specify dimensions
pic = slide.shapes.add_picture(
    img_path,
    left=Inches(2),
    top=Inches(2),
    width=Inches(3)
)

Graphic frame

Containers for tables, charts, and SmartArt:
from pptx import Presentation
from pptx.util import Inches

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

# Add table (creates graphic frame)
rows = cols = 3
left = top = Inches(1)
width = Inches(6)
height = Inches(2)
graphic_frame = slide.shapes.add_table(rows, cols, left, top, width, height)
table = graphic_frame.table

# Add chart (creates graphic frame)
from pptx.enum.chart import XL_CHART_TYPE
from pptx.chart.data import ChartData

chart_data = ChartData()
chart_data.categories = ['Q1', 'Q2', 'Q3']
chart_data.add_series('Sales', (100, 150, 125))

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

Group shape

A container for multiple shapes that can be manipulated as a unit:
from pptx import Presentation
from pptx.util import Inches

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

# Create shapes first
shape1 = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(1), Inches(1), Inches(1), Inches(1))
shape2 = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(2), Inches(1), Inches(1), Inches(1))

# Group them
group = slide.shapes.add_group_shape([shape1, shape2])

Connector

Lines that can connect to other shapes:
from pptx import Presentation
from pptx.enum.shapes import MSO_CONNECTOR_TYPE
from pptx.util import Inches

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

connector = slide.shapes.add_connector(
    MSO_CONNECTOR_TYPE.STRAIGHT,
    begin_x=Inches(1),
    begin_y=Inches(2),
    end_x=Inches(4),
    end_y=Inches(3)
)

Placeholder

Special shapes that inherit formatting from layouts:
from pptx import Presentation

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

# Access placeholders
title_placeholder = slide.shapes.title

# Check if shape is a placeholder
for shape in slide.shapes:
    if shape.is_placeholder:
        print(f"Placeholder: {shape.name}")
See Placeholders for detailed information.

The shape tree

Each slide has a shape tree (collection) that holds its shapes:
from pptx import Presentation

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

# Access shape tree
shapes = slide.shapes

# Shape tree supports list operations
count = len(shapes)
first_shape = shapes[0]

# Iterate through shapes
for idx, shape in enumerate(shapes):
    print(f"{idx}: {shape.name} (type: {shape.shape_type})")
The shape tree is hierarchical - group shapes can contain other shapes with the same semantics.

Common shape properties

All shapes share these fundamental properties:

Position and size

from pptx import Presentation
from pptx.util import Inches

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
shape = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(3), Inches(2))

# Read position and size (in EMU)
left = shape.left
top = shape.top
width = shape.width
height = shape.height

# Modify position and size
shape.left = Inches(2)
shape.top = Inches(3)
shape.width = Inches(4)
shape.height = Inches(1.5)
Position and size are expressed in English Metric Units (EMU). Use Inches(), Cm(), or Pt() for convenience.

Rotation

# Read rotation (degrees clockwise)
rotation = shape.rotation

# Set rotation
shape.rotation = 45.0

# Counter-clockwise rotation (becomes 315.0)
shape.rotation = -45.0

Name and ID

# Shape name (user-visible in PowerPoint)
print(shape.name)  # e.g., 'Rectangle 3'
shape.name = 'Logo Image'

# Shape ID (unique on slide, read-only)
shape_id = shape.shape_id

Shape type

from pptx.enum.shapes import MSO_SHAPE_TYPE

# Identify shape type
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
    print("This is a picture")
elif shape.shape_type == MSO_SHAPE_TYPE.PLACEHOLDER:
    print("This is a placeholder")
elif shape.shape_type == MSO_SHAPE_TYPE.AUTO_SHAPE:
    print("This is an auto shape")

Shape capabilities

Different shapes support different features:

Text capability

from pptx import Presentation

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
shape = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(3), Inches(1))

# Check if shape can contain text
if shape.has_text_frame:
    text_frame = shape.text_frame
    text_frame.text = "Hello, World!"
    
    # Add paragraphs
    p = text_frame.add_paragraph()
    p.text = "Second paragraph"
Auto shapes and placeholders can contain text. Pictures and connectors cannot.

Chart capability

# Check if shape contains a chart
if shape.has_chart:
    chart = shape.chart
    # Work with chart object

Table capability

# Check if shape contains a table
if shape.has_table:
    table = shape.table
    # Work with table object

Adding shapes

The shapes collection provides methods to add different shape types:

Add text box

from pptx import Presentation
from pptx.util import Inches

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

textbox = slide.shapes.add_textbox(
    left=Inches(1),
    top=Inches(2),
    width=Inches(3),
    height=Inches(1)
)
textbox.text = "Text box content"

Add auto shape

from pptx.enum.shapes import MSO_SHAPE
from pptx.util import Inches

shape = slide.shapes.add_shape(
    MSO_SHAPE.ROUNDED_RECTANGLE,
    left=Inches(1),
    top=Inches(1),
    width=Inches(2),
    height=Inches(1.5)
)
shape.text = "Click here"

Add picture

from pptx.util import Inches

picture = slide.shapes.add_picture(
    'image.jpg',
    left=Inches(1),
    top=Inches(1),
    width=Inches(3)  # height auto-calculated to maintain aspect ratio
)

Add table

from pptx.util import Inches

graphic_frame = slide.shapes.add_table(
    rows=3,
    cols=4,
    left=Inches(1),
    top=Inches(2),
    width=Inches(6),
    height=Inches(2)
)
table = graphic_frame.table
table.cell(0, 0).text = "Header 1"

Add chart

from pptx.enum.chart import XL_CHART_TYPE
from pptx.chart.data import ChartData
from pptx.util import Inches

chart_data = ChartData()
chart_data.categories = ['East', 'West', 'North']
chart_data.add_series('Sales', (100, 150, 75))

graphic_frame = slide.shapes.add_chart(
    XL_CHART_TYPE.BAR_CLUSTERED,
    x=Inches(1),
    y=Inches(2),
    cx=Inches(6),
    cy=Inches(4),
    chart_data=chart_data
)
chart = graphic_frame.chart

Shape styling

Fill

from pptx import Presentation
from pptx.enum.dml import MSO_FILL_TYPE
from pptx.util import RGBColor

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(1), Inches(1), Inches(3), Inches(2))

# Solid fill
fill = shape.fill
fill.solid()
fill.fore_color.rgb = RGBColor(255, 0, 0)

# Gradient fill
fill.gradient()
fill.gradient_angle = 45.0

Line (outline)

from pptx.util import Pt, RGBColor

line = shape.line
line.color.rgb = RGBColor(0, 0, 255)
line.width = Pt(2.5)

Shadow

shadow = shape.shadow
shadow.inherit = False
shadow.shadow_type = MSO_SHADOW.OUTER

Click actions

Add hyperlinks and click behaviors to shapes:
from pptx import Presentation
from pptx.util import Inches

prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
shape = slide.shapes.add_textbox(Inches(1), Inches(1), Inches(2), Inches(1))
shape.text = "Click me"

# Add hyperlink
click_action = shape.click_action
click_action.hyperlink.address = "https://example.com"

# Jump to slide
click_action.target_slide = prs.slides[0]

Performance optimization

When adding many shapes, enable turbo mode:
from pptx import Presentation
from pptx.util import Inches

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

# Enable turbo mode for better performance
slide.shapes.turbo_add_enabled = True

# Add many shapes
for i in range(1000):
    shape = slide.shapes.add_textbox(
        Inches(i % 10),
        Inches(i // 10),
        Inches(1),
        Inches(0.5)
    )
    shape.text = f"Box {i}"

# Disable when done
slide.shapes.turbo_add_enabled = False
Turbo mode caches shape IDs. Only use with a single Slide object to avoid ID collisions.

Complete example

Create a slide with multiple shape types:
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE
from pptx.util import Inches, Pt, RGBColor

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

# Add title
title = slide.shapes.add_textbox(Inches(0.5), Inches(0.5), Inches(9), Inches(0.5))
title.text = "Shape Examples"
title_para = title.text_frame.paragraphs[0]
title_para.font.size = Pt(32)
title_para.font.bold = True

# Add rectangle with text
rect = slide.shapes.add_shape(
    MSO_SHAPE.ROUNDED_RECTANGLE,
    Inches(1), Inches(2), Inches(3), Inches(1.5)
)
rect.text = "Call to Action"
rect.fill.solid()
rect.fill.fore_color.rgb = RGBColor(68, 114, 196)
rect.line.color.rgb = RGBColor(0, 0, 0)

# Add picture
pic = slide.shapes.add_picture(
    'logo.png',
    Inches(5), Inches(2), width=Inches(2)
)

# Add connector
connector = slide.shapes.add_connector(
    MSO_CONNECTOR_TYPE.STRAIGHT,
    Inches(4), Inches(2.75),
    Inches(5), Inches(2.75)
)

prs.save('shapes-demo.pptx')

API reference

BaseShape class

Properties:
  • click_action - ActionSetting for hyperlinks/click behavior
  • has_chart - True if contains chart
  • has_table - True if contains table
  • has_text_frame - True if can contain text
  • height - Height in EMU (read/write)
  • is_placeholder - True if is a placeholder
  • left - Left position in EMU (read/write)
  • name - Shape name (read/write)
  • rotation - Rotation in degrees (read/write)
  • shadow - ShadowFormat object
  • shape_id - Unique integer ID (read-only)
  • shape_type - MSO_SHAPE_TYPE member
  • top - Top position in EMU (read/write)
  • width - Width in EMU (read/write)

Shape collections

Methods:
  • add_chart() - Add chart graphic frame
  • add_connector() - Add connector line
  • add_group_shape() - Add group shape container
  • add_picture() - Add picture from file
  • add_shape() - Add auto shape
  • add_table() - Add table graphic frame
  • add_textbox() - Add text box
Properties:
  • turbo_add_enabled - Enable performance mode (read/write)
  • title - Title placeholder if present
Supports: indexing [i], len(), iteration

Build docs developers (and LLMs) love