Files
gh-k-dense-ai-claude-scient…/skills/reportlab/assets/report_template.py
2025-11-30 08:30:10 +08:00

344 lines
11 KiB
Python

#!/usr/bin/env python3
"""
Report Template - Complete example of a professional multi-page report
This template demonstrates:
- Cover page
- Table of contents
- Multiple sections with headers
- Charts and graphs integration
- Tables with data
- Headers and footers
- Professional styling
"""
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.platypus import (
BaseDocTemplate, PageTemplate, Frame, Paragraph, Spacer,
Table, TableStyle, PageBreak, KeepTogether, TableOfContents
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_RIGHT, TA_CENTER, TA_JUSTIFY
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.barcharts import VerticalBarChart
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from datetime import datetime
def header_footer(canvas, doc):
"""Draw header and footer on each page (except cover)"""
canvas.saveState()
# Skip header/footer on cover page (page 1)
if doc.page > 1:
# Header
canvas.setFont('Helvetica', 9)
canvas.setFillColor(colors.grey)
canvas.drawString(inch, letter[1] - 0.5*inch, "Quarterly Business Report")
canvas.line(inch, letter[1] - 0.55*inch, letter[0] - inch, letter[1] - 0.55*inch)
# Footer
canvas.drawString(inch, 0.5*inch, f"Generated: {datetime.now().strftime('%B %d, %Y')}")
canvas.drawRightString(letter[0] - inch, 0.5*inch, f"Page {doc.page - 1}")
canvas.restoreState()
def create_report(filename, report_data):
"""
Create a comprehensive business report.
Args:
filename: Output PDF filename
report_data: Dict containing report information
{
'title': 'Report Title',
'subtitle': 'Report Subtitle',
'author': 'Author Name',
'date': 'Date',
'sections': [
{
'title': 'Section Title',
'content': 'Section content...',
'subsections': [...],
'table': {...},
'chart': {...}
},
...
]
}
"""
# Create document with custom page template
doc = BaseDocTemplate(filename, pagesize=letter,
rightMargin=72, leftMargin=72,
topMargin=inch, bottomMargin=inch)
# Define frame for content
frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height - 0.5*inch, id='normal')
# Create page template with header/footer
template = PageTemplate(id='normal', frames=[frame], onPage=header_footer)
doc.addPageTemplates([template])
# Get styles
styles = getSampleStyleSheet()
# Custom styles
title_style = ParagraphStyle(
'ReportTitle',
parent=styles['Title'],
fontSize=28,
textColor=colors.HexColor('#2C3E50'),
spaceAfter=20,
alignment=TA_CENTER,
)
subtitle_style = ParagraphStyle(
'ReportSubtitle',
parent=styles['Normal'],
fontSize=14,
textColor=colors.grey,
alignment=TA_CENTER,
spaceAfter=30,
)
heading1_style = ParagraphStyle(
'CustomHeading1',
parent=styles['Heading1'],
fontSize=18,
textColor=colors.HexColor('#2C3E50'),
spaceAfter=12,
spaceBefore=12,
)
heading2_style = ParagraphStyle(
'CustomHeading2',
parent=styles['Heading2'],
fontSize=14,
textColor=colors.HexColor('#34495E'),
spaceAfter=10,
spaceBefore=10,
)
body_style = ParagraphStyle(
'ReportBody',
parent=styles['BodyText'],
fontSize=11,
alignment=TA_JUSTIFY,
spaceAfter=12,
leading=14,
)
# Build story
story = []
# --- COVER PAGE ---
story.append(Spacer(1, 2*inch))
story.append(Paragraph(report_data['title'], title_style))
story.append(Paragraph(report_data.get('subtitle', ''), subtitle_style))
story.append(Spacer(1, inch))
# Cover info table
cover_info = [
['Prepared by:', report_data.get('author', '')],
['Date:', report_data.get('date', datetime.now().strftime('%B %d, %Y'))],
['Period:', report_data.get('period', 'Q4 2023')],
]
cover_table = Table(cover_info, colWidths=[2*inch, 4*inch])
cover_table.setStyle(TableStyle([
('ALIGN', (0, 0), (0, -1), 'RIGHT'),
('ALIGN', (1, 0), (1, -1), 'LEFT'),
('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, -1), 11),
('TOPPADDING', (0, 0), (-1, -1), 6),
]))
story.append(cover_table)
story.append(PageBreak())
# --- TABLE OF CONTENTS ---
toc = TableOfContents()
toc.levelStyles = [
ParagraphStyle(name='TOCHeading1', fontSize=14, leftIndent=20, spaceBefore=10, spaceAfter=5),
ParagraphStyle(name='TOCHeading2', fontSize=12, leftIndent=40, spaceBefore=3, spaceAfter=3),
]
story.append(Paragraph("Table of Contents", heading1_style))
story.append(toc)
story.append(PageBreak())
# --- SECTIONS ---
for section in report_data.get('sections', []):
# Section heading
section_title = section['title']
story.append(Paragraph(f'<a name="{section_title}"/>{section_title}', heading1_style))
# Add to TOC
toc.addEntry(0, section_title, doc.page)
# Section content
if 'content' in section:
for para in section['content'].split('\n\n'):
if para.strip():
story.append(Paragraph(para.strip(), body_style))
story.append(Spacer(1, 0.2*inch))
# Subsections
for subsection in section.get('subsections', []):
story.append(Paragraph(subsection['title'], heading2_style))
if 'content' in subsection:
story.append(Paragraph(subsection['content'], body_style))
story.append(Spacer(1, 0.1*inch))
# Add table if provided
if 'table_data' in section:
table = create_section_table(section['table_data'])
story.append(table)
story.append(Spacer(1, 0.2*inch))
# Add chart if provided
if 'chart_data' in section:
chart = create_section_chart(section['chart_data'])
story.append(chart)
story.append(Spacer(1, 0.2*inch))
story.append(Spacer(1, 0.3*inch))
# Build PDF (twice for TOC to populate)
doc.multiBuild(story)
return filename
def create_section_table(table_data):
"""Create a styled table for report sections"""
data = table_data['data']
table = Table(data, colWidths=table_data.get('colWidths'))
table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#34495E')),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 11),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.white),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.lightgrey]),
('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 10),
]))
return table
def create_section_chart(chart_data):
"""Create a chart for report sections"""
chart_type = chart_data.get('type', 'bar')
drawing = Drawing(400, 200)
if chart_type == 'bar':
chart = VerticalBarChart()
chart.x = 50
chart.y = 30
chart.width = 300
chart.height = 150
chart.data = chart_data['data']
chart.categoryAxis.categoryNames = chart_data.get('categories', [])
chart.valueAxis.valueMin = 0
# Style bars
for i in range(len(chart_data['data'])):
chart.bars[i].fillColor = colors.HexColor(['#3498db', '#e74c3c', '#2ecc71'][i % 3])
elif chart_type == 'line':
chart = HorizontalLineChart()
chart.x = 50
chart.y = 30
chart.width = 300
chart.height = 150
chart.data = chart_data['data']
chart.categoryAxis.categoryNames = chart_data.get('categories', [])
# Style lines
for i in range(len(chart_data['data'])):
chart.lines[i].strokeColor = colors.HexColor(['#3498db', '#e74c3c', '#2ecc71'][i % 3])
chart.lines[i].strokeWidth = 2
drawing.add(chart)
return drawing
# Example usage
if __name__ == "__main__":
report = {
'title': 'Quarterly Business Report',
'subtitle': 'Q4 2023 Performance Analysis',
'author': 'Analytics Team',
'date': 'January 15, 2024',
'period': 'October - December 2023',
'sections': [
{
'title': 'Executive Summary',
'content': """
This report provides a comprehensive analysis of our Q4 2023 performance.
Overall, the quarter showed strong growth across all key metrics, with
revenue increasing by 25% year-over-year and customer satisfaction
scores reaching an all-time high of 4.8/5.0.
Key highlights include the successful launch of three new products,
expansion into two new markets, and the completion of our digital
transformation initiative.
""",
'subsections': [
{
'title': 'Key Achievements',
'content': 'Successfully launched Product X with 10,000 units sold in first month.'
}
]
},
{
'title': 'Financial Performance',
'content': """
The financial results for Q4 exceeded expectations across all categories.
Revenue growth was driven primarily by strong product sales and increased
market share in key regions.
""",
'table_data': {
'data': [
['Metric', 'Q3 2023', 'Q4 2023', 'Change'],
['Revenue', '$2.5M', '$3.1M', '+24%'],
['Profit', '$500K', '$680K', '+36%'],
['Expenses', '$2.0M', '$2.4M', '+20%'],
],
'colWidths': [2*inch, 1.5*inch, 1.5*inch, 1*inch]
},
'chart_data': {
'type': 'bar',
'data': [[2.5, 3.1], [0.5, 0.68], [2.0, 2.4]],
'categories': ['Q3', 'Q4']
}
},
{
'title': 'Market Analysis',
'content': """
Market conditions remained favorable throughout the quarter, with
strong consumer confidence and increasing demand for our products.
""",
'chart_data': {
'type': 'line',
'data': [[100, 120, 115, 140, 135, 150]],
'categories': ['Oct', 'Nov', 'Dec', 'Oct', 'Nov', 'Dec']
}
},
]
}
create_report("sample_report.pdf", report)
print("Report created: sample_report.pdf")