10 KiB
10 KiB
Tables Reference
Comprehensive guide to creating and styling tables in ReportLab.
Basic Table Creation
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
# Simple data (list of lists or tuples)
data = [
['Header 1', 'Header 2', 'Header 3'],
['Row 1, Col 1', 'Row 1, Col 2', 'Row 1, Col 3'],
['Row 2, Col 1', 'Row 2, Col 2', 'Row 2, Col 3'],
]
# Create table
table = Table(data)
# Add to story
story.append(table)
Table Constructor
table = Table(
data, # Required: list of lists/tuples
colWidths=None, # List of column widths or single value
rowHeights=None, # List of row heights or single value
style=None, # TableStyle object
splitByRow=1, # Split across pages by rows (not columns)
repeatRows=0, # Number of header rows to repeat
repeatCols=0, # Number of header columns to repeat
rowSplitRange=None, # Tuple (start, end) of splittable rows
spaceBefore=None, # Space before table
spaceAfter=None, # Space after table
cornerRadii=None, # [TL, TR, BL, BR] for rounded corners
)
Column Widths
from reportlab.lib.units import inch
# Equal widths
table = Table(data, colWidths=2*inch)
# Different widths per column
table = Table(data, colWidths=[1.5*inch, 2*inch, 1*inch])
# Auto-calculate widths (default)
table = Table(data)
# Percentage-based (of available width)
table = Table(data, colWidths=[None, None, None]) # Equal auto-sizing
Cell Content Types
Text and Newlines
# Newlines work in cells
data = [
['Line 1\nLine 2', 'Single line'],
['Another\nmulti-line\ncell', 'Text'],
]
Paragraph Objects
from reportlab.platypus import Paragraph
from reportlab.lib.styles import getSampleStyleSheet
styles = getSampleStyleSheet()
data = [
[Paragraph("Formatted <b>bold</b> text", styles['Normal']),
Paragraph("More <i>italic</i> text", styles['Normal'])],
]
table = Table(data)
Images
from reportlab.platypus import Image
data = [
['Description', Image('logo.png', width=1*inch, height=1*inch)],
['Product', Image('product.jpg', width=2*inch, height=1.5*inch)],
]
table = Table(data)
Nested Tables
# Create inner table
inner_data = [['A', 'B'], ['C', 'D']]
inner_table = Table(inner_data)
# Use in outer table
outer_data = [
['Label', inner_table],
['Other', 'Content'],
]
outer_table = Table(outer_data)
TableStyle
Styles are applied using command lists:
from reportlab.platypus import TableStyle
from reportlab.lib import colors
style = TableStyle([
# Command format: ('COMMAND', (startcol, startrow), (endcol, endrow), *args)
('GRID', (0, 0), (-1, -1), 1, colors.black), # Grid over all cells
('BACKGROUND', (0, 0), (-1, 0), colors.grey), # Header background
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), # Header text color
])
table = Table(data)
table.setStyle(style)
Cell Coordinate System
- Columns and rows are 0-indexed:
(col, row) - Negative indices count from end:
-1is last column/row (0, 0)is top-left cell(-1, -1)is bottom-right cell
# Examples:
(0, 0), (2, 0) # First three cells of header row
(0, 1), (-1, -1) # All cells except header
(0, 0), (-1, -1) # Entire table
Styling Commands
Text Formatting
style = TableStyle([
# Font name
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
# Font size
('FONTSIZE', (0, 0), (-1, -1), 10),
# Text color
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('TEXTCOLOR', (0, 1), (-1, -1), colors.black),
# Combined font command
('FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 12), # name, size
])
Alignment
style = TableStyle([
# Horizontal alignment: LEFT, CENTER, RIGHT, DECIMAL
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('ALIGN', (0, 1), (0, -1), 'LEFT'), # First column left
('ALIGN', (1, 1), (-1, -1), 'RIGHT'), # Other columns right
# Vertical alignment: TOP, MIDDLE, BOTTOM
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('VALIGN', (0, 0), (-1, 0), 'BOTTOM'), # Header bottom-aligned
])
Cell Padding
style = TableStyle([
# Individual padding
('LEFTPADDING', (0, 0), (-1, -1), 12),
('RIGHTPADDING', (0, 0), (-1, -1), 12),
('TOPPADDING', (0, 0), (-1, -1), 6),
('BOTTOMPADDING', (0, 0), (-1, -1), 6),
# Or set all at once by setting each
])
Background Colors
style = TableStyle([
# Solid background
('BACKGROUND', (0, 0), (-1, 0), colors.blue),
('BACKGROUND', (0, 1), (-1, -1), colors.lightgrey),
# Alternating row colors
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.lightblue]),
# Alternating column colors
('COLBACKGROUNDS', (0, 0), (-1, -1), [colors.white, colors.lightgrey]),
])
Gradient Backgrounds
from reportlab.lib.colors import Color
style = TableStyle([
# Vertical gradient (top to bottom)
('BACKGROUND', (0, 0), (-1, 0), colors.blue),
('VERTICALGRADIENT', (0, 0), (-1, 0),
[colors.blue, colors.lightblue]),
# Horizontal gradient (left to right)
('HORIZONTALGRADIENT', (0, 1), (-1, 1),
[colors.red, colors.yellow]),
])
Lines and Borders
style = TableStyle([
# Complete grid
('GRID', (0, 0), (-1, -1), 1, colors.black),
# Box/outline only
('BOX', (0, 0), (-1, -1), 2, colors.black),
('OUTLINE', (0, 0), (-1, -1), 2, colors.black), # Same as BOX
# Inner grid only
('INNERGRID', (0, 0), (-1, -1), 0.5, colors.grey),
# Directional lines
('LINEABOVE', (0, 0), (-1, 0), 2, colors.black), # Header border
('LINEBELOW', (0, 0), (-1, 0), 1, colors.black), # Header bottom
('LINEBEFORE', (0, 0), (0, -1), 1, colors.black), # Left border
('LINEAFTER', (-1, 0), (-1, -1), 1, colors.black), # Right border
# Thickness and color
('LINEABOVE', (0, 1), (-1, 1), 0.5, colors.grey), # Thin grey line
])
Cell Spanning
data = [
['Spanning Header', '', ''], # Span will merge these
['A', 'B', 'C'],
['D', 'E', 'F'],
]
style = TableStyle([
# Span 3 columns in first row
('SPAN', (0, 0), (2, 0)),
# Center the spanning cell
('ALIGN', (0, 0), (2, 0), 'CENTER'),
])
table = Table(data)
table.setStyle(style)
Important: Cells that are spanned over must contain empty strings ''.
Advanced Spanning Examples
# Span multiple rows and columns
data = [
['A', 'B', 'B', 'C'],
['A', 'D', 'E', 'F'],
['A', 'G', 'H', 'I'],
]
style = TableStyle([
# Span rows in column 0
('SPAN', (0, 0), (0, 2)), # Merge A cells vertically
# Span columns in row 0
('SPAN', (1, 0), (2, 0)), # Merge B cells horizontally
('GRID', (0, 0), (-1, -1), 1, colors.black),
])
Special Commands
Rounded Corners
table = Table(data, cornerRadii=[5, 5, 5, 5]) # [TL, TR, BL, BR]
# Or in style
style = TableStyle([
('ROUNDEDCORNERS', [10, 10, 0, 0]), # Rounded top corners only
])
No Split
Prevent table from splitting at specific locations:
style = TableStyle([
# Don't split between rows 0 and 2
('NOSPLIT', (0, 0), (-1, 2)),
])
Split-Specific Styling
Apply styles only to first or last part when table splits:
style = TableStyle([
# Style for first part after split
('LINEBELOW', (0, 'splitfirst'), (-1, 'splitfirst'), 2, colors.red),
# Style for last part after split
('LINEABOVE', (0, 'splitlast'), (-1, 'splitlast'), 2, colors.blue),
])
Repeating Headers
# Repeat first row on each page
table = Table(data, repeatRows=1)
# Repeat first 2 rows
table = Table(data, repeatRows=2)
Complete Examples
Styled Report Table
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.lib.units import inch
data = [
['Product', 'Quantity', 'Unit Price', 'Total'],
['Widget A', '10', '$5.00', '$50.00'],
['Widget B', '5', '$12.00', '$60.00'],
['Widget C', '20', '$3.00', '$60.00'],
['', '', 'Subtotal:', '$170.00'],
]
table = Table(data, colWidths=[2.5*inch, 1*inch, 1*inch, 1*inch])
style = TableStyle([
# Header row
('BACKGROUND', (0, 0), (-1, 0), colors.darkblue),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 12),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
# Data rows
('BACKGROUND', (0, 1), (-1, -2), colors.beige),
('GRID', (0, 0), (-1, -2), 0.5, colors.grey),
('ALIGN', (1, 1), (-1, -1), 'RIGHT'),
('ALIGN', (0, 1), (0, -1), 'LEFT'),
# Total row
('BACKGROUND', (0, -1), (-1, -1), colors.lightgrey),
('LINEABOVE', (0, -1), (-1, -1), 2, colors.black),
('FONTNAME', (2, -1), (-1, -1), 'Helvetica-Bold'),
])
table.setStyle(style)
Alternating Row Colors
data = [
['Name', 'Age', 'City'],
['Alice', '30', 'New York'],
['Bob', '25', 'Boston'],
['Charlie', '35', 'Chicago'],
['Diana', '28', 'Denver'],
]
table = Table(data, colWidths=[2*inch, 1*inch, 1.5*inch])
style = TableStyle([
# Header
('BACKGROUND', (0, 0), (-1, 0), colors.darkslategray),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
# Alternating rows (zebra striping)
('ROWBACKGROUNDS', (0, 1), (-1, -1),
[colors.white, colors.lightgrey]),
# Borders
('BOX', (0, 0), (-1, -1), 2, colors.black),
('LINEBELOW', (0, 0), (-1, 0), 2, colors.black),
# Padding
('LEFTPADDING', (0, 0), (-1, -1), 12),
('RIGHTPADDING', (0, 0), (-1, -1), 12),
('TOPPADDING', (0, 0), (-1, -1), 6),
('BOTTOMPADDING', (0, 0), (-1, -1), 6),
])
table.setStyle(style)
Best Practices
- Set colWidths explicitly for consistent layout
- Use repeatRows for multi-page tables with headers
- Apply padding for better readability (especially LEFTPADDING and RIGHTPADDING)
- Use ROWBACKGROUNDS for alternating colors instead of styling each row
- Put empty strings in cells that will be spanned
- Test page breaks early with realistic data amounts
- Use Paragraph objects in cells for complex formatted text
- Set VALIGN to MIDDLE for better appearance with varying row heights
- Keep tables simple - complex nested tables are hard to maintain
- Use consistent styling - define once, apply to all tables