I took a couple of quick shots of the group:
and the grid:
More details on my xml.com blog post.
Tim Bray has better photos here.
I took a couple of quick shots of the group:
and the grid:
More details on my xml.com blog post.
Tim Bray has better photos here.
Inspired by how easy it was to get JFreeChart working and some code from former colleague Andrew Bruno, I thought it’d be nice to write some JRuby to generate Edward Tufte’s Sparklines.
Here’s some simple example code on a semi-random dataset:
# Mostly inspired by # http://left.subtree.org/2007/01/15/creating-sparklines-with-jfreechart/ # have JFreeChart in your classpath, obviously, as well as jcommon.jar require 'java' module Graph class Sparkline include_class 'java.io.File' include_class 'org.jfree.chart.ChartUtilities' include_class 'org.jfree.chart.JFreeChart' include_class 'org.jfree.chart.axis.NumberAxis' include_class 'org.jfree.chart.plot.XYPlot' include_class 'org.jfree.chart.renderer.xy.StandardXYItemRenderer' include_class 'org.jfree.data.xy.XYSeries' include_class 'org.jfree.data.xy.XYSeriesCollection' include_class 'org.jfree.chart.plot.PlotOrientation' def initialize(width=200, height=80, data=[]) @width = width @height = height 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 series = XYSeries.new("Sparkline") data = [20] (1..99).each {|x| y = (data.last + (rand(x) + 1)) / 2 data << y series.add(x, y) } dataset = XYSeriesCollection.new dataset.addSeries(series) return dataset end def create_chart(dataset) x = NumberAxis.new x.setTickLabelsVisible(false) x.setTickMarksVisible(false) x.setAxisLineVisible(false) x.setNegativeArrowVisible(false) x.setPositiveArrowVisible(false) x.setVisible(false) y = NumberAxis.new y.setTickLabelsVisible(false) y.setTickMarksVisible(false) y.setAxisLineVisible(false) y.setNegativeArrowVisible(false) y.setPositiveArrowVisible(false) y.setVisible(false) plot = XYPlot.new plot.setDataset(dataset) plot.setDomainAxis(x) plot.setDomainGridlinesVisible(false) plot.setDomainCrosshairVisible(false) plot.setRangeGridlinesVisible(false) plot.setRangeCrosshairVisible(false) plot.setRangeAxis(y) plot.setOutlinePaint(nil) plot.setRenderer(StandardXYItemRenderer.new(StandardXYItemRenderer::LINES)) chart = JFreeChart.new(nil, JFreeChart::DEFAULT_TITLE_FONT, plot, false) chart.setBorderVisible(false); return chart end end # class Sparkline end # class Graph sp = Graph::Sparkline.new puts "Rendering sparkline" sp.render_to_file("sparkline.png")
And the resulting sparkline chart:
Code: http://kfahlgren.com/code/sparkline.jrb
UPDATE: Removed some of the useless sample generation code
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:
I just started reading the second edition of The Ruby Way by Hal Fulton and came across this gem:
We can’t avoid complexity, but we can push it around. We can bury it out of sight. This is the old “black box” principle at work; a black box performs a complex task, but it possesses simplicity on the outside.
This idea of managing complexity is one of the classic commandments of programming, of course, and a core theme of Structure and Interpretation of Computer Programs, but this was a nice restatement.
It looks like this edition (in all it’s 800+ page glory) will be quite a treat.