Chart with selectable legend [yui demo]
I wrote about YUI Charts the other day and I guess my conclusion was that the library is promising, but still a long way from being perfect. Today, I have been using it in a real-life setting a found that I wanted to do some stuff that’s isn’t supported out of the box in order to build something that looks like this:
Merge multiple dataset into one graph
By default the library accepts one datasource containing a category, which is turn can have multiple values. This would be an array, which looks like this in Yahoo’s own documentation:
var data =
[{ month: "January", rent: 880.00, utilities: 894.68 },
{ month: "February", rent: 880.00, utilities: 901.35 }];
This looks great paper, but when preparing data from the database it’s requires some clever trickery to set up such a datasource. Instead, I wanted to prepare several arrays containing label/value pairs and merge them into a data source. For example:
var rentValues =
[{label: "January", value:880.00},
{label: "February", value: 880.00}];
var utillitiesValues =
[{label: "January", value:894.68},
{label: "February", value: 901.35}];
The example includes a simple piece of code, which merges these two (or more) datasets into something which is edible for the YUI datasource. Make sure that the label properties are the same in all datasets though. Otherwise, you’ll see strange results..
Show a colorful legend
Even though you’ll actually be sending all the required information to the chart library, it won’t build a chart legend for you. Which is bad. Instead, the documentation shows how to set up something similar in HTML. In this case, I wanted to allow selection and de-selection of items on the chart and have the visualization scaled accordingly.
In the example I’m using the same data to build both a data chart and a HTML form, which displays the name and color of each line on the chart — and which handles a redrawing after selecting and deselecting individual items on the form.
Abstract some of the heavy lifting
Yahoo’s own examples are pretty cool, but drawing a chart isn’t exactly a one-line job. I wanted to make it — so I’ll be able to do something like this:
var rent = {displayName:'Rent', data:rentValues};
var utilities = {displayName:'Utillities',
data:utillitiesValues};
prepareChart('container',
[rent, utillities], 'formatFunction');
…where container is the name of the html elements holding the chart and the legend, and where formatFunction is a reference to the JavaScript function responsible for formating data on the Y-axis.
The data objects can be expanded slightly to include both information about the color of the line and when the dataset should be shown by default:
var rent = {displayName:'Rent', data:rentValues,
hidden:true, color:'#cc0022'};
In action…
The example generates some random data about a fictive web site and displays “New signups”, “Total number of users”, “Active users” and “Returning users” for the past two months (if somebody has ideas for real data to plot, please let me know). This it simply does:
var signupsPerDay = {displayName:'New signups',
data:randomSignupUsers};
var numusersPerDay = {displayName:'Total number of users',
data:randomTotalUsers, hidden:true};
var activeusersPerDay = {displayName:'Active users',
data:randomActiveUsers};
var returningusersPerDay = {displayName:'Returning users',
data:randomReturningUsers};
prepareChart('users',
[signupsPerDay, numusersPerDay,
activeusersPerDay, returningusersPerDay],
'usersCountFormat');

December 14th, 2007 at 6:23 pm
Thanks for sharing your thoughts on the YUI Charts. As the developer that built them, I completely agree that they could use some improvement, and I appreciate any and all suggestions on that front. They’re specified as “experimental” for good reason, and I’m excited to have a component with such a classification because it gives me many excellent opportunities to explore.
Legend support, as you mentioned, is lacking. I’m considering ways to build legends on both the Flash side and the HTML/JS/CSS side. I have a partial implementation for Flash already, but I simply didn’t have enough time to bring it to completion and expose it properly to meet the release deadline.
More flexible data handling was another thing I would have liked to support. The Flex charts, as you probably know, allow you to specify a chart-level data provider, much like how the YUI Charts use DataSource. Additionally, each series can have it’s own data provider. I’d definitely like to do something similar in the future.
If you run into any troubles with bugs or “missing” features, please don’t hesitate to file a report on SourceForge. Again, thanks for sharing your thoughts. I appreciate it!
Josh Tynjala
Yahoo! Flash Platform
December 15th, 2007 at 1:35 pm
Josh,
Thanks for your comments — I agree that it’s cool to see experimental stuff mixed in to YUI, and it’s even better to hear that you are still looking at ways to improve the already excellent library. As you said, automatic legend creation (including the ability to select and deselect?) and a more flexible use of datasources would be a great improvement. And you’re probably right that different sources for different series in the same chart is that way to go (although I’m thinking it might not be that easy to do…)
One thing I’d love to see included into upcoming releases is a DateAxis (in addition to NumericAxis). At the moment you could fake such an axis by a) sending epoch seconds to the keys in the dataset, b) using a NumericAxis, c) setting the axis to not include zero, and d) formating the epoch timestamp into a readable date/time with a format function. But that’s jumping through hoops, and you’ll probably see cases where you won’t get the desired results. A DateAxis would abstract all of this is some magical fashion, and possibly provide an easy way to format dates for different locales.
Thanks for listening — and keep up the good work…
December 17th, 2007 at 6:42 pm
There’s a YAHOO.widget.TimeAxis class hidden in with YUI Charts. You can specify minimum and maximum values as Date objects. majorUnit and minorUnit are numeric values, with majorTimeUnit and minorTimeUnit specifying the period of time to use with those values (Strings: year, month, day, hours, minutes, seconds or milliseconds). Like the NumericAxis, the TimeAxis does its best to determine a decent range by default based on the data. I don’t think I do any formatting of the Date string, but you can specify a labelFunction on the axis to format it as you like.
December 17th, 2007 at 6:51 pm
Thank Josh, I actually just saw that after having missed it on my first casual reading of the documentation. That’s great, and I’ll certainly be able to reformat to dates with something like datejs so that’s absolutely perfect.
If I could trouble you with one question though: Is there any way to force “null” values not to be drawn as “0″? The multiple series thing mentioned before is the perfect solution, but most people would be able to work well with the current DataSource scheme if only empty points were ignored. For example:
Using this data with a line chart will draw one line from (1, 0)->(2, 200)->(3, 0)->(4, 300) (and another one from 300->320->330->334). If only the first line would be drawn from point (2, 200) to (4, 300) people would be able to emulate the multiple series thing. Would this be possible? ;-)
December 17th, 2007 at 8:47 pm
If you specify null values with the keyword <code>null</code>, they won’t be interpreted as zero.
December 17th, 2007 at 9:58 pm
Nice trick! Is it documented somewhere ;-)
It won’t provide a quick-hack-way to handle multiple series though, since lines aren’t being connected. With the example data above and Josh’s trick you’d see two data points at x=2 and x=4 — but no connecting line. between the two points. This is probably by design, but still a shame…
July 29th, 2010 at 6:22 am
Is yui supports for Real time multi line graph?