@@ -13,9 +13,7 @@ description: >
1313
1414``` {r setup, include = FALSE}
1515library(learnr)
16- library(manynet)
17- library(patchwork)
18- library(ggplot2)
16+ library(migraph)
1917clear_glossary()
2018knitr::opts_chunk$set(echo = FALSE)
2119```
@@ -47,6 +45,8 @@ is enough to cause infection/adoption.
4745If the network is connected, the attribute will 'cascade' across the network
4846until all nodes are 'infected'/have adopted.
4947
48+ <img src =" https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExdXdqOXNjemNnZnhzOG50aTdlZzgzbWt2dTlmbGt4aGswNGRjdjd4eiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/11IuynebQzNpjq/giphy.gif " alt =" salt cascade gif " width = " 500 " />
49+
5050### Diffusing across a lattice
5151
5252Let us begin with a lattice network that shows us exactly how such a cascade works.
@@ -65,92 +65,84 @@ graphr(lat)
6565
6666Ok, great! That's made a nice little lattice network.
6767Next we want to play a diffusion process _ on_ this network.
68- To do this, we just need to run ` play_diffusion() ` ,
69- and assign the result.
70- Then we can investigate the resulting object in a few ways.
71- The first way is simply to print the result by calling the object.
72- The other way is to unpack the result by calling for its summary.
68+ To do this, we need to run ` play_diffusion() ` .
69+ This function plays a simple contagion process on a network,
70+ where any contact with an infected/adopter node
71+ is enough to cause susceptible nodes to adopt/become infected by the following timepoint.
72+ The function returns a network object that contains information about how the diffusion played out.
73+ Then we can investigate the diffusion process by extracting this information
74+ using ` as_changelist() ` and ` as_diffusion() ` .
75+ The first simply extracts the list of adoption/infection events,
76+ while the second summarises the diffusion process by time point.
7377
7478``` {r lat_diff, exercise = TRUE, exercise.setup = "clattice"}
75- lat_diff <- play_diffusion(lat)
76- lat_diff
77- summary(lat_diff )
79+ lat_w_diff <- play_diffusion(lat)
80+ (diff_events <- as_changelist(lat_w_diff))
81+ (diff_summ <- as_diffusion(lat_w_diff) )
7882```
7983
80- The main report from the ` lat_diff ` object shows the number of nodes that don't
81- (yet) have the attribute (S for susceptible, but can also be non-adopter)
82- and those that do have the attribute (I for infected, or adopter) at each time point (t).
83- We can see a steady growth here, except for a slower initialisation and winding down.
84-
85- The secondary report, ` summary(lat_diff) ` ,
86- presents a list of the events at each time point.
84+ The changelist presents a list of the events at each time point.
8785In the event variable, the 'I' indicates that these are all infection/adoption events.
8886Where 't' is 0, that means that these are the seeds producing the starting condition
8987for the diffusion.
90- The final column, 'exposure', records the number of infected nodes that the adopting
91- node was exposed to when it adopted.
92- Note that we have no information about the exposure for the seed nodes when they
93- were infected, and so this is a missing value.
94- The exposure at infection is recorded here to accelerate later analysis.
88+ The diffusion summary shows the number of nodes that don't
89+ (yet) have the attribute (S for susceptible, but can also be non-adopter)
90+ and those that do have the attribute (I for infected, or adopter) at each time point (t).
91+ We can see a steady growth here, except for a slower initialisation and winding down.
9592
9693### Visualising cascades
9794
9895We have several different options for visualising diffusions.
9996The first visualisation option that we have is to plot the diffusion result itself.
10097
101- ``` {r plotlat, exercise = TRUE, exercise.setup = "lat_diff", purl = FALSE, fig.width=9}
102- plot(lat_diff )
103- plot(lat_diff , all_steps = FALSE)
98+ ``` {r plotlat, exercise = TRUE, exercise.setup = "lat_diff", fig.width=9}
99+ plot(diff_summ )
100+ # plot(diff_summ , all_steps = FALSE) # To plot only 'where the action is', use the argument `all_steps = FALSE`.
104101```
105102
106103This plot effectively visualises what we observed from the print out of the
107- ` lat_diff ` object above.
104+ ` diff_summ ` object above.
108105The red line traces the proportion of infected;
109- the blue line the (inverse) proportion of susceptible.
106+ the blue line the (inverse) proportion of susceptible nodes in the network .
110107The grey histogram in the plot shows how many nodes are newly 'infected' at each
111108time point, or the so-called 'force of infection' ($F = \beta I$).
112109
113- We can see that by default the whole simulated period (32 steps) is shown,
114- even though there is complete infection after only 10 steps.
115- That's because the simulation runs over the number of nodes in the network
116- by default.
117- If the structure is amenable to diffusion, infection/diffusion will be completed
118- before that.
119- To plot only 'where the action is', use the argument ` all_steps = FALSE ` .
120-
121110But maybe we want to also/instead view the diffusion on the actual network.
122- Here we can use all the three main graphing techniques offered in ` {manynet } ` .
111+ Here we can use all the three main graphing techniques offered in ` {autograph } ` .
123112First, ` graphr() ` will graph a static network where the nodes are coloured
124113according to how far through the diffusion process the node adopted.
125114Note also that any seeds are indicated with a triangle.
126115
127- ``` {r graphrlat, exercise = TRUE, exercise.setup = "lat_diff", purl = FALSE, fig.width=9}
128- graphr(lat_diff , node_size = 0.3)
116+ ``` {r graphrlat, exercise = TRUE, exercise.setup = "lat_diff", fig.width=9}
117+ graphr(lat_w_diff , node_size = 0.3)
129118```
130119
131120Second, ` graphs() ` visualises the stages of the diffusion on the network.
132121By default it will graph the first and last wave,
133122but we can change this by specifying which waves to graph.
134123
135- ``` {r graphslat, exercise = TRUE, exercise.setup = "lat_diff", purl = FALSE, fig.width=9}
136- graphs(lat_diff )
137- graphs(lat_diff , waves = c(1,4,8 ))
124+ ``` {r graphslat, exercise = TRUE, exercise.setup = "lat_diff", fig.width=9}
125+ graphs(lat_w_diff )
126+ graphs(lat_w_diff , waves = c(1,4,7,10 ))
138127```
139128
129+ We can see here exactly how the attribute in question (ideas, information, disease?)
130+ is diffusing across the network.
131+ It's like a cascade of red sweeping across the space!
132+
140133Lastly, ` grapht() ` animates this diffusion process to a gif.
141134It can take a little time to encode, but it is worth it to see exactly
142135how the attribute is diffusing across the network!
143136Note that if you run this code in the console, you get a calming progress bar;
144137in the tutorial you will just need to be patient.
145138
139+ > NB: It is not currently working (for diffusions) at the moment,
140+ but a refactoring soon will fix this and other related bugs.
141+
146142``` {r graphtlat, exercise = TRUE, exercise.setup = "lat_diff", purl = FALSE, fig.width=9}
147- grapht(lat_diff , node_size = 10)
143+ # grapht(lat_w_diff , node_size = 10)
148144```
149145
150- We can see here exactly how the attribute in question (ideas, information, disease?)
151- is diffusing across the network.
152- It's like a cascade of red sweeping across the space!
153-
154146### Varying network structure
155147
156148While a lattice structure is one way of representing spatially governed diffusion,
@@ -177,8 +169,8 @@ graphr(play_diffusion(generate_smallworld(32, 0.025)))
177169Which diffusion process completed first?
178170` graphr() ` only colors nodes' relative adoption,
179171and ` graphs() ` (at least by default) only graphs the first and last step.
180- ` grapht() ` will show if and when there is complete infection,
181- but we need to sit through each 'movie'.
172+ <!-- `grapht()` will show if and when there is complete infection, -->
173+ <!-- but we need to sit through each 'movie'. -->
182174But there is an easier way.
183175Play these same diffusions again, this time nesting the call within ` net_infection_complete() ` .
184176
@@ -211,7 +203,6 @@ You can start the infection in California by specifying `seeds = 5`.
211203us_diff <- play_diffusion(irps_usgeo, seeds = 5)
212204plot(us_diff)
213205graphr(us_diff)
214- grapht(us_diff)
215206net_infection_complete(us_diff)
216207```
217208
@@ -227,6 +218,8 @@ This is known as a `r gloss("linear threshold", "LTM")` model,
227218where if infection/influence on a node through some (potentially weighted) network
228219exceeds some threshold, then they will adopt/become infected.
229220
221+ <img src =" https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZ3luZjc1aWhnYnhwNG9zazkzcjA2c2hiYzBjZXVlaTlvZnh6MHl2OCZlcD12MV9naWZzX3NlYXJjaCZjdD1n/2zowpb8JizmCRHq0PR/giphy.gif " alt =" morgan freeman breaking point gif " width = " 500 " />
222+
230223### Threshold rising
231224
232225Let's use the ring network again this time to
@@ -243,9 +236,9 @@ Let's see what the results are if you play four different diffusions:
243236
244237``` {r complex, exercise = TRUE, fig.width=9}
245238rg <- create_ring(32, width = 2)
246- plot(play_diffusion(rg, seeds = 1, thresholds = 1))/
247- plot(play_diffusion(rg, seeds = 1, thresholds = 2))/
248- plot(play_diffusion(rg, seeds = 1:2, thresholds = 2))/
239+ plot(play_diffusion(rg, seeds = 1, thresholds = 1))
240+ plot(play_diffusion(rg, seeds = 1, thresholds = 2))
241+ plot(play_diffusion(rg, seeds = 1:2, thresholds = 2))
249242plot(play_diffusion(rg, seeds = c(1,16), thresholds = 2))
250243```
251244
@@ -303,14 +296,14 @@ on the scale-free networks we have been using here.
303296```
304297
305298``` {r sfprop-hint, purl = FALSE}
306- plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = ____, steps = ____))/
307- plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = ____, steps = ____))/
299+ plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = ____, steps = ____))
300+ plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = ____, steps = ____))
308301plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = ____, steps = ____))
309302```
310303
311304``` {r sfprop-solution}
312- plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = 0.1, steps = 10))/
313- plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = 0.25, steps = 10))/
305+ plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = 0.1, steps = 10))
306+ plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = 0.25, steps = 10))
314307plot(play_diffusion(generate_scalefree(32, 0.025), seeds = 1:2, thresholds = 0.5, steps = 10))
315308```
316309
@@ -337,17 +330,14 @@ Something is going around Middle-Earth,
337330but different races have different resistances (i.e. thresholds).
338331Let us say that there is a clear ordering to this.
339332
340- ``` {r lotr-resist, exercise=TRUE}
333+ ``` {r lotr-resist, exercise=TRUE, fig.width=9 }
341334lotr_resist <- fict_lotr %>% mutate(resistance = dplyr::case_when(Race == "Dwarf" ~ 2,
342335 Race == "Elf" ~ 4,
343336 Race == "Ent" ~ 5,
344337 Race == "Hobbit" ~ 3,
345338 Race == "Human" ~ 1,
346339 Race == "Maiar" ~ 6))
347- ```
348-
349- ``` {r resistdiff, exercise=TRUE, exercise.setup = "lotr-resist", fig.width=9}
350- grapht(play_diffusion(lotr_resist, thresholds = "resistance"))
340+ graphs(play_diffusion(lotr_resist, thresholds = "resistance"))
351341```
352342
353343Fun! Now how would you interpret what is going on here?
@@ -362,12 +352,14 @@ Can you rewrite the code above so that fractional thresholds are used?
362352
363353<!-- ## Independent cascades -->
364354
365- ## Intervention
355+ ## Make it start
366356
367357Let's say that you have developed an exciting new policy and
368358you are keen to maximise how quickly and thoroughly it is adopted.
369359We are interested here in ` r gloss("network intervention", "intervention") ` .
370360
361+ <img src =" https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExbm9rc2trbGd5b2tzZ2d4cDNqeGVvNzJ3ZjhvMHhmdDF3c2ljcDZ5ZSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/5nsiFjdgylfK3csZ5T/giphy.gif " alt =" flamethrower gif " width = " 500 " />
362+
371363### Choosing where to seed
372364
373365Since the ring network we constructed is cyclical,
@@ -382,8 +374,8 @@ and see whether the result is any different.
382374```
383375
384376``` {r ring2-solution}
385- plot(play_diffusion(create_ring(32, width = 2), seeds = 1)) /
386- plot(play_diffusion(create_ring(32, width = 2), seeds = 16))
377+ plot(play_diffusion(create_ring(32, width = 2), seeds = 1))
378+ plot(play_diffusion(create_ring(32, width = 2), seeds = 16))
387379```
388380
389381``` {r ring2-interp, echo = FALSE, purl = FALSE}
@@ -458,14 +450,14 @@ one with the first node as seed and again one on the middle.
458450```
459451
460452``` {r lattice-solution}
461- plot(play_diffusion(lat, seeds = 1))/
453+ plot(play_diffusion(lat, seeds = 1))
462454plot(play_diffusion(lat, seeds = 16))
463455lat %>%
464456 add_node_attribute("color", c(1, rep(0, 14), 2, rep(0, 16))) %>%
465457 graphr(node_color = "color")
466458
467459# visualise diffusion in lattice graph
468- grapht (play_diffusion(lat, seeds = 16), layout = "grid", keep_isolates = FALSE )
460+ graphs (play_diffusion(lat, seeds = 16), layout = "grid")
469461```
470462
471463``` {r lattice-interp, echo = FALSE, purl = FALSE}
@@ -501,14 +493,14 @@ sf %>%
501493```
502494
503495``` {r scale-solution}
504- plot(play_diffusion(sf, seeds = 10, steps = 10)) /
505- plot(play_diffusion(sf, seeds = node_is_random(sf), steps = 10)) /
506- plot(play_diffusion(sf, seeds = node_is_max(node_degree(sf)), steps = 10)) /
496+ plot(play_diffusion(sf, seeds = 10, steps = 10))
497+ plot(play_diffusion(sf, seeds = node_is_random(sf), steps = 10))
498+ plot(play_diffusion(sf, seeds = node_is_max(node_degree(sf)), steps = 10))
507499plot(play_diffusion(sf, seeds = node_is_min(node_degree(sf)), steps = 10))
508500
509501# visualise diffusion in scalefree network
510502graphs(play_diffusion(sf, seeds = node_is_min(node_degree(sf)), steps = 10))
511- grapht (play_diffusion(sf, seeds = 16, steps = 10))
503+ graphs (play_diffusion(sf, seeds = 16, steps = 10), waves = 1:3 )
512504```
513505
514506``` {r mindeg-interp, echo = FALSE, purl = FALSE}
@@ -566,6 +558,8 @@ But before we get into that,
566558let's see how we can play and plot several simulations
567559to see what the range of outcomes might be like.
568560
561+ <img src =" https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExMXMwZ2xzcWJzNG1ubXp1YXhvbG12YmE0NzQzNDFwa3drdGd1bmdoYSZlcD12MV9naWZzX3NlYXJjaCZjdD1n/xUOxeZc41DVT2l9laU/giphy.gif " alt =" curb your enthusiasm luggage compartment gif " width = " 500 " />
562+
569563### Running multiple simulations
570564
571565To do this, we need to use ` play_diffusions() ` (note the plural).
@@ -698,14 +692,16 @@ set.seed(123)
698692plot(play_diffusion(rando, seeds = 10, latency = 0.25, recovery = 0.2))
699693
700694# visualise diffusion with latency and recovery
701- grapht (play_diffusion(rando, seeds = 10, latency = 0.25, recovery = 0.2))
695+ graphs (play_diffusion(rando, seeds = 10, latency = 0.25, recovery = 0.2), waves = c(1,5,10 ))
702696```
703697
704- ### Make it stop
698+ ## Make it stop
705699
706700In this section, we are interested in how to most effectively _ halt_
707701a diffusion process.
708702
703+ <img src =" https://media.giphy.com/media/v1.Y2lkPWVjZjA1ZTQ3N3JsNWhvMjM2amkwMnhqZ2ltb2h2c3Zha3dwOGx1dHZnbngzNTQxZyZlcD12MV9naWZzX3NlYXJjaCZjdD1n/LbvdcrbTOk6eK1kQ6u/giphy.gif " alt =" biden stop gif " width = " 500 " />
704+
709705An attribute's reproduction number, or $R_0$, is a measure of the rate of infection
710706or how quickly that attribute will reproduce period over period.
711707It is calculated as $R_0 = \min\left(\frac{T}{1/L}, \bar{k}\right)$,
@@ -762,7 +758,7 @@ But then...
762758### How many people do we need to vaccinate?
763759
764760We can identify how many people need to be vaccinated through
765- the ` gloss("Herd Immunity Threshold", "hit") ` or HIT.
761+ the ` r gloss("Herd Immunity Threshold", "hit")` or HIT.
766762HIT indicates the threshold at which the reduction of susceptible members
767763of the network means that infections will no longer keep increasing,
768764allowing herd immunity to be achieved.
@@ -849,6 +845,8 @@ usually rely on nodes' voluntary participation:
849845they must accept that vaccination, medication, or behavioral change is necessary
850846to combat the contagion.
851847
848+ <img src =" https://media.giphy.com/media/v1.Y2lkPWVjZjA1ZTQ3bXdtbGs1azJnZWUzdGZycTRsMGg0a2twM2RxYjdveWtuNzV3eWo1MiZlcD12MV9naWZzX3NlYXJjaCZjdD1n/xjQfDCSRr2jkH3SPab/giphy.gif " alt =" learn every day gif " width = " 500 " />
849+
852850Lastly, we're going to consider a rather simple type of learning model:
853851a DeGroot learning model.
854852A question often asked of these kinds of models is whether,
0 commit comments