Files
gh-k-dense-ai-claude-scient…/skills/reportlab/references/charts_reference.md
2025-11-30 08:30:10 +08:00

13 KiB

Charts and Graphics Reference

Comprehensive guide to creating charts and data visualizations in ReportLab.

Graphics Architecture

ReportLab's graphics system provides platform-independent drawing:

  • Drawings - Container for shapes and charts
  • Shapes - Primitives (rectangles, circles, lines, polygons, paths)
  • Renderers - Convert to PDF, PostScript, SVG, or bitmaps (PNG, GIF, JPG)
  • Coordinate System - Y-axis points upward (like PDF, unlike web graphics)

Quick Start

from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics import renderPDF

# Create drawing (canvas for chart)
drawing = Drawing(400, 200)

# Create chart
chart = VerticalBarChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 125
chart.data = [[100, 150, 130, 180]]
chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4']

# Add chart to drawing
drawing.add(chart)

# Render to PDF
renderPDF.drawToFile(drawing, 'chart.pdf', 'Chart Title')

# Or add as flowable to Platypus document
story.append(drawing)

Available Chart Types

Bar Charts

from reportlab.graphics.charts.barcharts import (
    VerticalBarChart,
    HorizontalBarChart,
)

# Vertical bar chart
chart = VerticalBarChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Single series
chart.data = [[100, 150, 130, 180, 140]]

# Multiple series (grouped bars)
chart.data = [
    [100, 150, 130, 180],  # Series 1
    [80, 120, 110, 160],   # Series 2
]

# Categories
chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4']

# Colors for each series
chart.bars[0].fillColor = colors.blue
chart.bars[1].fillColor = colors.red

# Bar spacing
chart.barWidth = 10
chart.groupSpacing = 10
chart.barSpacing = 2

Stacked Bar Charts

from reportlab.graphics.charts.barcharts import VerticalBarChart

chart = VerticalBarChart()
# ... set position and size ...

chart.data = [
    [100, 150, 130, 180],  # Bottom layer
    [50, 70, 60, 90],      # Top layer
]
chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4']

# Enable stacking
chart.barLabelFormat = 'values'
chart.valueAxis.visible = 1

Horizontal Bar Charts

from reportlab.graphics.charts.barcharts import HorizontalBarChart

chart = HorizontalBarChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

chart.data = [[100, 150, 130, 180]]
chart.categoryAxis.categoryNames = ['Product A', 'Product B', 'Product C', 'Product D']

# Horizontal charts use valueAxis horizontally
chart.valueAxis.valueMin = 0
chart.valueAxis.valueMax = 200

Line Charts

from reportlab.graphics.charts.linecharts import HorizontalLineChart

chart = HorizontalLineChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Multiple lines
chart.data = [
    [100, 150, 130, 180, 140],  # Line 1
    [80, 120, 110, 160, 130],   # Line 2
]

chart.categoryAxis.categoryNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May']

# Line styling
chart.lines[0].strokeColor = colors.blue
chart.lines[0].strokeWidth = 2
chart.lines[1].strokeColor = colors.red
chart.lines[1].strokeWidth = 2

# Show/hide points
chart.lines[0].symbol = None  # No symbols
# Or use symbols from makeMarker()

Line Plots (X-Y Plots)

from reportlab.graphics.charts.lineplots import LinePlot

chart = LinePlot()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Data as (x, y) tuples
chart.data = [
    [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16)],  # y = x^2
    [(0, 0), (1, 2), (2, 4), (3, 6), (4, 8)],   # y = 2x
]

# Both axes are value axes (not category)
chart.xValueAxis.valueMin = 0
chart.xValueAxis.valueMax = 5
chart.yValueAxis.valueMin = 0
chart.yValueAxis.valueMax = 20

# Line styling
chart.lines[0].strokeColor = colors.blue
chart.lines[1].strokeColor = colors.red

Pie Charts

from reportlab.graphics.charts.piecharts import Pie

chart = Pie()
chart.x = 100
chart.y = 50
chart.width = 200
chart.height = 200

chart.data = [25, 35, 20, 20]
chart.labels = ['Q1', 'Q2', 'Q3', 'Q4']

# Slice colors
chart.slices[0].fillColor = colors.blue
chart.slices[1].fillColor = colors.red
chart.slices[2].fillColor = colors.green
chart.slices[3].fillColor = colors.yellow

# Pop out a slice
chart.slices[1].popout = 10

# Label positioning
chart.slices.strokeColor = colors.white
chart.slices.strokeWidth = 2

Pie Chart with Side Labels

from reportlab.graphics.charts.piecharts import Pie

chart = Pie()
# ... set position, data, labels ...

# Side label mode (labels in columns beside pie)
chart.sideLabels = 1
chart.sideLabelsOffset = 0.1  # Distance from pie

# Simple labels (not fancy layout)
chart.simpleLabels = 1

Area Charts

from reportlab.graphics.charts.areacharts import HorizontalAreaChart

chart = HorizontalAreaChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Areas stack on top of each other
chart.data = [
    [100, 150, 130, 180],  # Bottom area
    [50, 70, 60, 90],      # Top area
]

chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4']

# Area colors
chart.strands[0].fillColor = colors.lightblue
chart.strands[1].fillColor = colors.pink

Scatter Charts

from reportlab.graphics.charts.lineplots import ScatterPlot

chart = ScatterPlot()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Data points
chart.data = [
    [(1, 2), (2, 3), (3, 5), (4, 4), (5, 6)],  # Series 1
    [(1, 1), (2, 2), (3, 3), (4, 3), (5, 4)],  # Series 2
]

# Hide lines, show points only
chart.lines[0].strokeColor = None
chart.lines[1].strokeColor = None

# Marker symbols
from reportlab.graphics.widgets.markers import makeMarker
chart.lines[0].symbol = makeMarker('Circle')
chart.lines[1].symbol = makeMarker('Square')

Axes Configuration

Category Axis (XCategoryAxis)

For categorical data (labels, not numbers):

# Access via chart
axis = chart.categoryAxis

# Labels
axis.categoryNames = ['Jan', 'Feb', 'Mar', 'Apr']

# Label angle (for long labels)
axis.labels.angle = 45
axis.labels.dx = 0
axis.labels.dy = -5

# Label formatting
axis.labels.fontSize = 10
axis.labels.fontName = 'Helvetica'

# Visibility
axis.visible = 1

Value Axis (YValueAxis)

For numeric data:

# Access via chart
axis = chart.valueAxis

# Range
axis.valueMin = 0
axis.valueMax = 200
axis.valueStep = 50  # Tick interval

# Or auto-configure
axis.valueSteps = [0, 50, 100, 150, 200]  # Explicit steps

# Label formatting
axis.labels.fontSize = 10
axis.labelTextFormat = '%d%%'  # Add percentage sign

# Grid lines
axis.strokeWidth = 1
axis.strokeColor = colors.black

Styling and Customization

Colors

from reportlab.lib import colors

# Named colors
colors.blue, colors.red, colors.green, colors.yellow

# RGB
colors.Color(0.5, 0.5, 0.5)  # Grey

# With alpha
colors.Color(1, 0, 0, alpha=0.5)  # Semi-transparent red

# Hex colors
colors.HexColor('#FF5733')

Line Styling

# For line charts
chart.lines[0].strokeColor = colors.blue
chart.lines[0].strokeWidth = 2
chart.lines[0].strokeDashArray = [2, 2]  # Dashed line

Bar Labels

# Show values on bars
chart.barLabels.nudge = 5  # Offset from bar top
chart.barLabels.fontSize = 8
chart.barLabelFormat = '%d'  # Number format

# For negative values
chart.barLabels.dy = -5  # Position below bar

Legends

Charts can have associated legends:

from reportlab.graphics.charts.legends import Legend

# Create legend
legend = Legend()
legend.x = 350
legend.y = 150
legend.columnMaximum = 10

# Link to chart (share colors)
legend.colorNamePairs = [
    (chart.bars[0].fillColor, 'Series 1'),
    (chart.bars[1].fillColor, 'Series 2'),
]

# Add to drawing
drawing.add(legend)

Drawing Shapes

Basic Shapes

from reportlab.graphics.shapes import (
    Drawing, Rect, Circle, Ellipse, Line, Polygon, String
)
from reportlab.lib import colors

drawing = Drawing(400, 200)

# Rectangle
rect = Rect(50, 50, 100, 50)
rect.fillColor = colors.blue
rect.strokeColor = colors.black
rect.strokeWidth = 1
drawing.add(rect)

# Circle
circle = Circle(200, 100, 30)
circle.fillColor = colors.red
drawing.add(circle)

# Line
line = Line(50, 150, 350, 150)
line.strokeColor = colors.black
line.strokeWidth = 2
drawing.add(line)

# Text
text = String(50, 175, "Label Text")
text.fontSize = 12
text.fontName = 'Helvetica'
drawing.add(text)

Paths (Complex Shapes)

from reportlab.graphics.shapes import Path

