更新时未从 D3 条形图中删除旧元素

old elements not removed from d3 bar chart on update

本文关键字:删除 元素 条形图 D3 更新      更新时间:2023-09-26

我正在 d3 中制作一个条形图,该条形图应该采用小型随机模拟模型的结果(在本例中为传染病传播的易感感染-康复模型),并将每天感染的新人数绘制为图表中条形的高度。

当我第一次运行模型时,这工作正常,但是在随后的运行中(使用 simulate() 函数或 html 中的"单击我"按钮)应该替换的旧元素(即上次运行中第 1 天感染的个体数量)没有显示在退出选择中,它始终为空。相反,新条形图会始终添加到末尾或绘制在现有条形图上。

我尝试了许多关键函数(包括没有键函数,以及将整数时间转换为字符串)。我确定我做错了什么,但不确定那是什么。因此,任何建议将不胜感激。

您还可以在此处找到此半工作代码的工作演示:

http://bl.ocks.org/jzelner/e06e2997429ada3534dc

谢谢!

var max_t = 20; N = 100; b = 1.1 total_id = 0;
function outbreak() {
    var S = N-1;
    var I = 1;
    var done = 0;
    var incidence = [{t:0, I:I, name: String(0)}];
    for (t = 1; t < max_t; t++) {
        var p_inf = 1.0-Math.exp(-b*I/N);
        var new_I = 0;
        for (i = 0; i < S; i++) {
            if (Math.random() < p_inf) {
                new_I++;
            }
        }
        if (new_I == 0) {
            break;
            done = 1;
        }
        incidence.push({t:t, I:new_I, name:String(t)});
        total_id++;
        S -= new_I;
        I = new_I;
    }
    return(incidence);
}
incidence = outbreak();

var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// Parse the date / time
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
      "translate(" + margin.left + "," + margin.top + ")");

xvals = [];
for (i = 0; i <= 20; i++){
    xvals.push(i);
}
x.domain(xvals);
y.domain([0, 20]);


function render(zz) {
    console.log(zz)
    var bar = svg.selectAll("bar")
        .data(zz, function(d) { return d.name;});
    bar.exit().remove();

    bar.attr("class", "update")
        .attr("x", function(d) { return x(d.t); })
        .attr("width", x.rangeBand())
        .attr("y", function(d) { return y(d.I); })
        .attr("height", function(d) { return height - y(d.I); });

    console.log("UPDATE", bar)
    console.log("ENTER", bar.enter())
    bar.enter().append("rect")
        .attr("class", "enter")
        .attr("x", function(d) { return x(d.t); })
        .attr("width", x.rangeBand())
        .attr("y", function(d) { return y(d.I); })
        .attr("height", function(d) { return height - y(d.I); });
    bar
        .attr("x", function(d) { return x(d.t); })
        .attr("width", x.rangeBand())
        .attr("y", function(d) { return y(d.I); })
        .attr("height", function(d) { return height - y(d.I); });
}

render(incidence);
function simulate() {
    render(outbreak());
}

如注释中所述,这样做:

svg.selectAll("path")
    .attr({
      d: line(data)
    });

取而代之的是:

svg.append("path")
    .data([data])
    .attr("class", "line")
    .attr("d", line);

解决了我的问题。