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. :)

About Ken Kousen
I teach software development training courses. I specialize in all areas of Java and XML, from EJB3 to web services to open source projects like Spring, Hibernate, Groovy, and Grails. Find me at Google+ on Google+ I am the author of "Making Java Groovy", a Java / Groovy integration book published by Manning in the Fall of 2013.

8 Responses to Simple Google Chart with Groovy

  1. Ken Kousen says:

    Of course, when I attempted to show my code that replaced semicolons with the entity reference “ampersand-amp-semicolon”, this page replaced it with a straight ampersand. Oh well.

    It should look like

    url.replaceAll(/&/,’&amp;’)

    We’ll see if that shows up correctly here.

  2. William G. Thompson, Jr. says:

    “I think of it as a RESTful web service, despite the fact that the return values aren’t, strictly speaking, XML.”

    A tenet of REST is that any suitable representation can be returned, not just XML.

  3. There is always a Groovy Chart Builder that Zan Thrash created:

    http://zanthrash.blogspot.com/2008/01/groovy-chart-builder.html

    Link to download is in the post somewhere.

  4. Ken Kousen says:

    I received an RSS message about the Groovy Chart Builder the day after I made this post. In a way, I’m glad, because I did spend the time to learn how to do this. But let’s be honest, Zan Thrash’s builder is superior in every way imaginable. I’m looking forward to using it in the future.

    I also found out that Grails has an excellent Google Chart Plugin, too, at http://grails.org/Google+Chart+Plugin.

  5. Ryan says:

    Hey Ken,

    I’ve had a great time reading your blog about groovy and grails. I am starting a similar adventure into groovy and grails, and I am curious if you have had any experience integrating groovy classes (specifically grails domains/services) with traditional Java classes?

    I know you can use interfaces, but if you have any tips or insight I think it would make a great blog post.

    Cheers!
    Ryan

    P.S. I realized I used the “Contact Me” link at your company website, which is probably inappropriate as it was not business related, sorry about that!

  6. Nils Kassube says:

    Of course there is more groovy way to build the list in encodeMap():

    list = ((‘A’..’Z’) + (‘a’..’z’) + (0..9)).toList()
    ;-)

  7. Nils Kassube says:

    And the method in addToMap is a one-liner:

    map[label] = map.get(label, 0) + 1

  8. Ken Kousen says:

    Ah, of course. Both those changes make the code much groovier. Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 1,375 other followers

%d bloggers like this: