简体   繁体   English

d3折线图和面积图未使用新数据数组更新

[英]d3 line and area charts not updating with new data array

I have written a reusable d3 line chart (code below). 我写了一个可重复使用的d3折线图(下面的代码)。 Unfortunately it only updates properly when the data array passed to it is updated; 不幸的是,只有在传递给它的数据数组更新时,它才能正确更新。 if it is passed a new data array, it does not update at all - you can see it in this jsfiddle . 如果将新数据数组传递给它,则它根本不会更新-您可以在此jsfiddle中看到它。

Here is the html, which is mostly the embedded demo calling script: 这是html,主要是嵌入式演示调用脚本:

<style>
  path { stroke: purple; stroke-width: 2px; fill: none; }
</style>
<body>
<div id="demo"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="demoChart.js"></script>
<script>
  var chart = demoChart();
  var pts = [[[0,0],[200,0.25],[500,1]]];

  d3.select("#demo").datum(pts).call(chart);
  setTimeout(function() {
    console.log("Modifying data array");
    pts[0][2][1] = 0.5;
    d3.select("#demo").datum(pts).call(chart);
  },1000);

  setTimeout(function() {
    console.log("Passing new data array");
    d3.select("#demo").datum([[[0,1],[200,0.45],[500,0]]]).call(chart);
  },2000);
</script>

You can see the second time it calls chart it directly updates a single point in the data array ( pts[0][3][1] = 0.5 ), and the chart animates properly. 您可以看到第二次调用chart它会直接更新数据数组中的单个点( pts[0][3][1] = 0.5 ),并且图表会正确设置动画。 The third time it passes a new data array, and the chart does not change. 它第三次通过新的数据数组,并且图表没有更改。

Here is the demoChart.js code (based on the reusable charts pattern): 这是demoChart.js代码(基于可重复使用的图表模式):

function demoChart() {

    function xs(d) { return xScale(d[0]) }
    function ys(d) { return yScale(d[1]) }

    var xScale = d3.scale.linear().domain([0, 500]).range([0, 400]),
        yScale = d3.scale.linear().domain([0, 1]).range([400, 0]),
        line = d3.svg.line().x(xs).y(ys);

    function chart(selection) {
        selection.each(function(data) {
            console.log("passed data: ", data);

            // Select the svg element, if it exists; otherwise create it
            var svg = d3.select(this).selectAll("svg").data([1]);
            var svgGEnter = svg.enter().append("svg").append("g");

            // Select/create/remove plots for each y, with the data
            var plots = svg.select("g").selectAll(".plot").data(data);
            plots.exit().remove();
            var plotsEnter = plots.enter().append("g").attr("class","plot");
            plotsEnter.append("path");

            // Update the line paths
            plots.selectAll("path")
                .transition()
                    .attr("d", function(d,i) {
                        console.log("transitioning line with data: ", d);
                        return line.apply(this, arguments);
                    });

            svg.attr("width", 400).attr("height", 400);

        });
    }

    return chart;
}

I suspect I am missing something fundamental about how d3 works. 我怀疑我缺少有关d3工作原理的一些基本知识。

How can I make the chart update properly when a new data array is passed? 传递新的数据数组时,如何使图表正确更新?

Where you update the line paths, via 在哪里更新线路径,通过

plots.selectAll("path")

it needs to be 它必须是

plots.select("path")

see mbostock's explanation of the subtle but crucial difference. 请参见mbostock对细微但至关重要的区别的解释

Here's a working fiddle , which also has a second path added, to verify that it works across plots. 这是一个有效的小提琴 ,其中还添加了第二条路径,以验证它可以跨图使用。

I actually had the same issue today. 我今天实际上也遇到了同样的问题。 So I may be able to help out. 因此,我可能可以提供帮助。 I noticed you're calling setTimeout to update the data in your html. 我注意到您正在调用setTimeout来更新html中的数据。

It seems you are calling chart() inside of that setTimeout. 看来您正在该setTimeout内调用chart()。 The only problem with that is that you aren't resetting your ranges. 唯一的问题是您没有重置范围。

Instead you should try calling demoChart(), or adding new ranges inside of your chart(). 相反,您应该尝试调用demoChart()或在chart()内添加新范围。 Your ranges are: 您的范围是:

function xs(d) { return xScale(d[0]) }
function ys(d) { return yScale(d[1]) }

var xScale = d3.scale.linear().domain([0, 500]).range([0, 400]),
    yScale = d3.scale.linear().domain([0, 1]).range([400, 0]),
    line = d3.svg.line().x(xs).y(ys);

If that doesn't fix it, it may because you are updating with two setTimeouts initiating each second simultaneously. 如果那不能解决问题,则可能是因为您正在更新同时启动两个setTimeouts的方式。 So the second data is overwriting the first immediately here: 因此,第二个数据将立即在此处覆盖第一个数据:

setTimeout(function() {
  console.log("Modifying data array");
  pts[0][2][1] = 0.5;
  d3.select("#demo").datum(pts).call(chart);
},1000);

setTimeout(function() {
  console.log("Passing new data array");
  d3.select("#demo").datum([[[0,1],[200,0.45],[500,0]]]).call(chart);
},1000);

Here's an article I found helpful: http://www.d3noob.org/2013/02/update-d3js-data-dynamically-button.html 这是我发现有帮助的文章: http : //www.d3noob.org/2013/02/update-d3js-data-dynamically-button.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM