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:

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.