path = Path()
path.moveTo(50, 50)
path.lineTo(100, 100)
path.curveTo(120, 120, 140, 100, 150, 50)
path.closePath()

path.fillColor = colors.lightblue
path.strokeColor = colors.blue
path.strokeWidth = 2

drawing.add(path)

Rendering Options

Render to PDF

from reportlab.graphics import renderPDF

# Direct to file
renderPDF.drawToFile(drawing, 'output.pdf', 'Chart Title')

# As flowable in Platypus
story.append(drawing)

Render to Image

from reportlab.graphics import renderPM

# PNG
renderPM.drawToFile(drawing, 'chart.png', fmt='PNG')

# GIF
renderPM.drawToFile(drawing, 'chart.gif', fmt='GIF')

# JPG
renderPM.drawToFile(drawing, 'chart.jpg', fmt='JPG')

# With specific DPI
renderPM.drawToFile(drawing, 'chart.png', fmt='PNG', dpi=150)

Render to SVG

from reportlab.graphics import renderSVG

renderSVG.drawToFile(drawing, 'chart.svg')

Advanced Customization

Inspect Properties

# List all properties
print(chart.getProperties())

# Dump properties (for debugging)
chart.dumpProperties()

# Set multiple properties
chart.setProperties({
    'width': 400,
    'height': 200,
    'data': [[100, 150, 130]],
})

Custom Colors for Series

# Define color scheme
from reportlab.lib.colors import PCMYKColor

colors_list = [
    PCMYKColor(100, 67, 0, 23),   # Blue
    PCMYKColor(0, 100, 100, 0),   # Red
    PCMYKColor(66, 13, 0, 22),    # Green
]

# Apply to chart
for i, color in enumerate(colors_list):
    chart.bars[i].fillColor = color

Complete Examples

Sales Report Bar Chart

from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.legends import Legend
from reportlab.lib import colors

drawing = Drawing(400, 250)

# Create chart
chart = VerticalBarChart()
chart.x = 50
chart.y = 50
chart.width = 300
chart.height = 150

# Data
chart.data = [
    [120, 150, 180, 200],  # 2023
    [100, 130, 160, 190],  # 2022
]
chart.categoryAxis.categoryNames = ['Q1', 'Q2', 'Q3', 'Q4']

# Styling
chart.bars[0].fillColor = colors.HexColor('#3498db')
chart.bars[1].fillColor = colors.HexColor('#e74c3c')
chart.valueAxis.valueMin = 0
chart.valueAxis.valueMax = 250
chart.categoryAxis.labels.fontSize = 10
chart.valueAxis.labels.fontSize = 10

# Add legend
legend = Legend()
legend.x = 325
legend.y = 200
legend.columnMaximum = 2
legend.colorNamePairs = [
    (chart.bars[0].fillColor, '2023'),
    (chart.bars[1].fillColor, '2022'),
]

drawing.add(chart)
drawing.add(legend)

# Add to story or save
story.append(drawing)

Multi-Line Trend Chart

from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.lib import colors

drawing = Drawing(400, 250)

chart = HorizontalLineChart()
chart.x = 50
chart.y = 50
chart.width = 320
chart.height = 170

# Data
chart.data = [
    [10, 15, 12, 18, 20, 25],  # Product A
    [8, 10, 14, 16, 18, 22],   # Product B
    [12, 11, 13, 15, 17, 19],  # Product C
]

chart.categoryAxis.categoryNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']

# Line styling
chart.lines[0].strokeColor = colors.blue
chart.lines[0].strokeWidth = 2
chart.lines[1].strokeColor = colors.red
chart.lines[1].strokeWidth = 2
chart.lines[2].strokeColor = colors.green
chart.lines[2].strokeWidth = 2

# Axes
chart.valueAxis.valueMin = 0
chart.valueAxis.valueMax = 30
chart.categoryAxis.labels.angle = 0
chart.categoryAxis.labels.fontSize = 9
chart.valueAxis.labels.fontSize = 9

drawing.add(chart)
story.append(drawing)

Best Practices

  1. Set explicit dimensions for Drawing to ensure consistent sizing
  2. Position charts with enough margin (x, y at least 30-50 from edge)
  3. Use consistent color schemes throughout document
  4. Set valueMin and valueMax explicitly for consistent scales
  5. Test with realistic data to ensure labels fit and don't overlap
  6. Add legends for multi-series charts
  7. Angle category labels if they're long (45° works well)
  8. Keep it simple - fewer data series are easier to read
  9. Use appropriate chart types - bars for comparisons, lines for trends, pies for proportions
  10. Consider colorblind-friendly palettes - avoid red/green combinations