2016-07-03 57 views
2

我使用add_trace()函數在中爲循環在plotly的scatter3d模式下爲3d網絡圖創建線。每個add_trace在網絡中的兩個節點之間繪製一條單獨的線。該方法正在工作,但有大量的循環,單個循環的速度似乎正在很快放緩。在for循環中優化add_trace()?

示例數據可以在這裏下載: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函數本身的緩慢工作。

有什麼建議嗎?

回答

0

以圖表形式添加多個線段的最有效方式不是分別作爲單獨的軌跡,而是僅使用包含所有線段的單個軌跡。您可以通過構建一個數據框來完成這一工作,每個節點的x,y座標都要連接,並在每個線段之間插入NA。然後使用connectgaps=FALSE在每個NA處將軌跡分解爲單獨的段。你可以看到這種方法的另一個例子,適用於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) 

enter image description here

對於這個問題

爲了方便重複性的數據,這裏是這個問題的數據。 OP需要從github下載.gml文件,並安裝庫(igraph)來處理數據。

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)) 
+0

謝謝@dww - 偉大的解決方案! –

+0

@GaborSzalai,你的歡迎。作爲未來的指針,如果你將問題簡化爲一個簡單的例子,你可以幫助人們更有效地回答問題。 'igraph'與這個問題無關,所以最好只提供一些數據(就像我上面所做的那樣)以及重現問題所需的最少量的代碼。看看[這](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example)一些很棒的提示 – dww