We have looked at line, area, and bar charts, and some of the limitations of these charts. We will start this chapter by looking at the best uses of horizontal and stacked bar charts. We will also learn how to hide different elements on our axes and modify our data point labels. The following topics will be covered in this chapter:
We come to work on Thursday morning to find an e-mail from Sara waiting for us. "I liked the chart you did with some of our product categories," she says. "I'm sending over numbers for a few others and I'd like this chart to be broken out by months instead of quarters."
We start thinking through how to best represent this data. There are more data series, and the legend takes up space within the div element. This limits the space available to us for a vertical bar chart, so we decide on a horizontal bar chart. Horizontal bar charts are rotated 90 degrees; the x axis becomes the vertical axis, and the y axis is the horizontal axis. If any of our data series contain both x
and y
values, we will need to switch their order to [[y, x], [y, x], [y,x]]
.
We open the spreadsheet Sara sent over. There are nine product categories to plot, with 12 data points per category. That's 108 bars on our graph. Even using a horizontal chart, it may be a tight fit. We decide to move forward and see what happens:
canvasAxisLabelRenderer
so that we can rotate the label on our y axis:<script src="../js/jqplot.categoryAxisRenderer.min.js"></script>
<script src="../js/jqplot.barRenderer.min.js"></script>
<script src="../js/jqplot.canvasTextRenderer.min.js"></script>
<script src="../js/jqplot.canvasAxisTickRenderer.min.js"></script>
<script src="../js/jqplot.canvasAxisLabelRenderer.min.js"></script>
<script>
x
and y
values:$(document).ready(function(){ var dvds = [151537.81, 141980.66, 126915.19, 96764.25, 152154.38, 130709.87, 120796.76, 111966.62, 86397.29, 74051.78, 67587.91, 83181.89]; var cds = [176794.11, 165644.10, 148067.72, 112891.63, 152154.38, 143780.85, 140929.55, 130627.73, 100796.84, 86393.75, 78852.56, 97045.54]; var tvs = [73633.00, 90200.42, 92964.15, 85527.02, 61356.34, 91614.46, 87949.88, 82453.01, 98218.97, 81849.15, 80212.16, 76345.37]; var computers = [106196.16, 117995.73, 142713.61, 172020.86, 108309.43, 139166.61, 142894.28, 130468.69, 143960.95, 149959.33, 155957.70, 134764.98]; var software = [150274.99, 139141.04, 124376.89, 90313.30, 178933.56, 133803.33, 112743.64, 104502.18, 60478.10, 41469.00, 35483.65, 43670.49]; var digital = [26519.12, 26503.06, 23690.84, 22578.33, 23938.96, 27405.50, 28185.91, 26125.55, 40318.73, 44924.75, 43368.91, 53375.05]; var consoles =[13962.94, 14237.89, 36609.86, 57494.22, 16792.64, 24069.15, 34096.61, 19356.21, 75174.26, 75775.12, 95298.26, 85518.01]; var dvd_players = [7518.51, 7666.55, 19713.00, 30958.43, 9042.19, 12960.31, 18359.72, 10422.58, 18793.56, 18943.78, 23824.56, 21379.50]; var media_streamers = [0, 0, 0, 0, 0, 0, 0, 0, 31322.61, 31572.97, 39707.61, 35632.50]; var ticks = ['Nov 2011', 'Dec 2011', 'Jan 2012', 'Feb 2012', 'Mar 2012', 'Apr 2012', 'May 2012', 'Jun 2012', 'Jul 2012', 'Aug 2012', 'Sep 2012', 'Oct 2012'];
var rev_category = $.jqplot ('rev_category', [ dvds, cds, software, digital, tvs, computers, consoles, dvd_players, media_streamers], { title:'Monthly Revenue by Product Category', axesDefaults: { tickRenderer: $.jqplot.CanvasAxisTickRenderer, tickOptions: { angle: -15 } },
shadow
option to false
. In order to make our chart horizontal, we set barDirection
to horizontal
under rendererOptions
. We also set barMargin
and barPadding
to 0
, so our bars will have a little more room to expand in the confines of our plot:seriesDefaults: { renderer:$.jqplot.BarRenderer, shadow: false, rendererOptions: { barDirection: 'horizontal', barPadding: 0, barMargin: 0 } },
color
option for eight of our series. The default color for the seventh series works with our other colors, saving us from finding another color:series: [ { label: 'DVDs/Blu-ray', color: '#FF0000' }, { label: 'Music CDs', color: '#0BBBE0' }, { label: 'Software', color: '#0000FF' }, { label: 'Digital', color: '#555' }, { label: 'TVs', color: '#FF960C' }, { label: 'Computers', color: '#00007F' }, { label: 'Game Consoles', }, { label: 'DVD Players', color: '#56C2B2' }, { label: 'Media Streamers', color: '#62FF0D' }, ], legend: { show: true, placement: 'outsideGrid', location: 'ne' },
axes:{ xaxis:{ label: 'Revenue in Dollars', tickOptions: { formatString: "$%'d" } },
CategoryAxisRenderer
, but for this chart we will change this to the y axis. Similar to how we set a renderer for our tick options, we pass the CanvasAxisLabelRenderer
class to labelRenderer
. By default, the angle of the label on the y axis will be 90 degrees, so we don't explicitly need to set an angle. If we do set it, we will set it under labelOptions
:yaxis: { renderer: $.jqplot.CategoryAxisRenderer, label: 'Months', labelRenderer: $.jqplot.CanvasAxisLabelRenderer, ticks: ticks, } } }); }); </script>
400px
, but we need it to be taller, so we set the height to 700px
:<div id="rev_category" style="width:700px;height:700px;"></div>
When we finish coding our plot, we load the new report in our browser. It appears we were overconfident about the abilities of a horizontal chart.
There are just too many data points. Also, since the bars are so small, it is hard to compare one to another. We can increase the height of the chart, but the user will have to scroll up and down trying to compare different months.
This dead end is a good time for us to remember a tenet we learned as children. Granted, it was not taught to us in the framework of data visualization, but it still applies. "Just because we can, doesn't mean we should." With jqPlot, we can import any type of data and create many different chart types. We have to keep in mind the type of data we are representing. Stephen Few points out that we need to compare our data side by side (http://www.tableausoftware.com/blog/stephen-few-data-visualization). Expecting people to hold 108 bars in memory and comparing them will wear out a user.
Another tenet of Stephen Few is to present data in different ways to see it from different angles. Thinking along these lines, we decide we can create a stacked bar chart. This way, we can visualize all the various product categories per month, but we will only have twelve bars in our chart. We only need to make a couple of changes to our existing code to transform our horizontal chart into a horizontal stacked bar chart.
We start by opening up the code from the previous chart:
stackSeries
to true
. {
title:'Monthly Revenue by Product Category',
stackSeries: true,
axesDefaults: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: { angle: -15 }
},
shadow
option and replace it with shadowAngle
. By setting the angle to 135
, our shadows appear underneath our bars, as if the light source was in the upper-right corner of our plot: seriesDefaults: {
renderer:$.jqplot.BarRenderer,
shadowAngle: 135,
shadowAlpha
to 0.1
to give our bars a little bit of shadow:rendererOptions: { barDirection: 'horizontal', barPadding: 5, barMargin: 10, shadowAlpha: 0.1 } },
series: [ { label: 'DVDs/Blu-ray' }, { label: 'Music CDs' }, { label: 'Software' }, { label: 'Digital' }, { label: 'TVs' }, { label: 'Computers' }, { label: 'Game Consoles' }, { label: 'DVD Players' }, { label: 'Media Streamers' } ],
legend: { show: true, placement: 'insideGrid', location: 'ne' },
axes:{
xaxis:{ label: 'Revenue in Dollars',
padMax: 1.3
tickOptions: { formatString: "$%'d" }
},
yaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
label: 'Months',
ticks: ticks
}
}
});
});
</script>
500px
:<div id="rev_category" style="width:700px;height:500px;"></div>
In the following screenshot, we see the results of our work. This chart works much better.
It's easier to see everything and it's possible to see trends in the data over the months. Also, we get a second benefit with a stacked bar chart; we can see the total revenue with all the bars stacked together.
This chart gets us thinking. Knowing how the VPs think, they might want to drill down into the data. We can implement an event handler for the jqplotDataClick
event. The problem lies in the data to pull with this event.
We can load two different charts when the user clicks on one of the bar stacks. One option is to load a second chart with 12 months of data for the clicked product category. The other option is to load the monthly data of all the product categories for the bar representing the month clicked.
This is when more detail will help us. We need to talk to Sara and the other VPs. When we have a better understanding of the issues they want to explore, we can create better visualizations of the data. We call Calvin and ask him to come by to chat. About 10 minutes later, Calvin walks in. "So, what's up?" he asks.
We show him the new charts and explain our concerns. Some of our charts have way too many data points and there are so many directions we could go with visualizing the data. Calvin nods his head for a few seconds after we finish our explanation. "I completely understand. I think what you've done is great and will help them. I think another problem we have is that some people are already thinking about phase two."
He continues, "A few have talked about a dashboard. They want each VP and manager to see a quick snapshot of all the relevant data for their areas. As a first step, why don't I walk Sara through these new charts and explain your rationale behind the design decisions. Then, we'll see what she thinks."
Calvin sends us to lunch while he talks with Sara. When we get back, Calvin is waiting on us. "Good news," he says. "Sara is on board with what you have. She had the idea of tweaking the large horizontal chart to only show the past month's data for all product categories. As a test of the phase two dashboard, make it compact so that it fits on a page with several other charts."
We tell Calvin we should have it wrapped up this afternoon and get ready for the big meeting tomorrow. He nods and walks out. Taking our earlier chart from 108 bars down to only nine bars will be a lot easier to compress.
18.223.170.63