Networks

Inferred transmission networks from time calibrated phylogenies

Transmission Networks

Serotype A

Load time-calibrated MCC tree.

Hide code
sero_A.tree <- read.nexus(here("local/beast/a_1/sero_a.mcc.tre"))

Read Beast log file for the tree

Hide code
get_A_stats <- get_tracer_stats(here("local/beast/a_1/sero_a.log.txt"))
Loading required package: coda
Hide code
root_age <- get_A_stats %>%
    filter(Parameter == "age.root.") %>%
    select(Median) %>%
    pull()
  
tree_mrsd <- get_A_stats %>%
    filter(Parameter == "treeModel.rootHeight") %>%
    select(Median) %>%
    pull() + root_age

sero_A.tree.p <- ptreeFromPhylo(sero_A.tree,
                                dateLastSample = tree_mrsd)

Choose prior
Constructing a gamma distribution that reflects FMDV generation time, ballpark 5-15 days, with 7-10 days being more likely.

Hide code
gam_params <- get_gamma_params(7, c(5, 15))

w.shape <- gam_params$shape
w.scale <- gam_params$scale

set.seed(1976)
check_gamma <- rgamma(1000, w.shape,   )
Hide code
plot_density(check_gamma, max_x = 20)

The dateT parameter is the date when observation stopped. Used 2017.5 due that being the most recent sample across the A, Asia1, and O serotypes in the study.

Hide code
tt_sero_A <- inferTTree(sero_A.tree.p,
                        mcmcIterations=10000,
                        w.shape=w.shape,
                        w.scale=w.scale,
                        dateT=2017.5)

saveRDS(tt_sero_A, here("local/assets/tt_sero_A.rds"))

Serotype Asia1

Hide code
sero_Asia1.tree <- read.nexus(here("local/beast/asia1_1/sero_asia1.mcc.tre"))
Asia1_stats <- get_tracer_stats(here("local/beast/asia1_1/sero_asia1.log.txt"))
Hide code
tt_sero_Asia1 <- infer_ttree(sero_Asia1.tree,
                             Asia1_stats,
                             w.shape=w.shape,
                             w.scale=w.scale,
                             dateT = 2017.5)

saveRDS(tt_sero_Asia1, here("local/assets/tt_sero_Asia1.rds"))

Serotype O

Hide code
sero_O.tree <- read.nexus(here("local/beast/o_1/sero_o.mcc.tre"))
O_stats <- get_tracer_stats(here("local/beast/o_1/sero_o.log.txt"))
Hide code
tt_sero_O <- infer_ttree(sero_O.tree,
                         O_stats,
                         w.shape=w.shape,
                         w.scale=w.scale,
                         dateT = 2017.5)

saveRDS(tt_sero_O, here("local/assets/tt_sero_O.rds"))

Get Networks

Hide code
A_net <- extract_transmission_network(tt_sero_A) %>%
  mutate(Serotype = "A")

Asia1_net <- extract_transmission_network(tt_sero_Asia1) %>%
  mutate(Serotype = "Asia1")

O_net <- extract_transmission_network(tt_sero_O) %>%
  mutate(Serotype = "O")

all_networks <- rbind(A_net, Asia1_net, O_net)

Match Metadata

Hide code
sero_df <- readRDS(here("local/assets/sero_df.rds")) # from preprocessing

animal_codes <- sero_df %>%
  filter(status == "Subclinical") %>%
  mutate(Status = status,
         host_id = label) %>%
  select(host_id, animal, farm_code, Status)

all_networks <-left_join(all_networks, animal_codes, by = "host_id") %>%
  mutate(animal = as.character(animal),
         Status = if_else(is.na(Status), "Clinical", Status),
         infected_ani = if_else(Status == "Subclinical", animal, host_id))

all_networks$infector_match <- with(animal_codes,
                                    animal[match(
                                      all_networks$infector,
                                      host_id)])

all_networks <- all_networks %>%
  mutate(infector_match = as.character(infector_match),
         infector_ani = if_else(is.na(infector_match), infector, infector_match),
         infection_date = as.Date(infection_date))

Set Vertices and Nodes

Hide code
edges <- data.frame(from = all_networks$infector_ani, to = all_networks$infected_ani)

g <- graph_from_data_frame(edges, directed = TRUE)

V(g)$Status <- "Unknown"

V(g)$Status[V(g)$name %in% all_networks$infected_ani] <- all_networks$Status[match(V(g)$name[V(g)$name %in% all_networks$infected_ani], all_networks$infected_ani)]

V(g)$Serotype <- "Origin"
V(g)$Serotype[V(g)$name %in% all_networks$infected_ani] <- 
  all_networks$Serotype[match(V(g)$name[V(g)$name %in% all_networks$infected_ani], all_networks$infected_ani)]

