无法改变使用networkD3的forceNetwork创建的网络图中的linkDistance

时间:2015-05-25 21:55:40

标签: r networkd3

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

2 个答案:

答案 0 :(得分:3)

networkD3包非常棒!!

经过详尽的调查后,我追踪了错误:networkD3生成的HTML / CSS / JavaScript代码似乎依赖d3jshttps://github.com/mbostock/d3/blob/master/d3.js提供{{1}文件是生成的Web代码的核心。 d3.min.js内部d3.min.js功能已在linkDistance内编码,并且存在错误。

不幸的是,正如文件名所示,JavaScript已缩小,但您可以从d3js网站访问非缩小来源,特别是在What is the difference between a function expression vs declaration in JavaScript?

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

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

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

要重复,x字符串。这意味着,{630}正在检查,typeof(x)将返回"string" "function"。因此,将调用三元的第二个替代方法+x,这是number的JavaScript风格强制,这将导致NaN。因此,NaN通过所有链接距离和坐标传播,一切都得到f *!%ed。

可以通过将其更改为:

来解决此问题
linkDistance = typeof x === "string" ? eval('('+x+')') : +x;

显然我已将"function"更改为"string",但我还必须添加eval()调用以实际从字符串中提取函数定义,以便将来使用的所有代码{ {1}}会起作用,因为它都假定它是一个函数,而不是一个字符串。最后,我不得不用括号连接以确保函数定义被表达化,否则,如果你使用linkDistance作为代码字符串的前导标记(你做了,他们在function中做了)文档,这是最明智的事情),然后它将被视为一个函数语句,这意味着它不会被解析为一个实际的表达式语句,networkD3调用将返回{{ 1}},当代码最终尝试在算术表达式中使用eval()值时,您最终得到undefined,从而导致相同的错误。 (请参阅https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/https://developer.apple.com/library/mac/documentation/AppKit/Reference/NSAccessibility_Protocol_Reference/index.html#//apple_ref/c/data/NSAccessibilityFocusedUIElementChangedNotification了解有关此区别的几个好消息来源,并且可能还有其他一百万个来源。)

我已经在我的机器上测试了上述修复程序,但它确实有效。我想这应该被报告为NaN人的错误,但我觉得我在这里做了足够多的工作而且不会感到困扰。请使用我的帖子作为参考,随时向他们报告。

答案 1 :(得分: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;', '}'))