在for循环中优化add_trace()? [英] Optimizing add_trace() in a for loop?

查看:175
本文介绍了在for循环中优化add_trace()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 for 循环中使用 add_trace()函数在plotly的scatter3d模式下为3d网络图创建线.每个add_trace在网络中的两个节点之间绘制一条单独的线.该方法有效,但是在循环数很大的情况下,单个循环的速度似乎正在迅速减慢.

I'm using the add_trace() function in a for loop to create lines for a 3d network graph in plotly's scatter3d mode. Each add_trace draws an individual line between two nodes in the network. The method is working, but with large number of loops, the speed of the individual loops seems to be slowing down very quickly.

示例数据可在此处下载: https://gist.github.com/pravj/9168fe52823c1702a07b

Example data can be downloaded here: https://gist.github.com/pravj/9168fe52823c1702a07b

library(igraph)
library(plotly)

G <- read.graph("karate.gml", format = c("gml"))
L <- layout.circle(G)

vs <- V(G)
es <- as.data.frame(get.edgelist(G))

Nv <- length(vs)
Ne <- length(es[1]$V1)

Xn <- L[,1]
Yn <- L[,2]

network <- plot_ly(type = "scatter3d", x = Xn, y = Yn, z = rep(0, Ne), mode = "markers", text = vs$label, hoverinfo = "text", showlegend = F)

for(i in 1:Ne) {
  v0 <- es[i,]$V1
  v1 <- es[i,]$V2

  x0 <-  Xn[v0]
  y0 <-  Yn[v0]
  x1 <-  Xn[v1]
  y1 <-  Yn[v1]

  df <-  data.frame(x = c(x0, x1), y = c(y0, y1), z = c(0, 0))
  network <- add_trace(network, data = df, x = x, y = y, z = z, type = "scatter3d", mode = "lines", showlegend = F, 
                       marker = list(color = '#030303'), line = list(width = 0.5))
}

此示例相当快,但是当我包含几百条或更多条边时,各个循环的执行将开始显着减慢速度.我尝试了不同的优化方法(矢量化等),但似乎无法解决add_trace函数本身的缓慢问题.

This example is fairly quick, but when I include a few hundred edges or more, the execution of the individual loops start to slow down radically. I tried different optimization methods (vectorisation etc), but there seems to be no working around the slowness of the add_trace function itself.

有什么建议吗?

推荐答案

在plotly中添加许多线段的最有效方法不是将每个线段作为单独的迹线,而是仅使用包含所有线段的单个迹线.您可以通过构造一个数据帧来实现,该数据帧具有要连接的每个节点的x,y坐标,并在每个线段之间散布着NA.然后使用connectgaps=FALSE将迹线分成每个NA的单独段.您可以在此答案中看到适用于意大利面条图的该方法的另一个示例.

The most efficient way to add many line segments in plotly is not as a separate trace each, but to use only a single trace that contains all the line segments. You can do this by constructing a data frame with the x,y coordinates of each node to be connected, interspersed with NA's between each line segment. Then use connectgaps=FALSE to break the trace into separate segments at each NA. You can see another example of this approach, applied to spaghetti plots in this answer.

es$breaks <- NA
lines <- data.frame(node=as.vector(t(es)), x=NA, y=NA, z=0)
lines[which(!is.na(lines$node)),]$x <- Xn[lines[which(!is.na(lines$node)),]$node]
lines[which(!is.na(lines$node)),]$y <- Yn[lines[which(!is.na(lines$node)),]$node]

network <- plot_ly(type = "scatter3d", x = Xn, y = Yn, z = rep(0, Ne), 
                   mode = "markers", text = vs$label, hoverinfo = "text", 
                   showlegend = F) %>% 
  add_trace(data=lines, x=x, y=y, z=z, showlegend = FALSE,
                      type = 'scatter3d', mode = 'lines+markers',
                      marker = list(color = '#030303'), line = list(width = 0.5),
                      connectgaps=FALSE)

该问题的可重复数据

为方便起见,以下是此问题的数据. OP需要从github下载.gml文件,并安装library(igraph)来将数据处理到其中.

For convenience, here are the data for this question. The OP required downloading a .gml file from github, and installing library(igraph) to process the data into these.

es <- structure(list(
  V1 = c(1, 1, 2, 1, 2, 3, 1, 1, 1, 5, 6, 1, 2, 3, 4, 1, 3, 3, 1, 5, 6, 1, 1, 4, 1, 2, 3, 4, 6, 7, 1, 2, 1, 2, 
    1, 2, 24, 25, 3, 24, 25, 3, 24, 27, 2, 9, 1, 25, 26, 29, 3, 9, 15, 16, 19, 21, 23, 24, 30, 31, 32, 9, 10, 14, 15, 16, 19, 20, 
    21, 23, 24, 27, 28, 29, 30, 31, 32, 33), 
  V2 = c(2, 3, 3, 4, 4, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 11, 11, 11, 12, 13, 13, 
    14, 14, 14, 14, 17, 17, 18, 18, 20, 20, 22, 22, 26, 26, 28, 28, 28, 29, 30, 30, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 
    33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34)), 
  .Names = c("V1", "V2"), row.names = c(NA, -78L), class = "data.frame")

theta <- seq(0,2,length.out=35)[1:34]
Xn <- cospi(theta)
Yn <- sinpi(theta)

Nv <- NROW(Xn)
Ne <- NROW(es)
vs <- data.frame(label = as.character(1:Nv))

这篇关于在for循环中优化add_trace()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