Simple Google Chart with Groovy

Google has a nice little chart plotting capability at Google Chart API. It’s a web service that generates images based on supplied parameters in a URL string. I think of it as a RESTful web service, despite the fact that the return values aren’t, strictly speaking, XML.

I thought I’d use it to create a pie chart showing the categories of courses I taught in 2007. That meant I had to grab the name of each course from my database, put it in a category, count how many times each category appeared, and then encode the results in a URL I could send to Google. I believe that the right way to solve that problem in the long run is to add a label or category to my Grails application and then search on that, but I haven’t done that yet.

At this point, I thought I’d do the whole thing as a simple Groovy script. I won’t bother discussing here how I retrieved the course titles from the database — that’s pretty straightforward. Putting the courses into categories consisted of snippets of code like:


courses.each { c ->
  if (c.name =~ (/Spring|Hibernate/) ) {
    addToMap('Open Source')
}

where addToMap() is a private function that checks to see if the label is already in the map and either adds it if it isn’t, or increments its value if it is.

For the record, that looks like:


def addToMap(label) {
  if (!map.containsKey(label)) {
    map.put(label,1)
  } else {
    map.put(label, map.get(label) + 1)
  }
}

I assume there’s a Groovier way to do that, but since I didn’t know what it might be, I fell back on straight Java.

The next part is to encode the results the way the Google Chart API expects. I put my courses into some pretty coarse (no pun intended) categories, so my map looks like:

["Open Source":9, "J2EE":12, "Web Services":9, "Ajax":9, "Other":1]

(Some of my courses — Ajax and Java, for example — fell into more than one category.)

Google Chart wants to see the chart labels as a string of values separated by vertical bars. In Groovy, that’s a one-liner:


map.keySet().collect {
  URLEncoder.encode(it,"UTF-8")
}.join('|')

which handles the situation where the label has a space in it, like “Web Services”.

The values are a bit more tricky. Google Chart uses a simple encoding scheme where all the numbers from 0 to 61 turn into the characters A through Z, a through z, and 0 through 9, in that order. The developer’s guide shows a JavaScript example for converting numerical values into those characters.

I decided to do it in Groovy, of course. There’s probably a simpler way, but this worked for me:


def encodeMap() {
  List list = []
  for (i in (('A'..'Z') + ('a'..'z') + (0..9)))  {
    list << i
  }
  String s = "&chd=s:"
  map.each { k,v ->
    s += list[v]
  }
  // ...
}

I initialized the string with “&chd=s:” which tells Google Chart I’m supplying chart data using the simple encoding. Starting from the map values shown above (9, 12, 9, 9, 1), my encoded values were “JMJJB”.

That created the string I needed. I was worried that the values would be retrieved in a different order from the keys returned by keySet(), but I think the map.each function retrieves the keySet first and then uses it to get each value, so it wasn’t a problem.

The rest is simple. I decided to use a 3D pie chart, and made it 500×150 pixels in size to make room for the labels. All Google Chart requests go to “http://chart.apis.google.com/chart&#8221;
and query parameters specify the chart type, size, data, and labels. In my case, the parameter string is


cht=p3
&chs=500x150
&chd=s:JMJJB
&chl=Open+Source|J2EE|Web+Services|Ajax|Other

Pasting the complete URL into a browser gives me the image, but what I really want is to make that the source of an HTML image tag. The developer’s guide says to do that, I need to put that URL in the src attribute, but I have to replace all the ampersands with the associated entity reference, &.

That too is easy enough in Groovy.

String urle = url.replaceAll(/&/,'&')

so the resulting image tag is


<img src='http://chart.apis.google.com/chart?cht=p3
&chs=500x150
&chd=s:JMJJB
&chl=Open+Source|J2EE|Web+Services|Ajax|Other'
alt='Course distribution'/>

all on one line, of course.

The final result is shown below.

That sure was a lot easier in Groovy than it would have been in Java. 🙂

%d bloggers like this: