Search code examples
javascripthtmld3.jsplottable

How to display a legend in Plottable.js multiple plot


I have the following code:

var indata = [{
  'sample': "Foo",
  "pies_pct": [{
    "score": 6.7530200000000002,
    "celltype": "Bcells"
  }, {
    "score": 11.432763461538459,
    "celltype": "DendriticCells"
  }]

}, {
  'sample': "Bar",
  "pies_pct": [{
    "score": 26.8530200000000002,
    "celltype": "Bcells"
  }, {
    "score": 31.432763461538459,
    "celltype": "DendriticCells"
  }]

}, ];



processData(indata);

function processData(data) {

  pies = data.map(function(data) {
    return {
      title: data.sample,
      dataset: data.pies_pct
    };


  });

  buildPlots();
}

function buildPlots() {
  var $pieContainer = $('#sample-pies');

  pies.forEach(function(pie, index) {
    var elementId = "sample-pie-" + index;

    $(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
      .css({
        width: '200px',
        height: '200px',
        display: 'inline-block'
      })
      .attr('id', elementId)
      .appendTo($pieContainer);


    plotSamplePie(pie.title, pie.dataset, '#' + elementId);
  });


}




function plotSamplePie(title, purity_data, targetElement) {
  var scale = new Plottable.Scales.Linear();
  var tableau20 = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728',
    '#9467BD', '#8C564B', '#CFECF9', '#7F7F7F', '#BCBD22', '#17BECF'
  ];
  var colorScale = new Plottable.Scales.Color();
  var legend = new Plottable.Components.Legend(colorScale);
  colorScale.range(tableau20);




  var titleLabel = new Plottable.Components.TitleLabel(title);
  var plot = new Plottable.Plots.Pie()
    .addDataset(new Plottable.Dataset(purity_data))
    .attr("fill", function(d) {
      return d.score;
    }, colorScale)
    .sectorValue(function(d) {
      return d.score;
    }, scale)
    .labelsEnabled(true);


  new Plottable.Components.Table([
    [titleLabel],
    [plot]
  ]).renderTo(targetElement);

}


function drawPieLegend(targetElement) {
  new Plottable.Components.Legend(colorScale)
    .renderTo(targetElement);
}


drawPieLegend('#pies-legend')
<html>

<head>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
  <link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />


</head>

<body>


  My Plot

  <!-- Show histograms -->
  <div id="sample-pies"></div>
  
  Legend here:
  <div id="pies-legend"></div>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>





</body>

</html>

What I want do do is to display one legend for both pie charts under '#pies-legend' as the target element called by the function drawPieLegend(). But why it does not show up?


Solution

  • colorScale is defined inside plotSamplePie(), so it doesn't appear in the scope of drawPieLegend(). Declaring colorScale outside both functions will make it possible for both functions to access it (although this is a bit messy since it is now a global variable). It'd probably be cleaner to create colorScale inside the processing function, then pass it to the functions that make the pies and the legend separately. Here's a quick attempt at fixing it:

    var indata = [{
      'sample': "Foo",
      "pies_pct": [{
        "score": 6.7530200000000002,
        "celltype": "Bcells"
      }, {
        "score": 11.432763461538459,
        "celltype": "DendriticCells"
      }]
    
    }, {
      'sample': "Bar",
      "pies_pct": [{
        "score": 26.8530200000000002,
        "celltype": "Bcells"
      }, {
        "score": 31.432763461538459,
        "celltype": "DendriticCells"
      }]
    
    }, ];
    
                  
    var colorScale = new Plottable.Scales.Color();
    var tableau20 = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728',
        '#9467BD', '#8C564B', '#CFECF9', '#7F7F7F', '#BCBD22', '#17BECF'
    ];
    colorScale.range(tableau20);
    
    processData(indata);
    
    function processData(data) {
    
      pies = data.map(function(data) {
        return {
          title: data.sample,
          dataset: data.pies_pct
        };
    
    
      });
    
      buildPlots();
    }
    
    function buildPlots() {
      var $pieContainer = $('#sample-pies');
    
      pies.forEach(function(pie, index) {
        var elementId = "sample-pie-" + index;
    
        $(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
          .css({
            width: '200px',
            height: '200px',
            display: 'inline-block'
          })
          .attr('id', elementId)
          .appendTo($pieContainer);
    
    
        plotSamplePie(pie.title, pie.dataset, '#' + elementId);
      });
    
    
    }
    
    
    
    
    function plotSamplePie(title, purity_data, targetElement) {
      var scale = new Plottable.Scales.Linear();
      var titleLabel = new Plottable.Components.TitleLabel(title);
      var plot = new Plottable.Plots.Pie()
        .addDataset(new Plottable.Dataset(purity_data))
        .attr("fill", function(d) {
          return d.celltype;
        }, colorScale)
        .sectorValue(function(d) {
          return d.score;
        }, scale)
        .labelsEnabled(true);
    
    
      new Plottable.Components.Table([
        [titleLabel],
        [plot]
      ]).renderTo(targetElement);
    
    }
    
    
    function drawPieLegend(targetElement) {
      new Plottable.Components.Legend(colorScale)
        .maxEntriesPerRow(Infinity)
        .renderTo(targetElement);
    }
    
    
    drawPieLegend('#pies-legend');
    <html>
    
    <head>
      <link href="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.css" rel="stylesheet" />
      <link href="https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.1/basic/jquery.qtip.css" rel="stylesheet" />
    
    
    </head>
    
    <body>
    
    
      My Plot
    
      <!-- Show histograms -->
      <div id="sample-pies"></div>
      
      Legend here:
      <svg id="pies-legend" height="50" width="400"></svg>
    
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/plottable.js/1.15.0/plottable.js"></script>
    
    
    
    
    
    </body>
    
    </html>

    Note also the change from

    .attr("fill", function(d) {
      return d.score;
    }, colorScale)
    

    to

    .attr("fill", function(d) {
      return d.celltype;
    }, colorScale)
    

    which causes the colors to be driven by celltype rather than score.