Add Eye-Catching Flash Charts to Your TurboGears Application that Will Make Your Users Say "WOW!"

TGFusionCharts is a TurboGears widget which lets you easily add FusionCharts Flash Charts to your application. TGFusionCharts is licensed under MIT License; FusionCharts has a commercial license, but offers a free trial.

Let's start with a simple example...

class MyFirstController(controllers.RootController):
    chart_widget = Column3DChartWidget(
            chart_id='chart1', width=200, height=200,
            chart=SingleSeriesChart(
                [3,4,1,5], 
                caption="New Incoming Links")
            )

    @expose(template=".templates.first_chart")
    def first_chart(self):
        # do your stuff here
        return dict(chart=chart_widget)
Chart

Then, by just throwing ${chart()} to your template, and you get the above chart.

Installing TGFusionCharts

The most recent version of TGFusionCharts can be installed using easy_install:

sudo easy_install TGFusionCharts


Alternatively, you can install from the tarball release:

  1. Download the most recent tarball: TGFusionCharts-0.1.tar.gz
  2. Unpack the tarball
  3. sudo python setup.py install


The development version can be obtained by SVN:

svn co http://svn.thesamet.com/TGFusionCharts/trunk TGFusionCharts

Installing FusionCharts' SWF Files

Important: Since FusionCharts is not a free software, it can not be shipped with TGFusionCharts. You can download a free trial from FusionCharts website.

The trial is fully functional, but can only be used for evaluation purposes as each chart will display a link to FusionCharts' website.

If you consider purchasing this component, please read "Helping TGFusionCharts"

Unpack the FusionCharts zipfile. From the Charts directory inside, copy all SWF files to a directory named /static/flash/ under your TG project. If you wish to have the files served from elsewhere, you can add to your dev.cfg/prod.cfg a line like:

TGFusionCharts.flash_dir="http://media.mydomain.com/flash"

Getting Started with TGFusionCharts

TGFusionCharts defines widgets for each of the supported chart types. The widget class name is based on the SWF filename of the chart. For example, the 2D Pie Chart is named Pie2D.swf, and the corresponding widget class is Pie2DChartWidget. You can see the names of the SWF files in FusionCharts' Documentation.

The widgets constructor take the following arguments:

Optionally, it can take a chart keyword argument which contains a chart object, such as an instance of SingleSeriesChart. Internally, this argument is transformed to an XML document compliant with FusionCharts specifications. The chart object holds both representation (fonts, colors, etc.) and data values for the chart.

To construct a chart object, use either SingleSeriesChart or MultiSeriesChart, according to the chart type.

Look at the following example:

class MySecondController(controllers.RootController):
    chart_widget = Pie2DChartWidget(
            chart_id='chart2', width=200, height=200,
            chart=SingleSeriesChart(
                [6,11,8,3], 
                caption="Comments Share")
            )

    @expose(template=".templates.first_chart")
    def second_chart(self):
        return dict(chart=chart_widget)
Chart

The first argument to SingleSeriesChart is a sequence containing the data series, the following arguments are used as attributes of the chart element in the generated XML.

TGFusionCharts passes the names of attributes as-is to FusionCharts. To learn which attributes are possible consult with the "Chart XML Reference" Section of FusionCharts Documentation.

In the previous example, the widget object was binded to a chart object at the time of the widget's construction. If the chart data is not fixed - and that is often the case - it is possible to pass to the widget a callable that returns a chart instance:

def get_chart():
    return SingleSeriesChart(
        [('david', 6),
         ('jane', 11, 'Who is Jane?'),
         '|',
         ('kate', 8),
         DataPoint(label='mike', value=6, dashed=1),
         ('george',3)], 
        caption="Comments Share",
        labelDisplay='STAGGER',
    )

chart_widget = Column2DChartWidget(
        chart_id='chart3', width=200, height=200,
        chart=get_chart)
Chart

Now, whenever the widget has to be rendered, the get_chart function is called to retrieve the actual chart. So, in this method, you can perform database queries to generate that data.

To make it more interesting, I've stuffed additional tricks to the above sample code. In the previous examples, each item in the data series was a plain number. In the code above we see additional types of items which TGFusionCharts understands:

The labelDisplay="STAGGER" makes more room for x-axis labels by using two lines. This is one of the many wonderful FusionCharts tricks which you can find out about in its documentation.

