Визуализация статических и динамических сетей на R, часть 7, последняя

от автора

В первой части:

  • визуализация сетей: зачем? каким образом?
  • параметры визуализации
  • best practices — эстетика и производительность
  • форматы данных и подготовка
  • описание наборов данных, которые используются в примерах
  • начало работы с igraph

Во второй части: цвета и шрифты в графиках R.

В третьей части: параметры графов, вершин и ребер.

В четвертой части: размещения сети.

В пятой части: акцентирование свойств сети, вершин, ребер, путей.

В шестой части: интерактивная визуализация сетей, другие способы представления сети.

В этой части: анимированная визуализация сетей, эволюция сети во времени.

Интерактивная и анимированная визуализация сети

Интерактивные трехмерные сети в R

Сейчас все легче экспортировать графики R в html/javascript. Есть много библиотек, таких как rcharts и htmlwidgets, которые пригодятся при создании веб-графиков непосредственно из R. Мы посмотрим на библиотеку networkD3, которая, как видно из названия, создает интерактивные визуализации сетей с помощью javascript библиотеки D3.

Следует понимать, что визуализации, созданные с помощью networkD3, наиболее полезны как отправная точка для дальнейшей работы. Если вы немного знаете javascript, можно их использовать как первый шаг и изменять до получения желаемого результата.

Если у вас нет библиотеки networkD3, установите ее:

install.packages("networkD3") 

Данные, которая использует эта библиотека — стандартный список ребер с парой небольших изменений. Для того, чтобы все заработало, нужно, чтобы идентификаторы вершин были числовыми и начинались с нуля. Легкий способ добиться этого — превратить наши буквенные идентификаторы в факторную переменную, полученный результат — в число, и обеспечить нумерацию с нуля вычитанием единицы.

library(networkD3)  el <- data.frame(from=as.numeric(factor(links$from))-1,                   to=as.numeric(factor(links$to))-1 ) 

Вершины должны быть в том же порядке, что и колонка-«источник» в связях:

nl <- cbind(idn=factor(nodes$media, levels=nodes$media), nodes)  

Теперь можно создать интерактивное представление. Параметр Group используется для раскрашивания вершин. Nodesize — это не размер вершины, как можно было бы подумать, а номер колонки в данных о вершинах, которую нужно использовать для задания размера. Параметр charge управляет отталкиванием (меньше нуля) или притяжением (больше нуля).

forceNetwork(Links = el, Nodes = nl, Source="from", Target="to",                NodeID = "idn", Group = "type.label",linkWidth = 1,                linkColour = "#afafaf", fontSize=12, zoom=T, legend=T,                Nodesize=6, opacity = 0.8, charge=-300,                 width = 600, height = 400) 

Простая анимация графиков в R

Если вы уже устанавливали ndtv, у вас также должен стоять пакет animation. Если же нет, сейчас самое время его установить — install.packages('animation'). Обратите внимание, этот пакет позволяет без труда создавать разные (не обязательно относящиеся к сетям) анимации в R. Это работает так: создается несколько графиков, которые потом объединяются в GIF.

Подвох здесь следующий: чтобы это заработало, нужен не только пакет R, но и специальная программа ImageMagick.

library(animation)  library(igraph)  ani.options("convert") # Убедитесь, что пакет знает, где находится ImageMagick # Если не находит, укажите правильный путь в вашей системе. ani.options(convert="C:/Program Files/ImageMagick-6.8.8-Q16/convert.exe")  

Теперь мы создадим 4 графика сети (те же, что и раньше), только в этот раз внутри команды saveGIF. Интервал анимации устанавливается параметром interval, параметр movie.name устанавливает название gif-файла.

