Search code examples
javascriptd3.jsdimple.js

Multi-series in dimplejs


I am tinkering with a multi-series chart in dimplejs and got a bit stuck with the multi axis logic.

With the following data:

var data = [
  {"Month":"01/2013", "Revenue":2000, "Profit":2000, "Units":4},
  {"Month":"02/2013", "Revenue":3201, "Profit":2000, "Units":3},
  {"Month":"03/2013", "Revenue":1940, "Profit":14000, "Units":5},
  {"Month":"04/2013", "Revenue":2500, "Profit":3200, "Units":1},
  {"Month":"05/2013", "Revenue":800, "Profit":1200, "Units":4}
]

I try to get a chart showing, by months, my revenue and my profit on the same y axis and my units on a secondary y axis.

With the code below, I could manage to display the 3 series. But the Profit series isn't really on the same axis as the Revenue one, and the whole thing seems more like a hack than a proper solution.

var chart = new dimple.chart(svg, data);

chart.setBounds(60,20,680,330);

var x = chart.addCategoryAxis("x", "Month");
var y1 = chart.addMeasureAxis("y", "Revenue");
chart.addSeries("null", dimple.plot.line, [x,y1]);
var y2 = chart.addMeasureAxis("y", "Units");
chart.addSeries("null", dimple.plot.bar, [x,y2]);
var y3 = chart.addMeasureAxis("y", "Profit");
chart.addSeries("null", dimple.plot.line, [x,y3]);

I guess my logic might be wrong with how to rightly play with series. Any help would be great.

Thanks a lot, Xavier

Full code:

var svg = dimple.newSvg("body", 800, 400);

var data = [
    {"Month":"01/2013", "Revenue":2000, "Profit":2000, "Units":4},
    {"Month":"02/2013", "Revenue":3201, "Profit":2000, "Units":3},
    {"Month":"03/2013", "Revenue":1940, "Profit":14000, "Units":5},
    {"Month":"04/2013", "Revenue":2500, "Profit":3200, "Units":1},
    {"Month":"05/2013", "Revenue":800, "Profit":1200, "Units":4}
]

var chart = new dimple.chart(svg, data);

chart.setBounds(60,20,680,330);

var x = chart.addCategoryAxis("x", "Month");
var y1 = chart.addMeasureAxis("y", "Revenue");
chart.addSeries("null", dimple.plot.line, [x,y1]);
var y2 = chart.addMeasureAxis("y", "Units");
chart.addSeries("null", dimple.plot.bar, [x,y2]);
var y3 = chart.addMeasureAxis("y", "Profit");
chart.addSeries("null", dimple.plot.line, [x,y3]);

x.dateParseFormat = "%m/%Y";
x.addOrderRule("Date");

chart.draw();

Solution

  • EDIT:

    This is no longer required since version 2. You can now use composite axes.

    ORIGINAL:

    I see the problem here, the issue isn't with multiple axes, it is with trying to draw multiple measures against a single axis which Dimple doesn't really support yet. I'm afraid the best I can do for now is a bit of a data hack:

    <div id="chartContainer">
      <script src="http://d3js.org/d3.v3.min.js"></script>
      <script src="/dist/dimple.v1.min.js"></script>
      <script type="text/javascript">
          var svg = dimple.newSvg("#chartContainer", 800, 400);
    
          // Data hack required to get revenue and profit on the same axis, units are
          // arbitrarily allocated to revenue but the values will be summed by date
          var data = [
              {"Month":"01/2013", "Metric":"Revenue", "Revenue/Profit":2000, "Units":4},
              {"Month":"02/2013", "Metric":"Revenue", "Revenue/Profit":3201, "Units":3},
              {"Month":"03/2013", "Metric":"Revenue", "Revenue/Profit":1940, "Units":5},
              {"Month":"04/2013", "Metric":"Revenue", "Revenue/Profit":2500, "Units":1},
              {"Month":"05/2013", "Metric":"Revenue", "Revenue/Profit":800, "Units":4},
              {"Month":"01/2013", "Metric":"Profit", "Revenue/Profit":2000, "Units":0},
              {"Month":"02/2013", "Metric":"Profit", "Revenue/Profit":2000, "Units":0},
              {"Month":"03/2013", "Metric":"Profit", "Revenue/Profit":14000, "Units":0},
              {"Month":"04/2013", "Metric":"Profit", "Revenue/Profit":3200, "Units":0},
              {"Month":"05/2013", "Metric":"Profit", "Revenue/Profit":1200, "Units":0}
          ];
    
          var chart = new dimple.chart(svg, data);
          chart.setBounds(60,20,680,330);
    
          // Add your x axis - nothing unusual here
          var x = chart.addCategoryAxis("x", "Month");
          // First y axis is the combination axis for revenue and profit
          var y1 = chart.addMeasureAxis("y", "Revenue/Profit");
          // Second is the units only
          var y2 = chart.addMeasureAxis("y", "Units");
    
          // Plot the bars first - the order of series determines their dom position
          // from back to front, this means bars are at the back.  It's important
          // to note that the string here "Unit Sales" is NOT in the data.  Any string
          // not in the data is just used to apply a label which can be used for colouring
          // as it is here and will also appear in tool tips
          var bars = chart.addSeries("Unit Sales", dimple.plot.bar, [x,y2]);
          // Use a simple line by metric for the other measures
          var lines = chart.addSeries("Metric", dimple.plot.line, [x,y1]);
    
          // Do a bit of styling to make it look nicer
          lines.lineMarkers = true;
          bars.barGap = 0.5;
          // Colour the bars manually so they don't overwhelm the lines
          chart.assignColor("Unit Sales", "black", "black", 0.15);
    
          x.dateParseFormat = "%m/%Y";
          x.addOrderRule("Date");
    
    
          // Here's how you add a legend for just one series.  Excluding the last parameter
          // will include every series or an array of series can be passed to select more than
          // one
          chart.addLegend(60, 5, 680, 10, "right", lines);
    
          chart.draw();
    
          // Once Draw is called, this just changes the number format in the tooltips which for these particular
          // numbers is a little too heavily rounded.  I assume your real data isn't like this
          // so you probably won't want this line, but it's a useful tip anyway!
          y1.tickFormat = ",d";
    
      </script>
    </div>
    

    This is currently a bit of a limitation but I've just had an idea for a really good implementation I can do to add proper support for composite axes like this. Hopefully that will be possible in the not too distant future.

    Good luck

    John