Creating and styling tables with cells, rows, and columns. Includes cell merging, text formatting, and table-wide styling options for structured data presentation.
Add tables to slides with specified dimensions and positioning.
# Table creation through shapes collection
def add_table(rows: int, cols: int, left: int, top: int, width: int, height: int) -> GraphicFrame:
"""
Add table to slide.
Parameters:
- rows: Number of table rows
- cols: Number of table columns
- left, top: Position in EMU
- width, height: Table dimensions in EMU
Returns:
GraphicFrame containing Table object
"""Access and configure table structure and properties.
class Table:
"""Table with rows, columns, and cells."""
@property
def rows(self) -> _RowCollection:
"""Collection of table rows."""
@property
def columns(self) -> _ColumnCollection:
"""Collection of table columns."""
def cell(self, row_idx: int, col_idx: int) -> _Cell:
"""
Get cell at specified position.
Parameters:
- row_idx: Row index (0-based)
- col_idx: Column index (0-based)
Returns:
_Cell object at specified position
"""
@property
def first_row(self) -> bool:
"""True if first row has special formatting."""
@first_row.setter
def first_row(self, first_row: bool):
"""Set first row special formatting."""
@property
def first_col(self) -> bool:
"""True if first column has special formatting."""
@first_col.setter
def first_col(self, first_col: bool):
"""Set first column special formatting."""
@property
def last_row(self) -> bool:
"""True if last row has special formatting."""
@last_row.setter
def last_row(self, last_row: bool):
"""Set last row special formatting."""
@property
def last_col(self) -> bool:
"""True if last column has special formatting."""
@last_col.setter
def last_col(self, last_col: bool):
"""Set last column special formatting."""
@property
def horz_banding(self) -> bool:
"""True if horizontal banding is applied."""
@horz_banding.setter
def horz_banding(self, banding: bool):
"""Set horizontal banding."""
@property
def vert_banding(self) -> bool:
"""True if vertical banding is applied."""
@vert_banding.setter
def vert_banding(self, banding: bool):
"""Set vertical banding."""Manage table rows including height and cell access.
class _RowCollection:
"""Collection of table rows."""
def __getitem__(self, index: int) -> _Row:
"""Get row by index."""
def __len__(self) -> int:
"""Number of rows."""
def __iter__(self):
"""Iterate over rows."""
class _Row:
"""Individual table row."""
@property
def height(self) -> int:
"""Row height in EMU."""
@height.setter
def height(self, height: int):
"""Set row height."""
@property
def cells(self) -> list:
"""List of cells in this row."""
def __getitem__(self, index: int) -> _Cell:
"""Get cell by column index."""Manage table columns including width properties.
class _ColumnCollection:
"""Collection of table columns."""
def __getitem__(self, index: int) -> _Column:
"""Get column by index."""
def __len__(self) -> int:
"""Number of columns."""
def __iter__(self):
"""Iterate over columns."""
class _Column:
"""Individual table column."""
@property
def width(self) -> int:
"""Column width in EMU."""
@width.setter
def width(self, width: int):
"""Set column width."""Work with individual table cells including content, formatting, and merging.
class _Cell:
"""Individual table cell with content and formatting."""
@property
def text(self) -> str:
"""Plain text content of cell."""
@text.setter
def text(self, text: str):
"""Set cell text content."""
@property
def text_frame(self) -> TextFrame:
"""Text frame for rich text formatting."""
@property
def fill(self) -> FillFormat:
"""Cell background fill formatting."""
@property
def margin_left(self) -> int:
"""Left margin in EMU."""
@margin_left.setter
def margin_left(self, margin: int):
"""Set left margin."""
@property
def margin_top(self) -> int:
"""Top margin in EMU."""
@margin_top.setter
def margin_top(self, margin: int):
"""Set top margin."""
@property
def margin_right(self) -> int:
"""Right margin in EMU."""
@margin_right.setter
def margin_right(self, margin: int):
"""Set right margin."""
@property
def margin_bottom(self) -> int:
"""Bottom margin in EMU."""
@margin_bottom.setter
def margin_bottom(self, margin: int):
"""Set bottom margin."""
@property
def vertical_anchor(self) -> MSO_VERTICAL_ANCHOR:
"""Vertical alignment of cell content."""
@vertical_anchor.setter
def vertical_anchor(self, anchor: MSO_VERTICAL_ANCHOR):
"""Set vertical alignment."""
def merge(self, other_cell: '_Cell') -> _Cell:
"""
Merge this cell with another cell.
Parameters:
- other_cell: Cell to merge with (must be adjacent)
Returns:
Merged cell object
"""
@property
def is_merge_origin(self) -> bool:
"""True if cell is origin of merged cell range."""
@property
def is_spanned(self) -> bool:
"""True if cell is part of merged range but not origin."""Usage examples:
from pptx import Presentation
from pptx.util import Inches
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT, MSO_VERTICAL_ANCHOR
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank layout
# Create table
rows, cols = 4, 3
left, top = Inches(1), Inches(1)
width, height = Inches(8), Inches(4)
table_shape = slide.shapes.add_table(rows, cols, left, top, width, height)
table = table_shape.table
# Set table formatting options
table.first_row = True # Header row formatting
table.horz_banding = True # Alternating row colors
# Add header row content
header_texts = ['Product', 'Q1 Sales', 'Q2 Sales']
for col_idx, text in enumerate(header_texts):
cell = table.cell(0, col_idx)
cell.text = text
# Format header cells
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(68, 114, 196)
# Format header text
paragraph = cell.text_frame.paragraphs[0]
paragraph.font.color.rgb = RGBColor(255, 255, 255)
paragraph.font.bold = True
paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
cell.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
# Add data rows
data = [
['Product A', '$12,000', '$15,000'],
['Product B', '$8,500', '$11,200'],
['Product C', '$6,800', '$9,100']
]
for row_idx, row_data in enumerate(data, start=1):
for col_idx, text in enumerate(row_data):
cell = table.cell(row_idx, col_idx)
cell.text = text
# Center align numeric columns
if col_idx > 0:
paragraph = cell.text_frame.paragraphs[0]
paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
cell.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
# Adjust column widths
table.columns[0].width = Inches(2.5) # Product name column
table.columns[1].width = Inches(2.0) # Q1 column
table.columns[2].width = Inches(2.0) # Q2 column
# Adjust row heights
for row in table.rows:
row.height = Inches(0.8)
# Create table with merged cells
slide2 = prs.slides.add_slide(prs.slide_layouts[6])
table2_shape = slide2.shapes.add_table(5, 4, Inches(1), Inches(1), Inches(8), Inches(4))
table2 = table2_shape.table
# Add title spanning multiple columns
title_cell = table2.cell(0, 0)
title_cell.text = "Annual Sales Report"
# Merge cells across columns for title
for col in range(1, 4):
title_cell.merge(table2.cell(0, col))
# Format merged title cell
title_cell.fill.solid()
title_cell.fill.fore_color.rgb = RGBColor(0, 100, 0)
title_para = title_cell.text_frame.paragraphs[0]
title_para.font.color.rgb = RGBColor(255, 255, 255)
title_para.font.bold = True
title_para.font.size = Pt(16)
title_para.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
title_cell.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
# Add quarter headers
quarters = ['', 'Q1', 'Q2', 'Q3']
for col_idx, quarter in enumerate(quarters):
cell = table2.cell(1, col_idx)
cell.text = quarter
if col_idx > 0: # Quarter cells
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(200, 200, 200)
cell.text_frame.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
# Add product data
products = ['Product X', 'Product Y', 'Product Z']
for row_idx, product in enumerate(products, start=2):
# Product name
table2.cell(row_idx, 0).text = product
# Sales data
for col_idx in range(1, 4):
cell = table2.cell(row_idx, col_idx)
cell.text = f"${(row_idx-1) * col_idx * 1000:,}"
cell.text_frame.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.RIGHT
# Demonstrate cell border formatting
for row_idx in range(table2.rows.__len__()):
for col_idx in range(table2.columns.__len__()):
cell = table2.cell(row_idx, col_idx)
# Note: Cell border formatting would require accessing
# cell.border properties if available in implementation
prs.save('tables-example.pptx')from pptx.util import Pt
# Complex cell merging example
def create_complex_table():
table = slide.shapes.add_table(6, 5, Inches(1), Inches(1), Inches(8), Inches(5)).table
# Create merged header spanning multiple rows and columns
top_left = table.cell(0, 0)
top_left.text = "Department Summary"
# Merge cells in L-shape
top_left.merge(table.cell(0, 1)) # Merge right
top_left.merge(table.cell(1, 0)) # Merge down
top_left.merge(table.cell(1, 1)) # Complete 2x2 merge
# Set cell margins for better text positioning
for row in table.rows:
for cell in row.cells:
cell.margin_left = Inches(0.1)
cell.margin_right = Inches(0.1)
cell.margin_top = Inches(0.05)
cell.margin_bottom = Inches(0.05)
return table
# Table styling with alternating colors
def apply_zebra_striping(table):
"""Apply alternating row colors to table."""
for row_idx, row in enumerate(table.rows):
if row_idx % 2 == 1: # Odd rows
for cell in row.cells:
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(245, 245, 245)
# Dynamic table sizing based on content
def auto_size_columns(table, content_data):
"""Adjust column widths based on content length."""
max_lengths = []
# Calculate maximum content length per column
for col_idx in range(len(table.columns)):
max_len = 0
for row_data in content_data:
if col_idx < len(row_data):
max_len = max(max_len, len(row_data[col_idx]))
max_lengths.append(max_len)
# Set column widths proportionally
total_width = Inches(8)
total_chars = sum(max_lengths)
for col_idx, max_len in enumerate(max_lengths):
proportion = max_len / total_chars if total_chars > 0 else 1/len(max_lengths)
table.columns[col_idx].width = int(total_width * proportion)# Header row styling
def format_header_row(table):
"""Apply consistent header formatting."""
header_row = table.rows[0]
header_row.height = Inches(0.6)
for cell in header_row.cells:
# Background
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(31, 78, 120)
# Text formatting
paragraph = cell.text_frame.paragraphs[0]
paragraph.font.color.rgb = RGBColor(255, 255, 255)
paragraph.font.bold = True
paragraph.font.size = Pt(12)
paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
# Cell alignment
cell.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
# Data row formatting
def format_data_rows(table, start_row=1):
"""Apply consistent data row formatting."""
for row_idx in range(start_row, len(table.rows)):
row = table.rows[row_idx]
row.height = Inches(0.4)
for cell in row.cells:
paragraph = cell.text_frame.paragraphs[0]
paragraph.font.size = Pt(10)
cell.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE