Adjusting small multiples sparklines

2020-07-25 09:02发布

I have an heatmap that show some data and a sparkline for each line of the heatmap. If the user click on a row label, then the data are ordered in decreasing order, so each rect is placed in the right position. Viceversa, if the user click on a column label.

Each react is placed in the right way but I'm not able to place the sparkline.

Here the code.

When the user click on a row label, also the path inside the svg containing the sparkline should be updated. And then, when the user click on a column label, the svg containing the sparkline should be placed in the correct line.

To place the svg in the right place, I try to use the x and y attributes of svg. They are updated but the svg doesn't change its position. Why? Here is a piece of code related to that:

var t = svg.transition().duration(1000);
var values = []; 
var sorted;
sorted = d3.range(numRegions).sort(function(a, b) {
    if(sortOrder) {
        return values[b] - values[a];
    } 
    else {
        return values[a] - values[b];
    }
});

t.selectAll('.rowLabel')
    .attr('y', function(d, k) {
        return sorted.indexOf(k) * cellSize;
    });

Also, I don't know how to change the path of every sparkline svg. I could take the data and order them manually, but this is only good for the row on which the user has clicked and not for all the others.

How can I do?

1条回答
迷人小祖宗
2楼-- · 2020-07-25 09:37

The vertical and horizontal re-positioning/redrawing of those sparklines require different approaches:

Vertical adjustment

For this solution I'm using selection.sort, which:

Returns a new selection that contains a copy of each group in this selection sorted according to the compare function. After sorting, re-inserts elements to match the resulting order.

So, first, we set our selection:

var sortedSVG = d3.selectAll(".data-svg")

Then, since selection.sort deals with data, we bind the datum, which is the index of the SVG regarding your sorted array:

.datum(function(d){
    return sorted.indexOf(+this.dataset.r)
})

Finally, we compare them in ascending order:

.sort(function(a,b){
    return d3.ascending(a,b)
});

Have in mind that the change is immediate, not a slow and nice transition. This is because the elements are re-positioned in the DOM, and the new structure is painted immediately. For having a slow transition, you'll have to deal with HTML and CSS inside the container div (which may be worth a new specific question).

Horizontal adjustment

The issue here is getting all the relevant data from the selection:

var sel = d3.selectAll('rect[data-r=\'' + k + '\']')
    .each(function() {
        arr.push({value:+d3.select(this).attr('data-value'),
            pos: +d3.select(this).attr('data-c')});
    });

And sorting it according to data-c. After that, we map the result to a simple array:

var result = arr.sort(function(a,b){
        return sorted.indexOf(a.pos) - sorted.indexOf(b.pos)
    }).map(function(d){
        return d.value
    });

Conclusion

Here is the updated Plunker: http://next.plnkr.co/edit/85fIXWxmX0l42cHx or http://plnkr.co/edit/85fIXWxmX0l42cHx

PS: You'll need to re-position the circles as well.

查看更多
登录 后发表回答