本文所涉及的内容是在做传染病领域的科研时做的一些探索性的工作,肯定还是有一些不完善的地方,欢迎讨论。
本文最终的目的是实现一个社会网络的动态演变过程,如下图所示,这是程序最终生成的视频,导出的一小段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")