gpt4 book ai didi

d3.js - 当用户更改数据的顺序时在迷你图上放置一个圆圈

转载 作者:行者123 更新时间:2023-12-03 20:53:09 25 4
gpt4 key购买 nike

我创建了 this question几天前关于当用户选择更改数据顺序时迷你图的顺序。答案已经解决了问题,但仍然是正确定位红色圆圈,突出显示用户放置鼠标的位置。
这是代码:PLUNKER .
我想过如何更改代码以在数据排序更改时重新定位迷你图圆圈。
我不明白在哪里以及如何更改代码。
下面我尝试根据有关迷你图的代码点来解释我的推理。
(1) 这两行代码定义了迷你图的域和范围。在我看来,当数据的顺序改变时,它们不应该改变。

// domain and range for sparkline lines
var xSpark = d3.scaleLinear().domain([0, numYears-1]).range([0, sparkLength]);
var ySpark = d3.scaleLinear().domain([minYvalue, maxYvalue]).range([itemSize-2, 2]);
(2) 这段代码选择了元素 #data-svg-i (其中 i 是迷你图),它会附加一个圆圈,将其定位在 cx 中, cy取决于 xSparkySpark .
如果 中提到的那个1 为真(即 xSparkySpark 是“固定”值),那么即使是这段代码在数据顺序发生变化时也不必更改。
var cells = svg.selectAll('.cell')
.data(data)
.enter()
.append('g')
.append('rect')
.on('mouseover', function(d, i) { // on mouseover rect
// get row, column and value of this rect
var idr = d3.select(this).attr('data-r'); // row
var idc = d3.select(this).attr('data-c'); // column
var value = d3.select(this).attr('data-value');
// highlight this rect
d3.select(this).style('stroke', 'red');
// add red dot to sparkline
d3.select('#data-svg-' + idr)
.append('circle')
.attr('r', 3) // radius
.style('stroke', 'red')
.style('fill', 'red')
.attr('cx', xSpark(idc))
.attr('cy', ySpark(value));
})
(3) 当数据顺序改变时,这段代码也不需要改变。
line = d3.line()
.x(function(d, i) {
return xSpark(i);
})
.y(function(d) {
return ySpark(d);
})
.defined(function(d) { // for missing (0) data
return d !== 0;
});
(4) data应该更新,但事实并非如此。排序前, data包含以正确顺序显示的数据,排序后, data还没有改变它应该,不是吗? pos我不认为它应该改变也不 cxcy因为他们依赖于 xSpark/ ySparkpos .
var sparkSvg = d3.select('#sparkline')
.append('svg')
.on('mousemove', function() { // on mousemove svg sparkline canvas
var mouse = d3.mouse(this); // mouse position [x, y]
var r = d3.select(this).attr('data-r'); // number of line
var data = d3.select(this).select('path').data(); // array containing all the data values of that line

var element = document.getElementById('data-path-' + r); // get the right path
var pos = get_data_on_line(data, mouse);
d3.selectAll('.data-svg').selectAll('circle').remove(); // remove old circles

// add new circle
d3.select('#data-svg-' + r)
.append('circle')
.attr('r', 3)
.style('stroke', 'red')
.attr('fill', 'red')
.attr('cx', xSpark(pos[1]))
.attr('cy', ySpark(pos[0]));
})
结论
总之,我不明白应该修改代码的哪一点以及如何修改。
有谁知道如何帮助我?
编辑 1
Mark 的回答解决了用户将鼠标悬停在文件映射矩形上的问题。
但是当用户将鼠标悬停在迷你图上时,红色圆圈的位置不正确。
我希望这张图片可以澄清问题所在。
enter image description here
我将鼠标悬停在与意大利相关的迷你图上,圆圈显示的不是在线而是上方。
此外,数据似乎混淆了。
编辑 2
我测试代码 here (马克的更新代码)。
我修改了代码添加了一些 console.log(d)当用户单击行和列标签时:
  var rowLabels = svg.append('g')
