12 Temporal

In the previous chapter we built a graph with dynamic edges. Let’s build a fully dynamic graph where both nodes and edges appear when they are first created.

12.1 Collect

We again collect tweets in a slightly different manner but feel free to use data from a previous chapter. We specify type as mixed in order to get a mix of popular and recent tweets.

# TK <- readRDS(file = "token.rds")
tweets <- search_tweets("#rstats filter:mentions", n = 300, token = TK, include_rts = FALSE, type = "mixed")
## Searching for tweets...
## Finished collecting tweets!

12.2 Build

We build the graph as we did in the previous chapter.

net <- tweets %>% 
  gt_edges(screen_name, mentions_screen_name, created_at) %>% 
  gt_nodes() %>% 
  gt_dyn() %>% 
  gt_collect()

12.3 Visualise

Again, we unpack the network and prepare nodes and edges for our visualisation. Then we define a rescale functiion to ensure our treatment of the date time columns are consistent across nodes and edges.

c(edges, nodes) %<-% net

#' @param x Date time column.
#' @param t Number of milliseconds to rescale to.
rescale <- function(x, t){
  x <- as.numeric(x)
  x <-  (x - min(x)) / (max(x) - min(x))
  x <- x * t
  return(x)
}

rtweet returns date time but sigmajs expects milliseconds; it needs to be converted.

Next we prepare the data, we define the t argument of our rescale function defined above as a constant so as to make sure we apply the same scale to both nodes and edges.

library(dplyr)

T <- 10000

lockBinding("T", globalenv())

nodes <- nodes %>% 
  nodes2sg() %>% 
  mutate(
    start = rescale(start, T)
  ) %>% 
  select(id, label, size, start)

edges <- edges %>% 
  mutate(
    id = 1:n(),
    created_at = as.numeric(created_at),
    created_at = rescale(created_at, T)
  ) %>% 
  select(id, source, target, created_at)

Now the actual visualisation, then again, we set cumsum = FALSE, and add a button (linked to two events add_nodes and add_edges) to let you trigger the visualisation. before then you should see a blank canvas.

sigmajs() %>% 
  sg_add_nodes(nodes, start, id, label, size, cumsum = FALSE) %>% 
  sg_add_edges(edges, created_at, id, source, target, cumsum = FALSE) %>% 
  sg_button(c("add_nodes", "add_edges"), "Start")

We forgot the layout and we do not color the nodes, let’s compute the layout and the clusters to color nodes.

nodes <- sg_get_layout(nodes, edges)

nodes <- sg_get_cluster(
  nodes, 
  edges,
  colors = c(
    "#0084b4",
    "#00aced",
    "#1dcaff",
    "#c0deed"
    )
  )
## Found # 105 clusters
sigmajs() %>% 
  sg_add_nodes(nodes, start, id, label, size, color, x, y, cumsum = FALSE) %>% 
  sg_add_edges(edges, created_at, id, source, target, cumsum = FALSE) %>% 
  sg_button(c("add_nodes", "add_edges"), "Start")

So we transformed our date time to milliseconds and rescaled to span 10 seconds. The problem with this is that we, in a way, lose track of time in the visualisation itself. It’d be great to add a ticker to display, say, the date.

Let’s explain how this is done in sigmajs; we simply create a table that maps dates to our milliseconds delay. To do so we extract the dates from our net object, we then rescale those dates just like we did for the nodes and edges.

dates <- as.Date(net$nodes$start)

ticker <- dplyr::tibble(
  dates = dates,
  delay = rescale(dates, T)
) %>% 
  arrange(delay)

head(ticker)
dates delay
2019-04-12 0.000
2019-04-13 3447.215
2019-04-14 8240.184

Now, how do we use this mapping table in sigmajs?

sigmajs() %>% 
  sg_add_nodes(nodes, start, id, label, size, color, x, y, cumsum = FALSE) %>% 
  sg_add_edges(edges, created_at, id, source, target, cumsum = FALSE) %>% 
  sg_progress(ticker, delay, dates, cumsum = FALSE) %>% 
  sg_settings(
    edgeColor = "default",
    defaultEdgeColor = "#d3d3d3"
  ) %>% 
  sg_button(c("add_nodes", "add_edges", "progress"), "Start")

We use the sg_progress function to which we pass both the ticker columns’ variables and we tie that event to our button.