Skip to content
Irene Ros edited this page Feb 19, 2014 · 3 revisions

Chart: Composing Multiple Charts

When creating a new d3.chart based chart constructor, you may want to use charts that already exist by composing them together. For example, if one has the following two charts:

  • BarChart - It draws a basic bar chart
  • PieChart - It draws a basic pie chart

You may combine them so that both charts are rendered together with one draw call with a new chart called PieBars that you can instantiate like so:

var data = {
  totals: [
    { name : "Red",  value : 40, p : 0.4  },
    { name : "Blue", value : 80, p : 0.23 },
    { name : "Pink", value : 30, p : 0.37 }
  ]
};

var chart = d3.select("#chart")
  .chart('PieBars')
  .height(400)
  .width(400);

chart.draw(data.totals);

Now in order to define our new PieBars chart, we would want to initialize our pie chart and our bar chart, and then use the attach method to attach them to their parent chart.

The attach method takes two arguments, a unique string name that identifies the chart and an instance of a chart to attach. For example:

(function() {
  d3.chart("PieBars", {
    initialize: function() {

      var chart = this;

      var svg = chart.base.append("svg");

      // create new containers for each of the charts
      var bases = {
        bar: svg.append("g").classed("bar", true),
        pie: svg.append("g").classed("pie", true)
      };

      // initialize the charts with their required setters/getters.
      chart.charts = {
        bargraph : bases.bar
          .chart('Barchart')
          .yFormat(d3.format("d")),

        piechart : bases.pie
          .chart('PieChart')
          .colors(d3.scale.category10())
      };

      // attach the charts under a specific name to the parent chart
      chart.attach("bar", chart.charts.bargraph);
      chart.attach("pie", chart.charts.piechart);
    }
});

When defining a chart that contains attached charts, you may need to transform your data for those specific charts. For example our original data looks like so:

[
  { name : "Red",  value : 40, p : 0.4  },
  { name : "Blue", value : 80, p : 0.23 },
  { name : "Pink", value : 30, p : 0.37 }
]

Our BarChart expects our data to look like so:

[
  { name : "someName",  value : 40 }, ...
]

And our PieChart expects our data to look like so:

[
  { name : "someName",  value : 0.4 }, ...
]

Unfortunetly, we already have our "value" property defined correctly for BarChart but not for PieChart. In order to fix that as a chart author, you can add a demux method that takes in a chart name and the original data. It should return the set of data that would be appropriate for that chart. In our case, we could:

demux: function(name, data) {
  // for a bar chart, we can just return the data as is since it has the
  // "value" property we need.
  if (name === "bar") {
    return data;
  } else {
    // for the pie chart, we need to remap the data so that our "p" attribute
    // is actually mapped to a "value" property. 
    return data.map(function(d) {
      return { name : d.name, value: d.p };
    });
  }
},
Clone this wiki locally