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.