Changes between Initial Version and Version 1 of Charts


Ignore:
Timestamp:
Sep 8, 2006, 5:17:12 PM (18 years ago)
Author:
andy@…
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Charts

    v1 v1  
     1This describes a simple way to create dynamic bitmap charts in Django. 
     2
     3!ReportLab's PDF library is well known, but less people are aware that it contains a
     4mature graphics package able to create most kinds of businss charts, as well as custom graphical widgets.
     5We've been serving GIF and PNG charts for many years.  Doing this within Django has turned out to be trivial; here's an example.
     6
     7= Installation =
     8You will need the !ReportLab library from http://www.reportlab.org/
     9
     10Also make sure you have compiled the ''_rl_accel'' and ''_renderPM'' packages.  The latter
     11is a sophisticated bitmap renderer with anti-aliasing, font handling and so on.
     12ReportLab's download page has a checker script to tell you what extensions
     13are installed.
     14
     15= Creating a chart =
     16The reportlab/graphics framework provides a Drawing object and many Shape objects,
     17which include primitive shapes, and high-level objects like charts and legends.  You
     18can easily write your own too if you want to make dynamic bitmap buttons or fancy
     19dashboard apps.
     20
     21The usual pattern we follow is to create a Drawing class with all of your widgets,
     22some sensible default data, and any visual settings you want.  Here is such a class,
     23which has a bar chart and a string for the chart title.
     24
     25{{{
     26#    mycharts.py 
     27from reportlab.graphics.shapes import Drawing, String
     28from reportlab.graphics.charts.barcharts import HorizontalBarChart
     29
     30class MyBarChartDrawing(Drawing):
     31    def __init__(self, width=400, height=200, *args, **kw):
     32        apply(Drawing.__init__,(self,width,height)+args,kw)
     33        self.add(HorizontalBarChart(), name='chart')
     34
     35        self.add(String(200,180,'Hello World'), name='title')
     36
     37        #set any shapes, fonts, colors you want here.  We'll just
     38        #set a title font and place the chart within the drawing
     39        self.chart.x = 20
     40        self.chart.y = 20
     41        self.chart.width = self.width - 20
     42        self.chart.height = self.height - 40
     43
     44        self.title.fontName = 'Helvetica-Bold'
     45        self.title.fontSize = 12
     46       
     47        self.chart.data = [[100,150,200,235]]
     48       
     49
     50if __name__=='__main__':
     51    #use the standard 'save' method to save barchart.gif, barchart.pdf etc
     52    #for quick feedback while working.
     53    MyBarChartDrawing().save(formats=['gif','png','jpg','pdf'],outDir='.',fnRoot='barchart')
     54}}}
     55
     56
     57Paste this into a file and execute it; you should get 4 chart files written to
     58disk in different formats.
     59
     60= Integrating into Django =
     61
     62Now we add a view to our ''views.py''.  This will examine the request
     63for any dynamic parameters, since there's not much point serving
     64a chart that doesn't vary.  We'll allow the user to pass in 4
     65things as GET or POST parameters:  a title, a comma-separated list of numbers,
     66and the overall width and height of the image.  Everything has a default in
     67our Drawing class anyway, so we only pass through parameters which are
     68present.
     69
     70You then ask the Drawing to render itself to your favourite bitmap format
     71and generate a response with the right content-type
     72
     73{{{
     74def barchart(request):
     75
     76    #instantiate a drawing object
     77    import mycharts
     78    d = mycharts.MyBarChartDrawing()
     79
     80    #extract the request params of interest.
     81    #I suggest having a default for everything.
     82    if request.has_key('height'):
     83        d.height = int(request['height'])
     84    if request.has_key('width'):
     85        d.height = int(request['width'])
     86   
     87    if request.has_key('numbers'):
     88        strNumbers = request['numbers']
     89        numbers = map(int, strNumbers.split(','))   
     90        d.chart.data = [numbers]   #bar charts take a list-of-lists for data
     91
     92    if request.has_key('title'):
     93        d.title.text = request['title']
     94 
     95
     96    #get a GIF (or PNG, JPG, or whatever)
     97    binaryStuff = d.asString('gif')
     98    return HttpResponse(binaryStuff, 'image/gif')
     99}}}
     100
     101Finally, you need a URL mapping.  In this case I have added this:
     102
     103{{{
     104    (r'^charts/bar/$', 'myapp.views.barchart'),
     105
     106}}}
     107
     108Now you can start Django, point your browser at the URL with no arguments,
     109and should see the chart.  Then try out a few parameters such as
     110  http://localhost:8000/charts/bar?title=awesome
     111and watch it redraw.
     112
     113= Tips =
     114The above approach will let you drive a chart by generating
     115img tags with all parameters embedded in them.   This will also let the world
     116use you as a chart server, so you might want to implement some authentication
     117on the chart requests.   
     118
     119Very often you are plotting data which mostly exists on the server side.
     120In this case it's inefficient to encode it all in a long URL in the HTML
     121then have this posted back to make the chart.  For example,
     122if you run an ISP and are plotting server uptime statistics, presumably
     123the URL or parameters would encode the customer and server ID, and you'd
     124look up all the numeric data or that chart in your view code in a database query.
     125
     126If you cannot always create a sensible chart from the input, it
     127may be a good idea to create an error handler which returns a rectangular
     128drawing with an error message, because this will usually be called inside an <img> tag
     129and the browser won't display any HTML error messages if it was expecting an image.
     130
     131= Learning More =
     132The available chart types, widgets and properties are covered in the two
     133Graphics manuals on this page.  Enjoy!
     134   http://www.reportlab.org/os_documentation.html
     135
     136If you have questions about the charts rather than the Django integration,
     137ask on the reportlab-users list:
     138  http://two.pairlist.net/mailman/listinfo/reportlab-users
Back to Top