D3 .merge 函数

Posted

技术标签:

【中文标题】D3 .merge 函数【英文标题】:D3 .merge function 【发布时间】:2018-04-14 11:33:43 【问题描述】:

尽管阅读了无数次 D3 API,但我仍在努力理解 D3 中的合并功能。

API 说:“此方法通常用于在数据连接后合并输入和更新选择。分别修改输入和更新元素后,您可以合并两个选择并在两者上执行操作,而无需重复代码。 "

这是一个在力导向图表中被认为是直接使用它的示例,其中每个刻度都会调用刻度函数:

var simulation = d3.forceSimulation(nodes)
    .force("charge", chargeForce)
    .force("center", centerForce)
    .on("tick", ticked);

    function ticked() 

    var u = d3.select("svg").selectAll("circle").data(nodes)

    u.enter().append("circle").attr("r",5)
        .merge(u) // What is the merge function doing here?
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

    u.exit().remove() // Why is it necessary to remove excess objects w/ the exit selection?

    

我了解数据绑定的工作原理,以及 enter() 和 exit() 选择的工作原理。但是,我以前从未使用过“合并”,我不明白它在这里做什么。如果有人可以逐步简要介绍此功能中发生的事情,那将非常有用。我相信其他人也有类似的问题。

【问题讨论】:

你从哪里得到这个例子的?您应该在 tick 函数中添加元素或重新绑定数据。 很难理解的是,您有 2 个选择并将它们组合成 1 个选择。就像你有 2 个数组,A 和 B。你可以将它们连接成数组 C。 @EricGuan 你说的不正确:merge() 不连接选择。 API 明确声明:“此方法不适用于连接任意选择,但是:如果此选择和指定的其他选择在同一索引处都有(非空)元素,此选择的元素在合并中返回,而另一个选择的元素被忽略。". @GerardoFurtado 我在这里找到了:d3indepth.com/force-layout,为什么这样做没有意义? @HarryCramer 这很容易理解:为什么要重新绑定数据并每秒计算数十次进入和退出选择,如果数据没有改变乙>?这没有道理!我刚刚用替代代码写了一个解释它的答案。 【参考方案1】:

文档很好地解释了该函数的作用,因此它的作用是您不必这样做

u.attr("cx", d => d.x)
 .attr("cy", d => d.y);

u.enter().append("circle").attr("r",5)
        .attr("cx", d => d.x)
        .attr("cy", d => d.y);

您只需拨打attr 一次即可

u.enter().append("circle").attr("r",5)
        .merge(u) // after this point, any updates will apply to both u and u.enter() selections
        .attr("cx", d => d.x)
        .attr("cy", d => d.y)

它将在u-更新选择和u.enter()-输入选择上设置属性cxcy

为什么有必要通过退出选择删除多余的对象?

因为退出选择包含任何额外的 DOM 元素,这些元素未绑定到您传递给 data() 的数组中的元素,所以您可以对退出集合执行任何您需要的操作,例如通过调用 u.exit().style(...) 设置样式等,而不是调用 remove 从 DOM 中删除它们

【讨论】:

【参考方案2】:

这里实际上有两个问题:

    了解merge() 方法; 了解您共享的那段代码;

关于#1,您已经收到了答复。关于#2,这是我的两分钱:该代码确实有意义。

这很容易理解:ticked 函数每秒运行几十次。 如果数据没有改变,你为什么要重新绑定数据并重新分配更新、进入和退出选择每秒数十次? (值得一提的是,那段代码的作者是个不错的程序员,这里发生了一些奇怪的事情……毕竟我们都会犯错误)

ticked 函数只需要计算元素的位置即可。

这是您与ticked 函数链接的相同代码,简化为:

function ticked() 
    u.attr('cx', function(d) 
            return d.x;
        )
        .attr('cy', function(d) 
            return d.y;
        )

这里是运行代码:

var width = 600,
  height = 400;

var colorScale = ['orange', 'lightblue', '#B19CD9'];
var xCenter = [100, 300, 500]

var numNodes = 100;
var nodes = d3.range(numNodes).map(function(d, i) 
  return 
    radius: Math.random() * 25,
    category: i % 3
  
);

var u = d3.select('svg g')
  .selectAll('circle')
  .data(nodes);

var enter = u.enter()
  .append('circle')
  .attr('r', function(d) 
    return d.radius;
  )
  .style('fill', function(d) 
    return colorScale[d.category];
  );

u = enter.merge(u);

u.exit().remove();

var simulation = d3.forceSimulation(nodes)
  .force('charge', d3.forceManyBody().strength(5))
  .force('x', d3.forceX().x(function(d) 
    return xCenter[d.category];
  ))
  .force('collision', d3.forceCollide().radius(function(d) 
    return d.radius;
  ))
  .on('tick', ticked);

function ticked() 
  u.attr('cx', function(d) 
      return d.x;
    )
    .attr('cy', function(d) 
      return d.y;
    )
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="content">
  <svg  >
    <g transform="translate(50, 200)"></g>
  </svg>
</div>

【讨论】:

谢谢 Gerardo,这很有帮助。我很困惑为什么需要重新选择,所以你的澄清很好。当你遇到这样的事情时,你永远不会知道自学。 不用担心。您可以随时向该代码的作者发送电子邮件,询问他为什么这样做。正如我所说,这对我来说没有多大意义。 "勾选的功能只需要设置位置" - 谢谢!【参考方案3】:

鉴于 cmets,我应该提醒读者这个答案可能是错误的。所以请先阅读cmets

TL;DR - 合并将两个节点集合合二为一

var x = d3.selectAll(".node");
var y = d3.selectAll(".link");
var z = x.merge(y);

z 现在包含 x 中的所有元素和 y 中的所有元素。

【讨论】:

那不正确。 x 和 y 将共享索引,因此您最终只会得到两个选择之一。准确地说 z 将只是 x 选择 @40detectives 我在发布之前测试了这段代码,效果很好 我看到@40detectives 描述的行为。 对不起,这个答案肯定是错误的,merge() 是为了结合selectAll()enter() 的结果,从第一个开始填写null 条目。要获得组合选择,您可以:selectAll('.node,.link').

以上是关于D3 .merge 函数的主要内容,如果未能解决你的问题,请参考以下文章

R中使用merge()函数合并数据

R语言merge函数全连接dataframe数据(Full (outer) join)merge函数进行全连接必须将参数all设置为true(all=TRUE)默认merge函数通过公共列名合并数

D3DXMatrixRotationY 函数

r语言 merge函数by.x啥意思

17、pandas的merge合并函数

R语言merge函数连接多个dataframe数据集迭代内连接dataframe数据( iteratively merge data frames in R)默认merge函数通过公共列名合并数据