tobi
tobi

Reputation: 2012

Why d3 removes data during second update

I update my data (using d3) twice with exactly the same model.

During the first update I can see that data().enter() contains some elements and data().exit() is empty. That is understandable for me.

During second update (with the same model) data().enter() is empty (as I thought), but data().exit() is not empty and because of that it removes all the nodes during second update. This is what I don't understand.

Here is simplified code (and jsfiddle; look at the console):

// http://jsfiddle.net/24yqteo0/
// http://jsfiddle.net/6du29258/ - example with displaying some data

var model = {
    smth: 'test',
    rows: [
        {
            label: 'label1',
            series: [
                {
                    test: 'test1_1'
                },
                {
                    test: 'test1_2'
                }
            ]
        },
        {
            label: 'label2',
            series: [
                {
                    test: 'test2'
                }
            ]
        }
    ]
};

var svg = d3.select("body").append("svg");
updateData(model);
console.log('// ------------- new update');
updateData(model);

function updateData(model) {
    var selection = svg.selectAll('g').data(model.rows);
    console.log('selection enter size: ' + selection.enter().size());

    var rows = selection.enter().append('g');

    var rowData = rows.append('g').selectAll('g')
    .data(function (d) {
        return d.series;
    });

    console.log('rowdata enter size: ' + rowData.enter().size());
    var seriesGroup = rowData.enter().append('g');

    console.log('rowdata exit size: ' + rowData.exit().size());
    rowData.exit().remove();

    console.log('selection exit size: ' + selection.exit().size());
    selection.exit().remove();
}

Upvotes: 2

Views: 56

Answers (1)

ahmohamed
ahmohamed

Reputation: 2970

Well, it is not helpful for debugging when you use just plain g elements for nested enters and exits.

I replaced the seriesGroup appends with text as follows fiddle here:

var seriesGroup = rowData.enter()
    .append('text')
    .text(function (d) { return d.test; });

I quickly spotted the problem in you code. It is actually the first line of updateData

var selection = svg.selectAll('g').data(model.rows);

This selection includes ALL g elements, including nested ones. (console.log selection to confirm) To prevent this behavior, you can add a more precise selector, such as class

var selection = svg.selectAll('g.row').data(model.rows);

and then append

var rows = selection.enter()
    .append('g')
    .classed('row', true);

Similarly for the second level:

var rowData = rows.append('g').selectAll('g.series')

and then

var seriesGroup = rowData.enter()
    .append('g')
    .classed('series', true);

Updated fiddle here.

Hope this helps.

Upvotes: 2

Related Questions