使用 D3 更新多折线图的模式

Posted

技术标签:

【中文标题】使用 D3 更新多折线图的模式【英文标题】:Update Pattern for Multi-Line Chart with D3 【发布时间】:2016-03-21 23:31:38 【问题描述】:

我正在 D3 中创建一个小型仪表板,其中:单击圆环图的一部分时,将更新相邻的折线图。代码大致基于此块http://bl.ocks.org/diethardsteiner/3287802。

这是我现在所拥有的和问题的 JSFiddle:https://jsfiddle.net/394mLyz9/

如果您滚动到小提琴的末尾,您会发现“更新”代码如下:

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(); 



您会注意到,当一个饼图被点击时,它会在现有的下方创建新的折线图,而不是更新现有的折线图。我已经阅读了一般更新模式教程,但仍然收效甚微。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

首先,您在更新功能中做了太多工作。如果您增加了一些变量的范围,则无需在每次更新时重新创建它们。 svgxScaleyScalemarginsline 都是您可以分享的初始抽奖和更新内容。

其次,虽然更新模式很重要,但在这种情况下,您并没有真正用新数据更新绘图,而是用所有新数据创建了一个全新的绘图。考虑到这一点,我将转储 SVG 的内容并重新添加您的行。

折线图功能:

// 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()
    ...

更新图表功能:

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)
  ...



完整代码示例:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.3" 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>

【讨论】:

正是我需要的建议,感谢您提供的其他建议!

以上是关于使用 D3 更新多折线图的模式的主要内容,如果未能解决你的问题,请参考以下文章

Python:如何在绘图中更改多折线图上线条的颜色? [复制]

D3-动态更新折线图

D3.JS 具有实时数据、平移和缩放的时间序列折线图

d3.js带圆圈的实时折线图

echarts框选+缩放折线图

D3 折线图显示为面积图