1

我正在尝试使用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 中使用 R 版本 3.1.3 for Windows,包 networkD3 版本 0.1.2.2。(我最初使用 CRAN 的 networkD3 版本 0.1.2.1 遇到了这个问题。所以我从 GitHub 安装了最新版本,并且遇到了同样的问题。)

4

2 回答 2

3

networkD3太棒了!!

经过详尽的调查,我找到了这个错误:生成的 HTML/CSS/JavaScript 代码networkD3似乎依赖于d3js,它提供了d3.min.js对生成的 Web 代码至关重要的文件。功能是在里面d3.min.js进行linkDistance编码的,而错误就是在那里发生的。

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

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

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

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

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

这可以通过将其更改为:

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

显然我更改"function""string",但我还必须添加一个eval()调用以实际将函数定义从字符串中拉出,以便所有未来的代码都可以使用linkDistance,因为它都假定它是一个函数,而不是一个字符串。最后,我必须用括号连接以确保函数定义被表达,否则,如果你用作function代码字符串的前导标记(你做了,他们在networkD3文档中做了,这是最明智的做法),那么它将被视为一个函数语句,这意味着它不会被解析为一个实际的表达式语句,并且eval()调用将返回undefined,并且您最终会得到NaN代码最终尝试使用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人们,但我觉得我在这里做了足够的工作,不能被打扰。使用我的帖子作为参考,请随时向他们报告。

于 2015-05-26T01:22:55.973 回答
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;', '}'))
于 2015-05-26T13:23:43.297 回答