Oftentimes, web sites need to display different kinds of data in web charts. As always, there are a bunch of different frameworks and libraries to choose from. After some investigation I decided to try out the Flot library together with Play.
Flot is an easy to use Javascript plotting library for JQuery producing nice looking charts on the client side. We’ll see how we can use Flot together with Play to create good looking charts with very little effort. There are a few things that makes this an especially smooth ride:
- The Flot library is really easy to use.
- The high usability of the Play framework
- JSON and JQuery
Post update
A while back Nico at Learn To Play was kind enough to put together a minimalistic working version based on the code in this post. If you’re going to use this in a project or similar I recommend that you download the code and give it a try. You’ll find the link to the zip in the comments section.
Getting started
In the following it is assumed that you already have the Play framework installed and have some basic understanding of how the framework works (if not you should take the time to read up, the documentation is really good)
Download the Flot library from Flot and import the the script in the page where you want to use it:
<script src="@{'/public/javascripts/jquery.flot.js'}"></script>
In my case I put the import in the main.html page that all the pages inherit from.
Take a look at the examples and documentation to get a basic understanding of how the library works. You don’t need to understand it all, but as a minimum you need to know how the plot function works and the basics around formatting the series.
Example: Displaying the number of visitors
The chart below shows the number of visitors on a make believe web site for March.
The chart was of course created with Flot. In my opinion the chart has an attractive look and best of all, it was created with only a few lines of code. Let’s see how…
Presentation Layer Code
As you probably know, a Play application follows the MVC architectural pattern. We’ll now look at the code for the View and the Controller.
#{extends 'main.html' /}
#{set title:'Dashboard' /}
<div id="mainContent">
<section id="comments">
<center><h1>Stats</h1></center>
<article>
<div id="placeholder" style="width: 800px; height: 400px;"></div>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var options = {
grid: {
hoverable: true, clickable: true, backgroundColor: { colors: ["#000", "#999"] }
},
series: {
lines: {show: true}
},
legend: { noColumns: 2, position: "ne" },
yaxis: { min: 0 },
xaxis: {mode: "time", timeformat: "%d/%m"}
};
var data = [];
var placeholder = $("#placeholder");
$.getJSON("@{Dashboard.getViewsPerDay(3)}", function(views){
$.each(views, function(index, view){
data.push([view.dayInMillis,view.totalViews]);
});
$.plot(placeholder, [ { label: "Views per day March", data: data } ], options);
});
});
</script>
</article>
</section>
</div>
The code should be fairly easy to understand. A couple of things worth noticing though. First of all the placeholder div is where the graph is going to end up, you need to specify the height and width. Next thing worth noticing is the declaration of the options variable. Here we define the the properties of the graph. You can learn more about the various possibilities by reading the Flot API description and examples.
Flot needs to get the data to plot as an array of points. So you can easily specify the data points directly in an array on the client side. Oftentimes though, you need to get the data from the server side. The JQuery $.getJSON method is a perfect fit for this. The method loads JSON encoded data from a server using a GET HTTP request. It takes an URL as input and if the request to the URL succeeds, a callback function is executed.
On line 27 we do the $.getJSON method call, getting view data from the server by calling the method getViewsPerDay(int month) on the Dashboard controller class. The result of the request is passed to the callback function. On lines 28 – 30 we loop through the list. For each object in the list we push the data to plot into the variable data. Notice that we must add the date in milliseconds as this is required by the flot library. Finally, on line 31 we do the plot. That’s it! Time to take a look at the Controller class
import models.*;
public class Dashboard extends Controller{
public static void views(){
render();
}
public static void getViewsPerDay(int month){
renderJSON(DailyView.findViewsForMonth(month));
}
}
Not much to explain. We get a List of DailyView objects for a month from the model object. This list is then passed to the built-in Play Controller method renderJSON which renders a 200 OK JSON response. No logic here, the controller class is just responsible for getting data and rendering it.
Model
Our example contains only one model class, the DailyView JPA model object. It contains a find method which gets the DailyView objects for the requested month. Here’s what it looks like.
package models;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import play.db.jpa.Model;
@Entity
public class DailyView extends Model{
public Date day;
public long totalViews;
public long dayInMillis;
public static List<DailyView> findViewsForMonth(int month) {
return find("select d from DailyView d where MONTH(d.day) =? ", month).fetch();
}
}
Next steps
With only a few lines of code we are able to create good looking charts displaying data we retrieve from the server. There are many ways to configure your charts with Flot, in this example we’ve only scratched the surface. I highly recommend looking at the Flot examples to learn more about how you can further customize your charts.



Pingback: Create Good Looking Charts With Play, Flot and JQuery « Walk the walk | Source code bank
Hi,
Interesting article, Any chance you could also add the output of your server side call. I’m having troubles getting ‘time’ data to display correctly. Everything else works and I really hoped the information I needed was here, even using your options don’t seem to do it. My x-axis just keep showing me integers. Have you had the same issues with the time feature while developping?
Hi, thank you for your feedback.
I did have a few problems during development with regards to displaying the dates correctly, the Flot library requires it to be in ms to display it. I did the conversion to milliseconds server side. I see that the code in the post does not show this explicitly. What I did was simply to loop through the dates and convert to milliseconds (server side). Not a very elegant solutiion but it worked.
So, check that you are returning the date as milliseconds. If you still can’t display the dates properly, please let me know and I will try to help as best as I can.
Hi again,
I’m actually tried this as well and it just doesn’t seem to do it, for some reason it just totally disregards all the time stuff. It keeps showing me the millisecond timestamps. I’m starting to think this is a bug, I mean, it’s not THAT hard to grasp imho still it doesn’t seem to work. Your post here was like the closest I could find with some real information I could use, the time examples on the flot page all use years which is just a integer and not a real date string. I stopped messing about once I noticed nothing really changed when I play with : tickFormatter, xaxis: {mode: “time”, timeformat: “%m/%d” } etc. It just keeps showing me the milliseconds numbers. Thanks a lot for your thoughts on the matter. (I use the API docs, the thing about milliseconds I knew already, I’m only so desperate since what I read and try doesn’t seem to work out as intented).
Ok, I understand. I know I had this working when posting this. Unfortunately I no longer have a running example, but I will try to get it up running again. I’ll let you know once I have something running.
Hi Ketil and all,
Since I wanted to give your flot demo using Play! a try, I played around and put together the minimalistic working solution based on your published code, it simply uses the in-memory store to put some sample data on startup and provides the flot graph using the default index action, just visit http://localhost:9000/ to see the graph.
You can download this mini play app (53K, using Play 1.0.3.2 and Flot 0.6) here.
Hope this will be a bit of help for other coming by your post.
Cheers,
Niko
Hi Niko,
Great! I was also able to run it with version 1.1.
Thanks for sharing!
Cheers,
Ketil
Pingback: 2010 in review | Walk the walk
Great blog Ketil, the integration of three incredible tools.
thank you
Thanks Rick, appreciate it
nice one i tried the sample provided by Niko,it worked perfect,
Just looking at your sample code, the Controller seems to have more { than }, so probably won’t compile, and I think it is missing the keyword “class” on line 3 as well.
Your absolutely right, thanks for pointing that out
Probably a copy paste error. The sample code is now corrected.
Hello, back again.
You might notice that this post is some hours after my previous post, well I finally got your code working.
You might also like to change line 15 in your model from
public long dayInMilles;
to
public long dayInMillis;
to match up with the rest of the references. I spent quite some time trying to find that bug.
Sorry if I am not quite as friendly / polite as I usually would be, but I had gone into this side project thinking that getting the demo code up and running would be a simple case of c+p and a little hacking. Little did I know i would have been far better off just following the documentation and never laying eyes on this post other than to know that flot exists.
Please at least run your demo code before you blog about how awesome it is and quick it is to get up and running..
Hi again,
I’m very sorry that I’ve wasted your time, my apologies.
About a year ago, Niko posted a comment where he shared a minimalistic version based on my sample code. Did you try that sample code? I tried it and at that time it worked at least on Play 1.1
I will link to this comment, or the code at the top of the post.
Wish you could have posted your comment before wasting too much time. Then I could have pointed you to the zip Nico created.
Thanks,
Ketil