More JRuby Play: JFreeChart

I’ve been messing around at work trying to make some automated scheduling charts (basically Gantt-like) in Ruby. I’ve implemented it a couple of times using SVG::Graph, which is close to what I need, but I end up having to rewrite a lot of methods whenever I really start using it. It occurred to me today that I might be able to co-opt a sexy Java library to do my dirty work. JFreeChart to the rescue!

As before, I’m generally amazed at how little work goes into integrating Java and JRuby these days. It’s a testament to the JRuby team and to the wealth of well-written, well-documented Java libraries out there.

Here’s some toy code that makes a simple Gantt chart and saves it as a PNG to a file:

# have jfreechart.jar in your classpath, obviously, as well as jcommon.jar
# and use a recent jruby
require 'java'
module Gantt
  class Simple
    include_class 'org.jfree.chart.ChartFactory'
    include_class 'org.jfree.chart.ChartUtilities'
    include_class 'org.jfree.chart.JFreeChart'
    include_class 'org.jfree.data.gantt.Task'
    include_class 'org.jfree.data.gantt.TaskSeries'
    include_class 'org.jfree.data.gantt.TaskSeriesCollection'
    include_class 'org.jfree.data.time.SimpleTimePeriod'
    include_class 'java.lang.System'
    include_class 'java.io.File'

    MILLIS_IN_A_DAY = 86400000

    def initialize(title="Chunky Bacon", width=700, height=400, data=[])
      @width = width
      @height = height
      @title = title
      dataset = create_sample_data() if data.empty?
      @chart = create_chart(dataset)
    end

    def render_to_file(filename, format="png")
      javafile = java.io.File.new(filename)
      ChartUtilities.saveChartAsPNG(javafile, @chart, @width, @height)
    end

    private
    def create_sample_data
      # dates as milliseconds seems the easiet
      now = System.currentTimeMillis
      tomorrow = now + (MILLIS_IN_A_DAY * 1)
      day_after_tomorrow = now + (MILLIS_IN_A_DAY * 2)
      week_from_today = now + (MILLIS_IN_A_DAY * 7)

      s1 = TaskSeries.new("JRuby")
      s1.add(Task.new("Download JRuby",
                      SimpleTimePeriod.new(now, tomorrow)))
      s1.add(Task.new("Write Code",
                      SimpleTimePeriod.new(tomorrow, day_after_tomorrow)))
      s1.add(Task.new("Setup CLASSPATH",
                      SimpleTimePeriod.new(day_after_tomorrow, week_from_today)))

      s2 = TaskSeries.new("Java")
      s2.add(Task.new("Read Comics",
                      SimpleTimePeriod.new(now, tomorrow)))
      s2.add(Task.new("Write Code",
                      SimpleTimePeriod.new(tomorrow, day_after_tomorrow)))
      s2.add(Task.new("Setup CLASSPATH",
                      SimpleTimePeriod.new(day_after_tomorrow, week_from_today)))

      collection = TaskSeriesCollection.new
      collection.add(s1)
      collection.add(s2)
      return collection
    end

    def create_chart(dataset)
      opts = {
              :title => @title,
              :domain_axis_label => "Task",
              :range_axis_label => "Date",
              :data => dataset,
              :include_legend => true,
              :tooltips => false,
              :urls => false
             }
      chart = ChartFactory.createGanttChart(
                                              opts[:title],
                                              opts[:domain_axis_label],
                                              opts[:range_axis_label],
                                              opts[:data],
                                              opts[:include_legend],
                                              opts[:tooltips],
                                              opts[:urls]
                                            )
      return chart
    end

  end # class Simple
end # module Gantt

chart = Gantt::Simple.new("Gantt Chart Demo")
puts "Rendering chart"
chart.render_to_file("simplegantt.png")

Example PNG:

A Simple Gantt Chart Example

Code: http://kfahlgren.com/code/simple_gantt.jrb

One Response to “More JRuby Play: JFreeChart”

  1. Evan says:

    Nice! Great Summary.

    I’ve had similar experience with SVG::Graph and slightly more recently Gruff. Gruff seemed the better of the two by a wide margin. That said, it requires RMagick which is (a) a PITA and (b) impractical with JRuby.