#!/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'{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")