statnet / ndtv

ndtv: Network Dynamic Temporal Visualizations in R
https://cran.r-project.org/web/packages/ndtv/index.html
46 stars 5 forks source link

render.animation errors on missing (NA) attribute #26

Closed nextensible closed 7 years ago

nextensible commented 7 years ago

I am not sure if this should be considered a bug or an inconvenience; Note the missing "weight" attribute in the first edge:

if (!require("pacman")) install.packages("pacman"); library("pacman")
pacman::p_load(network, networkDynamic, ndtv, lubridate)

stTransac <- "
'person', 'document', 'weight', 'instantId'
'A',      'a1',           ,     '100'
'B',      'a1',       '20',     '200'
'C',      'a1',       '30',     '300'
"
dfTransac <- read.csv(text = stTransac, sep = "," , quote = '\'' , strip.white = TRUE, stringsAsFactors = FALSE)

net <- network.initialize(0, directed = TRUE, bipartite = 3)

add.vertices.networkDynamic(net, 3, vertex.pid = c("A","B","C"))
add.vertices.networkDynamic(net, 1, vertex.pid = "a1")

net %v% "vertex.names" <- c(c("A","B","C"), "a1")
set.network.attribute(net,'vertex.pid','vertex.names')
set.network.attribute(net,'edge.pid','edge.names')

add.edges.networkDynamic(net,
                         tail = get.vertex.id(net, c("A","B","C")),
                         head = get.vertex.id(net, "a1"),
                         edge.pid = paste0(c("A","B","C"), "->a1"))

activate.edges(net,
               e = get.edge.id(net, paste0(dfTransac[["person"]], "->a1")),
               at = dfTransac$instantId)

activate.edge.attribute(net,
                        prefix = "weight",
                        value = dfTransac$weight,
                        e = get.edge.id(net, paste0(dfTransac[["person"]], "->a1")),
                        at = dfTransac$instantId)

reconcile.vertex.activity(net = net, mode = "encompass.edges", edge.active.default = FALSE)

compute.animation(net, slice.par = list(start = 100, end = 101, interval = 1, aggregate.dur = 1, rule = "any"))
render.animation(net, edge.lwd = 'weight')
skyebend commented 7 years ago

This is not really a bug. As documented, you can't currently activate multiple time points on a single network element in a single call (http://stackoverflow.com/questions/39508427/how-can-i-efficiently-activate-an-edge-attribute-at-multiple-times-in-a-networkd/39517933#39517933). Might be a useful feature, but implementing this efficiently probably need to be done at the C level. Ideally should warn the user when this happens instead of silently dropping the extra attributes ... but this would have a performance cost. Documentation needs to be improved (mentions that this is true for vertices, does not explicitly mention edges)

nextensible commented 7 years ago

Dear Skye,

AFAIU, these are two different issues. The issue at stack overflow deals with activating edge attributes at multiple time points. The issue described here deals with the missing attribute value (NA) on edge 1 at time 100.

skyebend commented 7 years ago

Oh sorry, didn't see the error message, so thought it was the same example. However, isn't this then the same issue as #25 ?

nextensible commented 7 years ago

I think it is a similar issue, though not the same.

When using the latest code from the bugfix branch (ndtv 0.12), the code reported in #25 does not give an error any more, but the code above still does...

skyebend commented 7 years ago

Looking at this in more detail, this doesn't actually seem like an error to me. The example has a missing weight value for edge 1. This ends up represented in the network as NA:

> get.edge.attribute(net,'weight.active',unlist=FALSE)[[1]]
[[1]]
[[1]][[1]]
[1] NA

[[2]]
     [,1] [,2]
[1,]  100  100

When it tries to appropriately convert this into an edge line with it gives an error

Error in plotArgs.network(x, "edge.lwd", edge.lwd, d = d) : 
  Attribute 'weight' had illegal missing values for edge.lwd or was not present in plot.network.default.

because when it looks up the attribute 'weight', the plotting lookup code is not able to distinguish the case of the value NA, and the NA that would be returned if the attribute 'weight' did not exist. Note that even if it was able to pass the NA value to plot.network, it would still give an error because NA is not a permissible line width.

For this example, I think you need to either replace the missing weights in the input data with a valid value (i.e. 0), or don't activate the edges at the time points where they have no active weight value.