l <- layout.fruchterman.reingold(net)  saveGIF( {  col <- rep("grey40", vcount(net))             plot(net, vertex.color=col, layout=l)                          step.1 <- V(net)[media=="Wall Street Journal"]             col[step.1] <- "#ff5100"             plot(net, vertex.color=col, layout=l)                          step.2 <- unlist(neighborhood(net, 1, step.1, mode="out"))             col[setdiff(step.2, step.1)] <- "#ff9d00"             plot(net, vertex.color=col, layout=l)                           step.3 <- unlist(neighborhood(net, 2, step.1, mode="out"))             col[setdiff(step.3, step.2)] <- "#FFDD1F"             plot(net, vertex.color=col, layout=l)  },           interval = .8, movie.name="network_animation.gif" )    detach(package:igraph)  detach(package:animation 

Интерактивные сети с ndtv-d3

Интерактивные графики статических сетей

В этом разделе мы создадим более сложные визуализации с пакетом ndtv. Для создания анимаций не нужно дополнительное ПО. Если же вы хотите сохранять анимации как видео-файлы (посмотрите ?saveVideo), вам понадобится видео-конвертер FFmpeg. Чтобы узнать, какой инсталлятор подходит для вашей ОС, выполните ?install.ffmpeg. Для того, чтобы использовать все доступные расположения, вам также понадобится Java.

install.packages("ndtv", dependencies=T) 

Поскольку этот пакет является часть Statnet, он будет принимать объекты из пакета network, как тот, что мы создавали раньше.

library(ndtv) net3  

Большинство параметров имеют интуитивно понятные названия (bg — цвет фона графика). Два новых параметра, которые раньше не использовались — vertex.tooltip и edge.tooltip. Они содержат информацию, которую можно увидеть, наведя курсор мыши на элемент сети. Обратите внимание, параметры для всплывающих подсказок принимают теги html — например, используем тег разрыва строки — <br>. Параметр launchBrowser указывает R открыть получившийся файл с визуализацией (filename) в браузере.

render.d3movie(net3, usearrows = F, displaylabels = F, bg="#111111",         vertex.border="#ffffff", vertex.col =  net3 %v% "col",        vertex.cex = (net3 %v% "audience.size")/8,         edge.lwd = (net3 %e% "weight")/3, edge.col = '#55555599',        vertex.tooltip = paste("<b>Name:</b>", (net3 %v% 'media') , "<br>",                               "<b>Type:</b>", (net3 %v% 'type.label')),        edge.tooltip = paste("<b>Edge type:</b>", (net3 %e% 'type'), "<br>",                              "<b>Edge weight:</b>", (net3 %e% "weight" ) ),        launchBrowser=F, filename="Media-Network.html", output.mode='inline')  

Анимация эволюции сети

Анимированные визуализации — хороший способ показать эволюцию во времени небольшой или среднего размера сети. На данный момент, ndtv — лучший пакет R, предназначенный для этой цели — особенно после того, как недавно была добавлена возможность трехмерной визуализации.

Для того, чтобы работать с анимацией сети в ndtv, нужно понимать динамический формат сети Statnet, реализованный в пакете networkDynamic. Давайте посмотрим на один из наборов данных, включенный в пакет как пример:

data(short.stergm.sim) short.stergm.sim  head(as.data.frame(short.stergm.sim)) 

##   onset terminus tail head onset.censored ## 1     0        1    3    5          FALSE ## 2    10       20    3    5          FALSE ## 3     0       25    3    6          FALSE ## 4     0        1    3    9          FALSE ## 5     2       25    3    9          FALSE ## 6     0        4    3   11          FALSE 

##   terminus.censored duration edge.id ## 1             FALSE        1       1 ## 2             FALSE       10       1 ## 3             FALSE       25       2 ## 4             FALSE        1       3 ## 5             FALSE       23       3 ## 6             FALSE        4       4 

Здесь мы видим список ребер. Каждое ребро исходит из вершины, идентификатор которой находится в колонке tail, и входит в вершину с идентификатором в колонке head. Ребро существует от временной отметки onset до временной отметки terminus. Onset и terminus, помеченные censored, означают начало и конец наблюдения за сетью, а не фактическое образование и исчезновение связей.

Можно легко построить сеть, не принимая во внимание ее временную составляющую (объединив все когда-либо представленные вершины и ребра):

plot(short.stergm.sim)  

Построим сеть в момент времени 1:

plot( network.extract(short.stergm.sim, at=1) ) 

Построим вершины и ребра, активные с первого по пятый момент времени:

plot( network.extract(short.stergm.sim, onset=1, terminus=5, rule="all") ) 

Построим вершины и ребра, активные с первого по десятый момент времени:

plot( network.extract(short.stergm.sim, onset=1, terminus=10, rule="any") )  

Давайте сделаем короткую трехмерную анимацию сети из примера:

render.d3movie(short.stergm.sim,displaylabels=TRUE)  

Теперь мы готовы создавать и анимировать свою собственную динамическую сеть. Объект-динамическую сеть можно получить несколькими способами: из набора сетей / матриц, представляющих разные моменты времени, из матриц / наборов данных со списками вершин и ребер, где указано, когда они активны или когда меняют состояние. Больше информации доступно в ?networkDynamic.

Добавим временной компонент в наш пример со средствами массовой информации. Код ниже берет временной интервал от 0 до 50 и делает активными вершины сети все это время. Ребра появляются одно за другим, каждое активно с момента появления до 50-го момента времени. Создадим такую сеть с помощью networkDynamic, время для вершин — node.spelss, для ребер — edge.spells.

vs <- data.frame(onset=0, terminus=50, vertex.id=1:17) es <- data.frame(onset=1:49, terminus=50,                   head=as.matrix(net3, matrix.type="edgelist")[,1],                  tail=as.matrix(net3, matrix.type="edgelist")[,2])  net3.dyn <- networkDynamic(base.net=net3, edge.spells=es, vertex.spells=vs) 

Если просто пытаться построить networkDynamic-сеть, получится комбинированная сеть за весь период наблюдения, т.е. исходный пример со средствами массовой информации.

plot(net3.dyn, vertex.cex=(net3 %v% "audience.size")/7, vertex.col="col") 

Один из способов показать эволюцию сети во времени — статические картинки для разных моментов времени. Хотя можно генерировать их по одной, как мы делали выше, ndtv предлагает более легкий способ. Команда для этого — filmstrip. Как и в функции par(), управляющей параметрами графиков R, здесь mfrow устанавливает количество строк и столбцов в таблице на несколько графиков.

filmstrip(net3.dyn, displaylabels=F, mfrow=c(1, 5),           slice.par=list(start=0, end=49, interval=10,                           aggregate.dur=10, rule='any')) 

Можно рассчитать заранее координаты анимации (в противном случае они считаются в момент создания анимации). Здесь animation.mode — алгоритм расположения — один из «kamadakawai», «MDSJ», «Graphviz» и «useAttribute» (координаты, заданные пользователем).

compute.animation(net3.dyn, animation.mode = "kamadakawai",                   slice.par=list(start=0, end=50, interval=1,                           aggregate.dur=1, rule='any'))  render.d3movie(net3.dyn, usearrows = F,         displaylabels = F, label=net3 %v% "media",        bg="#ffffff", vertex.border="#333333",        vertex.cex = degree(net3)/2,          vertex.col = net3.dyn %v% "col",        edge.lwd = (net3.dyn %e% "weight")/3,         edge.col = '#55555599',        vertex.tooltip = paste("<b>Name:</b>", (net3.dyn %v% "media") , "<br>",                               "<b>Type:</b>", (net3.dyn %v% "type.label")),        edge.tooltip = paste("<b>Edge type:</b>", (net3.dyn %e% "type"), "<br>",                              "<b>Edge weight:</b>", (net3.dyn %e% "weight" ) ),        launchBrowser=T, filename="Media-Network-Dynamic.html",        render.par=list(tween.frames = 30, show.time = F),        plot.par=list(mar=c(0,0,0,0)), output.mode='inline' ) 

В дополнение к динамическим вершинам и ребрам ndtv принимает динамические параметры. Можно было их добавить в наборы данных es и vs выше. Более того, функция построения может применять специальные параметры и создавать динамические аргументы непосредственно в процессе. Например, function(slice) { какие-то вычисления со slice } произведет действия в текущем временном срезе, позволяя тем самым динамически изменять параметры. Обратите внимание на размер вершин ниже:

compute.animation(net3.dyn, animation.mode = "kamadakawai",                   slice.par=list(start=0, end=50, interval=4,                           aggregate.dur=1, rule='any'))  render.d3movie(net3.dyn, usearrows = F,         displaylabels = F, label=net3 %v% "media",        bg="#000000", vertex.border="#dddddd",        vertex.cex = function(slice){ degree(slice)/2.5 },          vertex.col = net3.dyn %v% "col",        edge.lwd = (net3.dyn %e% "weight")/3,         edge.col = '#55555599',         vertex.tooltip = paste("<b>Name:</b>", (net3.dyn %v% "media") , "<br>",                               "<b>Type:</b>", (net3.dyn %v% "type.label")),        edge.tooltip = paste("<b>Edge type:</b>", (net3.dyn %e% "type"), "<br>",                              "<b>Edge weight:</b>", (net3.dyn %e% "weight" ) ),        launchBrowser=T, filename="Media-Network-even-more-Dynamic.html",        render.par=list(tween.frames = 15, show.time = F), output.mode='inline') 

ссылка на оригинал статьи http://habrahabr.ru/post/268979/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *