mjamie
mjamie

Reputation: 23

Update Pattern for Multi-Line Chart with D3

I'm creating a small dashboard in D3 where: when a slice of a donut chart is clicked, an adjacent line chart will be updated. The code is loosely based on this block http://bl.ocks.org/diethardsteiner/3287802.

Here is a JSFiddle of what I have now and the issue: https://jsfiddle.net/394mLyz9/

If you scroll to the end of the fiddle, you'll find the 'update' code as follows:

function updateLineChart(group, colorChosen) {


var basics = dsLineChartBasics();

var margin = basics.margin,
    width = basics.width,
    height = basics.height;

var currentDatasetLineChart = datasetLineChartChosen(group);

var dataNest1 = d3.nest()
    .key(function(d) {return d.group2;})
    .entries(currentDatasetLineChart); 

console.log(dataNest1);

console.log(currentDatasetLineChart);

var xScale = d3.scale.linear()
    .range([0, width])
    .domain(d3.extent(currentDatasetLineChart, function(d) { return d.category; }));

var yScale = d3.scale.linear()
    .range([height, 0])
    .domain([0, d3.max(currentDatasetLineChart, function(d) { return d.measure; })]);       

var line = d3.svg.line()
     .interpolate("basis")  
    .x(function(d, i) { return xScale(d.category); })
    .y(function(d) { return yScale(d.measure); });

var svg = d3.select("#lineChart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);   

var plot = svg.selectAll("plot")
  .data(dataNest1)
 .enter()
  .append("g")
.append("path")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  .attr("class", "line")
  .attr("d", function(d) { return line(d.values); })
  .style("stroke", colorChosen);

//plot.exit().remove(); 


}

As you'll notice, when a pie slice is clicked, it will create new line chart under the existing one rather than updating the existing one. I've read though the general update pattern tutorials and have still had little success. Any help would be appreciated.

Upvotes: 2

Views: 539

Answers (1)

Mark
Mark

Reputation: 108512

First, you are doing way too much work in your update function. If you increase the scope of a few of your variables, you don't need to recreate them on each update. svg, xScale, yScale, margins and line are all things your initial draw and updates can share.

Second, while the update pattern is important, in this situation, you aren't really updating a plot with new data, you are creating a whole new plot with all new data. With that in mind, I'd just dump the contents of the SVG and re-add your lines.

Line Chart Function:

// increase the scope of these
var margin, line, svg, xScale, yScale;

function lineChart() {

  var basics = dsLineChartBasics();

  // declared above
  margin = basics.margin,
    ...
  // declared above
  xScale = d3.scale.linear()
    ...
}

Update Chart Function:

function updateLineChart(group, colorChosen) {

  var currentDatasetLineChart = datasetLineChartChosen(group);

  ...

  // adjust xScale based on new data
  xScale.domain(d3.extent(currentDatasetLineChart, function(d) {
      return d.category;
    }));

  // adjust yScale based on new data
  yScale.domain([0, d3.max(currentDatasetLineChart, function(d) {
      return d.measure;
    })]);

  // remove contents of svg
  svg.selectAll("*").remove();

  // replot
  var plot = svg.selectAll("g") //<-- don't use "plot" here it has no meaning
    .data(dataNest1)
  ...

}

Full code example:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
  <style>
    #chart-container {
      float: left;
    }
    
    .line {
      fill: none;
      stroke-width: 3px;
    }
    
    #pieChart {
      float: left;
      width: 50%;
     }
    
    #lineChart {
      width: 50%;
      float: right;
    }
  </style>
</head>

<body>
  <div id="pieChart"></div>
  <div id="lineChart"></div>
  <script>
    function pieChart() {

      var dataset = [{
        category: "A",
        measure: 3270
      }, {
        category: "B",
        measure: 19309
      }, {
        category: "C",
        measure: 13120
      }, ];


      var width = 350,
        height = 350,
        outerRadius = Math.min(width, height) / 2,
        innerRadius = outerRadius * .5,
        color = d3.scale.category20();

      var svg = d3.select("#chart-container").append("svg")
        .attr("width", width)
        .attr("height", height)
        .attr("id", "chart");

      var vis = d3.select("#pieChart")
        .append("svg:svg")
        .data([dataset])
        .attr("width", width)
        .attr("height", height)
        .append("svg:g")
        .attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");

      var arc = d3.svg.arc()
        .outerRadius(outerRadius).innerRadius(innerRadius);


      var pie = d3.layout.pie()
        .value(function(d) {
          return d.measure;
        });

      var arcs = vis.selectAll("g")
        .data(pie)
        .enter()
        .append("svg:g")
        .on("click", change);

      arcs.append("svg:path")
        .attr("fill", function(d, i) {
          return color(i);
        })
        .attr("d", arc);

      //change event for line visualization
      function change(d, i) {

        updateLineChart(d.data.category, color(i));

      }
    }
    pieChart();

    var datasetLineChart = [

      //0
      {
        "group": "All",
        "category": 0,
        "measure": 171,
        "group2": 0
      }, {
        "group": "All",
        "category": 25,
        "measure": 191,
        "group2": 0
      }, {
        "group": "All",
        "category": 50,
        "measure": 239,
        "group2": 0
      }, {
        "group": "All",
        "category": 75,
        "measure": 1212,
        "group2": 0
      }, {
        "group": "All",
        "category": 100,
        "measure": 1773,
        "group2": 0
      }, {
        "group": "All",
        "category": 125,
        "measure": 3866,
        "group2": 0
      }, {
        "group": "All",
        "category": 150,
        "measure": 9092,
        "group2": 0
      }, {
        "group": "All",
        "category": 175,
        "measure": 6973,
        "group2": 0
      }, {
        "group": "All",
        "category": 200,
        "measure": 11717,
        "group2": 0
      },
      //1
      {
        "group": "All",
        "category": 0,
        "measure": 180,
        "group2": 1
      }, {
        "group": "All",
        "category": 25,
        "measure": 188,
        "group2": 1
      }, {
        "group": "All",
        "category": 50,
        "measure": 248,
        "group2": 1
      }, {
        "group": "All",
        "category": 75,
        "measure": 950,
        "group2": 1
      }, {
        "group": "All",
        "category": 100,
        "measure": 1607,
        "group2": 1
      }, {
        "group": "All",
        "category": 125,
        "measure": 3961,
        "group2": 1
      }, {
        "group": "All",
        "category": 150,
        "measure": 8405,
        "group2": 1
      }, {
        "group": "All",
        "category": 175,
        "measure": 17304,
        "group2": 1
      }, {
        "group": "All",
        "category": 200,
        "measure": 24097,
        "group2": 1
      },
      //20
      {
        "group": "All",
        "category": 0,
        "measure": 215,
        "group2": 20
      }, {
        "group": "All",
        "category": 25,
        "measure": 369,
        "group2": 20
      }, {
        "group": "All",
        "category": 50,
        "measure": 1311,
        "group2": 20
      }, {
        "group": "All",
        "category": 75,
        "measure": 3323,
        "group2": 20
      }, {
        "group": "All",
        "category": 100,
        "measure": 5766,
        "group2": 20
      }, {
        "group": "All",
        "category": 125,
        "measure": 13473,
        "group2": 20
      }, {
        "group": "All",
        "category": 150,
        "measure": 21960,
        "group2": 20
      }, {
        "group": "All",
        "category": 175,
        "measure": 28305,
        "group2": 20
      }, {
        "group": "All",
        "category": 200,
        "measure": 34886,
        "group2": 20
      },
      //100
      {
        "group": "All",
        "category": 0,
        "measure": 228,
        "group2": 100
      }, {
        "group": "All",
        "category": 25,
        "measure": 389,
        "group2": 100
      }, {
        "group": "All",
        "category": 50,
        "measure": 1981,
        "group2": 100
      }, {
        "group": "All",
        "category": 75,
        "measure": 3646,
        "group2": 100
      }, {
        "group": "All",
        "category": 100,
        "measure": 6846,
        "group2": 100
      }, {
        "group": "All",
        "category": 125,
        "measure": 17987,
        "group2": 100
      }, {
        "group": "All",
        "category": 150,
        "measure": 23910,
        "group2": 100
      }, {
        "group": "All",
        "category": 175,
        "measure": 29333,
        "group2": 100
      }, {
        "group": "All",
        "category": 200,
        "measure": 35154,
        "group2": 100
      },

      //0
      {
        "group": "A",
        "category": 0,
        "measure": 16,
        "group2": 0
      }, {
        "group": "A",
        "category": 25,
        "measure": 18,
        "group2": 0
      }, {
        "group": "A",
        "category": 50,
        "measure": 22,
        "group2": 0
      }, {
        "group": "A",
        "category": 75,
        "measure": 132,
        "group2": 0
      }, {
        "group": "A",
        "category": 100,
        "measure": 194,
        "group2": 0
      }, {
        "group": "A",
        "category": 125,
        "measure": 386,
        "group2": 0
      }, {
        "group": "A",
        "category": 150,
        "measure": 865,
        "group2": 0
      }, {
        "group": "A",
        "category": 175,
        "measure": 761,
        "group2": 0
      }, {
        "group": "A",
        "category": 200,
        "measure": 1214,
        "group2": 0
      },
      //1
      {
        "group": "A",
        "category": 0,
        "measure": 17,
        "group2": 1
      }, {
        "group": "A",
        "category": 25,
        "measure": 17,
        "group2": 1
      }, {
        "group": "A",
        "category": 50,
        "measure": 24,
        "group2": 1
      }, {
        "group": "A",
        "category": 75,
        "measure": 104,
        "group2": 1
      }, {
        "group": "A",
        "category": 100,
        "measure": 174,
        "group2": 1
      }, {
        "group": "A",
        "category": 125,
        "measure": 339,
        "group2": 1
      }, {
        "group": "A",
        "category": 150,
        "measure": 787,
        "group2": 1
      }, {
        "group": "A",
        "category": 175,
        "measure": 1583,
        "group2": 1
      }, {
        "group": "A",
        "category": 200,
        "measure": 2198,
        "group2": 1
      },
      //20
      {
        "group": "A",
        "category": 0,
        "measure": 20,
        "group2": 20
      }, {
        "group": "A",
        "category": 25,
        "measure": 34,
        "group2": 20
      }, {
        "group": "A",
        "category": 50,
        "measure": 142,
        "group2": 20
      }, {
        "group": "A",
        "category": 75,
        "measure": 340,
        "group2": 20
      }, {
        "group": "A",
        "category": 100,
        "measure": 585,
        "group2": 20
      }, {
        "group": "A",
        "category": 125,
        "measure": 1233,
        "group2": 20
      }, {
        "group": "A",
        "category": 150,
        "measure": 1998,
        "group2": 20
      }, {
        "group": "A",
        "category": 175,
        "measure": 2578,
        "group2": 20
      }, {
        "group": "A",
        "category": 200,
        "measure": 3278,
        "group2": 20
      },
      //100
      {
        "group": "A",
        "category": 0,
        "measure": 20,
        "group2": 100
      }, {
        "group": "A",
        "category": 25,
        "measure": 34,
        "group2": 100
      }, {
        "group": "A",
        "category": 50,
        "measure": 211,
        "group2": 100
      }, {
        "group": "A",
        "category": 75,
        "measure": 363,
        "group2": 100
      }, {
        "group": "A",
        "category": 100,
        "measure": 667,
        "group2": 100
      }, {
        "group": "A",
        "category": 125,
        "measure": 1593,
        "group2": 100
      }, {
        "group": "A",
        "category": 150,
        "measure": 2111,
        "group2": 100
      }, {
        "group": "A",
        "category": 175,
        "measure": 2636,
        "group2": 100
      }, {
        "group": "A",
        "category": 200,
        "measure": 3270,
        "group2": 100
      },

      //0
      {
        "group": "C",
        "category": 0,
        "measure": 37,
        "group2": 0
      }, {
        "group": "C",
        "category": 25,
        "measure": 45,
        "group2": 0
      }, {
        "group": "C",
        "category": 50,
        "measure": 52,
        "group2": 0
      }, {
        "group": "C",
        "category": 75,
        "measure": 413,
        "group2": 0
      }, {
        "group": "C",
        "category": 100,
        "measure": 527,
        "group2": 0
      }, {
        "group": "C",
        "category": 125,
        "measure": 1252,
        "group2": 0
      }, {
        "group": "C",
        "category": 150,
        "measure": 2914,
        "group2": 0
      }, {
        "group": "C",
        "category": 175,
        "measure": 2109,
        "group2": 0
      }, {
        "group": "C",
        "category": 200,
        "measure": 3687,
        "group2": 0
      },
      //1
      {
        "group": "C",
        "category": 0,
        "measure": 42,
        "group2": 1
      }, {
        "group": "C",
        "category": 25,
        "measure": 43,
        "group2": 1
      }, {
        "group": "C",
        "category": 50,
        "measure": 52,
        "group2": 1
      }, {
        "group": "C",
        "category": 75,
        "measure": 317,
        "group2": 1
      }, {
        "group": "C",
        "category": 100,
        "measure": 491,
        "group2": 1
      }, {
        "group": "C",
        "category": 125,
        "measure": 1225,
        "group2": 1
      }, {
        "group": "C",
        "category": 150,
        "measure": 2723,
        "group2": 1
      }, {
        "group": "C",
        "category": 175,
        "measure": 6004,
        "group2": 1
      }, {
        "group": "C",
        "category": 200,
        "measure": 8668,
        "group2": 1
      },
      //20
      {
        "group": "C",
        "category": 0,
        "measure": 47,
        "group2": 20
      }, {
        "group": "C",
        "category": 25,
        "measure": 80,
        "group2": 20
      }, {
        "group": "C",
        "category": 50,
        "measure": 422,
        "group2": 20
      }, {
        "group": "C",
        "category": 75,
        "measure": 1039,
        "group2": 20
      }, {
        "group": "C",
        "category": 100,
        "measure": 1826,
        "group2": 20
      }, {
        "group": "C",
        "category": 125,
        "measure": 4537,
        "group2": 20
      }, {
        "group": "C",
        "category": 150,
        "measure": 7782,
        "group2": 20
      }, {
        "group": "C",
        "category": 175,
        "measure": 10493,
        "group2": 20
      }, {
        "group": "C",
        "category": 200,
        "measure": 13122,
        "group2": 20
      },
      //100
      {
        "group": "C",
        "category": 0,
        "measure": 51,
        "group2": 100
      }, {
        "group": "C",
        "category": 25,
        "measure": 93,
        "group2": 100
      }, {
        "group": "C",
        "category": 50,
        "measure": 664,
        "group2": 100
      }, {
        "group": "C",
        "category": 75,
        "measure": 1171,
        "group2": 100
      }, {
        "group": "C",
        "category": 100,
        "measure": 2103,
        "group2": 100
      }, {
        "group": "C",
        "category": 125,
        "measure": 6414,
        "group2": 100
      }, {
        "group": "C",
        "category": 150,
        "measure": 8713,
        "group2": 100
      }, {
        "group": "C",
        "category": 175,
        "measure": 10830,
        "group2": 100
      }, {
        "group": "C",
        "category": 200,
        "measure": 13120,
        "group2": 100
      },

      //0
      {
        "group": "B",
        "category": 0,
        "measure": 110,
        "group2": 0
      }, {
        "group": "B",
        "category": 25,
        "measure": 123,
        "group2": 0
      }, {
        "group": "B",
        "category": 50,
        "measure": 155,
        "group2": 0
      }, {
        "group": "B",
        "category": 75,
        "measure": 773,
        "group2": 0
      }, {
        "group": "B",
        "category": 100,
        "measure": 1093,
        "group2": 0
      }, {
        "group": "B",
        "category": 125,
        "measure": 2307,
        "group2": 0
      }, {
        "group": "B",
        "category": 150,
        "measure": 5579,
        "group2": 0
      }, {
        "group": "B",
        "category": 175,
        "measure": 3969,
        "group2": 0
      }, {
        "group": "B",
        "category": 200,
        "measure": 6754,
        "group2": 0
      },
      //1
      {
        "group": "B",
        "category": 0,
        "measure": 114,
        "group2": 1
      }, {
        "group": "B",
        "category": 25,
        "measure": 112,
        "group2": 1
      }, {
        "group": "B",
        "category": 50,
        "measure": 163,
        "group2": 1
      }, {
        "group": "B",
        "category": 75,
        "measure": 576,
        "group2": 1
      }, {
        "group": "B",
        "category": 100,
        "measure": 994,
        "group2": 1
      }, {
        "group": "B",
        "category": 125,
        "measure": 2422,
        "group2": 1
      }, {
        "group": "B",
        "category": 150,
        "measure": 5140,
        "group2": 1
      }, {
        "group": "B",
        "category": 175,
        "measure": 10315,
        "group2": 1
      }, {
        "group": "B",
        "category": 200,
        "measure": 13675,
        "group2": 1
      },
      //20
      {
        "group": "B",
        "category": 0,
        "measure": 139,
        "group2": 20
      }, {
        "group": "B",
        "category": 25,
        "measure": 243,
        "group2": 20
      }, {
        "group": "B",
        "category": 50,
        "measure": 799,
        "group2": 20
      }, {
        "group": "B",
        "category": 75,
        "measure": 2027,
        "group2": 20
      }, {
        "group": "B",
        "category": 100,
        "measure": 3507,
        "group2": 20
      }, {
        "group": "B",
        "category": 125,
        "measure": 8148,
        "group2": 20
      }, {
        "group": "B",
        "category": 150,
        "measure": 12621,
        "group2": 20
      }, {
        "group": "B",
        "category": 175,
        "measure": 15735,
        "group2": 20
      }, {
        "group": "B",
        "category": 200,
        "measure": 18961,
        "group2": 20
      },
      //100
      {
        "group": "B",
        "category": 0,
        "measure": 149,
        "group2": 100
      }, {
        "group": "B",
        "category": 25,
        "measure": 259,
        "group2": 100
      }, {
        "group": "B",
        "category": 50,
        "measure": 1189,
        "group2": 100
      }, {
        "group": "B",
        "category": 75,
        "measure": 2213,
        "group2": 100
      }, {
        "group": "B",
        "category": 100,
        "measure": 4311,
        "group2": 100
      }, {
        "group": "B",
        "category": 125,
        "measure": 10631,
        "group2": 100
      }, {
        "group": "B",
        "category": 150,
        "measure": 13645,
        "group2": 100
      }, {
        "group": "B",
        "category": 175,
        "measure": 16443,
        "group2": 100
      }, {
        "group": "B",
        "category": 200,
        "measure": 19309,
        "group2": 100
      }

    ];

    // set initial group value
    var group = "All";

    function datasetLineChartChosen(group) {
      var ds = [];
      for (x in datasetLineChart) {
        if (datasetLineChart[x].group == group) {
          ds.push(datasetLineChart[x]);
        }
      }
      return ds;
    }

    var firstDatasetLineChart = datasetLineChartChosen(group);

    function dsLineChartBasics() {

      var margin = {
          top: 0,
          right: 0,
          bottom: 0,
          left: 0
        },
        width = 500 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;

      return {
        margin: margin,
        width: width,
        height: height
      }
    }


    var margin, line, svg, xScale, yScale;

    function lineChart() {

      var basics = dsLineChartBasics();

      margin = basics.margin,
        width = basics.width,
        height = basics.height;

      var dataNest = d3.nest()
        .key(function(d) {
          return d.group2;
        })
        .entries(firstDatasetLineChart);

      xScale = d3.scale.linear()
        .range([0, width])
        .domain(d3.extent(datasetLineChart, function(d) {
          return d.category;
        }));

      yScale = d3.scale.linear()
        .range([height, 0])
        .domain([0, d3.max(datasetLineChart, function(d) {
          return d.measure;
        })]);

      line = d3.svg.line()
        .interpolate("basis")
        .x(function(d) {
          return xScale(d.category);
        })
        .y(function(d) {
          return yScale(d.measure);
        });

      svg = d3.selectAll("#lineChart")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


      svg.selectAll("plot")
        .data(dataNest)
        .enter()
        .append("path")
        .attr("class", "line")
        .attr("d", function(d) {
          return line(d.values);
        })
        .style("stroke", "lightGrey");
    }

    lineChart();

    function updateLineChart(group, colorChosen) {


      var currentDatasetLineChart = datasetLineChartChosen(group);

      var dataNest1 = d3.nest()
        .key(function(d) {
          return d.group2;
        })
        .entries(currentDatasetLineChart);

      console.log(dataNest1);

      console.log(currentDatasetLineChart);

      xScale.domain(d3.extent(currentDatasetLineChart, function(d) {
          return d.category;
        }));

      yScale.domain([0, d3.max(currentDatasetLineChart, function(d) {
          return d.measure;
        })]);
        
      
      svg.selectAll("*").remove();

      var plot = svg.selectAll("g")
        .data(dataNest1)
        .enter()
        .append("g")
        .append("path")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
        .attr("class", "line")
        .attr("d", function(d) {
          return line(d.values);
        })
        .style("stroke", colorChosen);

      //plot.exit().remove();	


    }
  </script>
</body>

</html>

Upvotes: 1

Related Questions