【问题标题】:Unable to vary linkDistance in network graph created using forceNetwork of networkD3无法改变使用 networkD3 的 forceNetwork 创建的网络图中的 linkDistance
【发布时间】:2015-05-25 21:55:40
【问题描述】:

我正在尝试使用 networkD3 包在 R 中创建一个力导向网络图。一切正常...

devtools::install_github('christophergandrud/networkD3')
library(networkD3)
links2 <- data.frame(
  Source = c(0, 0, 0, 1, 2, 3), 
  Target = c(1, 4, 5, 3, 4, 5), 
  Value = c(1, 9.9, 10, 8.8, 6.6, 7.2))
nodes2 <- data.frame(ID = 0:5, 
  Group = c(1L, 1L, 1L, 2L, 1L, 2L))

# this works
forceNetwork(Links=links2, Nodes=nodes2, 
  Source="Source", Target="Target", Value="Value", 
  NodeID="ID", Group="Group")

... 直到我开始使用 linkDistance 参数。当我将它设置为我想要的,Value 的一个函数时,我得到一个网络图,它由设备左上角的单个节点组成。

# this doesn't work
forceNetwork(Links=links2, Nodes=nodes2, 
  Source="Source", Target="Target", Value="Value", 
  NodeID="ID", Group="Group",
  linkDistance="function(d) { return d.value; }")

如果有任何关于如何改变链接长度的建议,我将不胜感激。

我在 R Studio 版本 0.98.1103 中使用适用于 Windows 的 R 版本 3.1.3,包 networkD3 版本为 0.1.2.2。 (我最初使用 CRAN 的 networkD3 版本 0.1.2.1 遇到问题。所以我从 GitHub 安装了最新版本,并且遇到了同样的问题。)

【问题讨论】:

  • 我将此问题提交给 networkD3,github.com/christophergandrud/networkD3/issues/37。我从@jjallaire那里收到了一个有效的答案!先附加library(htmlwidgets),然后在linkDistance参数中使用JS函数:forceNetwork(Links=links2, Nodes=nodes2, Source="Source", Target="Target", Value="Value", NodeID="ID", Group="Group", linkDistance=JS('function(d) {', 'return d.value;', '}'))

标签: r networkd3


【解决方案1】:

networkD3 包太棒了!!

经过详尽的调查,我找到了这个错误:networkD3 生成的 HTML/CSS/JavaScript 代码似乎依赖于 d3js,它提供了 d3.min.js 文件,该文件是生成的网页代码。 linkDistance 功能是在 d3.min.js 内部编码的,并且在那里发生了错误。

不幸的是,正如文件名所示,JavaScript 已被缩小,但您可以从 d3js 站点访问未缩小的源,特别是在 https://github.com/mbostock/d3/blob/master/d3.js

如果您查看d3.js 的第 6307 行(以及周围的上下文),您会发现:

force.linkDistance = function(x) {
  if (!arguments.length) return linkDistance;
  linkDistance = typeof x === "function" ? x : +x;
  return force;
};

此函数在初始化期间的某个时间点被调用,x 是您最初在 R 调用 forceNetwork() 时提供的 字符串(顺便说一下,该字符串嵌入在 index.html networkD3 作为 JSON 数据生成的文件以及所有其他输入数据)。

重复一遍,x 是一个字符串。这意味着 typeof(x) 将返回 "string"not "function",因为第 6307 行正在检查。因此,将调用三元的第二个替代方案+x,这是对number 的JavaScript 样式强制转换,这将导致NaN。因此,NaN 通过所有链接距离和坐标传播,所有内容都得到 f*!%ed。

这可以通过将其更改为来解决:

linkDistance = typeof x === "string" ? eval('('+x+')') : +x;

显然我将"function" 更改为"string",但我还必须添加一个eval() 调用以实际将函数定义从字符串中拉出,以便将来所有与linkDistance 一起使用的代码都可以工作,因为这一切都假设它是一个函数,而不是一个字符串。最后,我必须用括号连接以确保函数定义被表达,否则,如果您使用 function 作为代码字符串的前导标记(您这样做了,他们在 networkD3 文档中也这样做了,那就是最明智的做法),那么它将被视为一个函数语句,这意味着它不会被解析为一个实际的表达式语句,并且eval()调用将返回undefined,你最终会得到@ 987654359@ 当代码最终尝试在算术表达式中使用undefined 值时,会导致相同的错误。 (请参阅 What is the difference between a function expression vs declaration in JavaScript?https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/ 了解有关此区别的几个很好的来源,并且可能还有一百万个其他来源。)

我已经在我的机器上测试了上述修复,它可以工作。我想这应该作为一个错误报告给d3js 人,但我觉得我在这里已经做了足够的工作,不能被打扰。随时向他们报告,使用我在此处的帖子作为参考。

【讨论】:

  • 我很确定你很棒,这可以作为答案。让我澄清几点。 (1) 你是说,如果不深入研究d3js,我就不能用当前版本的 networkD3 改变链接的长度,对吧? (2) 但是,如果我将d3js 源代码下载到我的PC 并按照您的建议进行修改,那么networkD3 函数forceNetwork 将像宣传的那样工作,对吧?
  • 我刚刚将您建议的更改作为新问题提交:github.com/mbostock/d3/issues/2451
  • @JeanV.Adams (1) 正确。 (2) 正确,尽管我认为这需要修改 networkD3 安装,因为我假设它在其安装中打包了 d3.min.js 的副本。显然,与当前安装相比,您希望问题得到更持久的修复,因此错误报告是最好的选择。
  • 此问题已在 d3jsgithub.com/mbostock/d3/issues/2451“抱歉,但这不是解决问题的正确位置。如果您有一个字符串表示一个函数,而您想评估该字符串以将其转换为代码,您应该在 D3 API 之外进行。” 我已通知 networkD3github.com/christophergandrud/networkD3/issues/37。跨度>
  • 我得到了一个适用于当前 networkD3 和 d3js 的答案(请参阅我对原始帖子的评论)。
【解决方案2】:

如果您希望评估从 R 传递到 JavaScript 的值(即将字符串解析为函数),请将其包含在 htmlwidgets::JS 函数中。例如:

library(htmlwidgets)
forceNetwork(Links=links2, Nodes=nodes2, 
             Source="Source", Target="Target", Value="Value", 
             NodeID="ID", Group="Group",
             linkDistance=JS('function(d) {', 'return d.value;', '}'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多