基於R的ndtv、network包實現動態社會網絡可視化

本文所涉及的內容是在做傳染病領域的科研時做的一些探索性的工作,肯定還是有一些不完善的地方,歡迎討論。

本文最終的目的是實現一個社會網絡的動態演變過程,如下圖所示,這是程序最終生成的視頻,導出的一小段GIF。

照慣例推薦幾篇非常好的參考文章,建議均至少通讀一遍:

1. http://statnet.csde.washington.edu/workshops/SUNBELT/current/ndtv/ndtv_workshop.html

2. Network visualization with R,PolNet 2018 Workshop, Washington, DC 

3. R的ndtv包、networkDynamic包幫助文檔

我的數據裏有30萬個獨立的社會網絡,最大的一個3000多人,我的R語言非常小白,所以用java寫了一個工具,實現的功能是用戶隨便輸入一個community的編號即可,視頻就自動生成了,不用敲其他任何代碼,在這裏我把R的代碼貼上,有些中間數據是用java生成的,我都會標出來。

library(network)
library(ndtv)

nodes <- read.csv("F:/HIV & Drug analysis/Social network/data/34499/nodes.csv", header=T, as.is=T)
edges <- read.csv("F:/HIV & Drug analysis/Social network/data/34499/edges.csv", header=T, as.is=T)

上述代碼首先讀入節點表和邊表,,節點表就記錄每個節點的ID,邊表記錄源節點、目標節點的ID、關係類型、權重。如下圖:

        

net <- network(edges, vertex.attr=nodes, matrix.type="edgelist", loops=F, multiple=F, ignore.eval = F)

ns <- data.frame(read.csv("F:/HIV & Drug analysis/Social network/data/34499/ns.csv",header=T, as.is=T))
es <- data.frame(read.csv("F:/HIV & Drug analysis/Social network/data/34499/es.csv",header=T, as.is=T))

上述代碼一個作用是創建一個network對象,另一個就是讀入節點和邊的動態變化數據,ns和es的格式如下:

比如ns文件的第一行的意思就是節點1出現的時刻是85,消失時刻爲178;

es文件的第一行意思就是源節點98,目標節點68的邊,出現時刻爲154,消失時刻爲178。

    

當然上述4個文件你都可以存儲在內存中,不需要保存成文件。繼續往下看:

activate.vertex.attribute(net,'color','black',onset=-Inf,terminus=Inf)
activate.vertex.attribute(net,'color','green',onset=117,terminus=178,v=1)
activate.vertex.attribute(net,'color','green',onset=94,terminus=178,v=2)
activate.vertex.attribute(net,'color','green',onset=80,terminus=178,v=3)
activate.vertex.attribute(net,'color','green',onset=162,terminus=178,v=14)
###這裏記錄你需要動態變更顏色的節點

上述代碼記錄你需要變更顏色的節點,注意,第一行的意思是所有節點的初始顏色都是黑色的,從開始到結束。邊的顏色、節點的大小、邊的寬度都可以動態設置,參考文章前面推薦的文獻。

第二行代碼的意思就是編號爲1的節點,從時刻117到時刻178,這期間的顏色設置爲綠色。

net.dyn <- networkDynamic(base.net=net, edge.spells=es, vertex.spells=ns)

上述代碼創建networkDynamic對象,把由靜態數據nodes、edges構建的net對象和動態數據ns、es結合在了一起。

compute.animation(net.dyn, animation.mode = "MDSJ",slice.par=list(start=1, end=178, interval=1, aggregate.dur=1, rule='any'))

上述代碼用來計算每一個時刻的佈局,使用的算法是MDSJ,開始時刻、結束時刻、間隔時間要根據自己數據的情況設置一下。關於佈局算法建議好好看一下我文章開頭推薦的第一篇文章裏介紹的各種佈局算法,再結合自己的數據測試一下。

saveVideo(
render.animation(
net.dyn,
render.par = list(tween.frames = 25, show.time = FALSE, show.stats = NULL, extraPlotCmds=NULL),
#tween.frames應該類似於幀數,越大越平滑
plot.par = list(bg='white'),
ani.options = list(interval=0.02), 
#這裏的interval參數越小,視頻播放越快
render.cache = 'none',
#不緩存在內存中,直接寫入硬盤,數據量大建議配置成none
verbose=TRUE,
usearrows=FALSE,
#是否使用有向邊
vertex.col='color',
#重要!!指定節點的顏色是名爲color的列
vertex.cex = 0.5,
#節點大小
edge.lwd = 1,
#邊的寬度
edge.col='black',
#邊的顏色
displaylabels=FALSE),
video.name="F:/HIV & Drug analysis/Social network/video/Network-34499-Dynamic.mp4",
ani.width=1000,ani.height=1000,
#畫布的長和寬,建議配置在2000以下,2000以上有些播放器播放時會報錯
other.opts="-b:v 5000k")

暫時結束,利用tsna應該可以在這個過程中做一些動態的網絡分析,抽取一些信息出來,後邊再看吧。文章最後附上整個源代碼:

library(network)
library(ndtv)

