Я смотрю, как со временем меняются государственные органы. Планируется использовать пакет ndtv для визуализации изменений. У меня есть список узлов, в котором перечислены идентификаторы вершин, имя агентства, начало узла и конец узла:
nodelist <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist.csv", header=T, stringsAsFactors = F)
и список ребер, показывающий начало и конец ребер:
edgelist <- read.csv("https://github.com/aterhorst/data/raw/master/edgelist.csv", header=T, stringsAsFactors = F)
Я могу довольно легко создать сетевой объект:
nw <- network(edgelist,
vertex.attr = nodelist[,c(1,2)],
vertex.attrnames = c("vertex.id", "agency"),
directed = F)
nd <-networkDynamic(nw,
edge.spells = edgelist[,c(3,4,2,1)],
vertex.spells=nodelist[,c(3,4,1)])
Я могу анимировать сеть с точки зрения ребер, вершин без проблем:
reconcile.vertex.activity(nd, mode = "match.to.edges")
filmstrip(nd,
displaylabels = FALSE,
frames = 5,
slice.par = list(start = 2014, end = 2019, interval = 1, aggregate.dur = 1, rule = 'any'))
render.d3movie(nd,
filename = "~/owncloud/longspine/data/animation.html",
displaylabels = FALSE,
# This slice function makes the labels work
vertex.tooltip = function(slice) {paste("<b>Agency:</b>", (slice %v% "agency"))})
По сути, это показывает, как ребра и вершины появляются и исчезают с течением времени. Затем я хочу определить размер вершин в соответствии с бюджетом агентства. Это меняется из года в год. Как мне это сделать? Онлайн-уроки немного сложны для понимания. В моем примере у нас всего 217 агентств. У каждого будет годовой бюджет (если они существуют в начале, конце в списке узлов). Любые советы или советы будут оценены.
чтобы настроить динамические атрибуты вершин, вы можете использовать функцию activate.vertex.attribute()
, чтобы определить, какие вершины должны иметь какие значения для какой продолжительности. Например, чтобы создать динамический атрибут в вершине 1 с именем «бюджет» со значением 10 000 за период с 2014 по 2015 год:
nd <-activate.vertex.attribute(nd,'budget',
value=10000,
onset=2014,
terminus=2015,
v=1)
Скорее всего, вы захотите сделать это сразу при создании объекта. Если вы настроите свой nodelist
так, чтобы он имел одну строку на вершину в год, вы должны иметь возможность использовать параметр create.TEAs
конструктора networkDynamic()
для инициализации объекта с помощью заклинаний активности атрибутов, которые вам нужны. Итак, если ваш nodelist
выглядит так:
vertex.id agency portfolio onset terminus budget
1 1 AAF Company FALSE 2014-07-01 2015-07-01 10000
2 1 AAF Company FALSE 2015-07-01 2016-07-01 10500
...
тогда
nd <-networkDynamic(nw,
edge.spells = edgelist[,c(3,4,2,1)],
vertex.spells=nodelist[,c(3,4,1)],
create.TEAs=TRUE,
vertex.TEA.names='budget')
Раздел в виньетке пакета networkDynamic
«Активация атрибутов TEA» должен содержать более полезную информацию https://cran.r-project.org/web/packages/networkDynamic/vignettes/networkDynamic.pdf
Затем вы сможете сопоставить атрибут динамической вершины со свойством сюжета анимации в ndtv
(ndtv
будет управлять преобразованием динамического атрибута в статический в каждый момент времени по мере его рендеринга)
render.d3movie(nd,vertex.cex='budget')
Если у этих организаций скромные бюджеты необычно, я предполагаю, что вы захотите использовать log()
бюджета или каким-либо другим способом преобразовать необработанные цифры бюджета, иначе узлы будут невообразимо большими.
Существует также учебник, в котором это рассматривается более подробно, поскольку есть некоторые необходимые тонкости в том, как работает агрегирование значений во временных окнах: http://statnet.csde.washington.edu/workshops/SUNBELT/current/ndtv/ndtv_workshop.html#controlling-plot-properties-using-dynamic-attributes-teas
Кстати, заклинания активности - это "право открытые" интервалы, поэтому я изменил дату окончания на 07-01, чтобы не оставить организации без финансирования на один день.
Спасибо. У меня возникают проблемы с согласованием бюджетов с агентствами, поэтому я пока не могу протестировать ваше решение. Легче сказать, чем сделать увязку бюджетных документов с административными мероприятиями.
nodelist_expanded <- read.csv("github.com/aterhorst/data/raw/master/nodelist_expanded.csv", header=T, stringsAsFactors = F)
nodelist_expanded требует, чтобы даты были выровнены, чтобы не было пробелов в один день. Однако я не слишком хорошо разбираюсь в TEA. Я получаю эту ошибку при попытке использовать nodelist_expanded: Ошибка в networkDynamic(edge.spells = edgelist[, c(4, 5, 3, 2)], vertex.spells = nodelist_expanded[,: вектор vertex.TEA.names должен соответствовать количеству оставшихся столбцов в vertex.spells
Фиксированные даты, чтобы они совпадали, сейчас.
Мне удалось заставить что-то работать.
require(sna)
require(tsna)
require(ndtv)
require(networkDynamic)
require(lubridate)
nodelist <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist.csv", header=T, stringsAsFactors = F)
edgelist <- read.csv("https://github.com/aterhorst/data/raw/master/edgelist.csv", header=T, stringsAsFactors = F)
nodelist_expanded <- read.csv("https://github.com/aterhorst/data/raw/master/nodelist_expanded.csv", header=T, stringsAsFactors = F)
# onset date must be numeric (does not like date?)
nodelist$onset <- year(nodelist$onset)
nodelist$terminus <- year(nodelist$terminus)
# colour nodes by portfolio type
nodelist$col <- ifelse(nodelist$portfolio == T, "red", "blue")
nodelist_expanded$onset <- year(nodelist_expanded$onset)
nodelist_expanded$terminus <- year(nodelist_expanded$terminus)
# scale attributes
nodelist_expanded$log_appropriation <- log(nodelist_expanded$appropriation + 10) / 10
nodelist_expanded$log_ext_revenue <- log(nodelist_expanded$ext_revenue + 10) / 10
edgelist$onset <- year(edgelist$onset)
edgelist$terminus <- year(edgelist$terminus)
# create basic network object
nw <- network(edgelist[,c(2,3)],
vertex.attr = nodelist[,c(1:3,6)],
vertex.attrnames = c("vertex.id", "agency", "portfolio", "col"),
directed = F)
# plot basic network object
plot(nw, vertex.col = "col")
# make dynamic network object
nd <-networkDynamic(nw,
edge.spells = edgelist[,c(4,5,3,2)],
vertex.spells = nodelist_expanded[,c(6,7,1,8,9)],
create.TEAs = TRUE,
vertex.TEA.names = c("log_appropriation", "log_ext_revenue"))
# reconcile things
reconcile.vertex.activity(nd, mode = "match.to.edges")
# make movie!
render.d3movie(nd,
displaylabels = FALSE,
vertex.col = "col",
vertex.tooltip = function(slice) {
paste("<b>Agency:</b>", (slice %v% "agency"))})
похоже, что список узлов в вашем примере на самом деле загружает файл списка краев?