【问题标题】:How to sort nodes in D3 so that connecting paths will be clear?如何对 D3 中的节点进行排序以使连接路径清晰?
【发布时间】:2018-04-13 07:51:15
【问题描述】:


我正在制作一个图表来显示两组之间的关系。
为了说明问题,假设这两组是城市和超级英雄,对于每个城市,我们会显示哪个超级英雄访问过它,反之亦然。

Here is a codepen 我当前的代码。

将鼠标悬停在每个节点上以查看其名称并突出显示它所连接的节点。

如您所见,我在顶部有一行,每个城市都有节点,在底部有一行,每个超级英雄都有节点,两行之间的路径显示了关系:

如您所见,在大多数情况下,路径很长并且经常相互交叉。它使图表在视觉上非常混乱。

我敢肯定,如果我以更智能的方式对城市和/或超级英雄进行排序,图表会更加清晰。
(当前的城市顺序和超级英雄的顺序都没有意义,为了说明这一点,我在加载图表之前对这两个数组进行了洗牌)

cities = _.shuffle(cities);
superheros = _.shuffle(superheros);

我的问题:
我如何对城市和/或英雄进行排序,以使两者之间的联系更加清晰(路径不会那么长,路径不会相互交叉,等等)。
是否有一个众所周知的算法?可能是 D3 中的辅助函数?或者我可能完全使用了错误类型的图表。

