Alan Dunning
Alan Dunning

Reputation: 1351

Remove old circles from scatter graph on update

I have a scatter graph built with d3.js. It plots circles in the graph for the spending habits of specific people.

I have a select menu that changes the specific user and updates the circles on the scatter graph.

The problem is the old circles are not removed on update.

Where are how should I use .remove() .update(), please see this plnkr for a working example

http://plnkr.co/edit/qtj1ulsVVCW2vGBvDLXO?p=info

Upvotes: 0

Views: 1065

Answers (1)

saaj
saaj

Reputation: 25194

First, Alan, I suggest you to adhere to some coding style convention to make your code readable. I know that D3 examples, and the library code per se, almost never promote code readability, but it's in your interest first, because it's much easier to maintain readable code.

Second, you need to understand how D3 works with enter, update and exit sets, when you change data. Mike Bostock's Thinking with Joins may be a good start. Unless you understand how the joins work, you won't be able to program dynamic D3 charts.

Third, here's a bug in updateScatter. name.length makes no sense because your first name variable is value. So it's not the case of deleting old data in the first place.

// Update circles for the selected user chosen in the select menu.
svg.selectAll(".markers")
    .data(data.filter(function(d){ return d.FirstName.substring(0, name.length) === value;}))
    .transition().duration(1000)
    .attr("cx", function(d) { return xScale(d.timestamp); })
    .attr("cy", function(d) { return yScale(d.price); });

Also what that weird equality comparison is d.FirstName.substring(0, name.length) === name. Your first name data is not even spaced in CSV file. Plain d.FirstName == name is fair enough. If you expect trailing spaces anyway, just trim your strings in the place where you coerce prices and dates.

This is how correct updateScatter may look look like:

function updateScatter() 
{
  var selectedFirstName = this.value;
  var selectedData      = data.filter(function(d) 
  {
    return d.FirstName == selectedFirstName;
  });

  yScale.domain([
    0, 
    d3.max(selectedData.map(function(d) 
    {
      return d.price;
    }))
  ]);

  svg.select(".y.axis")
    .transition().duration(750)
    .call(yAxis);

  // create *update* set
  var markers = svg.selectAll(".markers").data(selectedData);

  // create new circles, *enter* set
  markers.enter()
    .append('circle')
    .attr("class", 'markers')
    .attr("cx", function(d) 
    {
      return xScale(d.timestamp);
    })
    .attr("cy", function(d) 
    {
      return yScale(d.price);
    })
    .attr('r', 5)
    .style('fill', function(d) 
    {
      return colour(cValue(d));
    });

  // transition *update* set
  markers.transition().duration(1000)
    .attr("cx", function(d) 
    {
      return xScale(d.timestamp);
    })
    .attr("cy", function(d) 
    {
      return yScale(d.price);
    });

  // remove *exit* set
  markers.exit().remove();
}

Upvotes: 3

Related Questions