nodes <- read.csv("F:/HIV & Drug analysis/Social network/data/34499/nodes.csv", header=T, as.is=T)
edges <- read.csv("F:/HIV & Drug analysis/Social network/data/34499/edges.csv", header=T, as.is=T)

net <- network(edges, vertex.attr=nodes, matrix.type="edgelist", loops=F, multiple=F, ignore.eval = F)

ns <- data.frame(read.csv("F:/HIV & Drug analysis/Social network/data/34499/ns.csv",header=T, as.is=T))
es <- data.frame(read.csv("F:/HIV & Drug analysis/Social network/data/34499/es.csv",header=T, as.is=T))

activate.vertex.attribute(net,'color','black',onset=-Inf,terminus=Inf)
activate.vertex.attribute(net,'color','green',onset=117,terminus=178,v=1)
activate.vertex.attribute(net,'color','green',onset=94,terminus=178,v=2)
activate.vertex.attribute(net,'color','green',onset=80,terminus=178,v=3)
activate.vertex.attribute(net,'color','green',onset=162,terminus=178,v=14)
activate.vertex.attribute(net,'color','green',onset=145,terminus=178,v=15)
activate.vertex.attribute(net,'color','green',onset=98,terminus=178,v=16)
activate.vertex.attribute(net,'color','green',onset=60,terminus=178,v=21)
activate.vertex.attribute(net,'color','green',onset=71,terminus=178,v=22)
activate.vertex.attribute(net,'color','green',onset=69,terminus=178,v=30)
activate.vertex.attribute(net,'color','green',onset=69,terminus=178,v=32)
activate.vertex.attribute(net,'color','green',onset=140,terminus=178,v=33)
activate.vertex.attribute(net,'color','green',onset=119,terminus=178,v=34)
activate.vertex.attribute(net,'color','green',onset=90,terminus=178,v=35)
activate.vertex.attribute(net,'color','green',onset=92,terminus=178,v=37)
activate.vertex.attribute(net,'color','green',onset=94,terminus=178,v=38)
activate.vertex.attribute(net,'color','green',onset=94,terminus=178,v=39)
activate.vertex.attribute(net,'color','green',onset=78,terminus=178,v=40)
activate.vertex.attribute(net,'color','green',onset=78,terminus=178,v=41)
activate.vertex.attribute(net,'color','green',onset=98,terminus=178,v=42)
activate.vertex.attribute(net,'color','green',onset=98,terminus=178,v=43)
activate.vertex.attribute(net,'color','green',onset=149,terminus=178,v=44)
activate.vertex.attribute(net,'color','green',onset=162,terminus=178,v=45)
activate.vertex.attribute(net,'color','green',onset=21,terminus=178,v=57)
activate.vertex.attribute(net,'color','green',onset=39,terminus=178,v=58)
activate.vertex.attribute(net,'color','green',onset=44,terminus=178,v=59)
activate.vertex.attribute(net,'color','green',onset=62,terminus=178,v=60)
activate.vertex.attribute(net,'color','green',onset=72,terminus=178,v=62)
activate.vertex.attribute(net,'color','green',onset=100,terminus=178,v=66)
activate.vertex.attribute(net,'color','green',onset=111,terminus=178,v=67)
activate.vertex.attribute(net,'color','green',onset=155,terminus=178,v=68)
activate.vertex.attribute(net,'color','green',onset=108,terminus=178,v=74)
activate.vertex.attribute(net,'color','green',onset=126,terminus=178,v=80)
activate.vertex.attribute(net,'color','green',onset=110,terminus=178,v=84)
activate.vertex.attribute(net,'color','green',onset=37,terminus=178,v=88)
activate.vertex.attribute(net,'color','green',onset=25,terminus=178,v=89)
activate.vertex.attribute(net,'color','green',onset=23,terminus=178,v=90)
activate.vertex.attribute(net,'color','green',onset=18,terminus=178,v=91)
activate.vertex.attribute(net,'color','green',onset=16,terminus=178,v=92)
activate.vertex.attribute(net,'color','green',onset=50,terminus=178,v=93)
activate.vertex.attribute(net,'color','green',onset=30,terminus=178,v=97)
activate.vertex.attribute(net,'color','green',onset=27,terminus=178,v=98)
activate.vertex.attribute(net,'color','green',onset=16,terminus=178,v=99)

net.dyn <- networkDynamic(base.net=net, edge.spells=es, vertex.spells=ns)

compute.animation(net.dyn, animation.mode = "MDSJ",slice.par=list(start=1, end=178, interval=1, aggregate.dur=1, rule='any'))

saveVideo(
render.animation(
net.dyn,
render.par = list(tween.frames = 25, show.time = FALSE, show.stats = NULL, extraPlotCmds=NULL),
plot.par = list(bg='white'),
ani.options = list(interval=0.02), 
render.cache = 'none',
verbose=TRUE,
usearrows=FALSE,
vertex.col='color',
vertex.cex = 0.5,
edge.lwd = 1,
edge.col='black',
displaylabels=FALSE),
video.name="F:/HIV & Drug analysis/Social network/video/Network-34499-Dynamic.mp4",
ani.width=1000,ani.height=1000,
other.opts="-b:v 5000k")

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章