V(g)$infection_date <- as.Date("1995-07-10")
V(g)$infection_date[V(g)$name %in% all_networks$infected_ani] <- 
  all_networks$infection_date[match(V(g)$name[V(g)$name %in% all_networks$infected_ani], all_networks$infected_ani)]

V(g)$infection_date <- as.Date(V(g)$infection_date)

V(g)$infection_steps <- as.integer(as.factor(V(g)$infection_date))

Tree network showing descent

Hide code
p <- ggraph(g, layout = 'tree') + 
  geom_edge_diagonal(start_cap = circle(2, 'mm'), end_cap = circle(2, 'mm'),
                 color = 'gray20', alpha=0.9, 
                 arrow = arrow(type = "closed", length = unit(2, "mm"))) +
  geom_node_point(aes(color = Status, shape = Serotype), size = 4, alpha = 0.6) +
  scale_color_manual(values = c("Subclinical" = "orange", 
                                "Clinical" = "steelblue", 
                                "Unknown" = "gray50")) +
  #geom_node_label(aes(label = name), repel = TRUE) +
  theme_void() +
  labs(title = "FMDV Transmission Network",
       subtitle = "Nodes are animals, arrows extend from infector to infectee")

p

Showing individuals with multiple infections (red color)

Hide code
set.seed(1976)

tg <- as_tbl_graph(g)

tg <- tg %>%
    activate(nodes) %>%  
    mutate(in_degree = centrality_degree(mode = "in"),
           multiple_incoming = ifelse(in_degree > 1, "multiple", "single"))

tg <- tg %>%
    mutate(alpha = ifelse(multiple_incoming == "multiple", 1, 0.6))

layout <- layout_with_fr(as.igraph(tg), niter = 5000)

layout_df <- as.data.frame(layout)
colnames(layout_df) <- c("x", "y")

spread_factor <- 25
layout_df$x <- layout_df$x * spread_factor
layout_df$y <- layout_df$y * spread_factor

tg <- tg %>%
    mutate(x = layout_df$x, y = layout_df$y)

p <- ggraph(tg, x = x, y = y) + 
  geom_edge_diagonal(aes(color = as.factor(from), alpha = 0.9), 
                     start_cap = circle(3, 'mm'), end_cap = circle(3, 'mm'),
                     arrow = arrow(type = "closed", length = unit(2, "mm")),
                     show.legend = FALSE) +
  geom_node_point(aes(color = Status, shape = Serotype, 
                      fill = multiple_incoming, alpha = alpha),
                      size = 3, stroke=1.5) +  
  scale_shape_manual(values = c("A" = 21,
                                "Asia1" = 22,
                                "O" = 24,
                                "Origin" = 13)) +
  scale_color_manual(values = c("Subclinical" = "orange", 
                                "Clinical" = "steelblue", 
                                "Unknown" = "gray50")) +
  scale_fill_manual(values = c("multiple" = "red", "single" = NA), guide = "none") +
  scale_alpha_identity() +  
  theme_void() +
  labs(title = "FMDV Transmission Network",
       subtitle = "Nodes are animals. Red indicates multiple infections")

p

Animated version

Hide code
p <- ggraph(tg, x = x, y = y) + 
  geom_edge_diagonal(aes(color = as.factor(from), alpha = 0.9), 
                     start_cap = circle(3, 'mm'), end_cap = circle(3, 'mm'),
                     arrow = arrow(type = "closed", length = unit(2, "mm")),
                     show.legend = FALSE) +
  geom_node_point(aes(color = Status, shape = Serotype, 
                      fill = multiple_incoming, alpha = alpha),
                      size = 3, stroke=1.5) +  
  scale_shape_manual(values = c("A" = 21,
                                "Asia1" = 22,
                                "O" = 24,
                                "Origin" = 13)) +
  scale_color_manual(values = c("Subclinical" = "orange", 
                                "Clinical" = "steelblue", 
                                "Unknown" = "gray50")) +
  scale_fill_manual(values = c("multiple" = "red", "single" = NA), guide = "none") +
  scale_alpha_identity() +  
  theme_void() +
  labs(title = "FMDV Transmission Network",
       subtitle = "Nodes are animals. Red indicates multiple infections") +
  transition_time(infection_steps) +
  labs(subtitle = 'Date: {frame_time}') +
    shadow_mark(alpha = alpha / 2)

ani_net <- animate(p, width = 800, height = 800, 
                   fps = 10, end_pause = 20,
                   renderer = gifski_renderer())

anim_save(here("local/assets/coinfect_network_animation.gif"), ani_net)
Hide code
knitr::include_graphics(here("local/assets/coinfect_network_animation.gif"))

To be continued…