- Database-driven PDF Reports with Charts Using ReportLab
- Published: 2009-08-14 10:04:20
- Updated: 2009-08-14 10:06:47
- Language: Python
- Author: jonesy
- Description:
You can see more about how this was put together at my blog: http://www.protocolostomy.com/2008/10/22/generating-reports-with-charts-using-python-reportlab/
This is an example script that will create a PDF with various text objects, a code sample, and a line chart using data from a database. It utilizes ReportLab, an excellent report generation library written in Python, for Python developers. It's done a great job for what I've used it for. The learning curve looks worse than it is -- you can get a lot done by reading a little documentation and looking at the examples that come with the library. You can get the library here: http://www.reportlab.org/rl_toolkit.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #!/usr/bin/env python
import MySQLdb
import sys
import string
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.platypus import *
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.rl_config import defaultPageSize
from reportlab.lib.units import inch
dbhost = 'localhost'
dbname = 'httplog'
dbuser = 'jonesy'
dbpasswd = 'mypassword'
PAGE_HEIGHT=defaultPageSize[1]
styles = getSampleStyleSheet()
Title = "Generating Reports with Python"
Author = "Brian K. Jones"
URL = "http://www.protocolostomy.com"
email = "bkjones@gmail.com"
Abstract = """This is a simple example document that illustrates how to put together a basic PDF with a chart.
I used the PLATYPUS library, which is part of ReportLab, and the charting capabilities built into ReportLab."""
Elements=[]
HeaderStyle = styles["Heading1"]
ParaStyle = styles["Normal"]
PreStyle = styles["Code"]
def header(txt, style=HeaderStyle, klass=Paragraph, sep=0.3):
s = Spacer(0.2*inch, sep*inch)
para = klass(txt, style)
sect = [s, para]
result = KeepTogether(sect)
return result
def p(txt):
return header(txt, style=ParaStyle, sep=0.1)
def pre(txt):
s = Spacer(0.1*inch, 0.1*inch)
p = Preformatted(txt, PreStyle)
precomps = [s,p]
result = KeepTogether(precomps)
return result
def connect():
try:
conn1 = MySQLdb.connect(host = dbhost, user = dbuser, passwd = dbpasswd, db = dbname)
return conn1
except MySQLdb.Error, e:
print "Error %d: %s" % (e.args[0], e.args[1])
sys.exit (1)
def getcursor(conn):
cursor = conn.cursor()
return cursor
def totalevents_hourly(rcursor):
rcursor.execute("""select hour, count(*) as hits from hits group by hour;""")
return rcursor
def graphout(catnames, data):
drawing = Drawing(400, 200)
lc = HorizontalLineChart()
lc.x = 30
lc.y = 50
lc.height = 125
lc.width = 350
lc.data = data
catNames = catnames
lc.categoryAxis.categoryNames = catNames
lc.categoryAxis.labels.boxAnchor = 'n'
lc.valueAxis.valueMin = 0
lc.valueAxis.valueMax = 1500
lc.valueAxis.valueStep = 300
lc.lines[0].strokeWidth = 2
lc.lines[0].symbol = makeMarker('FilledCircle') # added to make filled circles.
lc.lines[1].strokeWidth = 1.5
drawing.add(lc)
return drawing
def go():
doc = SimpleDocTemplate('gfe.pdf')
doc.build(Elements)
mytitle = header(Title)
myname = header(Author, sep=0.1, style=ParaStyle)
mysite = header(URL, sep=0.1, style=ParaStyle)
mymail = header(email, sep=0.1, style=ParaStyle)
abstract_title = header("ABSTRACT")
myabstract = p(Abstract)
head_info = [mytitle, myname, mysite, mymail, abstract_title, myabstract]
Elements.extend(head_info)
code_title = header("Basic code to produce output")
code_explain = p("""This is a snippet of code. It's an example using the Preformatted flowable object, which
makes it easy to put code into your documents. Enjoy!""")
code_source = pre("""
def header(txt, style=HeaderStyle, klass=Paragraph, sep=0.3):
s = Spacer(0.2*inch, sep*inch)
para = klass(txt, style)
sect = [s, para]
result = KeepTogether(sect)
return result
def p(txt):
return header(txt, style=ParaStyle, sep=0.1)
def pre(txt):
s = Spacer(0.1*inch, 0.1*inch)
p = Preformatted(txt, PreStyle)
precomps = [s,p]
result = KeepTogether(precomps)
return result
def go():
doc = SimpleDocTemplate('gfe.pdf')
doc.build(Elements)
""")
codesection = [code_title, code_explain, code_source]
src = KeepTogether(codesection)
Elements.append(src)
hourly_title = header("Hits logged, per hour")
hourly_explain = p("""This shows aggregate hits across a 24-hour period. """)
conn = connect()
cur = getcursor(conn)
te_hourly = totalevents_hourly(cur)
catnames = []
data = []
values = []
for row in te_hourly:
catnames.append(str(row[0]))
values.append(row[1])
data.append(values)
hourly_chart = graphout(catnames, data)
hourly_section = [hourly_title, hourly_explain, hourly_chart]
Elements.extend(hourly_section)
go()
|