简体   繁体   中英

How to update a bar chart with accompanying text in d3?

I'm creating a bar chart as part of a bigger data visualization in d3. I want to be able to change the data in one part of the visualization and all the charts will be updated. A simplified version of the chart is as follows.

var dataset = [1, 3, 5, 3, 3];

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

    var g = svg.append("g");
...

I create other charts like a map, circle etc with this svg element. The bar chart is implemented like this.

 function bars(dataset) {
      var barChart = g.selectAll("rect.bar")
        .data(dataset)
        .enter();

      barChart.append("rect")
        .attr("class", "bar")
        .attr("x", function(d, i) { return i * 30 + 100; })
        .attr("y", function(d) { return (height - 130) - d * 4;})
        .attr("width", 25)
        .attr("height", function(d) { return d * 4; });


       barChart.append("text")
        .text(function(d) { return d; })
        .attr("x", function(d, i) { return i * 30 + 103; })
        .attr("y", function(d) { return (height - 130) - d/10 - 5;})
        .attr("font-family", "sans-serif")
        .attr("font-size", "10px")
        .attr("fill", "darkgray"); 
}

Now this renders the bar chart fine but there is a function

...
.on("click", function() {
   ...
   var newdata = [5, 2, 6, 2, 4]; // new values
   g.selectAll("rect.bar").remove();  // This removes the bars
   g.selectAll("text").remove();    // Problem here: All texts are removed
   bars(newdata);
}

I have tried to transition the bar chart with new values with the .remove() function. This works for the bar rectangles because there are no othe bar charts but when I tried to remove the value labels like shown above all the other text elements were also removed. Is there a way to only update the text associated with the bars?

Have you tried applying a class to the text and only selecting those ones for removal? eg

barChart.append("text")
  .attr('class','label')
  .text(function(d) { return d; })

then

g.selectAll(".label").remove();

Incidentally, if not all of the elements are being deleted between updates, then instead of removing all of the elements, have you considered using enter() and exit() to bind the new data to the existing elements and only remove the elements that are changing?

EDIT Like this:

function bars(dataset) {
  var bar = g.selectAll(".bar").data(dataset);

  bar.exit().remove();

  bar.enter().append("rect").attr("class", "bar");

  bar
    .attr("x", function(d, i) { return i * 30 + 100; })
    .attr("y", function(d) { return (height - 130) - d * 4;})
    .attr("width", 25)
    .attr("height", function(d) { return d * 4; });

  var label = g.selectAll(".label").data(dataset);

  label.exit().remove();

  label.enter().append("text").attr("class", "label");

  label
    .text(function(d) { return d; })
    .attr("x", function(d, i) { return i * 30 + 103; })
    .attr("y", function(d) { return (height - 130) - d/10 - 5;})
    .attr("font-family", "sans-serif")
    .attr("font-size", "10px")
    .attr("fill", "darkgray"); 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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