goblin-esque
goblin-esque

Reputation: 465

d3.js - .exit().remove() a group element is not working

I'm building a dynamic bar chart looking at boys' and girls' test scores from Kenya and Tanzania. Users can select, from drop-down menus, which country (Kenya, Tanzania) and which year (2010, 2011) they'd like to see scores from. I've cleaned and organized all the data into separate country-year .csv files. The bars are grouped in g elements showing, overlapping, the boys' and girls' scores for a specific region.

Everything is working fine, except the bar chart keeps generating itself over the previous one. If a user picks Kenya 2010 first, and then Kenya 2011 second, the Kenya-2011 data gets drawn over the existing Kenya-2010 graph. So .exit().remove() doesn't seem to be working.

Full code in a Plunkr here.

The relevant code bits below:

        //Creating groups for regions
        regions = svg.append("g")
          .classed("regions", true);

        region = regions.selectAll(".region")
          .data(dataset);

        region.enter()
          .append("g")
          .attr("class", "region");

        //This transition moves the rects horizontally. 
        //exit().remove() is not working.
        region.transition()
          .duration(1500)
          .attr("transform", function(d) { 
              return "translate(" + x(d.key) + ",0)"; 
            });

        region.exit().remove();

        rects = region.selectAll("rect")
            .data(function(region) { 
              return region.values;
            });

        rects.enter()
            .append("rect")
            .attr("x", 0)
            .attr("width", barWidth);

        rects.transition()
            .duration(2000)
            .attr("y", function(region) {
              return y(region.values[0][subject]);
            })
            .attr("height", function(region) { 
              return h - y(region.values[0][subject]);
            })
            .attr("class", function(region) { return region.key; });

        rects.exit().remove();

Here's what it looks like:

enter image description here

Any help appreciated; thanks in advance.

Upvotes: 3

Views: 4956

Answers (2)

Mark
Mark

Reputation: 108512

@EthanJewett is on to the right answer but really all your code takes is some restructuring. Anytime you are doing an update to an existing visualization and you call append it must be on an enter selection. In your code, you re-append the container elements for the regions, x axis, y axis, title and sub-titles.

Pulling those appends into your initial canvas set-up fixes your problem:

//canvas
var svg = d3.select("body")
  .append("svg")
  .attr("width", w + margin.left + margin.right)
  .attr("height", h + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//creating groups for regions
var regions = svg.append("g")
  .classed("regions", true);

var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom")
  .tickSize(.1);

svg.append("g")
  .attr("class", "x axis")
  .attr("transform", "rotate(-90)")
  .attr("transform", "translate(0," + h + ")")

var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left")
  .tickSize(.5)
  .ticks(7);

svg.append("g")
  .attr("class", "y axis")

var title = svg.append("text")
  .attr("class", "title")
  .attr("dx", (w - 300) + "px")
  .attr("dy", ".71em");

var subtitle = svg.append("text")
  .attr("class", "subtitle")
  .attr("dx", (w - 200) + "px")
  .attr("dy", "50px");

function viz() {
   ....

Here's a fixed up plunker.

Upvotes: 1

Ethan Jewett
Ethan Jewett

Reputation: 6010

You append a new 'g' element with class 'regions' every time, so it is empty and your selectAll(".region") is also empty, resulting in every data point being in the enter() set. You should check if an element with class "regions" exists and select it instead of appending it. That is, start out with

//Creating groups for regions
regions = svg.select(".regions");
if(regions.empty()) {
  regions = svg.append("g")
    .classed("regions", true);
}

Upvotes: 4

Related Questions