D3 Tips and Tricks v4

Sunday, 4 August 2013

Add a row chart in dc.js

The following post is a portion of the D3 Tips and Tricks book which is free to download. To use this post in context, consider it with the others in the blog or just download the the book as a pdf / epub or mobi .
----------------------------------------------------------
The row chart provides an excellent mechanism for presenting and filtering on discrete values or identifiers.
The row chart that we'll create will be a representation of the number of earthquake events that occur on a particular day of the week. As such it doesn't represent any logical reason for selecting a Saturday over a Wednesday, and it is used here solely because the data makes a nice row chart :-). In this respect, what we are expecting to see is the number of events on the x axis and the individual days on the x axis.
It should end up looking a bit like this.
Now for a super cool feature with row charts...
Click on one of the rows...
How about that!
You can select an individual row from your chart and all the other rows reflect the selection. Go ahead and select other combinations of more than one row if you want. Welcome to data immersion!
Just as with the previous chart examples chart, we'll work through adding the chart in the following stages.
  1. Position the chart
  2. Assign type
  3. Dimension and Group
  4. Configure chart parameters

Position the row chart

We are going to position our row chart above our data table (and below the line chart)and we'll divide the row that it sits in into 3 equally spaced spans of span3. The additional two spans we'll leave blank for future use.
Just under the row of code that defined the containers for the line graph;
  <div class='row'>
    <div class='span12' id='dc-time-chart'>
      <h4>Events per hour</h4>
    </div>
  </div>
We add in a new row that has our three span4's.
  <div class='row'>
    <div class='span4' id='dc-dayweek-chart'>
      <h4>Day of the Week</h4>
    </div>
    <div class='span4' id='blank1'>
      <h4>Blank 1</h4>
    </div>   
    <div class='span4' id='blank2'>
      <h4>Blank 2</h4>
    </div> 
  </div>
We've given it an ID selector of dc-dayweek-chart. So when we we assign our chart that selector, it will automatically appear in that position. We've also put another simple title in place (<h4>Day of the Week</h4>).
The additional two span4's have been left blank.

Assign the row chart type

Here we give our chart it's name (dayOfWeekChart), assign it with a dc.js chart type (in this case rowChart) and assign it to the ID selector (dc-dayweek-chart).
Under the row that assigns the depthChart chart...
  var depthChart = dc.barChart("#dc-depth-chart");
... add in the equivalent for our row chart.
  var dayOfWeekChart = dc.rowChart("#dc-dayweek-chart");

Dimension and group the row chart data

We'll put the code between the dimension and group of the line (time) chart and the data table dimension (this is just to try and keep the code in the same order as the graphs on the page).
When adding our dimension for our day of the week we want to provide an appropriate label so our code does something extra.
  var dayOfWeek = facts.dimension(function (d) {
    var day = d.dtg.getDay();
    switch (day) {
      case 0:
        return "0.Sun";
      case 1:
        return "1.Mon";
      case 2:
        return "2.Tue";
      case 3:
        return "3.Wed";
      case 4:
        return "4.Thu";
      case 5:
        return "5.Fri";
      case 6:
        return "6.Sat";
    }
  });
This dimension (dayOfWeek) uses the same facts data, but when we return our key values we are going to return them as a combination of their numerical order (0 = Sunday etc) and their abbreviation (Sun = Sunday etc). This is essentially defining the categories of the values on the y axis for our row chart.
The code snippet looks a little strange, but think of it as extracting the numerical representation of the day of the week from our data (var day = d.dtg.getDay();) and then matching each number with an appropriate label (0 = '0.Sun', 1 = '1.Mon' etc). It's these labels that are now our key values in our dimension.
Then we want to group the data by using the default action of the .group() function to count the number of events of for each day of the week.
  var dayOfWeekGroup = dayOfWeek.group();

Configure the row chart parameters

As with the previous charts, there are plenty of parameters that can be configured. The best way to learn what they do is still to have a play with them. So here is the block of code for configuring the row chart. Once you are happy that it works on your system, take some time and go through the settings in conjunction with the information from the demo page and the api reference.
This should go just before the block that configures the dataTable (again, this is just to try and keep the code in the same order as the graphs on the page).
  // row chart day of week
  dayOfWeekChart.width(300)
    .height(220)
    .margins({top: 5, left: 10, right: 10, bottom: 20})
    .dimension(dayOfWeek)
    .group(dayOfWeekGroup)
    .colors(d3.scale.category10())
    .label(function (d){
       return d.key.split(".")[1];
    })
    .title(function(d){return d.value;})
    .elasticX(true)
    .xAxis().ticks(4);
That should get you working. With the addition of this portion of the code, you should have a functioning visualization that can be filtered dynamically by clicking on the appropriate day of the week in your row chart. Just check to make sure that everything is working properly and we'll go through some of the configuration options to see what they do.To start with, your page should look something like this;

The configuration options start by declaring the name of the chart (dayOfWeekChart) and setting the height and width of the chart.
  dayOfWeekChart.width(300)
    .height(220)
In the case of our example I have selected the width based on the default size for a span4 grid segment in bootstrap and adjusted the height to make it look suitable.
Then we have our margins set up.
    .margins({top: 5, left: 10, right: 10, bottom: 20})
Nothing too surprising there although I did reduce the top margin is slightly more than I thought I would need. You can be the judge for your own charts.
Then we define which dimension and grouping we will use.
    .dimension(dayOfWeek)
    .group(dayOfWeekGroup)
For a row chart, think of the .dimension declaration being the y axis and the .group declaration being the x axis (the opposite to the previous charts).
We can set the range of colours to use one of the standard palettes.
    .colors(d3.scale.category10())
Then we add the labels to our categories by splitting the key values (remember 0.Sun1.Mon etc) at the decimal point and returning the second part of the split value (which is the SunMon part) as the label.
    .label(function (d){
       return d.key.split(".")[0];
    })
The end result produces...
The next line in the configuration adds a tool tip to our row chart using the value when the mouse hovers over the appropriate bar.
    .title(function(d){return d.value;})

We can set the x axis to dynamically adjust when the number of events are filtered by selections on any of the other charts using the following configuration line.
    .elasticX(true)
For instance if we select a subset of the earthquakes using our time / line chart, our row chart will have a corresponding selection of the appropriate days and the x axis will alter accordingly.

Lastly we set up out x axis with 4 ticks.
    .xAxis().ticks(4);

The description above (and heaps of other stuff) is in the D3 Tips and Tricks book that can be downloaded for free (or donate if you really want to :-)).

2 comments:

  1. when I have more than 30 horizontal bars in row chart in div with a heith of 800 , labels are not are getting below the bottom of the bars. How do align label y position with the middle of the bar.

    ReplyDelete
    Replies
    1. OK, I think your problem will be that there is a 'standard' width (in your case vertical) for the bars. If you try to fit in more than will support the height of the text (assuming this is the reason for the bar width being set as it is). To test it, adjust the height of your div (currently 800, so try 400 and 1200) to see if it changes the positioning of the text. Then you will know which direction you will need to follow to solve the problem. Good luck

      Delete