Meaningful graphs are a necessity in any full-featured reporting system. In the course of developing a new Ruby on Rails-based SEO management platform for my company, SEO Logic, I had the opportunity to research a number of graphing tools, but found all of them lacking in one respect or another.

There are a number of decent graphing libraries for Ruby and Rails, but most require ImageMagick on the server side to generate static graphs in an image format. Client-side graphing libraries require SVG or HTML Canvas support, which is notoriously tricky to implement in a cross-browser fashion.

My search started and ended with Google-- first its search engine, and then its own internal code. I realized that what I really wanted was the sort of graphing capabilities on display at the Google Analytics site. I was in luck: it ends up that Google has open-sourced its own graphing code, published as a JavaScript library called the Google Visualization API.

Seer, a semantically rich Ruby on Rails wrapper for the Google Visualization API.
Seer is a lightweight, semantically rich Ruby on Rails gem that provides a seamless interface to the Google Visualization API. You can easily create a graph or chart in a variety of formats and display it in your app with only a single line of code.

With the release of the Google Visualization API back in 2008, a world of streamlined, beautiful, client-side graphing capabilities opened up. Google uses this code internally for all of its charting and graphing needs, so it's guaranteed to be full-featured and high-quality. I had found the graphing library that I needed.

The only thing missing was a native Ruby on Rails wrapper for this powerful graphing API.

Until now.

Introducing Seer

Seer is a lightweight, semantically rich Ruby on Rails gem that provides a seamless interface for the Google Visualization API. It allows you to easily create a visualization of data in a variety of formats, and displaying a chart requires only a single line of code in your view.

Supported Chart Types

Seer can generate a variety of charts, including:

  • area charts,
  • bar charts,
  • column charts,
  • gauges,
  • line charts, and
  • pie charts.
Montage of graphs generated by Seer.

Support for additional chart types, including motion, geographic, and org charts, is slated for the next release.

Installing Seer

Install Seer as you would any other gem:

$ gem install seer

Note that since Seer is hosted on Gemcutter, you'll have to have added Gemcutter to your gem sources first, if you haven't already. This is easily accomplished:

$ gem update --system
$ gem install gemcutter --source http://gemcutter.org
$ gem tumble

Once the gem is installed, add this line to the <head> of either your layout file or the page that will be displaying your graph:

<%= Seer::init_visualization -%>

Now you're ready to leverage the graphing library.

Preparing your data

Regardless of the type of graph that you want, you'll need an array of objects whose properties you want to visuallize. For the purpose of this tutorial, let's say that you have Widgets and WidgetStats. A Widget has_many :widget_stats and a WidgetStat belongs_to :widget. The stat object stores information about the number of available widgets for a given date, and comprises date and quantity attributes. A Widget is a lean object with only one attribute, a name, and a method for retrieving its current quantity from its last WidgetStat object.

Your widget class may look something like this:


class Widget < ActiveRecord::Base

  has_many :widget_stats

  def date
    self.widget_stats.last.date
  end
  
  def quantity
    self.widget_stats.last.quantity
  end

end

Visualizing Your Data in a Chart

Now suppose that we want to create a column graph that shows how many widgets are currently on hand. With Seer, this is trivial.

In our controller, we gather the data and assign it to an instance variable:


  def report
    @widgets = Widget.all
  end

Now, in the view, we add an HTML element (in this case, a div) that will contain our graph, and invoke the visualization method:



<div id="chart"></div>

<%= Seer::visualize(
      @widgets, 
      :as => :column_chart,
      :in_element =>'chart', 
      :series => {:series_label => 'name', :data_method => 'quantity'},
      :chart_options => {
        :height => 300,
        :width => 100 * @widgets.size,
        :is_3_d => true,
        :legend => 'none',
        :colors => "[{color:'#990000', darker:'#660000'}]",
        :title => "Widget Quantities",
        :title_x => 'Widgets',
        :title_y => 'Quantities'
      }
    )
 -%>

Reading as English, this method states that we want to visualize widgets as a column chart in the HTML element with the id 'chart'. Widgets will be displayed by name, and the data will be retrieved from each using the 'quantity' method.

The chart options are optional, and allow granular control over every aspect of the chart's presentation, including colors, size, legends and titles, and whether the graph should be 2d or 3d. (A list of chart options is provided in the documentation for each chart class.)

This code generates the following graph:

Column chart generated by Seer.

Note that clicking on a column reveals additional information about the data in a JavaScript popup control.

The same data can easily be displayed as a bar chart, pie chart, or gauge chart by altering the visualization parameters:


<%= Seer::visualize(
    @data, 
    :as => :pie_chart,
    :in_element => 'chart',
    :series => {
      :series_label => 'name',
      :data_method => 'quantity'
    },
    :chart_options => { 
      :height => 300,
      :width => 300,
      :axis_font_size => 11,
      :title => "Widget Quantities",
      :point_size => 5,
      :is_3_d => true
    }
   )
-%>
  
Pie chart generated by Seer.


<%= Seer::visualize(
      @data, 
      :as => :gauge,
      :in_element => 'chart',
      :series => {
        :series_label => 'name',
        :data_method => 'quantity'
      },
      :chart_options => {
        :green_from => 0,
        :green_to => 50,
        :height => 300,
        :max => 100,
        :min => 0,
        :minor_ticks => 5,
        :red_from => 76,
        :red_to => 100,
        :width => 600,
        :yellow_from => 51,
        :yellow_to => 75
      }
    )
 -%>
  
Gauge chart generated by Seer.

Visualizing Data with Multiple Dimensions

Since we have data representing widget quantities for specific dates, it's reasonable to want to display quantities of widgets over time, perhaps with a line graph. Once again, Seer makes this easy. There's just a little more work to do in the controller, to create an instance variable for the data series:


  def report
    @data = Widget.all
    @series = @data.map{|w| w.widget_stats}
  end

The @series instance variable contains the data series that we want to map, consisting of an array of widget stats. So in our view, we invoke visualize using the now-familiar syntax:


<%= Seer::visualize(
      @data, 
      :as => :line_chart,
      :in_element => 'chart',
      :series => {
        :series_label => 'name',
        :data_label => 'date',
        :data_method => 'quantity',
        :data_series => @series
      },
      :chart_options => { 
        :height => 300,
        :width => 600,
        :axis_font_size => 11,
        :colors => ['#7e7587','#990000','#009900'],
        :title => "Widget Quantities",
        :point_size => 5
      }
     )
 -%>

There are a couple of subtle differences in the parameters, however. Note that in the series argument, both name and date are methods that will be called on each object in the data series (the WidgetStat array @series in this case). The data method, quantity, represents the data that will be graphed on the date dimension.

This code produces the following graph:

Line chart created by Seer.

Seer, your next graphing utility.

Seer provides an easy way to integrate the power of the Google Visualization API into your Rails project. In the near future, the gem will be extended to support additional graph types, including the ever-so-sexy motion chart.

As with all of my open source work, feedback and forks are welcome. You can find the project on GitHub at http://github.com/Bantik/seer; in addition to hosting the source code, GitHub also provides an issue tracker for Seer.

So get started with some graphing! And if you have some time, hack away at the Seer source code to help improve the tool.

Related Articles


Comments

Darian Shimy
February 16, 2010 at 10:32 PM

Look great, can't wait to try it out. Thanks!

James Thompson
February 17, 2010 at 12:53 AM

Awesome stuff! Where were you a few months ago? :)

AkitaOnRails
February 17, 2010 at 7:40 AM

I am not aware of the google visualization api, is it all client-side with javascript or does it require calling back home to google servers in order to render the graphs?

aRJ
February 17, 2010 at 8:53 PM

The visualization API uses google to render the charts. another privacy for convenience question that needs to be answered by each user.

andhapp
February 18, 2010 at 9:03 AM

Gemcutter's api has changed considerably since it is the official rubygem host now which means some of the instructions are out of date.

Werner
February 27, 2010 at 1:59 PM

Would be great to have complete app zip file.. to get a running example...I only get error messages:

Corey Ehmke
March 1, 2010 at 9:01 PM

Werner, there's now a sample project linked off the GitHub project page. Let me know if you still need help getting up and running.

Fonsan
March 2, 2010 at 1:39 PM

I checked out the sample project and ran rake:setup but the gauge samples are the only ones that seem to work running ruby 1.8.7 on rails 2.3.5

Fonsan
March 2, 2010 at 2:12 PM

I have seem to have found the problem: something is wrong with the generation of line 8 in area_chart.html.erb :in_element => 'my_area_chart', becomes line 59 in the source of area_chart: var container = document.getElementById('chart'); somehow the underscores get stripped away because changing line 8 in line 8 in area_chart.html.erb to :in_element => 'chart', fixes the issue * hopes for a fix soon to this great gem

Corey Ehmke
March 2, 2010 at 2:48 PM

Fonsan, Try the latest version of the gem. It contains a fix for an issue regarding the hardcoding of the chart element ID.

Evgeniy Dolzhenko
March 3, 2010 at 9:13 AM

Looks like GitHub project link is broken (i.e. leads to your home page)

Werner
March 4, 2010 at 5:33 PM

Thanks for the sample app, Corey.. works great..looks great.. will try more next days.. Werner

Simon
March 5, 2010 at 4:16 AM

The sample is linked to at the bottom of the linked GitHub page. For convenience: http://github.com/Bantik/seer_sample

Nico
March 20, 2010 at 2:27 AM

Great gem, thanks! I changed it a bit to support select callbacks. To support multiple charts on one page with callbacks I needed to make the chart and chartdata variables globally accessible. So I added a Seer object to the global namespace which stores an array of all charts on the page, an array of chartData and a chartsCount. To add a select callback to a chart you can use the :on_select option for charts that support it. I also added the capability of showing more than one data series in the column chart, similar to the line chart. So the data options for the column chart are now identical to the ones for the line chart. You find the modified gem at rubygems.org. It is called ncri-seer. Oh, one more comment: I do find the gem code has a lot of duplication. The various chart types have a lot of common code that should better be shared I think. Nico

Corey Ehmke
March 22, 2010 at 12:13 AM

Nico, If you fork Seer on GitHub I'll be able to review your additions and changes and possibly fold them into the core project. Thanks!

Boar
March 27, 2010 at 6:31 PM

Corey, the example seems to have issues with being run in the current version of safari (4.0.5), but is fine with firefox (3.5, 3.6) the js debugger is saying google.load('visualization', '1', {'packages':['areachart']}); ReferenceError: Can't find variable: google so... does safari have issues with the way you load the google js library? because if i change the layout to have this: <script type="text/javascript" src="http://www.google.com/jsapi"> </script> <%= Seer::init_visualization -%> then everything is fine...

Gabe
April 6, 2010 at 9:33 PM

just read through this - how awesome! will definitely be using this in the future.

Nigel
April 22, 2010 at 5:55 PM

Great gem. I can think of a lot of uses for it. I have basic charts working, but I have not been able to get stacked bar charts to work, any one have an example? thanks,

Nigel
April 22, 2010 at 5:58 PM

Great gem. Have a lot of uses for this. Anyone have an example of a stacked bar chart? Thanks,
Leave a Comment


IdolHands.com Spam-o-MeterTM
Bot
Spammer
Moron
Human






* Required fields.