From fdae8b43891cb26dacf2fb94b19031de45dc9d4c Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Fri, 20 Mar 2026 20:02:50 +0000 Subject: [PATCH 01/19] fix deprecated age.limits -> age_limits in contact_matrix() calls The dot notation age.limits was deprecated in favor of age_limits. Update compare-interventions.Rmd (2 occurrences) and template.Rmd (3 occurrences). Co-Authored-By: Claude Sonnet 4.6 --- episodes/compare-interventions.Rmd | 4 ++-- episodes/template.Rmd | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/episodes/compare-interventions.Rmd b/episodes/compare-interventions.Rmd index 3a1cd163..fd4e0646 100644 --- a/episodes/compare-interventions.Rmd +++ b/episodes/compare-interventions.Rmd @@ -16,7 +16,7 @@ polymod <- socialmixr::polymod contact_data <- socialmixr::contact_matrix( polymod, countries = "United Kingdom", - age.limits = c(0, 15, 65), + age_limits = c(0, 15, 65), symmetric = TRUE ) @@ -359,7 +359,7 @@ polymod <- socialmixr::polymod contact_data <- socialmixr::contact_matrix( survey = polymod, countries = "United Kingdom", - age.limits = c(0, 20, 40), + age_limits = c(0, 20, 40), symmetric = TRUE ) # prepare contact matrix diff --git a/episodes/template.Rmd b/episodes/template.Rmd index 28b271a3..7be659ed 100644 --- a/episodes/template.Rmd +++ b/episodes/template.Rmd @@ -67,7 +67,7 @@ polymod <- socialmixr::polymod contact_data <- socialmixr::contact_matrix( polymod, countries = "United Kingdom", - age.limits = c(0, 20, 40), + age_limits = c(0, 20, 40), symmetric = TRUE ) contact_data @@ -82,7 +82,7 @@ polymod <- socialmixr::polymod contact_data <- socialmixr::contact_matrix( polymod, countries = "United Kingdom", - age.limits = c(0, 20, 40), + age_limits = c(0, 20, 40), symmetric = TRUE ) contact_data @@ -120,7 +120,7 @@ polymod <- socialmixr::polymod contact_data <- socialmixr::contact_matrix( polymod, countries = "Poland", - age.limits = c(0, 15, 50), + age_limits = c(0, 15, 50), symmetric = TRUE ) contact_data From bfe07ccfdb617b53ea992801f19093b0a3957d66 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Fri, 20 Mar 2026 20:04:23 +0000 Subject: [PATCH 02/19] update contact-matrices.Rmd with contactsurveys/socialmixr pattern - Add library(contactsurveys) and replace socialmixr::polymod loading with contactsurveys::download_survey() + socialmixr::load_survey() using the Zenodo DOI for POLYMOD and Zambia surveys - Add return_demography = TRUE to all contact_matrix() calls - Standardize object names: contacts_byage, contacts_byage_matrix - Add callout warning users to always specify countries = argument - Add text explaining return_demography requirement for {epidemics} Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 71 +++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 28b8ab1c..ebefccf6 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -38,6 +38,7 @@ Some groups of individuals have more contacts than others; the average schoolchi ```{r,message=FALSE,warning=FALSE} +library(contactsurveys) library(socialmixr) ``` @@ -80,29 +81,47 @@ For a contact matrix with rows $i$ and columns $j$: Contact matrices are commonly estimated from studies that use diaries to record interactions. For example, the POLYMOD survey measured contact patterns in 8 European countries using data on the location and duration of contacts reported by the study participants [(Mossong et al. 2008)](https://doi.org/10.1371/journal.pmed.0050074). -The R package `{socialmixr}` contains functions which can estimate contact matrices from POLYMOD and other surveys. We can load the POLYMOD survey data: +The R package `{socialmixr}` contains functions which can estimate contact matrices from POLYMOD and other surveys. We can download and load the POLYMOD survey data directly from Zenodo using `{contactsurveys}` and `{socialmixr}`: +```{r polymod_, echo = TRUE, message = FALSE} +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) + +survey_load <- socialmixr::load_survey(files = survey_files) +``` + +::::::::::::::::::::::::::::::::::::: callout +### Specify the country name + +A single survey file can contain data from multiple countries. You can inspect the available countries with: -```{r polymod_, echo = TRUE} -polymod <- socialmixr::polymod +```{r polymod_countries, echo = TRUE} +levels(survey_load$participants$country) ``` -Then we can obtain the contact matrix for the age categories we want by specifying `age_limits`. +Always pass the `countries =` argument to `contact_matrix()` to make sure you use data from the intended country only. + +:::::::::::::::::::::::::::::::::::::::::::::::: + +Then we can obtain the contact matrix for the age categories we want by specifying `age_limits`. We also add `return_demography = TRUE` to include demographic information in the output, which is required when using the contact matrix with `{epidemics}`. ```{r polymod_uk, echo = TRUE} -contact_data <- socialmixr::contact_matrix( - survey = polymod, +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) -contact_data +contacts_byage ``` -**Note: although the contact matrix `contact_data$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words: -`contact_data$matrix[j,i]*contact_data$demography$proportion[j] = contact_data$matrix[i,j]*contact_data$demography$proportion[i]`. +**Note: although the contact matrix `contacts_byage$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words: +`contacts_byage$matrix[j,i]*contacts_byage$demography$proportion[j] = contacts_byage$matrix[i,j]*contacts_byage$demography$proportion[i]`. For the mathematical explanation see [the corresponding section in the socialmixr documentation](https://epiforecasts.io/socialmixr/articles/socialmixr.html#symmetric-contact-matrices).** @@ -122,13 +141,16 @@ If `symmetric` is set to TRUE, the `contact_matrix()` function will internally u :::::::::::::::::::::::::::::::::::::::::::::::: -The example above uses the POLYMOD survey. There are a number of surveys available in `socialmixr`. To list the available surveys, use `socialmixr::list_surveys()`. To download a survey, we can use `socialmixr::get_survey()` +The example above uses the POLYMOD survey. There are a number of surveys available in `socialmixr`. To list the available surveys, use `socialmixr::list_surveys()`. To download a survey from Zenodo and load it, we use `contactsurveys::download_survey()` followed by `socialmixr::load_survey()`: ```{r, message = FALSE, warning = FALSE} -# Access the contact survey data from Zenodo -zambia_sa_survey <- socialmixr::get_survey( - "https://doi.org/10.5281/zenodo.3874675" +# Download and load the contact survey data for Zambia from Zenodo +zambia_survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874675", + verbose = FALSE ) + +zambia_sa_survey <- socialmixr::load_survey(files = zambia_survey_files) ``` :::::::::::::::::: spoiler @@ -179,20 +201,21 @@ Similar to the code above, to access vector values within a dataframe, you can u :::::::::::::::::::::::: instructor -```{r polymod_poland} +```{r zambia_solution} # Generate the contact matrix for Zambia only -contact_data_zambia <- socialmixr::contact_matrix( +contacts_byage_zambia <- socialmixr::contact_matrix( survey = zambia_sa_survey, countries = "Zambia", # key argument age_limits = c(0, 20), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # Print the contact matrix for Zambia only -contact_data_zambia +contacts_byage_zambia # Print the vector of population size for {epidemics} -contact_data_zambia$demography$population +contacts_byage_zambia$demography$population ``` ::::::::::::::::::::::::::::::::: @@ -290,12 +313,12 @@ When simulating an epidemic, we often want to ensure that the average number of Rather than just using the raw number of contacts, we can instead normalise the contact matrix to make it easier to work in terms of $R_0$. In particular, we normalise the matrix by scaling it so that if we were to calculate the average number of secondary cases based on this normalised matrix, the result would be 1 (in mathematical terms, we are scaling the matrix so the largest eigenvalue is 1). This transformation scales the entries but preserves their relative values. -In the case of the above model, we want to define $\beta C_{i,j}$ so that the model has a specified valued of $R_0$. If the entry of the contact matrix $C[i,j]$ represents the contacts of population $i$ with $j$, it is equivalent to `contact_data$matrix[i,j]`, and the maximum eigenvalue of this matrix represents the typical magnitude of contacts, not typical magnitude of transmission. We must therefore normalise the matrix $C$ so the maximum eigenvalue is one; we call this matrix $C_{normalised}$. Because the rate of recovery is $\gamma$, individuals will be infectious on average for $1/\gamma$ days. So $\beta$ as a model input is calculated from $R_0$, the scaling factor and the value of $\gamma$ (i.e. mathematically we use the fact that the dominant eigenvalue of the matrix $R_0 \times C_{normalised}$ is equal to $\beta / \gamma$). +In the case of the above model, we want to define $\beta C_{i,j}$ so that the model has a specified valued of $R_0$. If the entry of the contact matrix $C[i,j]$ represents the contacts of population $i$ with $j$, it is equivalent to `contacts_byage$matrix[i,j]`, and the maximum eigenvalue of this matrix represents the typical magnitude of contacts, not typical magnitude of transmission. We must therefore normalise the matrix $C$ so the maximum eigenvalue is one; we call this matrix $C_{normalised}$. Because the rate of recovery is $\gamma$, individuals will be infectious on average for $1/\gamma$ days. So $\beta$ as a model input is calculated from $R_0$, the scaling factor and the value of $\gamma$ (i.e. mathematically we use the fact that the dominant eigenvalue of the matrix $R_0 \times C_{normalised}$ is equal to $\beta / \gamma$). ```{r} -contact_matrix <- t(contact_data$matrix) -scaling_factor <- 1 / max(eigen(contact_matrix)$values) -normalised_matrix <- contact_matrix * scaling_factor +contacts_byage_matrix <- t(contacts_byage$matrix) +scaling_factor <- 1 / max(eigen(contacts_byage_matrix)$values) +normalised_matrix <- contacts_byage_matrix * scaling_factor ``` As a result, if we multiply the scaled matrix by $R_0$, then converting to the number of expected secondary cases would give us $R_0$, as required. @@ -317,7 +340,7 @@ Normalisation can be performed by the function `contact_matrix()` in `{socialmix ```{r, message = FALSE} contact_data_split <- socialmixr::contact_matrix( - survey = polymod, + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), symmetric = TRUE, From 8d5ce7f5c0f4d24d0165ac89a0c999a6858e03fa Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Fri, 20 Mar 2026 20:09:25 +0000 Subject: [PATCH 03/19] apply contactsurveys/socialmixr pattern to all downstream episodes Replace socialmixr::polymod and socialmixr::get_survey() with contactsurveys::download_survey() + socialmixr::load_survey() using the Zenodo DOI. Add return_demography = TRUE and standardize object names (contacts_byage, contacts_byage_matrix) across: - simulating-transmission.Rmd - modelling-interventions.Rmd - compare-interventions.Rmd - disease-burden.Rmd - vaccine-comparisons.Rmd - template.Rmd Co-Authored-By: Claude Sonnet 4.6 --- episodes/compare-interventions.Rmd | 50 +++++++++++-------- episodes/disease-burden.Rmd | 27 +++++++---- episodes/modelling-interventions.Rmd | 32 ++++++++----- episodes/simulating-transmission.Rmd | 36 ++++++++------ episodes/template.Rmd | 63 ++++++++++++++++-------- episodes/vaccine-comparisons.Rmd | 72 +++++++++++++++------------- 6 files changed, 170 insertions(+), 110 deletions(-) diff --git a/episodes/compare-interventions.Rmd b/episodes/compare-interventions.Rmd index fd4e0646..18bc2af7 100644 --- a/episodes/compare-interventions.Rmd +++ b/episodes/compare-interventions.Rmd @@ -12,20 +12,26 @@ library(epidemics) # hidden seed for stable stochastic output in lesson set.seed(33) -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 15, 65), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # prepare contact matrix -contact_matrix <- t(contact_data$matrix) +contacts_byage_matrix <- t(contacts_byage$matrix) # prepare the demography vector -demography_vector <- contact_data$demography$population -names(demography_vector) <- rownames(contact_matrix) +demography_vector <- contacts_byage$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix) # initial conditions: one in every 1 million is infected initial_i <- 1e-6 @@ -35,15 +41,15 @@ initial_conditions <- c( # build for all age groups initial_conditions <- matrix( - rep(initial_conditions, dim(contact_matrix)[1]), + rep(initial_conditions, dim(contacts_byage_matrix)[1]), ncol = 5, byrow = TRUE ) -rownames(initial_conditions) <- rownames(contact_matrix) +rownames(initial_conditions) <- rownames(contacts_byage_matrix) # prepare the population to model as affected by the epidemic uk_population <- epidemics::population( name = "UK", - contact_matrix = contact_matrix, + contact_matrix = contacts_byage_matrix, demography_vector = demography_vector, initial_conditions = initial_conditions ) @@ -355,19 +361,25 @@ output <- epidemics::model_vacamole( 1. Run the model ```{r} -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - survey = polymod, +survey_files_2 <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load_2 <- socialmixr::load_survey(files = survey_files_2) + +contacts_byage_2 <- socialmixr::contact_matrix( + survey = survey_load_2, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # prepare contact matrix -contact_matrix <- t(contact_data$matrix) +contacts_byage_matrix_2 <- t(contacts_byage_2$matrix) # extract demography vector -demography_vector <- contact_data$demography$population -names(demography_vector) <- rownames(contact_matrix) +demography_vector <- contacts_byage_2$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix_2) # prepare initial conditions initial_i <- 1e-6 @@ -385,12 +397,12 @@ initial_conditions_vacamole <- rbind( initial_conditions_vacamole, initial_conditions_vacamole ) -rownames(initial_conditions_vacamole) <- rownames(contact_matrix) +rownames(initial_conditions_vacamole) <- rownames(contacts_byage_matrix_2) # prepare population object uk_population_vacamole <- epidemics::population( name = "UK", - contact_matrix = contact_matrix, + contact_matrix = contacts_byage_matrix_2, demography_vector = demography_vector, initial_conditions = initial_conditions_vacamole ) diff --git a/episodes/disease-burden.Rmd b/episodes/disease-burden.Rmd index 519e0342..ef8fabb4 100644 --- a/episodes/disease-burden.Rmd +++ b/episodes/disease-burden.Rmd @@ -47,6 +47,7 @@ In this tutorial, we'll focus on the separated approach, where we first run an e ```{r, warning = FALSE, message = FALSE} library(epiparameter) library(epidemics) +library(contactsurveys) library(socialmixr) library(tidyverse) ``` @@ -83,21 +84,27 @@ We'll use `{epiparameter}` to define these delay distributions. The Gamma distri :::::::::::::::: instructor ```{r, echo = TRUE, message = FALSE} -# load contact and population data from socialmixr::polymod -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, +# download and load contact and population data from Zenodo +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # prepare contact matrix -contact_matrix <- t(contact_data$matrix) +contacts_byage_matrix <- t(contacts_byage$matrix) # prepare the demography vector -demography_vector <- contact_data$demography$population -names(demography_vector) <- rownames(contact_matrix) +demography_vector <- contacts_byage$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix) # initial conditions: one in every 1 million is infected initial_i <- 1e-6 @@ -115,12 +122,12 @@ initial_conditions <- rbind( initial_conditions_free, initial_conditions_free ) -rownames(initial_conditions) <- rownames(contact_matrix) +rownames(initial_conditions) <- rownames(contacts_byage_matrix) # prepare the population to model as affected by the epidemic uk_population <- epidemics::population( name = "UK", - contact_matrix = contact_matrix, + contact_matrix = contacts_byage_matrix, demography_vector = demography_vector, initial_conditions = initial_conditions ) diff --git a/episodes/modelling-interventions.Rmd b/episodes/modelling-interventions.Rmd index cc5f482d..2e11549d 100644 --- a/episodes/modelling-interventions.Rmd +++ b/episodes/modelling-interventions.Rmd @@ -57,6 +57,7 @@ In this tutorial, we will learn how to use `{epidemics}` to model interventions ```{r,message=FALSE,warning=FALSE} library(epidemics) +library(contactsurveys) library(socialmixr) library(tidyverse) ``` @@ -85,23 +86,28 @@ We will investigate the effect of interventions on a COVID-19 outbreak using an The SEIR model divides the population into four compartments: Susceptible (S), Exposed (E), Infectious (I), and Recovered (R). We will set the following parameters for our model: $R_0 = 2.7$ (basic reproduction number), latent period or pre-infectious period $= 4$ days, and the infectious period $= 5.5$ days (parameters adapted from [Davies et al. (2020)](https://doi.org/10.1016/S2468-2667(20)30133-X)). We adopt a contact matrix with age bins 0-18, 18-65, 65 years and older using `{socialmixr}`, and assume that one in every 1 million individuals in each age group is infectious at the start of the epidemic. ```{r model_setup, echo = TRUE, message = FALSE} -# load survey data -survey_data <- socialmixr::polymod +# download and load survey data +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) # generate contact matrix -cm_results <- socialmixr::contact_matrix( - survey = survey_data, +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 15, 65), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # transpose contact matrix -cm_matrix <- t(cm_results$matrix) +contacts_byage_matrix <- t(contacts_byage$matrix) # prepare the demography vector -demography_vector <- cm_results$demography$population -names(demography_vector) <- rownames(cm_matrix) +demography_vector <- contacts_byage$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix) # initial conditions: one in every 1 million is infected initial_i <- 1e-6 @@ -119,12 +125,12 @@ initial_conditions <- base::rbind( initial_conditions, initial_conditions ) -rownames(initial_conditions) <- rownames(cm_matrix) +rownames(initial_conditions) <- rownames(contacts_byage_matrix) # prepare the population to model as affected by the epidemic uk_population <- epidemics::population( name = "UK", - contact_matrix = cm_matrix, + contact_matrix = contacts_byage_matrix, demography_vector = demography_vector, initial_conditions = initial_conditions ) @@ -176,7 +182,7 @@ The first NPI we will consider is the effect of school closures on reducing the To include an intervention in our model we must create an `intervention` object. The inputs are the name of the intervention (`name`), the type of intervention (`contacts` or `rate`), the start time (`time_begin`), the end time (`time_end`) and the reduction (`reduction`). The values of the reduction matrix are specified in the same order as the age groups in the contact matrix. ```{r} -rownames(cm_matrix) +rownames(contacts_byage_matrix) ``` Therefore, we specify `reduction = matrix(c(0.5, 0.01, 0.01))`. We assume that the school closures start on day 50 and continue to be in place for a further 100 days. Therefore our intervention object is: @@ -433,8 +439,8 @@ Here we will assume all age groups are vaccinated at the same rate 0.01 and that # prepare a vaccination object vaccinate <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(cm_matrix)), - time_end = matrix(40 + 150, nrow(cm_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0.01, 0.01, 0.01)) ) ``` diff --git a/episodes/simulating-transmission.Rmd b/episodes/simulating-transmission.Rmd index 90e2a98d..eacaf19a 100644 --- a/episodes/simulating-transmission.Rmd +++ b/episodes/simulating-transmission.Rmd @@ -63,6 +63,7 @@ In this tutorial we are going to learn how to use the `{epidemics}` package to s ```{r,message=FALSE,warning=FALSE} library(epidemics) +library(contactsurveys) library(socialmixr) library(tidyverse) ``` @@ -185,7 +186,7 @@ Using the R package `socialmixr`, obtain the contact matrix for the United Kingd + age between 20 and 40, + 40 years and over. -Use the survey available at `socialmixr::polymod` +Use the POLYMOD survey available at `https://doi.org/10.5281/zenodo.3874557` :::::::::::::::: hint @@ -196,30 +197,35 @@ Use the survey available at `socialmixr::polymod` :::::::::::::::::::::::: solution ```{r polymod_uk, echo = TRUE, message = FALSE} -# Access the contact survey data -polymod <- socialmixr::polymod +# Download and load the contact survey data +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) # Generate the contact matrix -contact_data <- socialmixr::contact_matrix( - polymod, +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # prepare contact matrix -socialcontact_matrix <- t(contact_data$matrix) +contacts_byage_matrix <- t(contacts_byage$matrix) # print -socialcontact_matrix +contacts_byage_matrix ``` Remember that the matrix satisfies the `symmetric = TRUE` condition at the level of total number of contacts. -The total number of contacts between groups $i$ and $j$ is calculated as the mean number of contacts (`contact_data$matrix`) multiplied by the number of individuals in group $i$ (`contact_data$demography$population`) +The total number of contacts between groups $i$ and $j$ is calculated as the mean number of contacts (`contacts_byage$matrix`) multiplied by the number of individuals in group $i$ (`contacts_byage$demography$population`) ```{r} -contact_data$matrix * contact_data$demography$population +contacts_byage$matrix * contacts_byage$demography$population ``` ::::::::::::::::::::::::::::::::: @@ -284,7 +290,7 @@ initial_conditions <- rbind( ) # use contact matrix to assign age group names -rownames(initial_conditions) <- rownames(socialcontact_matrix) +rownames(initial_conditions) <- rownames(contacts_byage_matrix) initial_conditions ``` @@ -292,14 +298,14 @@ initial_conditions ### 3. Population structure -The population object requires a vector containing the demographic structure of the population. The demographic vector must be a named vector containing the number of individuals in each age group of our given population. In this example, we can extract the demographic information from the `contact_data` object that we obtained using the `socialmixr` package. +The population object requires a vector containing the demographic structure of the population. The demographic vector must be a named vector containing the number of individuals in each age group of our given population. In this example, we can extract the demographic information from the `contacts_byage` object that we obtained using the `socialmixr` package. ```{r demography} # extract the demography vector -demography_vector <- contact_data$demography$population +demography_vector <- contacts_byage$demography$population # use contact matrix to assign age group names -names(demography_vector) <- rownames(socialcontact_matrix) +names(demography_vector) <- rownames(contacts_byage_matrix) demography_vector ``` @@ -310,7 +316,7 @@ library(epidemics) uk_population <- epidemics::population( name = "UK", - contact_matrix = socialcontact_matrix, + contact_matrix = contacts_byage_matrix, demography_vector = demography_vector, initial_conditions = initial_conditions ) diff --git a/episodes/template.Rmd b/episodes/template.Rmd index 7be659ed..de929aa3 100644 --- a/episodes/template.Rmd +++ b/episodes/template.Rmd @@ -60,32 +60,47 @@ Lesson content ## Challenge 1 : can the learner run existing code -Load contact and population data from socialmixr::polymod +Load contact and population data from the POLYMOD Zenodo survey ```r -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, +library(contactsurveys) +library(socialmixr) + +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) -contact_data +contacts_byage ``` -:::::::::::::::::::::::: solution +:::::::::::::::::::::::: solution ## Output - -```{r polymod_uk, echo = FALSE} -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, + +```{r polymod_uk, echo = FALSE, message = FALSE} +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 20, 40), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) -contact_data +contacts_byage ``` @@ -107,7 +122,7 @@ Add additional maths (or epi) content for novice learners ## Challenge 2 : edit code/answer a question -Load contact and population data for Poland from socialmixr::polymod using the following age bins: +Load contact and population data for Poland from the POLYMOD Zenodo survey using the following age bins: + [0,15) + [15, 50) @@ -115,15 +130,21 @@ Load contact and population data for Poland from socialmixr::polymod using the f :::::::::::::::::::::::: solution -```{r polymod_poland} -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, +```{r polymod_poland, message = FALSE} +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "Poland", age_limits = c(0, 15, 50), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) -contact_data +contacts_byage ``` ::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::: diff --git a/episodes/vaccine-comparisons.Rmd b/episodes/vaccine-comparisons.Rmd index 1d7b1537..e5dd136d 100644 --- a/episodes/vaccine-comparisons.Rmd +++ b/episodes/vaccine-comparisons.Rmd @@ -40,6 +40,8 @@ In this tutorial we will compare different vaccination strategies using models f ```{r, message = FALSE} library(ggplot2) library(epidemics) +library(contactsurveys) +library(socialmixr) library(dplyr) library(purrr) ``` @@ -66,21 +68,27 @@ We will illustrate this using results from `model_default()` in `{epidemics}`. T ```{r, echo = FALSE, message = FALSE} -polymod <- socialmixr::polymod -contact_data <- socialmixr::contact_matrix( - polymod, +survey_files <- contactsurveys::download_survey( + survey = "https://doi.org/10.5281/zenodo.3874557", + verbose = FALSE +) +survey_load <- socialmixr::load_survey(files = survey_files) + +contacts_byage <- socialmixr::contact_matrix( + survey = survey_load, countries = "United Kingdom", age_limits = c(0, 15, 65), - symmetric = TRUE + symmetric = TRUE, + return_demography = TRUE ) # prepare contact matrix -contact_matrix <- t(contact_data$matrix) +contacts_byage_matrix <- t(contacts_byage$matrix) # prepare the demography vector -demography_vector <- contact_data$demography$population -names(demography_vector) <- rownames(contact_matrix) +demography_vector <- contacts_byage$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix) # initial conditions: one in every 1 million is infected initial_i <- 1e-6 @@ -90,15 +98,15 @@ initial_conditions <- c( # build for all age groups initial_conditions <- matrix( - rep(initial_conditions, dim(contact_matrix)[1]), + rep(initial_conditions, dim(contacts_byage_matrix)[1]), ncol = 5, byrow = TRUE ) -rownames(initial_conditions) <- rownames(contact_matrix) +rownames(initial_conditions) <- rownames(contacts_byage_matrix) # prepare the population to model as affected by the epidemic uk_population <- epidemics::population( name = "UK", - contact_matrix = contact_matrix, + contact_matrix = contacts_byage_matrix, demography_vector = demography_vector, initial_conditions = initial_conditions ) @@ -119,15 +127,15 @@ transmission_rate <- basic_reproduction / infectious_period # prepare vaccination objects vaccinate_01 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(0, nrow(contact_matrix)), - time_end = matrix(150, nrow(contact_matrix)), + time_begin = matrix(0, nrow(contacts_byage_matrix)), + time_end = matrix(150, nrow(contacts_byage_matrix)), nu = matrix(c(0.001, 0.001, 0.001)) ) vaccinate_02 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(0, nrow(contact_matrix)), - time_end = matrix(150, nrow(contact_matrix)), + time_begin = matrix(0, nrow(contacts_byage_matrix)), + time_end = matrix(150, nrow(contacts_byage_matrix)), nu = matrix(c(0.01, 0.01, 0.01)) ) ``` @@ -494,7 +502,7 @@ For infections that have a higher burden in different risk groups, targeted vacc We will use the same contact matrix as above from [Modelling interventions](../episodes/modelling-interventions.md): ```{r} -contact_matrix +contacts_byage_matrix ``` There is higher levels of mixing within the 0-15 and 15-65 age groups than in the 65+ age group, so we expect that targeting different age groups will result in different disease trajectories. @@ -514,22 +522,22 @@ To show the effect of targeted vaccination, we will compare the following scenar ```{r, echo = FALSE} vaccinate_group_1 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0.001 * 3, 0, 0)) ) vaccinate_group_2 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0, 0.001 * 3, 0)) ) vaccinate_group_3 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0, 0, 0.001 * 3)) ) @@ -638,22 +646,22 @@ output_infections %>% ```{r, echo = TRUE, eval = FALSE} vaccinate_group_1 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0.001 * 3, 0, 0)) ) vaccinate_group_2 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0, 0.001 * 3, 0)) ) vaccinate_group_3 <- epidemics::vaccination( name = "vaccinate all", - time_begin = matrix(40, nrow(contact_matrix)), - time_end = matrix(40 + 150, nrow(contact_matrix)), + time_begin = matrix(40, nrow(contacts_byage_matrix)), + time_end = matrix(40 + 150, nrow(contacts_byage_matrix)), nu = matrix(c(0, 0, 0.001 * 3)) ) @@ -781,7 +789,7 @@ Targeting specific age groups can reduce the number of deaths in the eldest age ```{r} ifr <- c(0.00001, 0.001, 0.4) -names(ifr) <- rownames(contact_matrix) +names(ifr) <- rownames(contacts_byage_matrix) ``` To convert infections to deaths, we will need new infections by age group, so we call `new_infections()` with `by_group = TRUE` and then multiply the new infections by the IFR for that age group: @@ -937,8 +945,8 @@ close_schools_early <- epidemics::intervention( # vaccination late vacc_late <- epidemics::vaccination( name = "vaccinate late", - time_begin = matrix(late_start, nrow(contact_matrix)), - time_end = matrix(late_start + duration, nrow(contact_matrix)), + time_begin = matrix(late_start, nrow(contacts_byage_matrix)), + time_end = matrix(late_start + duration, nrow(contacts_byage_matrix)), nu = matrix(c(0.01, 0.01, 0.01)) ) @@ -960,8 +968,8 @@ output_npi_early_vacc_late <- epidemics::model_default( # vaccinate early vacc_early <- epidemics::vaccination( name = "vaccinate early", - time_begin = matrix(early_start, nrow(contact_matrix)), - time_end = matrix(early_start + duration, nrow(contact_matrix)), + time_begin = matrix(early_start, nrow(contacts_byage_matrix)), + time_end = matrix(early_start + duration, nrow(contacts_byage_matrix)), nu = matrix(c(0.01, 0.01, 0.01)) ) From d2e3678b3640eef27fafdde5812a254d5eedf302 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Fri, 20 Mar 2026 22:18:21 +0000 Subject: [PATCH 04/19] suppress load_survey() 'No reference provided' warning Add warning = FALSE to all chunk headers that call contactsurveys::download_survey() + socialmixr::load_survey(), suppressing the cosmetic 'No reference provided' warning from socialmixr. Co-Authored-By: Claude Sonnet 4.6 --- episodes/compare-interventions.Rmd | 2 +- episodes/contact-matrices.Rmd | 4 ++-- episodes/disease-burden.Rmd | 2 +- episodes/modelling-interventions.Rmd | 2 +- episodes/simulating-transmission.Rmd | 2 +- episodes/template.Rmd | 4 ++-- episodes/vaccine-comparisons.Rmd | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/episodes/compare-interventions.Rmd b/episodes/compare-interventions.Rmd index 18bc2af7..c745dbfa 100644 --- a/episodes/compare-interventions.Rmd +++ b/episodes/compare-interventions.Rmd @@ -360,7 +360,7 @@ output <- epidemics::model_vacamole( 1. Run the model -```{r} +```{r, message = FALSE, warning = FALSE} survey_files_2 <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index ebefccf6..714038e8 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -83,7 +83,7 @@ Contact matrices are commonly estimated from studies that use diaries to record The R package `{socialmixr}` contains functions which can estimate contact matrices from POLYMOD and other surveys. We can download and load the POLYMOD survey data directly from Zenodo using `{contactsurveys}` and `{socialmixr}`: -```{r polymod_, echo = TRUE, message = FALSE} +```{r polymod_, echo = TRUE, message = FALSE, warning = FALSE} survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE @@ -201,7 +201,7 @@ Similar to the code above, to access vector values within a dataframe, you can u :::::::::::::::::::::::: instructor -```{r zambia_solution} +```{r zambia_solution, message = FALSE, warning = FALSE} # Generate the contact matrix for Zambia only contacts_byage_zambia <- socialmixr::contact_matrix( survey = zambia_sa_survey, diff --git a/episodes/disease-burden.Rmd b/episodes/disease-burden.Rmd index ef8fabb4..432e6de4 100644 --- a/episodes/disease-burden.Rmd +++ b/episodes/disease-burden.Rmd @@ -83,7 +83,7 @@ We'll use `{epiparameter}` to define these delay distributions. The Gamma distri :::::::::::::::: instructor -```{r, echo = TRUE, message = FALSE} +```{r, echo = TRUE, message = FALSE, warning = FALSE} # download and load contact and population data from Zenodo survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", diff --git a/episodes/modelling-interventions.Rmd b/episodes/modelling-interventions.Rmd index 2e11549d..b0f6731c 100644 --- a/episodes/modelling-interventions.Rmd +++ b/episodes/modelling-interventions.Rmd @@ -85,7 +85,7 @@ We will investigate the effect of interventions on a COVID-19 outbreak using an The SEIR model divides the population into four compartments: Susceptible (S), Exposed (E), Infectious (I), and Recovered (R). We will set the following parameters for our model: $R_0 = 2.7$ (basic reproduction number), latent period or pre-infectious period $= 4$ days, and the infectious period $= 5.5$ days (parameters adapted from [Davies et al. (2020)](https://doi.org/10.1016/S2468-2667(20)30133-X)). We adopt a contact matrix with age bins 0-18, 18-65, 65 years and older using `{socialmixr}`, and assume that one in every 1 million individuals in each age group is infectious at the start of the epidemic. -```{r model_setup, echo = TRUE, message = FALSE} +```{r model_setup, echo = TRUE, message = FALSE, warning = FALSE} # download and load survey data survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", diff --git a/episodes/simulating-transmission.Rmd b/episodes/simulating-transmission.Rmd index eacaf19a..e2f837cf 100644 --- a/episodes/simulating-transmission.Rmd +++ b/episodes/simulating-transmission.Rmd @@ -196,7 +196,7 @@ Use the POLYMOD survey available at `https://doi.org/10.5281/zenodo.3874557` :::::::::::::::::::::::: solution -```{r polymod_uk, echo = TRUE, message = FALSE} +```{r polymod_uk, echo = TRUE, message = FALSE, warning = FALSE} # Download and load the contact survey data survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", diff --git a/episodes/template.Rmd b/episodes/template.Rmd index de929aa3..74ddcd35 100644 --- a/episodes/template.Rmd +++ b/episodes/template.Rmd @@ -86,7 +86,7 @@ contacts_byage ## Output -```{r polymod_uk, echo = FALSE, message = FALSE} +```{r polymod_uk, echo = FALSE, message = FALSE, warning = FALSE} survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE @@ -130,7 +130,7 @@ Load contact and population data for Poland from the POLYMOD Zenodo survey using :::::::::::::::::::::::: solution -```{r polymod_poland, message = FALSE} +```{r polymod_poland, message = FALSE, warning = FALSE} survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE diff --git a/episodes/vaccine-comparisons.Rmd b/episodes/vaccine-comparisons.Rmd index e5dd136d..0806ab8d 100644 --- a/episodes/vaccine-comparisons.Rmd +++ b/episodes/vaccine-comparisons.Rmd @@ -67,7 +67,7 @@ We will illustrate this using results from `model_default()` in `{epidemics}`. T + vaccination program 02: vaccination rate 0.01. -```{r, echo = FALSE, message = FALSE} +```{r, echo = FALSE, message = FALSE, warning = FALSE} survey_files <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE From f2227d8d61f5ecc6caf8fb1d2d8bd6f820ec16b3 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Fri, 20 Mar 2026 22:25:22 +0000 Subject: [PATCH 05/19] remove unnecessary warning = FALSE from zambia_solution chunk The warning is emitted by load_survey(), not contact_matrix(), so suppressing it on the contact_matrix() chunk has no effect. Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 714038e8..d4e0a58f 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -201,7 +201,7 @@ Similar to the code above, to access vector values within a dataframe, you can u :::::::::::::::::::::::: instructor -```{r zambia_solution, message = FALSE, warning = FALSE} +```{r zambia_solution} # Generate the contact matrix for Zambia only contacts_byage_zambia <- socialmixr::contact_matrix( survey = zambia_sa_survey, From 7251923ee4df9a686443868a9b072e7cad21f44c Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 12:00:38 +0000 Subject: [PATCH 06/19] polish the setup page --- learners/setup.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/learners/setup.md b/learners/setup.md index 3af54bfe..5e077557 100644 --- a/learners/setup.md +++ b/learners/setup.md @@ -13,13 +13,13 @@ Epiverse-TRACE aims to provide a software ecosystem for [**outbreak analytics**] Our tutorials are built around an outbreak analysis pipeline split into three stages: **Early tasks**, **Middle tasks** and **Late tasks**. The outputs of tasks completed in earlier stages commonly feed into the tasks required for later ones. -![An overview of the tutorial topics](https://epiverse-trace.github.io/task_pipeline-minimal.svg) +![An overview of the tutorial topics arranged by the three stages of outbreak analytics.](https://epiverse-trace.github.io/task_pipeline-minimal.svg) -Each task has its tutorial website and each tutorial website consists of a set of episodes covering different topics. +Each stage has its tutorial website and each tutorial website consists of a set of episodes covering different topics. | [Early task tutorials ➠](https://epiverse-trace.github.io/tutorials-early/) | [Middle task tutorials ➠](https://epiverse-trace.github.io/tutorials-middle) | [Late task tutorials ➠](https://epiverse-trace.github.io/tutorials-late/) | |---|---|---| -| Read and clean case data, and make linelist | Real-time analysis and forecasting | Scenario modelling | +| Import and standardized outbreak data, and produce epicurves | Real-time analysis and forecasting | Scenario modelling | | Read, clean and validate case data, convert linelist data to incidence for visualization. | Access delay distributions and estimate transmission metrics, forecast cases, estimate severity and superspreading. | Simulate disease spread and investigate interventions. | Each episode contains: @@ -30,20 +30,20 @@ Each episode contains: + **Challenges**: challenges that can be completed to test your understanding. + **Explainers**: boxes to enhance your understanding of mathematical and modelling concepts. -Also check out the [glossary](./reference.md) for any terms you may be unfamiliar with. +Also check out the [glossary](./reference.md) for any terms you may be unfamiliar with. The **More** tab provides detailed technical documentation and case studies. ### Epiverse-TRACE R packages Our strategy is to gradually incorporate specialised **R packages** into a traditional analysis pipeline. These packages should fill the gaps in these epidemiology-specific tasks in response to outbreaks. -![In **R**, the fundamental unit of shareable code is the **package**. A package bundles together code, data, documentation, and tests and is easy to share with others ([Wickham and Bryan, 2023](https://r-pkgs.org/introduction.html))](episodes/fig/pkgs-hexlogos-2.png) +![In **R**, the fundamental unit of shareable code is the **package**. A package bundles together code, data, documentation, and tests and is easy to share with others ([Wickham and Bryan, 2023](https://r-pkgs.org/introduction.html))](episodes/fig/pkgs-hexlogos-2.png). :::::::::::::::::::::::::::: prereq This content assumes intermediate R knowledge. This tutorials are for you if: -- You can read data into R, transform and reshape data, and make a wide variety of graphs -- You are familiar with functions from `{dplyr}`, `{tidyr}`, and `{ggplot2}` +- You can read data into R, transform and reshape data, and make a wide variety of graphs. +- You are familiar with functions from `{dplyr}`, `{tidyr}`, and `{ggplot2}`. - You can use the magrittr pipe `%>%` and/or native pipe `|>`. From c9fbb940f469aca017ffbe061de941f342ee9f47 Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 12:06:21 +0000 Subject: [PATCH 07/19] remove an empty instructor call. --- episodes/contact-matrices.Rmd | 7 ------- 1 file changed, 7 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index d4e0a58f..3fb84792 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -42,13 +42,6 @@ library(contactsurveys) library(socialmixr) ``` - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: instructor - - - -:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: - ## The contact matrix The basic contact matrix represents the amount of contact or mixing within and between different subgroups of a population. The subgroups are often age categories but can also be: From 2fa8026eb99790a9b48d8b8480ebebb818551ff7 Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 12:18:32 +0000 Subject: [PATCH 08/19] shortend the explanation of contact matrix. --- episodes/contact-matrices.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 3fb84792..75356ad2 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -59,15 +59,15 @@ $$ \end{bmatrix} $$ -In this example, we would use this to represent that children meet, on average, 2 other children and 2 adult per day (first row), and adults meet, on average, 1 child and 3 other adults per day (second row). We can use this kind of information to account for the role heterogeneity in contact plays in infectious disease transmission. +In this example, we would use this to represent that children meet, on average, 2 other children and 2 adult per day (first row), and adults meet, on average, 1 child and 3 other adults per day (second row). We can use this kind of information to account for the role that heterogeneity in contact plays in infectious disease transmission. ::::::::::::::::::::::::::::::::::::: callout ### A Note on Notation -For a contact matrix with rows $i$ and columns $j$: +In a contact matrix, the entry $C[i,j]$, at row $i$ and column $j$: -- $C[i,j]$ represents the average number of contacts that individuals in group $i$ have with individuals in group $j$ -- This average is calculated as the total number of contacts between groups $i$ and $j$, divided by the number of individuals in group $i$ +- Represents the average number of contacts an individual in group $i$ has with individuals in group $j$ +- This is calculated by dividing the total number of contacts between groups $i$ and $j$ by the size of group $i$ :::::::::::::::::::::::::::::::::::::::::::::::: ## Using `socialmixr` From 1687a28bfc8471396001fe008fede8c2682f9376 Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 12:35:58 +0000 Subject: [PATCH 09/19] remove compartment E fron SIR model example. --- episodes/contact-matrices.Rmd | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 75356ad2..f7c55181 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -113,9 +113,9 @@ contacts_byage -**Note: although the contact matrix `contacts_byage$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words: +**Note**: although the contact matrix `contacts_byage$matrix` is not itself mathematically symmetric, it satisfies the condition that the total number of contacts of one group with another is the same as the reverse. In other words: `contacts_byage$matrix[j,i]*contacts_byage$demography$proportion[j] = contacts_byage$matrix[i,j]*contacts_byage$demography$proportion[i]`. -For the mathematical explanation see [the corresponding section in the socialmixr documentation](https://epiforecasts.io/socialmixr/articles/socialmixr.html#symmetric-contact-matrices).** +For the mathematical explanation see [the corresponding section in the socialmixr documentation](https://epiforecasts.io/socialmixr/articles/socialmixr.html#symmetric-contact-matrices). ::::::::::::::::::::::::::::::::::::: callout @@ -220,8 +220,6 @@ Contact matrices can be estimated from data obtained from diary (such as POLYMOD :::::::::::::::::::::::::::::::::::::::::::::::: - - ## Analyses with contact matrices Contact matrices can be used in a wide range of epidemiological analyses, they can be used: @@ -244,7 +242,7 @@ Whereas a contact matrix gives the average number of contacts that one groups ma ### In mathematical models -Consider the SIR model where individuals are categorized as either susceptible $S$, infected but not yet infectious $E$, infectious $I$ or recovered $R$. The schematic below shows the processes which describe the flow of individuals between the disease states $S$, $I$ and $R$ and the key parameters for each process. +Consider the SIR model where individuals are categorized as either susceptible $S$, infected $I$ and recovered $R$. The schematic below shows the processes which describe the flow of individuals between the disease states $S$, $I$ and $R$ and the key parameters for each process. ```{r diagram, echo = FALSE, message = FALSE} DiagrammeR::grViz("digraph { @@ -289,7 +287,7 @@ To add age structure to our model, we need to add additional equations for the i $$ \beta S_i \sum_j C_{i,j} I_j/N_j. $$ -Susceptible individuals in age group $i$ become infected dependent on their rate of contact with individuals in each age group. For each disease state ($S$, $E$, $I$ and $R$) and age group ($i$), we have a differential equation describing the rate of change with respect to time. +Susceptible individuals in age group $i$ become infected dependent on their rate of contact with individuals in each age group. For each disease state ($S$, $I$ and $R$) and age group ($i$), we have a differential equations describing the rate of change with respect to time. $$ \begin{aligned} From 3ff67d51a398867a4d3ee3649dfdc033f69ec37a Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 13:03:40 +0000 Subject: [PATCH 10/19] polish transmission episode --- episodes/simulating-transmission.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/episodes/simulating-transmission.Rmd b/episodes/simulating-transmission.Rmd index e2f837cf..b56923e8 100644 --- a/episodes/simulating-transmission.Rmd +++ b/episodes/simulating-transmission.Rmd @@ -29,7 +29,7 @@ webshot::install_phantomjs(force = TRUE) ::::::::::::::::::::::::::::::::::::: prereq -+ Complete tutorial on [Contact matrices](../episodes/contact-matrices.md). ++ Complete tutorial on [contact matrices](../episodes/contact-matrices.md). Learners should familiarise themselves with following concept dependencies before working through this tutorial: @@ -43,7 +43,7 @@ Learners should familiarise themselves with following concept dependencies befor :::::::::: spoiler -Install packages if their are not already installed +Install these packages if their are not already installed ```r if (!base::require("pak")) install.packages("pak") @@ -605,7 +605,7 @@ In this tutorial, we have learnt how to simulate disease spread using a mathemat ::::::::::::::::::::::::::::::::::::: keypoints -- Disease trajectories can be generated using the R package `epidemics` +- Disease trajectories can be generated using the R package `{epidemics}` - Uncertainty should be included in model trajectories using a range of model parameter values :::::::::::::::::::::::::::::::::::::::::::::::: From 31f35d09e11bd5c5e7bab55c6303538072f6b4b5 Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 13:12:02 +0000 Subject: [PATCH 11/19] polish model choice episode. --- episodes/model-choices.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/episodes/model-choices.Rmd b/episodes/model-choices.Rmd index 0476e5b2..dd66377d 100644 --- a/episodes/model-choices.Rmd +++ b/episodes/model-choices.Rmd @@ -29,7 +29,7 @@ set.seed(33) ::::::::::::::::::::::::::::::::::::: prereq -+ Complete tutorial [Simulating transmission](../episodes/simulating-transmission.md) ++ Complete tutorial [simulating transmission](../episodes/simulating-transmission.md) ::::::::::::::::::::::::::::::::: @@ -206,7 +206,7 @@ The key parameters affecting the transition between states are: + $\rho^E$, the mean preinfectious period, + $p_{hosp}$ the probability of being transferred to the hospitalised compartment. -**Note: the functional relationship between the preinfectious period ($\rho^E$) and the transition rate between exposed and infectious ($\gamma^E$) is $\rho^E = k^E/\gamma^E$ where $k^E$ is the shape of the Erlang distribution. Similarly for the infectious period $\rho^I = k^I/\gamma^I$. For more detail on the stochastic model formulation refer to the section on [Discrete-time Ebola virus disease model](https://epiverse-trace.github.io/epidemics/articles/model_ebola.html#details-discrete-time-ebola-virus-disease-model) in the "Modelling responses to a stochastic Ebola virus epidemic" vignette. ** +**Note:** the functional relationship between the preinfectious period ($\rho^E$) and the transition rate between exposed and infectious ($\gamma^E$) is $\rho^E = k^E/\gamma^E$ where $k^E$ is the shape of the Erlang distribution. Similarly for the infectious period $\rho^I = k^I/\gamma^I$. For more detail on the stochastic model formulation refer to the section on [Discrete-time Ebola virus disease model](https://epiverse-trace.github.io/epidemics/articles/model_ebola.html#details-discrete-time-ebola-virus-disease-model) in the "Modelling responses to a stochastic Ebola virus epidemic" vignette. ```{r, echo = FALSE, message = FALSE} DiagrammeR::grViz("digraph { From c2b888f2913f69d84444b87581bac4b9699d59ab Mon Sep 17 00:00:00 2001 From: Degoot-AM Date: Mon, 23 Mar 2026 13:36:03 +0000 Subject: [PATCH 12/19] fix space and : --- episodes/compare-interventions.Rmd | 26 +++++++++++++------------- episodes/contact-matrices.Rmd | 2 +- episodes/disease-burden.Rmd | 4 ++-- episodes/model-choices.Rmd | 16 ++++++++-------- episodes/modelling-interventions.Rmd | 2 +- episodes/simulating-transmission.Rmd | 8 ++++---- episodes/template.Rmd | 4 ++-- episodes/vaccine-comparisons.Rmd | 12 ++++++------ 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/episodes/compare-interventions.Rmd b/episodes/compare-interventions.Rmd index c745dbfa..1ae9932c 100644 --- a/episodes/compare-interventions.Rmd +++ b/episodes/compare-interventions.Rmd @@ -109,7 +109,7 @@ output_baseline <- epidemics::model_default( Learners should familiarise themselves with following concept dependencies before working through this tutorial: -**Outbreak response** : [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). +**Outbreak response**: [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). ::::::::::::::::::::::::::::::::: @@ -340,7 +340,7 @@ There is no vaccination scheme in place ::::::::::::::::: hint -### HINT : Running the model with default parameter values +### HINT: Running the model with default parameter values We can run the Vacamole model with [default parameter values](https://epiverse-trace.github.io/epidemics/articles/model_vacamole.html#model-epidemic-using-vacamole) by just specifying the population object and number of time steps to run the model for: @@ -543,9 +543,9 @@ output_baseline <- epidemics::model_default( Then, we create a list of all the interventions we want to include in our comparison. We define our scenarios as follows: -+ scenario 1 : close schools -+ scenario 2 : mask mandate -+ scenario 3 : close schools and mask mandate. ++ scenario 1: close schools ++ scenario 2: mask mandate ++ scenario 3: close schools and mask mandate. In R we specify this as: ```{r} @@ -579,7 +579,7 @@ head(output) Now that we have our model output for all of our scenarios, we want to compare the outputs of the interventions to our baseline. -We can do this using `outcomes_averted()` in `{epidemics}`. This function calculates the final epidemic size for each scenario, and then calculates the number of infections averted in each scenario compared to the baseline. To use this function we specify the : +We can do this using `outcomes_averted()` in `{epidemics}`. This function calculates the final epidemic size for each scenario, and then calculates the number of infections averted in each scenario compared to the baseline. To use this function we specify the: + output of the baseline scenario + outputs of the intervention scenario(s). @@ -617,9 +617,9 @@ We recommend to read the vignette on [Modelling responses to a stochastic Ebola ::::::::::::::::::::::::::::::::::::: challenge -## Challenge : Ebola outbreak analysis +## Challenge: Ebola outbreak analysis -You have been tasked to investigate the potential impact of an intervention on an Ebola outbreak in Guinea (e.g. a reduction in risky contacts with cases). Using `model_ebola()` and the the information detailed below, find the number of infections averted when : +You have been tasked to investigate the potential impact of an intervention on an Ebola outbreak in Guinea (e.g. a reduction in risky contacts with cases). Using `model_ebola()` and the the information detailed below, find the number of infections averted when: + an intervention is applied to reduce the transmission rate by 50% from day 60 and, + an intervention is applied to reduce transmission by 10% from day 30. @@ -628,11 +628,11 @@ For both interventions, we assume there is some uncertainty about the baseline t *Note: Depending on the number of replicates used, this simulation may take several minutes to run.* -+ Population size : 14 million -+ Initial number of exposed individuals : 10 -+ Initial number of infectious individuals : 5 -+ Time of simulation : 120 days -+ Parameter values : ++ Population size: 14 million ++ Initial number of exposed individuals: 10 ++ Initial number of infectious individuals: 5 ++ Time of simulation: 120 days ++ Parameter values: + $R_0$ (`r0`) = 1.1, + $p^I$ (`infectious_period`) = 12, + $p^E$ (`preinfectious_period`) = 5, diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index f7c55181..71efff8d 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -283,7 +283,7 @@ $$ \end{aligned} $$ -To add age structure to our model, we need to add additional equations for the infection states $S$, $I$ and $R$ for each age group $i$. If we want to assume that there is heterogeneity in contacts between age groups then we must adapt the transmission term $\beta SI$ to include the contact matrix $C$ as follows : +To add age structure to our model, we need to add additional equations for the infection states $S$, $I$ and $R$ for each age group $i$. If we want to assume that there is heterogeneity in contacts between age groups then we must adapt the transmission term $\beta SI$ to include the contact matrix $C$ as follows: $$ \beta S_i \sum_j C_{i,j} I_j/N_j. $$ diff --git a/episodes/disease-burden.Rmd b/episodes/disease-burden.Rmd index 432e6de4..d394788e 100644 --- a/episodes/disease-burden.Rmd +++ b/episodes/disease-burden.Rmd @@ -160,7 +160,7 @@ new_cases <- new_infections(output, by_group = FALSE) head(new_cases) ``` -To convert the new infections to hospitalisations we need to parameter distributions to describe the following processes : +To convert the new infections to hospitalisations we need to parameter distributions to describe the following processes: + the time from infection to admission to hospital, @@ -185,7 +185,7 @@ infection_to_admission <- epiparameter( # with right-skewed distribution reflecting variability in disease progression ``` -To visualise this distribution we can create a density plot : +To visualise this distribution we can create a density plot: ```{r} x_range <- seq(0, 60, by = 0.1) diff --git a/episodes/model-choices.Rmd b/episodes/model-choices.Rmd index dd66377d..07d615a2 100644 --- a/episodes/model-choices.Rmd +++ b/episodes/model-choices.Rmd @@ -47,7 +47,7 @@ The focus of this tutorial is understanding existing models to decide if they ar ### Choosing a model -When deciding which mathematical model to use, there are a number of questions we must consider : +When deciding which mathematical model to use, there are a number of questions we must consider: ::::::::::::::::::::::::::::::::::::::::::::::::::: @@ -274,7 +274,7 @@ An advantage of using `finalsize` is that fewer parameters are required. You onl :::::::::::::::::::::::::::::::::::::::::::::::: -## Challenge : Ebola outbreak analysis +## Challenge: Ebola outbreak analysis @@ -287,11 +287,11 @@ You have been tasked to generate initial trajectories of an Ebola outbreak in Gu 1. Run the model once and plot the number of infectious individuals through time 2. Run model 100 times and plot the mean, upper and lower 95% quantiles of the number of infectious individuals through time -+ Population size : 14 million -+ Initial number of exposed individuals : 10 -+ Initial number of infectious individuals : 5 -+ Time of simulation : 120 days -+ Parameter values : ++ Population size: 14 million ++ Initial number of exposed individuals: 10 ++ Initial number of infectious individuals: 5 ++ Time of simulation: 120 days ++ Parameter values: + $R_0$ (`r0`) = 1.1, + $p^I$ (`infectious_period`) = 12, + $p^E$ (`preinfectious_period`) = 5, @@ -332,7 +332,7 @@ guinea_population <- population( ::::::::::::::::: hint -### HINT : Multiple model simulations +### HINT: Multiple model simulations Adapt the code from the [accounting for uncertainty](../episodes/simulating-transmission.md#accounting-for-uncertainty) section diff --git a/episodes/modelling-interventions.Rmd b/episodes/modelling-interventions.Rmd index b0f6731c..7a77fab6 100644 --- a/episodes/modelling-interventions.Rmd +++ b/episodes/modelling-interventions.Rmd @@ -27,7 +27,7 @@ library(epidemics) Learners should also familiarise themselves with following concept dependencies before working through this tutorial: -**Outbreak response** : [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). +**Outbreak response**: [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). **R packages installed**: `{epidemics}`, `{socialmixr}`, `{scales}`, `{tidyverse}`. diff --git a/episodes/simulating-transmission.Rmd b/episodes/simulating-transmission.Rmd index b56923e8..e1feb195 100644 --- a/episodes/simulating-transmission.Rmd +++ b/episodes/simulating-transmission.Rmd @@ -33,9 +33,9 @@ webshot::install_phantomjs(force = TRUE) Learners should familiarise themselves with following concept dependencies before working through this tutorial: -**Mathematical Modelling** : [Introduction to infectious disease models](https://doi.org/10.1038/s41592-020-0856-2), [state variables](../learners/reference.md#state), [model parameters](../learners/reference.md#parsode), [initial conditions](../learners/reference.md#initial), [differential equations](../learners/reference.md#ordinary). +**Mathematical Modelling**: [Introduction to infectious disease models](https://doi.org/10.1038/s41592-020-0856-2), [state variables](../learners/reference.md#state), [model parameters](../learners/reference.md#parsode), [initial conditions](../learners/reference.md#initial), [differential equations](../learners/reference.md#ordinary). -**Epidemic theory** : [Transmission](https://doi.org/10.1155/2011/267049), [Reproduction number](https://doi.org/10.3201/eid2501.171901). +**Epidemic theory**: [Transmission](https://doi.org/10.1155/2011/267049), [Reproduction number](https://doi.org/10.3201/eid2501.171901). **R packages installed**: `{epidemics}`, `{socialmixr}`, `{scales}`, `{tidyverse}`. @@ -159,7 +159,7 @@ Confusion sometimes arises when referring to the terms 'exposed', 'infected' and We will use the following definitions for our state variables: -+ $E$ = Exposed : infected **but not yet** infectious, ++ $E$ = Exposed: infected **but not yet** infectious, + $I$ = Infectious: infected **and** infectious. :::::::::::::::::::::::::::::::::::::::::::::::: @@ -345,7 +345,7 @@ To run our model we need to specify the model parameters: - infectiousness rate $\alpha$ (preinfectious period=$1/\alpha$), - recovery rate $\gamma$ (infectious period=$1/\gamma$). -In `epidemics`, we specify the model inputs as : +In `epidemics`, we specify the model inputs as: - `transmission_rate` $\beta = R_0 \gamma$, - `infectiousness_rate` = $\alpha$, diff --git a/episodes/template.Rmd b/episodes/template.Rmd index 74ddcd35..72aa3275 100644 --- a/episodes/template.Rmd +++ b/episodes/template.Rmd @@ -58,7 +58,7 @@ Lesson content ::::::::::::::::::::::::::::::::::::: challenge -## Challenge 1 : can the learner run existing code +## Challenge 1: can the learner run existing code Load contact and population data from the POLYMOD Zenodo survey @@ -120,7 +120,7 @@ Add additional maths (or epi) content for novice learners ::::::::::::::::::::::::::::::::::::: challenge -## Challenge 2 : edit code/answer a question +## Challenge 2: edit code/answer a question Load contact and population data for Poland from the POLYMOD Zenodo survey using the following age bins: diff --git a/episodes/vaccine-comparisons.Rmd b/episodes/vaccine-comparisons.Rmd index 0806ab8d..700e3d07 100644 --- a/episodes/vaccine-comparisons.Rmd +++ b/episodes/vaccine-comparisons.Rmd @@ -25,7 +25,7 @@ exercises: 20 Learners should familiarise themselves with following concept dependencies before working through this tutorial: -**Outbreak response** : [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). +**Outbreak response**: [Intervention types](https://www.cdc.gov/nonpharmaceutical-interventions/). ::::::::::::::::::::::::::::::::: @@ -309,11 +309,11 @@ output %>% To understand the **indirect** effect of vaccinations, we want to know the effect that vaccination has on transmission, and hence the rate at new infections occur. We will use the function `new_infections()` in `{epidemics}` to calculate the number of new infections over time for the different vaccination programs. -The inputs required are : +The inputs required are: -+ `data` : the model output, -+ `exclude_compartments` : this is an optional input, but in our case needed. We don't want the number of people vaccinated to be counted as new infections, so we need to specify the name of the model compartment where individuals transition out from `susceptible` (in this example `vaccinated`), -+ `by_group` : should the results be calculated for each demographic group separately. ++ `data`: the model output, ++ `exclude_compartments`: this is an optional input, but in our case needed. We don't want the number of people vaccinated to be counted as new infections, so we need to specify the name of the model compartment where individuals transition out from `susceptible` (in this example `vaccinated`), ++ `by_group`: should the results be calculated for each demographic group separately. ```{r} @@ -919,7 +919,7 @@ The NPI we will consider is temporarily closing schools, an intervention that ha We define **early implementation** as the first day of the simulation (i.e. when there are less than 100 infections in total), and **late implementation** as 50 days after the start of the simulation (i.e. when there are approximately 50,000 infections in total). We assume the control measures are in place for 100 days after they start. -The combinations we will consider are : +The combinations we will consider are: + early implementation of closing schools, + early implementation of a vaccine, From 6e966a693718b64afb632e08cb2405cb2d7769b9 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 17:21:25 +0000 Subject: [PATCH 13/19] fix deprecated socialmixr::list_surveys() and link Zenodo community in contact-matrices Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 71efff8d..e050cd33 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -134,7 +134,7 @@ If `symmetric` is set to TRUE, the `contact_matrix()` function will internally u :::::::::::::::::::::::::::::::::::::::::::::::: -The example above uses the POLYMOD survey. There are a number of surveys available in `socialmixr`. To list the available surveys, use `socialmixr::list_surveys()`. To download a survey from Zenodo and load it, we use `contactsurveys::download_survey()` followed by `socialmixr::load_survey()`: +The example above uses the POLYMOD survey. A number of surveys are available in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/). To list available surveys programmatically, use `contactsurveys::list_surveys()`. To download a survey from Zenodo and load it, we use `contactsurveys::download_survey()` followed by `socialmixr::load_survey()`: ```{r, message = FALSE, warning = FALSE} # Download and load the contact survey data for Zambia from Zenodo @@ -151,11 +151,11 @@ zambia_sa_survey <- socialmixr::load_survey(files = zambia_survey_files) You can explore all the available surveys from the Zenodo repository at . If you are interested in accessing to a specific URL within R, you can try: ```r -library(socialmixr) +library(contactsurveys) library(tidyverse) -# Get URL for Zambia contact survey data from {socialmixr} -socialmixr::list_surveys() %>% +# Get URL for Zambia contact survey data from {contactsurveys} +contactsurveys::list_surveys() %>% dplyr::filter(stringr::str_detect(title, "Zambia")) %>% dplyr::pull(url) ``` From 75ef4cc5bf7aff34eff036fdcb9d9dec1b648e1b Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 17:31:22 +0000 Subject: [PATCH 14/19] clarify country selection prose and update callout title in contact-matrices Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index e050cd33..7fe03844 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -86,7 +86,7 @@ survey_load <- socialmixr::load_survey(files = survey_files) ``` ::::::::::::::::::::::::::::::::::::: callout -### Specify the country name +### Inspect available countries A single survey file can contain data from multiple countries. You can inspect the available countries with: @@ -94,11 +94,9 @@ A single survey file can contain data from multiple countries. You can inspect t levels(survey_load$participants$country) ``` -Always pass the `countries =` argument to `contact_matrix()` to make sure you use data from the intended country only. - :::::::::::::::::::::::::::::::::::::::::::::::: -Then we can obtain the contact matrix for the age categories we want by specifying `age_limits`. We also add `return_demography = TRUE` to include demographic information in the output, which is required when using the contact matrix with `{epidemics}`. +We obtain the contact matrix for the United Kingdom — passing `countries = "United Kingdom"` to select data from the intended country, `age_limits` to define age categories, and `return_demography = TRUE` to include demographic information required by `{epidemics}`. ```{r polymod_uk, echo = TRUE} contacts_byage <- socialmixr::contact_matrix( From d245791bc6cf6f62022cffb6e8a66a8fc5731183 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 17:43:09 +0000 Subject: [PATCH 15/19] convert spoiler code block to executable chunk in contact-matrices Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 7fe03844..08cd1ec1 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -148,7 +148,7 @@ zambia_sa_survey <- socialmixr::load_survey(files = zambia_survey_files) You can explore all the available surveys from the Zenodo repository at . If you are interested in accessing to a specific URL within R, you can try: -```r +```{r} library(contactsurveys) library(tidyverse) From 3204b5f0d1b5bcfea56fb92f28ff401ab24c0c4a Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 17:56:17 +0000 Subject: [PATCH 16/19] rename zambia survey objects to survey_files_zambia and survey_load_zambia Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 08cd1ec1..4b3329be 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -136,12 +136,12 @@ The example above uses the POLYMOD survey. A number of surveys are available in ```{r, message = FALSE, warning = FALSE} # Download and load the contact survey data for Zambia from Zenodo -zambia_survey_files <- contactsurveys::download_survey( +survey_files_zambia <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874675", verbose = FALSE ) -zambia_sa_survey <- socialmixr::load_survey(files = zambia_survey_files) +survey_load_zambia <- socialmixr::load_survey(files = survey_files_zambia) ``` :::::::::::::::::: spoiler @@ -177,11 +177,11 @@ The R package {socialmixr} contains functions which can estimate contact matrice ::::::::::::::::::::: hint -The survey object `zambia_sa_survey` contains data from two countries. If you need to estimate the social contact matrix from data of the specific country of Zambia, identify what argument in `socialmixr::contact_matrix()` you need for this. +The survey object `survey_load_zambia` contains data from two countries. If you need to estimate the social contact matrix from data of the specific country of Zambia, identify what argument in `socialmixr::contact_matrix()` you need for this. ```{r} # Inspect the countries within the survey object -levels(zambia_sa_survey$participants$country) +levels(survey_load_zambia$participants$country) ``` Similar to the code above, to access vector values within a dataframe, you can use the dollar-sign operator: `$` @@ -195,7 +195,7 @@ Similar to the code above, to access vector values within a dataframe, you can u ```{r zambia_solution} # Generate the contact matrix for Zambia only contacts_byage_zambia <- socialmixr::contact_matrix( - survey = zambia_sa_survey, + survey = survey_load_zambia, countries = "Zambia", # key argument age_limits = c(0, 20), symmetric = TRUE, From f56293600158f12dff52083745dd3f941e506877 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 17:57:16 +0000 Subject: [PATCH 17/19] rename _2 survey objects to survey_files_uk, survey_load_uk, contacts_byage_uk in compare-interventions Co-Authored-By: Claude Sonnet 4.6 --- episodes/compare-interventions.Rmd | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/episodes/compare-interventions.Rmd b/episodes/compare-interventions.Rmd index 1ae9932c..8947d1ba 100644 --- a/episodes/compare-interventions.Rmd +++ b/episodes/compare-interventions.Rmd @@ -361,25 +361,25 @@ output <- epidemics::model_vacamole( 1. Run the model ```{r, message = FALSE, warning = FALSE} -survey_files_2 <- contactsurveys::download_survey( +survey_files_uk <- contactsurveys::download_survey( survey = "https://doi.org/10.5281/zenodo.3874557", verbose = FALSE ) -survey_load_2 <- socialmixr::load_survey(files = survey_files_2) +survey_load_uk <- socialmixr::load_survey(files = survey_files_uk) -contacts_byage_2 <- socialmixr::contact_matrix( - survey = survey_load_2, +contacts_byage_uk <- socialmixr::contact_matrix( + survey = survey_load_uk, countries = "United Kingdom", age_limits = c(0, 20, 40), symmetric = TRUE, return_demography = TRUE ) # prepare contact matrix -contacts_byage_matrix_2 <- t(contacts_byage_2$matrix) +contacts_byage_matrix_uk <- t(contacts_byage_uk$matrix) # extract demography vector -demography_vector <- contacts_byage_2$demography$population -names(demography_vector) <- rownames(contacts_byage_matrix_2) +demography_vector <- contacts_byage_uk$demography$population +names(demography_vector) <- rownames(contacts_byage_matrix_uk) # prepare initial conditions initial_i <- 1e-6 @@ -397,12 +397,12 @@ initial_conditions_vacamole <- rbind( initial_conditions_vacamole, initial_conditions_vacamole ) -rownames(initial_conditions_vacamole) <- rownames(contacts_byage_matrix_2) +rownames(initial_conditions_vacamole) <- rownames(contacts_byage_matrix_uk) # prepare population object uk_population_vacamole <- epidemics::population( name = "UK", - contact_matrix = contacts_byage_matrix_2, + contact_matrix = contacts_byage_matrix_uk, demography_vector = demography_vector, initial_conditions = initial_conditions_vacamole ) From d76eea587eb99f57e4fe917b4c87fa5631b7f524 Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 18:16:11 +0000 Subject: [PATCH 18/19] rewrite survey discovery prose and update spoiler structure in contact-matrices Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 4b3329be..3cf58c91 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -132,7 +132,7 @@ If `symmetric` is set to TRUE, the `contact_matrix()` function will internally u :::::::::::::::::::::::::::::::::::::::::::::::: -The example above uses the POLYMOD survey. A number of surveys are available in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/). To list available surveys programmatically, use `contactsurveys::list_surveys()`. To download a survey from Zenodo and load it, we use `contactsurveys::download_survey()` followed by `socialmixr::load_survey()`: +The example above uses the POLYMOD survey. Other surveys are available in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/). To use a different survey, first identify its DOI (see below), then download and load it with `contactsurveys::download_survey()` and `socialmixr::load_survey()`. Here we use the Zambia and South Africa contact survey: ```{r, message = FALSE, warning = FALSE} # Download and load the contact survey data for Zambia from Zenodo @@ -146,7 +146,9 @@ survey_load_zambia <- socialmixr::load_survey(files = survey_files_zambia) :::::::::::::::::: spoiler -You can explore all the available surveys from the Zenodo repository at . If you are interested in accessing to a specific URL within R, you can try: +**Find a survey DOI with contactsurveys** + +Browse available surveys in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/), or list them programmatically: ```{r} library(contactsurveys) From 7642fca443b77724dc26981d9f701801a336203d Mon Sep 17 00:00:00 2001 From: Andree Valle Campos Date: Mon, 23 Mar 2026 18:24:40 +0000 Subject: [PATCH 19/19] suppress spoiler chunk output in contact-matrices Co-Authored-By: Claude Sonnet 4.6 --- episodes/contact-matrices.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/episodes/contact-matrices.Rmd b/episodes/contact-matrices.Rmd index 3cf58c91..6a48b0bd 100644 --- a/episodes/contact-matrices.Rmd +++ b/episodes/contact-matrices.Rmd @@ -150,7 +150,7 @@ survey_load_zambia <- socialmixr::load_survey(files = survey_files_zambia) Browse available surveys in the [Zenodo Social Contact Data community](https://zenodo.org/communities/social_contact_data/), or list them programmatically: -```{r} +```{r,message=FALSE,warning=FALSE} library(contactsurveys) library(tidyverse)