goldb.org home

AS OF MAY 2008, THIS BLOG IS NO LONGER BEING UPDATED.
Visit the new blog at: http://coreygoldberg.blogspot.com



 Friday, March 23, 2007

Python - Creating Bar Graphs with Matplotlib

Matplotlib is an open source 2D plotting library for Python.  It is very impressive and robust, but the API and documentation is maddeningly difficult to follow.

Here I have provided a function that will create a bar graph [as a png image] from a Python dictionary using the Matplotlib API.

It will auto-size the bars and auto-adjust the axis labels for you. All you need to pass into it is a dictionary data structure (and optionally a graph title and output name).


We start with a Python dictionary like this:

{'A': 70, 'B': 290, 'C': 130}


... and the function will use Matplotlib to create a graph like this:


Here is a sample script that uses my function:


#!/usr/bin/env python

from pylab import *

def main():  
    my_dict = {'A': 70, 'B': 290, 'C': 130}
    bar_graph(my_dict, graph_title='ABC')


def bar_graph(name_value_dict, graph_title='', output_name='bargraph.png'):
    figure(figsize=(4, 2)) # image dimensions  
    title(graph_title, size='x-small')
   
    # add bars
    for i, key in zip(range(len(name_value_dict)), name_value_dict.keys()):
        bar(i + 0.25 , name_value_dict[key], color='red')
   
    # axis setup
    xticks(arange(0.65, len(name_value_dict)),
        [('%s: %d' % (name, value)) for name, value in
        zip(name_value_dict.keys(), name_value_dict.values())],
        size='xx-small')
    max_value = max(name_value_dict.values())
    tick_range = arange(0, max_value, (max_value / 7))
    yticks(tick_range, size='xx-small')
    formatter = FixedFormatter([str(x) for x in tick_range])
    gca().yaxis.set_major_formatter(formatter)
    gca().yaxis.grid(which='major')
   
    savefig(output_name)


if __name__ == "__main__":
    main()


enjoy.

-Corey

#    Comments [6] |
Saturday, March 24, 2007 10:05:46 PM (Eastern Standard Time, UTC-05:00)
Something I just stumbled upon a few days ago ...

Instead of:
for i, key in zip(range(len(name_value_dict)), name_value_dict.keys()):

try:
for i, key in enumerate(name_value_dict):

"enumerate" is the magic thing here ... you get teh same awesomeness w/o the zip(range(len(..))) business ...

-steve
Sunday, March 25, 2007 12:35:45 AM (Eastern Standard Time, UTC-05:00)
Speaking of complicated documentation, I started to put together my own graphing library after finding out how complicated matplotlib is. It's a great library, but was seemingly too heavy for what I was trying to do. Therefore, I created a simple, easy to use/extend library (dependent on gd) that as of right now does bar charts and line graphs. It's only ~ 600 LOC, but pretty easily extendable. It's just recently released so considered very beta, but you might want to try it out for some simple things like you do above:

http://code.google.com/p/graphn/

BSD licensed, so have at it :)
Kevin
Sunday, March 25, 2007 1:15:12 AM (Eastern Standard Time, UTC-05:00)
Steve, thanks..

> "enumerate" is the magic thing here

nice, I use that 'zip(range(len' thing *all* the time. thanks for the tip.
Sunday, March 25, 2007 1:16:25 AM (Eastern Standard Time, UTC-05:00)
> I started to put together my own graphing library
> after finding out how complicated matplotlib is.

kevin.. I'll definitely check it out when I have time and let you know what I think. I'd love a dead simple graphing library.

-Corey
Wednesday, April 11, 2007 12:20:55 PM (Eastern Standard Time, UTC-05:00)
[('%s: %d' % (name, value)) for name, value in zip(name_value_dict.keys(), name_value_dict.values())],

That is WAY too long as well.

try changing it to something like this:

['%s: %d' % (kv) for kv in name_value_dict.items()]

name_value_dict.items() returns a tuple of (key, value) so you can pass that right to formatter.

Anthony
Wednesday, April 11, 2007 1:01:10 PM (Eastern Standard Time, UTC-05:00)
Anthony, thanks for the tip.

-Corey
Comments are closed.