Multi Series Charts

Working with Multi Series charts is quite similar to the Single Series Chart. The main difference is that you instantiate an instance of MultiSeriesChart instead of SingleSeriesChart. That instance has to be provided with a list of categories (which usually become x-axis labels), and one or more instances of DataSet (which become y-values).

def get_chart():
    chart = MultiSeriesChart(
                caption="Referrer Breakdown",
                labelDisplay='STAGGER',)
    chart.set_categories(
        ['Jan', 'Feb', 'Mar', 'Apr', 'May'])
    chart.add_dataset(DataSet([4,7,8,9,9], 
        seriesName='Google'))
    chart.add_dataset(DataSet([2,5,3,4,3], 
        seriesName='Yahoo'))
    chart.add_dataset(DataSet([2,3,2,2,3], 
        seriesName='Microsoft'))
    return chart

chart_widget = StackedColumn3DChartWidget(
        chart_id='chart4', width=200, height=300,
        chart=get_chart)
Chart

The code should be self-explanatory. The above method calls can be eliminated, if you'd like, by passing all data at once to the constructor:

def get_chart_b():
    chart = MultiSeriesChart(
      caption="Referrer Breakdown",
      labelDisplay='STAGGER',
      categories=[
          'Jan', 'Feb', 'Mar', 'Apr', 'May'],
      datasets=[
        DataSet([4,7,8,9,9], seriesName='Google'),
        DataSet([2,5,3,4,3], seriesName='Yahoo'),
        DataSet([2,3,2,2,3], seriesName='Microsoft')])
    return chart

Trend Lines, Styles, and Animations

To add one trend line or more to a chart, and set the caption style:

def get_chart():
    chart = SingleSeriesChart(
            [32.76, 30.15, 37.18, 39.1],
        caption="Stock Price",
        labelDisplay='STAGGER',
        yAxisMinValue=24,
        lineColor='0000ff',
        numberPrefix='$',
        decimals=2, forceDecimals=1,
        showValues=0,
    )
    chart.apply_style('Caption', 
            Style('myCaptionFont', 'font', 
                font='Arial', size='14', 
                color='006600', 
                bold='1', underline='1'))
    chart.add_trendline(
        Line(
            startValue=32, endValue=38, 
            color='ff0000'))
    return chart

chart_widget = LineChartWidget(
        chart_id='chart6', width=200, height=300,
        chart=get_chart)
Chart

You can apply the same Style instance to several chart objects. You can also apply several styles to a chart object at once by using a call of the form:

chart.apply_style('subCaption', style1, style2)

It is also possible to add several trendlines at once with:

chart.add_trendlines(line1, line2)

Insteaad of calling add_trendline() or add_trendlines(), you can pass a sequence of trendlines to the constructor of the chart using the keyword argument trendlines.

AJAX Charts: Updating a Chart Without Reloading the Page

In the former examples, the automatically generated chart's XML is written to the HTML page containing the widget. If we would like to be able to update the chart without reloading the page, we have to create a method that returns the XML. It is really easy:

class AjaxController(controllers.RootController):
    chart_widget = LineChartWidget(
            chart_id='chart5', width=200, height=200,
            chart_url='/get_chart')

    @expose(template=".templates.first_chart")
    def my_page(self):
        return dict(chart=chart_widget)

    @expose_chart()
    def get_chart(self):
        return SingleSeriesChart(
                [3,4,1,5], 
                caption="Bananas")

Note that widget gets a chart_url argument, pointing it to a URL to retrive the XML from. The get_chart() method returns the chart object. The decorator @expose_chart converts the returned object to XML and makes sure it is served properly to the client.

To update the chart with new data without reloading the page, all you have to do is to throwing the following javascript snippet to a function which is called whenever the chart should be update:

getChartFromId("my_chart_id").setDataURL("/path/to/new/data");

Helping TGFusionCharts

If you plan to purchase FusionCharts, you can help TGFusionCharts by buying from one of the links below. If you place an order from a link in this page, TGFusionCharts is given a small portion of the sale. To determine which license you need, please see the License Comparison page at FusionCharts.

Once your order is placed, please send me an e-mail to nadav at thesamet.com

Author

The author of TGFusionCharts is Nadav Samet. Feel free to contact him at nadav at thesamet.com.