BT
x Your opinion matters! Please fill in the InfoQ Survey about your reading habits!

Amazing Charts In Rails

Posted by Srividya Sharma on Jan 29, 2009 |
Web applications often analyze data in the database by generating reports. Charts provide a visual representation of the reports, can be used for understanding trends and generally facilitate better synthesis of data. Ruby On Rails is one of the technologies that can be used to create these web applications with reports and charts. In this article, we will discuss how to create charts in Ruby on Rails.

For generating charts from reports or data in the database, we need a good charting product. Gruff, JFreeChart, XML/SWF charts, FusionCharts are few of the products available for Ruby on Rails. The following table gives a rough comparison of these charting products. Note that not all products have been tried and tested. Most of the analysis below is based on information gathered from the documentation of the products.
Gruff JFreeChart XML/SWF FusionCharts Free FusionCharts v3 (Paid)
Type Ruby classes Java Class files Flash charting component Flash Charting component Flash Charting component
Operating System O/S Independent O/S Independent O/S Independent O/S Independent O/S Independent
Adobe Flash Plug-in required No No Yes Yes Yes
Suitable for Advanced Data Analysis No Yes Yes No Yes
Any plug-ins or software to be installed Yes- RMagick, ImageMagick and Gruff Yes, JDK version 1.3 or later No No No
Can the charts be animated? No Yes Yes Yes Yes
Ability to save chart as image Yes Yes Yes No Yes
UTF8 support Not Documented Yes Yes Yes Yes
Ease Of Use In RoR Yes, but lot of coding involved. Not very easy to use. Not meant for end-user. Complex, too many xml tags for configuring the chart. Very easy to use. Developers and end-users can use it. Very easy to use. Developers and end-users can use it.
Bar Charts 2D, 3D Yes Yes Yes Yes Yes
Line Charts Yes Yes Yes Yes Yes
Scatter Charts Yes Yes Yes Yes Yes
Area Charts Yes Yes Yes Yes Yes
Pie 2D, 3D Yes Yes Yes Yes Yes
Doughnut 2D, 3D No Yes, Ring Chart Yes Yes Yes
Gantt Charts No Yes No Yes Yes ( as part of FusionWidgets v3)
Combination Charts No Yes Yes Yes Yes
Gauge charts No Yes ( as part of XML/SWF Gauge) Yes No Yes ( as part of FusionWidgets v3)
Real-time charts No No No No Yes ( as part of FusionWidgets v3)
Data-driven Maps No No No No Yes ( as part of FusionWidgets v3)

In this article, we will explore charting in Rails using FusionCharts and MySQL database. FusionCharts is a flash-based charting component which can generate interactive and animated charts. FusionCharts can be used with any web scripting language, to deliver powerful charts with fairly minimal coding. FusionCharts comes with wrapper modules for use with RoR. Easy to use, variety of chart types, good documentation and great support is the motivation behind using FusionCharts for this article.

This article describes the mechanism of generating charts using FusionCharts in Ruby on Rails through a sample application. To run the sample application discussed in this article, the following would be needed:

•  FusionCharts Free/ v3:

FusionCharts Free can be downloaded from www.fusioncharts.com/free , or the commercial version with more options can be downloaded from www.fusioncharts.com . In this article, we use the free version to create the charts.

Installation of FusionCharts merely involves copying and pasting the SWF and .rb files from the download package into appropriate application folder. The .rb files are present in Download Package > Code > RoR > Libraries folder.

•  Ruby 1.8.6 or above:

Available at http://www.rubyonrails.org/down

•  Rails gem 2.0.2 or above:

With RubyGems loaded, you can install all of Rails and its dependencies through the command line:

   gem install rails

Rails can also be downloaded as stand-alone package from here .

• MySQL 4.0 or above:

Can be downloaded from here .

The sample application developed for this article is a basic time tracker application. This is a simple application where an employee fills out time for a week and views the chart based on the input hours. This article will discuss the sample application in two parts. The first part deals with the development of the basic application which includes list, edit, show and destroy for employees and timesheets. If you already have an application in which you have to integrate charts, then you can skip this part and go directly to the next part, which explains the integration of charts with the application. The article expects the reader to have a basic knowledge of Ruby on Rails.

Creating the Basic time tracker application

Using scaffold, the basic functionality of list, show, edit and delete for employees and timesheets can be generated. The commands to generate the basic employee and timesheet controllers are as follows: (run the last two commands from within the TimeTrackerApplication folder created with the first command)

rails –d mysql TimeTrackerApplication
ruby script/generate scaffold Employee name:text
ruby script/generate scaffold Timesheet log_date:datetime hours_spent:integer employee_id:integer

Next, you would modify the database.yml present in the config folder to point to “timetrackerdb” and the username and password entries corresponding to your database. Then, you would run the following rake commands to create the database,

rake db:create
rake db:migrate

In order to establish the foreign key relationship between employees and timesheets table, you would run the following query in your mysql instance:

alter table timesheets add constraint fk_employee_id foreign key fk_employee_id(employee_id) references employees(id) on delete cascade 

Of course, there are other ways of creating foreign keys; the discussion of which is beyond the scope of this article. To represent the above foreign key relationship in Ruby on Rails, you will have to create an association between the models.

In Employee Model, after the class declaration statement, write the following statement:

has_many :timesheets 

And in Timesheet Model you need to write:

belongs_to :employee 

To insert the sample values into the database, you would need to run the sql script db/sampledata.sql. The basic application is now ready. You can add, view, edit or delete employees.

Integrating Charts In The Application

With the basic time tracker application in place, here is what it takes to generate the time tracker charts for an employee:

•  Copy the FusionCharts folder available in the download package of FusionCharts Free/Pro
   (Download Package > Code > FusionCharts), to the public folder of TimeTrackerApplication.

•  Copy the file FusionCharts.js present in the Download Package > Code > FusionCharts folder
    
to the public/javascripts folder.

•  Copy the fusioncharts_helper.rb from the Download Package > Code > RoR > Libraries folder
    of the download into the lib folder of TimeTrackerApplication.

That completes the FusionCharts setup.

From the list of employees page, a link to the Time Tracker Chart needs to be created. Thus, for every employee, there will be a link to view his time as a chart. The link to the time tracker chart is created in the app/views/employees/index.html.erb file. Listing 1 shows the details of the link added. Add this link after the other links in the page.

Listing 1

 <td><%= link_to 'Time Chart', {:action=>'view_timesheet_chart',:id=>employee.id} %></td>

Figure 1 illustrates the list of employees page from the application. The features seen in Figure 1 have been acheived easily via database setup and ruby scaffold as seen in the previous section. This page can be viewed by accessing the address "http://yourserver:port/employees". The relevant portion of this screen is shown in Figure 1.

Figure 1

The action invoked on clicking this "Time Chart" link is the view_timesheet_chart action of the employees controller. Listing 2 shows the code for this action. This action renders the chart for the selected employee. The action contacts the Employee model to find the timesheets for this employee in the date range "2008-12-01" to "2008-12-07" and then renders the "view_timelog_chart.html.erb". To keep things simple, the date range has been fixed in the controller. In real world applications, the date range for generating the report/ chart would be selected by the user.

Listing 2

EmployeesController

  def view_timesheet_chart
    start_date= "2008-12-01"
    end_date="2008-12-07"
    @employee_id = params[:id]
    employee_details_with_timesheets =  Employee.find_with_timesheets_in_date_range(@employee_id,start_date,end_date)
    if(!employee_details_with_timesheets.nil?)
        @employee_details_with_timesheets =employee_details_with_timesheets[0]
    else
      @employee_details_with_timesheets =nil;
    end
    headers["content-type"]="text/html"
end

Using the employee id as parameter, this action contacts the Employee model to find the timesheets for this employee within the specified period. The function to be added in the Employee model is shown in Listing 3 below:

Listing 3

Employee.rb

def self.find_with_timesheets_in_date_range(id, start_date, end_date)
    conditions="employees.id =? and log_date between ? and ?"
    employee_details_with_timesheets=self.find(:all, :include=>'timesheets', :conditions=> [conditions,id,start_date,end_date], :order=>'log_date asc')
    return employee_details_with_timesheets
end

The action finally renders "view_time_chart.html.erb". The template "view_timelog_chart.html.erb" uses the layout "employees.html.erb" which is common to all views of employees controller. Hence, the code in the view is short and sweet as seen in Listing 4.

Listing 4

view_timesheet_chart.html.erb (in app/views/employees folder)

<%= javascript_include_tag "FusionCharts"%>
<%
# The xml is obtained as a string from builder template.
str_xml = render "employees/timesheet_data"
#Create the chart - Column 3D Chart with data from strXML
render_chart '/FusionCharts/Column3D.swf' , '' , str_xml , 'TimeChart' ,  650 ,  400 ,  false ,  false do -%>

<%  end -%> 

From the above code, we understand the following as the steps involved to render the chart in the view page:

  1. Include the FusionCharts.js file.
  2. Obtain the xml data from the builder. ( The builder uses the data from the controller action to build the xml)
  3. Render the chart by calling render_chart function with appropriate parameters

Usually, time is represented in a Gantt chart and this chart is also available in FusionCharts. Here, for the sake of simplicity, the Column chart has been used.

The second step involves the creation of xml. FusionCharts uses XML (eXtensible Markup Language) to create and manipulate charts. The entire FusionCharts chart is controlled by XML parameters i.e., you use XML to define the cosmetic as well as functional properties for the chart. There are a lot of properties that you can define for each chart type. FusionCharts has a specific XML structure for each chart. The chart under discussion is a single-series chart (having only one set of data), representing the day of the week and the number of hours spent by the employee on that day. A sample xml for this chart is shown in Listing 5.

Listing 5

Sample Single-Series Chart XML

<graph xAxisName="Day" showValues="1" caption="Time Tracker Chart" numberSuffix=" hrs." subcaption="For Employee John Wilson" yAxisName="Hours Spent">
    <set name="Monday" value="8" color="AFD8F8"/>
    <set name="Tuesday" value="6" color="F6BD0F"/>

    <set name="Wednesday" value="5" color="8BBA00"/>
    <set name="Thursday" value="9" color="A66EDD"/>
    <set name="Friday" value="9" color="F984A1"/>
    <set name="Saturday" value="8" color="CCCC00"/>
</graph>

To generate an xml similar to the one shown in Listing 5 but with the data present in the database, the builder file is used.

How does the builder build the chart xml? The builder builds the xml for the chart using the @employee_details_with_timesheets variable stored in the action. Listing 6 shows the contents of the builder file.

Listing 6

timesheet_data.builder (in app/views/employees folder)

xml = Builder::XmlMarkup.new(:indent=>0)
options = {
 :caption=>'Time Tracker Chart',
 :subcaption=>'For Employee '+ @employee_details_with_timesheets.name   ,
 :yAxisName=>'Hours Spent',
 :xAxisName=>'Day',
 :showValues=>'1',
 :formatNumberScale=>'0',
 :numberSuffix=>' hrs.'
}
xml.graph(options) do
  for timesheet in @employee_details_with_timesheets.timesheets do
     log_day = timesheet.log_date.strftime('%a')
     xml.set(:name=>log_day,:value=>timesheet.hours_spent,:color=>''+get_FC_color)
  end
end

In the builder, you would first create a new XMLMarkup object with the value for "indent" equal to zero and use this object for building the xml.

All the options required for configuring the chart is present in a hash named options, which is passed to the top-most (graph) tag. For details on the options that can be provided to the chart, please refer to the complete FusionCharts documentation. The xml root element is "graph". Within this, there is a "set" element corresponding to each timesheet of the selected employee. Each “set” element has name and value as attributes. The name would contain the day of the week and the value will contain the hours spent on that day by that employee. The builder uses the @employee_details_with_timesheets variable present in the controller action, to obtain these values.

Finally, in the view page, the chart is rendered using the function render_chart which takes the swf chart file name, url, xml, width, height, debugMode, registerWithJS as parameters. This function is available in the fusioncharts_helper module present in the lib folder. This can be made accessible to all the views by including it in the application_helper.rb as shown in Listing 7.

Listing 7

application_helper.rb

require 'fusioncharts_helper'
include FusionChartsHelper 

The swf files required to show the charts are present in the public/FusionCharts folder. Here the Column3D.swf has been used but any other type of single-series chart could also be generated by just changing the swf filename. The data has been provided using dataXML method but the data could also be provided through a dataURL. Examples of this are present in FusionCharts documentation.

Now, on clicking the "Time Chart" link for an employee in the list of employees page, the time log entries for the week 01/12/2008 to 07/12/2008 are displayed in the form of a chart. The timesheet chart will be similar to Figure 2 shown below.

Figure 2

Summary of steps to generate chart:

After the setup of FusionCharts in the application and including FusionChartsHelper in the application_helper.rb, the following are the steps

  1. In the controller action, find the data required for the chart from the database.
  2. Write a builder to build the chart xml from this data.
  3. In the view for the controller action in step 1, get the xml from the builder by either passing the data to it or letting the builder use the data from the controller action.
  4. Next, call the function render_chart with appropriate parameters (including the xml obtained from step 3)

In this article, you have learnt how to create a simple chart using FusionCharts in Ruby on Rails through the time tracker application. With a few modifications to the sample application, you could create a chart with the overview of time log for all the employees. Probably, from this chart you could drill-down on a particular employee to get the time details for him. You could use Ajax for retrieving the chart. The possibilities are innumerable. FusionCharts download package itself contains a number of examples which can be explored. The entire sample application discussed in this article is available for download here.

About the Author:

The author is a Consultant with over 6 years of experience in the IT Industry and has interests in a wide range of web technologies involving the J2EE stack, Ruby On Rails & PHP.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

JS approach by Anselmo da Silva

As you mentioned, there are several ways to create charts in rails, but each one has some terrible dependency (ie: rmagick == memory killer + server-work, swf==another client layer, plus the excess of animations).

The point is Data-Visualization, and here, you could include in your analyze, the "Javascript Canvas" approach.

As js engines getting faster, the use of this canvas element becomes even more interesting. The caveat is the no-direct-support in IE.

We use the approach in controlled client environments, and it results to be an elegant solution, with simple deploy and control.

Some references:
Flot: code.google.com/p/flot/
Protochart: www.deensoft.com/lab/protochart/
PlotKit: www.liquidx.net/plotkit/

Thanks for your sharing
Anselmo
twitter.com/anselmo

Re: JS approach by Werner Schuster

Anselmo,
thanks for the links - definitely an approach to watch.

BTW we also featured an article on using Google Charts from Ruby:
www.infoq.com/articles/bass-google-charts-gchartrb
which has neither client nor serverside dependencies, but of course you'll tie yourself to Google's servers.

Re: JS approach by Anselmo da Silva

Just a last reference:
jsxgrap => jsxgraph.uni-bayreuth.de/cms/index.php?page=exa...

Over OFC2? by Jonathan Calvert

What does this give me over OpenFlashChart2? I'm not so sure I see it. I would definitely agree that the charting solutions for Rails are generally less than satisfactory. OFC is free and with the JSON support is excellent. I've even been using that to 'store' charts in CouchDB.

But anyway, there is one real problem with Flash based charting as opposed to server side image compilation, and that's handling large data sets(10s or 100s of thousands of data points) for scatter plots.

Ezgraphix Plugin. by Juan Esteban Pemberthy

Hello there, I made this plugin for FusionCharts usage in Rails,

github.com/jpemberthy/ezgraphix/tree/master

Documentation and a live demo are listed in the project's readme, it's still a basic plugin but Im thinkin in making a second version supporting more charts.

Enjoy it.

Re: Over OFC2? by Srividya Sharma

I would say, FusionCharts Free provides more chart types and better animation. Both are totally free - so one cannot complain much about free solutions - it is up to you what you choose.
Of course, upgrading to FusionCharts v3 opens a new set of benefits like more chart types, maps, power charts, visual debugger and not to mention the personal support.

Re: JS approach by Jerven Bolleman

There is the free java implementation of the google chart api.
www.jfree.org/eastwood/

Gruff has no scatterplott-charts (but gnuplot) by Oliver Haag

There is a mistake in this elsewise great overview, Gruff has no support for scattercharts.

Instead FusionCharts indeed is a good solution for simple scattercharts. For really komplex data I prefer something not on the list: gunplot with the rgplot ruby wrapper.

- gnuplot.sourceforge.net/
- rgplot.rubyforge.org/

Hope it helps.
Oliver

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

8 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT