Creating Beautiful Charts with JRuby and JFreeChart
I recently returned from RubyKaigi where I had the opportunity to sit down with members of the Japanese Ruby community and show them a little bit of JRuby. One of the items that came up a few times was the difficulty of utilizing external libraries from Ruby: if it’s a C library, typically you have to either write a C extension or do the extra work of writing up an FFI binding.
If the library is not implemented in C or Ruby, things get even weirder.
One example is the Charty library, one of the more popular options for generating beautiful chart graphics on Ruby. But Charty actually wraps a Python library called matplotlib, and the bindings for CRuby literally load Python into the current process and call it via Ruby C API calls which then make Python C API calls. The horror!
Also recently, a Reddit Ruby post demonstrated the use of the QuickChart library, which is implemented in JavaScript… yuck! In this case, the call-out is via process launching to the QuickChart command line, but either way it’s not at really integrated into the Ruby app using it.
Is there a better way? You bet there is: use a JVM-based library from JRuby! This post will show you how to get started with JRuby’s Java integration and a few quick examples of using the JFreeChart library from Ruby code. I promise you won’t have to write a single line of Java, C, Python, or JavaScript.
JFreeChart
The JFreeChart library provides an extensive set of chart formats, with a huge array of rendering options and easy integration with either JVM-based GUI toolkits or simple image-file output. Unlike many of the other charting libraries, it also supports live updating of a given chart GUI, making it an excellent choice for desktop monitoring tools.
Building a GUI with JRuby is fun and easy, but for this post we’ll focus on just the chart and image generation parts of the API and how you can use them easily from Ruby.
JRuby’s Java Integration
The magic starts with JRuby’s Java integration layer. The simplest way to use a Java library is to basically pretend it’s a Ruby library, with a few tweaks along the way:
- Download the library’s jar file and dependencies, or use jar-dependencies (part of JRuby’s standard library) to fetch them for you.
- Require the jar file and dependencies manually (a simple
require "myfile.jar"
works in JRuby!) or by usingrequire_jar
fromjar-dependencies
. - Call the Java classes you’re interested from Ruby as if they were plain old Ruby classes. You can even import them, Java-style, but it’s often not necessary.
Let’s start with a simple example.
Calling into the java.lang.Runtime class
Assuming you’ve installed JRuby 10, you can start playing with JVM libraries directly from IRB. Let’s fire it up and make sure we’re running on JRuby.
$ irb
irb(main):001> RUBY_ENGINE
=> "jruby"
irb(main):002>
The JDK comes with a large number of built-in features, of course, and I like to use the java.lang.Runtime class for quick demonstrations. It provides methods to query a bit of information about the running JVM and the host operating system. Let’s “import” it into our session and call a few methods.
irb(main):002> rt = java.lang.Runtime.runtime
=> #<Java::JavaLang::Runtime:0x39a87e72>
irb(main):003> rt.available_processors
=> 8
irb(main):004> rt.free_memory
=> 222145360
There’s a few bits of magic here that make it really feel like Ruby:
- JRuby defines a few top-level methods for common Java package roots like
java
,javax
,org
, andcom
. We use this to reference the Java packagejava.lang
here and access theRuntime
class. Runtime
defines a static method (similar to a Ruby class or singleton method) calledgetRuntime
which gets the singleton instance ofRuntime
for the current JVM process. JRuby turns Java “getter” and “setter” methods into Ruby “attribute accessors”, so you can just callRuntime.runtime
here.- The Ruby calls to
available_processors
andfree_memory
translate to the Java methodsgetAvailableProcessors
andgetFreeMemory
in the same way. The original methods are still callable, but we add aliases for the Ruby-friendly names.
We can accomplish a tremendous amount with the libraries shipped in the JDK, ranging from simple database access to professional desktop GUI development.
If the libraries we want to use are not shipped with the JDK, however, we need to fetch them. It’s always possible to download the library’s “jar” file directly, but then you may also have to hunt down its dependency jars. A better way is to use JRuby’s jar-dependencies library.
jar-dependencies
Like Ruby gems get pushed to rubygems.org, Java libraries get published as jar files to Maven repositories, a global, federated repository of every version of every Java library known to man. In order to make it as easy as possible to use these libraries from JRuby, we’ve built extensive Maven tooling for both Ruby and Java applications.
The simplest way to load a JVM library from Maven into your JRuby app is to use jar-dependencies
, a built-in tool for fetching and managing Java dependencies in either standalone applications or in gems.
For our examples, we want to fetch JFreeChart and its dependency libraries. If we search for it at search.maven.org, we can acquire its “Maven coordinates”.
The most recently-published artifact is jfreechart 1.5.5. From here we can see the coordinates we’re looking for:
- The group ID, used for namespacing libraries, is
org.jfree
. - The artifact ID, which identifies the library, is
jfreechart
. - And the version we want is
1.5.5
(Maven strongly encourages always using specific versions).
Given that, we can set up our JFreeChart project.
JRuby and JFreeChart: Happy Together!
Without knowing anything about JFreeChart, I was able to load it up and get some simple examples working from IRB just last night. I was so impressed, I decided to write this blog post!
I’ve pushed this example as headius/jruby-charts on GitHub so you can follow along.
Using jar-dependencies to fetch JFreeChart
We’ll start by creating a jar-dependencies
“Jarfile”, which is roughly equivalent to Bundler’s “Gemfile”:
jar 'org.jfree:jfreechart:1.5.5'
Similar to a Gemfile’s gem name and version, we specify the Maven coordinates of the library we want (separated by colons). Once we have this file, we can fetch and “lock” this dependency with the lock_jars
command.
jruby-charts $ lock_jars
-- jar root dependencies --
org.jfree:jfreechart:1.5.5:compile
Jars.lock created
This command fetches JFreeChart and any other dependencies to your local Maven repository, which by default is in ~/.m2/repository
. In general, we recommend using jar-dependencies this way, so that your jars don’t conflict with other gems’ jars, and all applications on a given system use the same set of downloaded files. It’s also possible to fetch the jars and ship them inside your application or gem, but we’ll leave that example for another day.
Let’s get to the fun stuff: using JFreeChart from Ruby!
Generating a simple bar chart
Our first example will create a simple bar chart.
First, we need to load in the jars we just downloaded and locked.
# Use jar-dependencies, included with JRuby, to load JFreeChart
require 'jar-dependencies'
require_jar 'org.jfree', 'jfreechart', '1.5.5'
At this point all of the classes of JFreeChart are available to Ruby. We start by creating a DefaultCategoryDataset which will hold our bar chart data.
# Create an empty CategoryDataSet
bar_data = org.jfree.data.category.DefaultCategoryDataset.new
JFreeChart provides a wide array of dataset types that can source data from a database, a JVM-based collection object (which includes Ruby collections), or other forms of structured data. The “default” version works nicely for a simple example. Let’s fill it with some data.
# Add values to the dataset
bar_data.add_value 44, "Ben and Jerry's", "Flavors"
bar_data.add_value 31, "Baskin Robbins", "Flavors"
bar_data.add_value 11, "Cold Stone", "Flavors"
This bar chart will display a count of ice cream flavors from three well-known purveyors of the creamery arts. The add_value
method here is addValue
in Java, and takes a number, a column key, and a row key.
Given our dataset, we can now request that JFreeChart create a basic bar chart for us using the ChartFactory class.
# Create a bar chart with default settings
java_import org.jfree.chart.ChartFactory
bar_chart = ChartFactory.create_bar_chart "How Many Ice Cream Flavors?",
"Flavors", "Creamery", bar_data
We import the ChartFactory
class for convenience (which is basically equivalent to doing ChartFactory = org.jfree.chart.ChartFactory
) and then call create_bar_chart
to generate a bar chart with default settings. The arguments we pass are the name of the chart, the label for the X axis, and the label for the Y axis, and our dataset.
Now that we have a chart, we can use Java’s graphics APIs (provided with the JDK by default) to output a PNG file.
# Create a buffered image in memory at 500x500
bar_image = bar_chart.create_buffered_image 500, 500
# Write the image as a PNG to a file
bar_file = File.open("barchart.png", "w")
javax.imageio.ImageIO.write(bar_image, "PNG", bar_file.to_outputstream)
JFreeChart’s bar chart type knows how to create a Java2D BufferedImage, which we can then pass to ImageIO to write it out. In this case, we even use a Ruby File
as the target, using a bit of JRuby magic that turns it into a Java OutputStream!
With our jar dependencies locked and our script written, we can simply run it with JRuby from a command line.
jruby-charts $ jruby examples/barchart.rb
2025-04-30 14:58:21.744 java[84148:2288876] +[IMKClient subclass]: chose IMKClient_Modern
2025-04-30 14:58:21.744 java[84148:2288876] +[IMKInputSession subclass]: chose IMKInputSession_Modern
Depending on your platform, you may see a little bit of “helpful” JVM output indicating that the graphics subsystem has been loaded.
Let’s see what we just made!
Just a few lines of code and we’re done! Such fun!
Everyone loves pie!
The Java integration walkthrough and bar chart example above should whet your appetite for doing cool things with JRuby, but I include a pie chart example here to show a few differences:
# Use jar-dependencies, included with JRuby, to load JFreeChart
require 'jar-dependencies'
require_jar 'org.jfree', 'jfreechart', '1.5.5'
# Create an empty PieDataset
pie_data = org.jfree.data.general.DefaultPieDataset.new
# Add values to the dataset
pie_data.insert_value 0, "Fun", 0.45
pie_data.insert_value 1, "Useful", 0.25
pie_data.insert_value 2, "Cool", 0.15
pie_data.insert_value 3, "Enterprisey", 0.10
pie_data.insert_value 4, "Exciting", 0.5
# Create a pie chart with default settings
pie_chart = org.jfree.chart.ChartFactory.create_pie_chart "Why JRuby?", pie_data
# Anti-alias the chart to look a bit cleaner
pie_chart.anti_alias = true
# Access the actual PiePlot to tweak additional settings
pie_plot = pie_chart.plot
pie_plot.set_explode_percent "Fun", 0.20
# Create a buffered image in memory at 500x500
pie_image = pie_chart.create_buffered_image 500, 500
# Write the image as a GIF to a file
pie_file = File.open("piechart.gif", "w")
javax.imageio.ImageIO.write(pie_image, "gif", pie_file.to_outputstream)
This example takes advantage of a few customizations provided by JFreeChart:
- The edges of the pie are set to anti-alias for a cleaner look (
pie_chart.anti_alias = true
, which calls setAntiAlias). - We access the actual PiePlot object to “explode” one of the elements out of the pie.
- Instead of a PNG, we output a GIF, just because. The standard Java ImageIO support can handle BMP, GIF, JPEG, PNG, TIFF, and WBMP, and there’s third-party support for everything else.
And here’s the resulting pie chart:
It’s as easy as pie!
Your Turn
In this post, you learned the following:
- Basics of Java integration in JRuby
- How to fetch and load Java libraries from Maven
- A few simple ways to create charts with JFreeChart
We didn’t have to write a single line of Java code, and we didn’t have to call out to any nasty C, Python, or JavaScript libraries. The code you see and the libraries we loaded all run in the same JVM process alongside your Ruby code, and can be easily deployed to any system with a JDK. It’s really that simple!
JFreeChart is just one charting library out of many in the Java ecosystem, and there’s thousands of other useful libraries you can start using with JRuby today. Need to generate PDFs or Office documents? Try OpenPDF or Apache Poi. Need to integrate with unusual databases? JDBC has you covered with a standard API. Want to deploy a single binary for your entire application? JRuby’s Warbler project allows you to bundle everything up as a single jar file.
Ruby faces many challenges these days, and we’re solving them one at a time with JRuby and the JVM. I hope you will experiment with JRuby yourself and create something beautiful!
Join the discussion on Reddit!
JRuby Support and Sponsorship
This is a call to action!
JRuby development is funded entirely through your generous sponsorships and the sale of commercial support contracts for JRuby developers and enterprises around the world. If you find my work exciting or believe it is important your company or your projects, please consider partnering with me to keep JRuby strong and moving forward!