【问题讨论】:

    标签: javascript algorithm sorting d3.js data-visualization


    【解决方案1】:

    可以使用其他可视化类型,它们可能会更清楚地显示此信息。我想到了一个网格,但它在视觉上可能不如你目前拥有的那种可视化那么令人兴奋:

    Les Misérables [character] Co-occurance(迈克·博斯托克):

    这种类型的可视化可以很容易地用于显示角色和位置的重叠。网格的镜像不会出现在位置/字符轴上。但是,如果需要节点和链接,我们当然可以使用它。


    解开可视化

    传统上,我会通过进一步纠缠来混淆这种类型的图表。这将涉及在学校测验中过于复杂的those spaghetti style matching questions,以期让老师相信,让我从怀疑中受益比追踪路径更容易。使这些网络在视觉上无法追踪是如此容易,这表明如果您的可视化变得更详细,这可能不是一种理想的风格。但是,为了弥补我之前在制作无法读取的网络方面的罪过,让我们梳理一下我们拥有的东西。

    肯定有一种很好的算法可以计算绘制图表所需的最短路径长度,将孤立的网络彼此分开,并在 x 轴上尽可能靠近地对齐源和目标。尽管这可能会将所有高度连接的节点靠近在一起,导致可视化的中心看起来像一盘意大利面。

    但是,由于我很懒,我宁愿让图表进行某种自我组织。幸运的是,在 d3 中我们有一个力布局。

    让我们保持您的总体布局开始,一排英雄和一排城市。我们可以设置一些力和参数来发挥作用,而不是随机化每个节点的位置并绘制连接线:

    • 修复 y 坐标以便保留行
    • 高度重视链接距离,以便将链接的节点紧密地拉在一起
    • 从节点之间的轻微吸引力开始以允许混合,然后慢慢开始迫使它们分开
    • 随着布局的发展,增加碰撞半径,使节点等距分布

    如果我们正确地做到这一点,我们会发现一个很好的可视化效果,它可以分隔孤立的网络(对于这种类型的可视化来说是必不可少的),并且在大多数情况下保持链接相对较短。

    这是一个使用这种方法的随机输出示例(减半):

    与随机排序节点相比,关系更清晰(除了侥幸的幸运结果),有一些链接似乎延伸得很远,但它们的数量相对有限。孤立的网络在视觉上也是分离的,这从拓扑的角度来看很重要。

    为了比较,这是原始布局的随机加载(我确实出于某种原因更改了节点样式和行顺序,但我手中的啤酒杯说不更正) :

    这是一个特别倒霉的随机抽奖,黑寡妇连接到x轴上的第一个和最后一个位置。

    原始布局中的平均链接比强制布局中的平均链接更水平 - 更多的垂直链接通过减少交叉点的数量同时缩短链接长度来提高清晰度并减少混乱。

    我们可以尝试量化部队布局带来的改进。例如,随机排序(样本大小 = 10)中的平均链接长度(测量为沿 x 轴的源和目标之间的距离)为 521 px,而强制布局排序的平均链接长度为 208 px(样本大小也是 10)。这是每个布局链接长度的直方图:

    我的样本量很小,但模式应该很清楚。

    好的,我已经展示了结果并说明了一般要求,但是演示一下如何。无需深入了解力图的工作原理或编码方式,这里有一个快速演示 bl.ock,下面是我使用的关键参数的快速说明:

    1. 设置模拟的启动属性:

    一旦模拟开始,这些将被修改,但这些是很好的起点:

    var simulation = d3.forceSimulation()
        // set optimal distance to be 1 pixel between source and target:
        .force("link", d3.forceLink().id(function(d) { return d.name; }).distance(1))
        // set the distance at which forces apply to be limited to some distance,
        // make nodes attracted to each other to start:
        .force("charge", d3.forceManyBody().distanceMax(cities.length+1/width).strength(10))
        // try to keep nodes centered:
        .force("center", d3.forceCenter(width / 2, height / 2))
        // slow decay time, increases time to simulation end
        .alphaDecay(0.01);
    
    1. 随着模拟的进行修改力:

    我们想改变一些力,例如随着模拟的结束,吸引力变为排斥力。

    function ticked() {
        var force = this;
        var alpha = force.alpha(); // current alpha
        var padding = 20; // minimum distance from sides of visualization
        var targetSeparation = (width-padding*2)/(cities.length*2) // ideal separation between nodes on x axis.
    
        // if we are late in the simulation, change collide radius to ideal separation
        // also change the charge between nodes to repulsion
        if (alpha < 0.5) {
            force.force( "collide",d3.forceCollide((0.5 - alpha)*2*targetSeparation) )
                 .force("charge", d3.forceManyBody().distanceMax(targetSeparation).strength((0.5 - alpha) * 50))
        }
    
    1. 别忘了用d.fy固定力节点的y坐标

    进一步改进

    所以现在我们很纠结,但我们可以做得更好。为什么将自己限制在 2 行? 3 可能是理想的:

    如果说一个有两种类型的字符要显示,这可能是理想的。幸运的是,每个英雄都有一个恶棍。最好按照自然划分进行分离,例如:女性/男性、前科学家和拥有高级学位的英雄/其他所有人、来自地球/不是来自地球、浣熊/不是浣熊......

    但即使无法按照某个主题进行分离,它仍会进一步解开可视化。基于此,与我这里的第一个示例和this one (shown above) 的唯一变化是我将英雄分开(并为可视化增加了一点高度)。


    如果冷却时间难以忍受(您可以在排序时对单独的节点进行某种缩放),那么您可以在不绘制它的情况下运行模拟 - 仅加载最终版本(或者甚至存储布局以供将来使用,如果它的节点和链接不会改变每个负载)。但是,对于不同的问题,这是不同类型的问题。

    【讨论】:

    • 这是一个不错的答案(尽管它是基于意见的,而且大部分与代码无关!)。 OP explore 还有其他一些不错的 dataviz 替代品。可能应该有一个 "Dataviz SE" 网站...
    • @GerardoFurtado,同意,这是一个让我受益匪浅的偏好问题 - 尽管我会说通常会考虑强制布局比随机化更好地排列数据。我觉得答案将是对非典型示例的使用力的巧妙探索。
    • 我不喜欢这种特定情况下的强制布局,因为您使用它不是为了更好地显示数据,而只是为了改善元素的分布。在我看来,这是对布局的不充分使用,这不是力导向图表的目的。关于这个问题,我还要提到一个和弦图,或者它的 Nadieh Bremmer 版本:visualcinnamon.com/2017/08/d3-loom.html
    • @GerardoFurtado,Nadieh Bremmer 的作品总是很漂亮,看着它我总是很受启发。我同意它较少使用强制布局(排序) - 尽管在改善元素的分布方面它确实更好地显示数据(主观而言) - 但绝对会带来更大/更好的收益完全使用力布局 - 或弦,而不是某种混合力/平行坐标(在我看来,二维网格最清晰,但这更加主观)。
    • 刚刚注意到 dataviz 网站的建议,有一个 UI 交换,似乎可以通过数据交换来补充它和 SO。
    猜你喜欢
    • 2012-11-18
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 2014-03-05
    • 2013-07-26
    • 2019-07-14
    • 1970-01-01
    相关资源
    最近更新 更多