.attr('class', 'rowLabels')
.selectAll('.rowLabels')
.data(regionsName)
.enter().append('text')
.text(function(d) {
return d;
})
.attr('x', 0)
.attr('y', function(d, i) {
return i * cellSize;
})
.attr('transform', function(d, i) {
return 'translate(-3, 11)';
})
.attr('class', 'rowLabel mono')
.attr('id', function(d) {
return 'rowLabel_' + regionsName.indexOf(d);
})
.attr('label-r', function(d) {
return regionsName.indexOf(d);
})
.attr('font-weight', 'normal')
.style('text-anchor', 'end')
.on('click', function(d, i) {
console.log(d); // <-- ADDDED
rowSortOrder = !rowSortOrder;
sortByValues('r', i, rowSortOrder);
});

// year labels
var colLabels = svg.append('g')
.attr('class', 'colLabels')
.selectAll('.colLabels')
.data(yearsName)
.enter().append('text')
.text(function(d) {
return d;
})
.attr('transform', function(d, i) {
return 'translate(' + (i * cellSize) + ', 2) rotate(-65)';
})
.attr('class', 'colLabel mono')
.attr('id', function(d) {
return 'colLabel_' + yearsName.indexOf(d);
})
.attr('label-c', function(d) {
return yearsName.indexOf(d);
})
.attr('font-weight', 'normal')
.style('text-anchor', 'left')
.attr('dx', '.8em')
.attr('dy', '.5em')
.on('click', function(d, i) {
console.log(d); // <-- ADDDED
colSortOrder = !colSortOrder;
sortByValues('c', i, colSortOrder);
});
错误示例 :当用户点击德国,然后是 2000 年,然后是 2002 年,然后是 2005 年,然后是 2003 年,最后是意大利,结果如下:
enter image description here
如您所见,迷你图和热图不正确,因为迷你图与 Italy 相关联有缺失的数据,实际上它没有。
编辑 3
我创建了这个 gif,显示了问题所在:
enter image description here
最初,德国有两个未知值(与 2000 年和 2001 年相关)。相应的迷你图是正确的。
当您点击 Germany ,数据按降序排序,迷你图仍然正确。
然后点击年份 2002并且数据按降序排序,然后按正确的顺序重新定位行。并且迷你图是正确的。
然后点击 2005 ,数据已排序且迷你图正确。
然后点击 2003一切又是正确的。
最后点击 Italy并且图表不再正确。德国有两个缺失数据,但从对应的迷你图中,没有突出显示。相反,这两个缺失的数据位于意大利的迷你图上。

最佳答案

