1

I'm following the given tutorial on D3 bar chart -2

I've setup my code in two functions one is init and one is update

var xScale = null;
var chart = null;
function init(w, c) {
    xScale = d3.scale.linear()
        .range([0, w]);
    chart = d3.select(c)
        .append('svg')
            .attr('width', w);

function update(data) {
        xScale.domain([0, d3.max(data, function(d) { return +d.value; })]);                
        chart.attr('height', 20 * data.length);           
        var bars = chart.selectAll('g')         
            .data(data);
        bars.exit().remove();
        bars.enter().append('g')
            .attr('transform', function(d, i) { return 'translate(0,' + i * 20 + ')'; });
        bars.append('rect')
            .attr('width', function(d) { return xScale(+d.value); })
            .attr('height', 18);

        bars.append('text')
            .attr('x', function(d) { return xScale(+d.value); })
            .attr('y', 10)
            .attr('dy', '.45em')
            .text(function (d) { return d.name; });
}

When I call update first time, the bar chart is created correctly, on subsequenet update calls, it creates rect and text elements under tags instead of updating

My data is a dict {'name': a, 'value': 12, .....} The number of elements per update can be different. There might be same keys(names) with different values in each update

gizgok
  • 7,303
  • 21
  • 79
  • 124

1 Answers1

0
bars = chart.selectAll('g')

You are selecting all of the g elements (both new and existing).

bars.append('rect');
bars.append('text');

As a result, when you call append on bars, you are appending rect and text elements to both the new and existing g elements.

/* Enter */
enter = bars.enter().append('g');
enter.append('rect');
enter.append('text');

/* Update */
bars.attr('transform', function(d, i) { 
  return 'translate(0,' + i * 20 + ')';
});
bars.select('rect')
  .attr('width', function(d) { return xScale(+d.value); })
  .attr('height', 18);
bars.select('text')
  .attr('x', function(d) { return xScale(+d.value); })
  .attr('y', 10)
  .attr('dy', '.45em')
  .text(function (d) { return d.name; });

This allows you to append rect and text elements only to the enter selection, yet still allows you to update all the elements using your new data.

Note:
The enter selection merges into the update selection when you append or insert. Rather than applying the same operators to the enter and update selections separately, you can now apply them only once to the update selection after entering the nodes.
See: https://github.com/mbostock/d3/wiki/Selections#data

Wex
  • 15,539
  • 10
  • 64
  • 107