# Chapter 11 Dynamic Edges

So far we have been drawing static graphs, in this chapter we look at dynamic ones, namely temporal. However, being an introduction we’ll start with dynamic edges only: we’ll plot the nodes and have the edges appear dynamically .We’ll tackle the fully temporal network further down the book.

## 11.1 Rationale

We’ve been visualising Twitter interactions in a static manner, but they are dynamic when you think of it. Twitter conversations happen over time, thus far, we’ve just been drawing all encompassing snapshots. So let’s take into account the time factor to make a where the edges appear at different time steps.

## 11.2 Collect

We’ll collect some tweets again, we’ll use retweets this time, so we build the corresponding search.

``````# TK <- readRDS(file = "token.rds")
tweets <- search_tweets("#rstats filter:retweets", n = 3000, token = TK, include_rts = TRUE)``````
``## Searching for tweets...``
``## Finished collecting tweets!``

## 11.3 Build

Now onto building the graph.

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

Quite a few things differ from previous graphs we have built.

1. We pass `created_at` in `gt_edges`. This in effect adds the `created_at` column to our edges, so that we know the created time of post in which the edge appears.
2. We use `gt_dyn` which stands for `dynamic`, to essentially compute the time at which edges and nodes should appear on the graph.
``head(net\$edges)``
source target created_at n end
kisi gp_pulipaka 2018-08-15 18:49:05 1 2018-08-16 09:17:48
perside gp_pulipaka 2018-08-14 17:10:50 1 2018-08-16 09:17:48
perside gp_pulipaka 2018-08-15 08:06:30 1 2018-08-16 09:17:48
perside missdkingsbury 2018-08-15 08:06:30 1 2018-08-16 09:17:48
phanhoang mattmayo13 2018-08-14 17:22:05 1 2018-08-16 09:17:48
_alexbowles grrrck 2018-08-16 08:09:55 1 2018-08-16 09:17:48

## 11.4 Visualise

Now for the visualisation, let’s build it step by step; first we prep the data as we did before: renaming a few columns but also running a few unfamiliar computations.

To explain how we build the visualisation, we first need to tell you how the edges will dynamically appear on the graph. The way this works in sigmajs is by specifying the delay in milliseconds before each respective edge should be added. Therefore, we need to transform the date to milliseconds and rescale them to be within a reasonable range: we don’t want the edges to actually take 15 days to appear on the graph.

1. We change the date time column (`POSIXct` actually) to a numeric, which gives the number of milliseconds since 1970.
2. We rescale between 0 and 1 then multiply by 10,000 (milliseconds) so that the edges are added over 10 seconds.
``````library(dplyr)

c(edges, nodes) %<-% net # unpack

nodes <- nodes2sg(nodes)

edges <- edges %>%
mutate(
id = 1:n(),
created_at = as.numeric(created_at),
created_at = (created_at - min(created_at)) / (max(created_at) - min(created_at)),
created_at = created_at * 10000
) %>%
select(id, source, target, created_at)``````

Let’s inspect what we obtain.

``head(net\$edges)``
id source target created_at
1 kisi gp_pulipaka 6396.28864
2 perside gp_pulipaka 15.14135
3 perside gp_pulipaka 3730.64983
4 perside missdkingsbury 3730.64983
5 phanhoang mattmayo13 61.80991
6 _alexbowles grrrck 9718.39847

We see that the column `created_at` has changed from Date time (`POSIXct`) to a numeric. As mentioned previously, we rescaled it to be between 0 and 10,000 milliseconds, let’s see if that is correct.

``range(edges\$created_at)``
``## [1]     0 10000``

So for instance the edge at row 25, a tweet where @paulamoraga tags @rladiesmvd will appear after 7546 milliseconds.

``edges[25,]``
``````## # A tibble: 1 x 4
##      id source        target     created_at
##   <int> <chr>         <chr>           <dbl>
## 1    25 _paulamoraga_ rladiesmvd      7546.``````

Now, the actual visualisation, as mentioned at the begining to the chapter, we’ll plot the nodes then add edges dynamically. Let’s break it down step by step.

First, we plot the nodes.

``````sigmajs() %>%
sg_nodes(nodes, id, size, label) ``````

We’ll add the layout as it looks a bit messy with nodes randomly scattered across the canvas. We’ll have to compute the layout differently this time, we cannot simply use `sg_layout` as it requires both nodes and edges and we only have nodes on the graph (since edges are to be added later on, dynamically); instead we use `sg_get_layout`.

You cannot use `sg_cluster` and `sg_layout` in dynamic graphs as they require both nodes and edges, use the `sg_get_*` alternatives.

This is something that we had not shared with you earlier on, `sg_nodes` must have `x` and `y` coordinates of each node, however, if missing they are generated randomly by the package. `sg_get_layout` computes the coordinates of the nodes (`x` and `y`) and adds them to our nodes data.frame.

``````nodes <- sg_get_layout(nodes, edges, layout = igraph::layout_components)
id label start end type size x y
__jsta __jsta 2018-08-15 09:17:29 2018-08-16 09:17:48 user 1 -95.49617 115.69956
kisi kisi 2018-08-15 18:49:05 2018-08-16 09:17:48 user 1 166.95508 13.90131
perside perside 2018-08-14 17:10:50 2018-08-16 09:17:48 user 3 163.60098 13.90635
phanhoang phanhoang 2018-08-14 17:22:05 2018-08-16 09:17:48 user 1 16.08325 226.93781
_alesssia _alesssia 2018-08-14 17:23:47 2018-08-16 09:17:48 user 6 -51.85844 -91.43477
_alexbowles _alexbowles 2018-08-16 08:09:55 2018-08-16 09:17:48 user 1 -120.98685 11.49636

Now we can simply pass the coordinates `x` and `y` to `sg_nodes`.

``````sigmajs() %>%
sg_nodes(nodes, id, size, label, x, y) ``````

Let’s beautify the graph a little, this deep black is somewhat unnerving.

``````sigmajs() %>%
sg_nodes(nodes, id, size, label, x, y) %>%
sg_settings(
defaultNodeColor = "#127ba3",
edgeColor = "default",
defaultEdgeColor = "#d3d3d3",
minNodeSize = 1,
maxNodeSize = 4,
minEdgeSize = 0.3,
maxEdgeSize = 0.3
)``````

Now we have something that looks like a graph, except it’s missing edges. Let’s add them.

We add the edges almost exactly as we did before, we use `sg_add_edges` instead of `sg_edges`. Other than the function name, the only difference is that we pass `created_at` as `delay`. We also set `cumsum` to `FALSE` otherwise the function computes the cumulative sum on the `delay`, which is, here, our `created_at` column, and does not require counting the cumulative sum.

``````sigmajs() %>%
sg_nodes(nodes, id, size, label, x, y) %>%
sg_add_edges(edges, created_at, id, source, target, cumsum = FALSE, refresh = TRUE) %>%
sg_settings(
defaultNodeColor = "#127ba3",
edgeColor = "default",
defaultEdgeColor = "#d3d3d3",
minNodeSize = 1,
maxNodeSize = 4,
minEdgeSize = 0.3,
maxEdgeSize = 0.3
)``````