这是一个新颖而简洁的可视化概念。如果我理解正确,无论排序如何,我们都需要在矩形和迷你图、鼠标悬停和工具提示之间完全对齐。对于我的回答,我将使用您首先链接到的 plunkr(不是 Mark 的版本)。如果我正确理解了这个问题,那么有五个问题需要解决:

  • 垂直排序会删除鼠标悬停中使用的数据

  • 首先,在垂直排序您的 svg 迷你图时,您正在分配新数据 - 这些会覆盖路径的子数据,这就是为什么一旦垂直排序鼠标悬停在迷你图上时不起作用(圆圈拥抱每个 svg 的顶部)。例如,请参阅此简化示例:

    var div = d3.select("body").append("div");
    div.append("p").datum("hello").text(function(d) { return d; });
    div.datum("new datum").select("p").text(function(d) { return d; });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>


    这打破了从路径数据中获取信息的代码部分 get_data_on_line() , 而不是所有点的数组,您现在拥有路径的索引。

    这是一个挑战,这可以通过不使用 forEach 循环来附加 svg 而是使用适当的输入/更新/退出循环来缓解,并为此指定更多的数据而不仅仅是行本身的数组(特别是,如果索引包含在数据中,这会容易得多)。

    话虽如此,在不大量修改代码的情况下执行此操作的最简单方法是将其替换为:
    var sortedSVG = d3.selectAll(".data-svg")
    .datum(function(d){
    return sorted.indexOf(+this.dataset.r)})
    .sort(function(a,b){
    return d3.ascending(a,b)
    });

    与:
      sortedVertical.forEach(function(d) {
    d3.select("#data-svg-"+d).raise();
    })

    这将按所需顺序对 SVG 进行排序,并且不会更改 SVG 的数据或路径。

    我已将垂直和水平顺序拆分为两个独立的变量,更多的是在第二个变量中
  • 每个矩形的鼠标悬停使用固定的列/x 值

  • 在矩形鼠标悬停功能的迷你图上设置圆的坐标时,您使用固定值:
     .attr('cx', xSpark(idc))
    idc不会变,比例也不会变。因此,无论矩形重新排序如何,每个矩形都将继续突出显示 Spark 图的同一部分。为了解决这个问题,我们需要保留索引的水平顺序。我用了 sorted变量,但给它一个范围,以便鼠标悬停函数和排序函数都可以访问它:
    var sorted = [0,1,2,3,4,5]; // base ordering

    然后我可以设置矩形鼠标悬停以获得迷你图上的正确列:
     .attr('cx', xSpark(sorted.indexOf(+idc))) 

    确保删除 sorted 的定义在排序功能中。
    因此,这也需要使用两个变量,一个用于水平排序,另一个用于垂直排序,因为我们需要鼠标悬停时的水平排序,而不仅仅是在排序函数中
  • 垂直排序时,您正在移动节点,但不要考虑它

  • 通过垂直排序节点,您可以在水平排序时打破路径所需的排序:
    d3.selectAll('.sparkline-path')

    这将按照它们在 DOM 中出现的顺序选择元素 - 但由于用户可能已经通过排序修改了这个顺序,当使用上述选择的索引选择矩形时,索引不再引用正确的数据:
    d3.selectAll('.sparkline-path')
    .attr('d', function(d, k) {
    var arr = [];
    var sel = d3.selectAll('rect[data-r=\'' + (index) + '\']')
    ....

    相反,让我们将其修改为:
    .attr('d', function(d, k) {
    var index = d3.select(this).attr("id").split("-")[2]; // get the original index
    var arr = [];
    var sel = d3.selectAll('rect[data-r=\'' + index + '\']')

    索引来自 SVG 的 id 属性,它让我们可以使用正确的数据——如果索引来自 SVG 排序后的顺序,我们就会遇到问题。
  • 即使路径发生变化,迷你图路径的基准也保持不变。

  • 基准在更新路径时保持不变,但基准用于计算要突出显示的正方形以及如何放置圆。每次修改时,我们都需要更新迷你图的数据:
    d3.select(this).datum(result);
  • 需要根据排序数据更新工具提示位置

  • 为了使工具提示正确对齐,我们需要考虑我们所做的重新排序:

    而不是:
    if(rect_r == r && rect_c == pos[1] ) {

    确保在考虑订购后比较每个的相对位置:
    if(rect_r == r && sorted.indexOf(+rect_c) == pos[1] ) {  

    总的来说,根据我的统计,这在大约 11 个地方更改了代码(包括一些仅传播上述更改的更改)。我创建了一个更新的 plunkr: http://plnkr.co/edit/Bgbp7swTs98CMDFkSss3?p=preview

    每次更改都清楚地标明旧代码已注释掉,新代码放置在下方。

    不过,我将再次强调,使用输入循环输入路径和 SVG(或者, g s)具有更多描述性数据绑定(bind)将允许更容易的排序、更新和最可能更容易的调试.输入循环似乎适用于矩形,但我不确定为什么路径的方法不同。此 answer想到

    关于d3.js - 当用户更改数据的顺序时在迷你图上放置一个圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49982686/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com