The Pebble Game

The Pebble Game (alternative link) is a shiny application that simulates the pebble game. This is a simple game that has been developed by BIDD at the University of Bristol, to help a general audience understand the role of vaccination in preventing the onward transmission of infectious disease. It involves repeatedly drawing pebbles from a bag, which contains two distinct pebble types (to represent vaccinated and unvaccinated individuals). The number of pebbles that are drawn each round is dependent on the number of infect-able (i.e unvaccinated) cases drawn in the previous round, and the infectiousness of the simulated disease. For a more detailed explanation of the mechanics of the game, examples of using the app, suggested questions, and instructions for local installation continue reading. Otherwise enjoy exploring a simple system with complex dynamics!

Using the app

Whilst the Pebble Game has been designed to be user friendly, I've written a blog post that takes you through using the app in more detail. If in using the app you discover something that you think is worth sharing then please contact me either via twitter or email.

Some suggested questions

  • Look up some real world disease reproduction numbers (the number that each diseased pebble infects). What effect does varying this have?
  • For a given reproduction number what effect does varying the proportion of vaccinated pebbles have?
  • What happens if you repeat the game using the same parameters multiple times? Can you explain this?
  • How does population size effect the spread of the disease?

Playing the game for yourself

Whilst the web app fully captures the dynamics of the pebble game it may be useful to physically play the game for yourself. To do that follow the instructions below:

What you will need

  • A bag or box (it is important that the pebbles cannot be seen).
  • A set of pebbles/counters etc. of 2 different colours (these represent those who are vaccinated versus unvaccinated).
  • Some paper to note down your results.

Set up

To play the game you must pick some basic parameters that define your pebble population and the disease. These are:

  • The total number of pebbles (for best results it is suggested to use at least 50). The pebble population should be made up of;
    • A number of vaccinated pebbles (choose a colour to represent this)
    • A number of unvaccinated pebbles (using your other colour)
  • The number of pebbles in the first generation of the disease (for the simplest game pick 1)
  • The number of pebbles that each diseased pebble subsequently infects (in epidemiology this is known as the basic reproduction number).

Playing the game

  1. Pick pebbles from the bag equal to the number in the first generation times the number that each diseased pebble infects.
  2. Count the number of pebbles that are unvaccinated that you have picked, these are the next generation of infected pebbles (note this number down).
  3. For the new generation multiply the number in the new generation against the number that each diseased pebble infects and pick this many pebbles from the bag.
  4. Repeat steps 2. and 3. until you pick no unvaccinated pebbles or until the bag is empty.

Installing the shiny app locally

To install and run the shiny app locally on your own computer you will need to first install R, it is also suggested that you install Rstudio. After downloading the source code from this repository click on the thepebblegame.Rprof file, this will open an Rstudio window. Type the following code into the command line;

install.packages("shiny")
install.packages("shinydashboard")
install.packages("shinyBS")
install.packages("tidyverse")
install.packages("rmarkdown")

To run the app open the ui.R file and press run, depending on your computer this may take some time. Enjoy playing the pebble game!

Game Parameters

Plot

Disease Parameters

Simulation Functions

Download

### Pebble game outline
library(tidyverse)

### Input
## Number of simulations - slider
## R0 - slider 
## Proportion Vaccinated - slider
## Population - slider

### Output 
## Graph of Simulation Trends over time
## Summary stats of Trends over time

## Function to estimate the number of cases in a generation
no_in_gen <- function(df, vac_status = 'no') {
  df %>% 
    filter(generation == max(generation, na.rm = TRUE), 
           vaccinated %in% vac_status) %>% 
    nrow
} 

## Function to run a pebble game simulation
gen_pebble_game <- function(df, generation_no, r0, no_in_first_gen) {
  ##define sampled population
  df_sampled <- filter(df, !is.na(generation))
  
  ## Calculated generation number
  if (generation_no > 1) {
    no_in_generation <- no_in_gen(df_sampled)
  } else {
    no_in_generation <- no_in_first_gen
  }
  
  ## Restrict to unsampled pebbles
  df_unsampled <- filter(df, is.na(generation))
  
  ## Sample pebbles
  no_sample <- no_in_generation * r0
  
  if (no_sample < length(df_unsampled$id)) {
    pebble_sample <- sample(df_unsampled$id, no_sample, replace = FALSE)
  }else {
    pebble_sample <- df_unsampled$id
  }
  
  
  df_unsampled <- mutate(df_unsampled, 
                         generation = replace(generation, 
                                              id %in% pebble_sample,
                                              generation_no)
    )
  
  ##Combine held back population with sampled population
  df <- bind_rows(df_sampled, df_unsampled)
  
  return(df)
}

##Function to run a single simulation of the pebble game
pebble_game <- function(r0, 
                        no_in_first_gen,
                        prop_vac, 
                        population,
                        verbose) {
  ## Check parameters
  population <- population %>% as.numeric
  
  ## number vaccinated
  no_vac <- round(prop_vac * population, digits = 0)
  
  ## create population in a data frame
  pebbles <- data_frame(id = seq(1, population, 1), 
                        vaccinated = c(rep("yes", no_vac), 
                                       rep("no", population - no_vac)),
                        generation = NA
                        )
  
  ## Define first generation
  generation_no <- 1
  no_left_to_infect <- population - no_vac
  no_in_generation <- 1
  
  ## Repeatedly sample pebbles
  while (no_left_to_infect > 0 & no_in_generation > 0) {
    ## Update pebbles
    pebbles <- gen_pebble_game(pebbles,
                      generation_no = generation_no, 
                      r0 = r0,
                      no_in_first_gen =  no_in_first_gen)
    
    ## Check if there are any unvaccinated pebbles left
    no_left_to_infect <- filter(pebbles, is.na(generation),
             vaccinated %in% "no") %>% 
      nrow
    
    ## Check if there are any unvaccinated pebbles
    ## in the current generation
    no_in_generation <- no_in_gen(pebbles)
    
    ## Advance generation number
    generation_no <- generation_no + 1
    
    if (verbose) {
      message("The generation number is:",  generation_no)
    }
  
  }

  return(pebbles)
}


## Function to run multiple simulations of the pebble game
multi_sim_pebble_game <- function(r0, 
                                  no_in_first_gen,
                                  prop_vac, 
                                  population,
                                  simulations,
                                  verbose = FALSE) {
  
  df <- map_df(1:simulations, function(sim) {
    if (verbose) {
      message("Starting simulation number:", sim)
    }

    df <- pebble_game(r0, 
                      no_in_first_gen,
                      prop_vac, 
                      population,
                      verbose) %>% 
            mutate(simulation = sim)
    return(df)
  }
  ) 
 ## clean up table
  df <- df %>% 
    mutate(generation = as.integer(generation))
 return(df)
}

## generate summaries by generation for data - count
summarise_pebble_game_sim <- function(df, 
                                      simulations,
                                      population,
                                      prop_vac) {
 
  ## Parameter check
  population <- population %>% as.numeric
  
  ##Calc number unvaccinated
  no_unvac <- round((1 - prop_vac) * population, digits = 0)
  
   df_count <- df %>% 
    filter(vaccinated %in% "no",
           !is.na(generation)) %>% 
    group_by(simulation, generation) %>% 
    count
 
  ## Detect simmulations that have no intial cases
  ## Add these to the data frame with a generation number of 1, and n = 0
  df_count <- df_count %>% 
    bind_rows(data_frame(simulation = 1:simulations,
                                      generation = 1,
                                      n = 0) %>% 
    mutate(simulation = simulation %>% 
             replace(simulation %in% unique(df_count$simulation), NA)
           ) %>% 
    na.omit
    )
  
  ## Added in generations for which no pebbles were infected
  zero_generations <- df_count %>%
    group_by(simulation) %>% 
    filter(generation == max(generation)) %>%
    do(data_frame(simulation = .$simulation,
            generation = seq(.$generation + 1, max(df_count$generation) + 1, 1),
            n = 0
            )
    )
    
  ## Calculate cumulative sum and percentage of unvaccinated infected
  df_cum <- df_count %>% 
    bind_rows(zero_generations) %>% 
    group_by(simulation) %>% 
    mutate(cumsum = cumsum(n)) %>%
    mutate(perinfect = round(cumsum / no_unvac * 100, digits = 0)) %>% 
    rename(Generation = generation,
           Simulation = simulation,
           `No. of pebbles` = n,
           `Cumulative no. of pebbles` = cumsum,
           `Percentage (%) of unvaccinated infected` = perinfect)
  
  return(df_cum)
}

##Add mean and ci to df 
df_mean_ci <- function(df, y, group_by) {
  ## Estimate mean and ci's
  df_trans <- df %>% 
    group_by_(.dots = group_by) %>% 
    mutate_(mean = paste0("mean(", y, ")")) %>% 
    mutate_(sd = paste0("sd(", y, ")")) %>%
    mutate_(sqrt_sample = paste0("sqrt(length(", y, "))")) %>% 
    ungroup %>% 
    mutate(se = sd / sqrt_sample,
           lci = mean - 1.96 * se,
           uci = mean + 1.96 * se) 
  
  return(df_trans)
}

## Make ggplot for playing the game 
plot_pebbles <- function(df, y, colour =  "dodgerblue2") {
  
df <- df %>% 
  df_mean_ci(y = y, group_by = c("Generation"))
    
  df %>% 
    ggplot(aes_string(x = "Generation", y = y)) +
    geom_point(alpha = 0.2, 
               colour = colour, 
               aes(group = Simulation)) +
    geom_line(alpha = 0.2, 
              colour = colour, 
              aes(group = Simulation)) +
    geom_line(aes(x = Generation, y = mean),
              colour = colour,
              alpha = 1,
              size = 1.5) +
    geom_ribbon(aes(x = Generation, ymin = lci, ymax = uci),
                fill = "grey",
                alpha = 0.4) + 
    theme_minimal() -> plot
  
  return(plot)
}

##  Make a ggplot for comparing diseases
plot_pebbles_compare <- function(df, y) {

  df <- df %>% 
    df_mean_ci(y = y, group_by = c("Disease", "Generation"))
  
  df %>% 
    ggplot(aes_string(x = "Generation",
                      y = y,
                      colour = "Disease",
                      group = "interaction(Disease, Simulation)")) +
    geom_point(alpha = 0.2) +
    geom_line(alpha = 0.2) +
    geom_line(aes(x = Generation, 
                  y = mean),
              alpha = 1,
              size = 1.5) +
    scale_colour_manual(values=c("dodgerblue2", "firebrick2")) +
    geom_ribbon(aes(x = Generation,
                    ymin = lci, 
                    ymax = uci,
                    group = Disease),
                fill = "grey",
                alpha = 0.4) + 
    theme_minimal() +
    theme(legend.position = "bottom") -> plot
  
  return(plot)
}

## Add a summary statistic
add_sum_stat <- function(df, stat_vect, sum_measure) {
  df <- df %>% 
    add_row(`Summary Measure` = sum_measure,
            Mean = stat_vect %>% 
              mean,
            Median = stat_vect %>% 
              median,
            `25% Quantile` = stat_vect %>% 
              quantile(probs = 0.25),
            `75% Quantile` = stat_vect %>% 
              quantile(probs = 0.75))
  
  return(df)
}
## Make table of summary data
## mean, medium, CI of generations reached
## 
summary_table <- function(df, 
                          population,
                          prop_vac) {
  ## Check parameters
  population <- population %>% as.numeric
  
  ## Set up dataframe
  sum_tab <- data_frame(`Summary Measure` = NA, Mean = NA, Median = NA, `25% Quantile` = NA, `75% Quantile` = NA)
  
  ## No. in a generation
  sum_tab <- sum_tab %>% 
    add_sum_stat(stat_vect = df$`No. of pebbles`, 
                 sum_measure = "No. in a generation")
  
  ## no. of generations
  no_of_generations <- df %>% 
    group_by(Simulation) %>%
    filter(`No. of pebbles` > 0) %>%  
    summarise(no_of_gen = max(Generation))
  
  sum_tab <- sum_tab %>% 
    add_sum_stat(stat_vect = no_of_generations$no_of_gen, 
                 sum_measure = "No. of generations")
  
  ## Totol no. of infected pebbles
  total_no_infected_pebbles <- df %>% 
    group_by(Simulation) %>% 
    summarise(total_infect = max(`Cumulative no. of pebbles`))
  
  sum_tab <- sum_tab %>% 
    add_sum_stat(stat_vect = total_no_infected_pebbles$total_infect, 
                 sum_measure = "Total no. of infected")
  
  ## Number unvaccinated
  no_unvac <- round((1 - prop_vac) * population, digits = 0)
  
  ## Calculate percentage of susceptible pop that are infected
  ## Tidy results
  sum_tab <- sum_tab %>%
    mutate_at(vars(Mean, Median, `25% Quantile`, `75% Quantile`), funs(as.character(as.integer(round(., digits = 0))))) %>% 
    bind_rows(sum_tab %>%
                filter(`Summary Measure` %in% "Total no. of infected") %>% 
                mutate_at(vars(Mean, Median, `25% Quantile`, `75% Quantile`), funs(paste0(round(. / no_unvac * 100, digits = 0), "%"))) %>% 
                mutate(`Summary Measure` = "Percentage of unvaccinated infected")
    )

  ## Clear first row
  sum_tab <- sum_tab %>% na.omit
  
  return(sum_tab)
}
## Wrap everything into a wrapper function for portability
sim_then_plot_pebble_game <- function(r0 = 3, 
                                      no_in_first_gen = 1,
                                      prop_vac = 0.6, 
                                      population = 1000,
                                      simulations = 100,
                                      verbose = FALSE,
                                      y = "`No. of pebbles`") {
  plot <- multi_sim_pebble_game(r0 = r0, 
                                no_in_first_gen = no_in_first_gen,
                                prop_vac = prop_vac, 
                                population = population,
                                simulations = simulations,
                                verbose = verbose) %>% 
    summarise_pebble_game_sim %>% 
    plot_pebbles(y = y)
  return(plot)
}

## Summary of functions
## df <- multi_sim_pebble_game(r0 = 3, no_in_first_gen = 1,prop_vac = 0.6, population = 1000, simulations = 100, verbose = FALSE) 
## df_count <- df %>% summarise_pebble_game_sim(simulations = 100, population = 1000, prop_vac = 0.6)
## plot_pebbles(df_count, y = "`No. of pebbles`") %>% ggplotly
## plot_pebbles(df_count, y = "`Cumulative no. of pebbles`") %>% ggplotly

UI

Download

## Load packages
library(shiny)
library(shinydashboard)
library(shinyBS)
library(tidyverse)
library(rmarkdown)

sidebar <- dashboardSidebar(
  hr(),
  sidebarMenu(id = "tabs",
              menuItem("Play the game", tabName="pebble_game", icon=icon("line-chart"), selected=TRUE),
              menuItem("Compare diseases", tabName = "disease_com", icon = icon("random")),
              menuItem("How to play the game", tabName = "readme", icon=icon("mortar-board")),
              menuItem("Code",  icon = icon("code"),
                       menuSubItem("Github", href = "https://github.com/seabbs/thepebblegame", icon = icon("github")),
                       menuSubItem("pebble_game.R", tabName = "pebble_game_code", icon = icon("angle-right")),
                       menuSubItem("ui.R", tabName = "ui", icon = icon("angle-right")),
                       menuSubItem("server.R", tabName = "server", icon = icon("angle-right"))
              )
  ),
  hr(),
  helpText("Developed by ", a("Sam Abbott, ", href="http://samabbott.co.uk"), 
           a("Bristol Infectious Disease Dynamics, ", href="http://www.bristol.ac.uk/social-community-medicine/research/groups/bidd/"), "University of Bristol", style="padding-left:1em; padding-right:1em;position:absolute; bottom:1em; ")
)

body <- dashboardBody(
  tabItems(
    tabItem(tabName = "readme",
            withMathJax(), 
            includeMarkdown("README.md")
    ),
    tabItem(tabName = "pebble_game",
            fluidRow(
              tags$head(includeScript("google-analytics.js")),
              column(width = 4, 
                     box( width = NULL,
                          tipify(sliderInput("r0",
                                      "Reproduction no.:",
                                      min = 1,
                                      max = 50,
                                      value = 3),
                                 title = "The basic reproduction rate (R0) is used to measure the transmission potential of a disease. It is thought of as the number of secondary infections produced by a typical case of an infection in a population that is totally susceptible."
                                 ),
                          tipify(sliderInput("no_in_first_gen",
                                      "No. in first generation:",
                                      min = 1,
                                      max = 50,
                                      value = 1),
                                 title = "The number of infected pebbles introduced into the population. Does altering this have any effect on the epidemic dynamics?"),
                          tipify(sliderInput("prop_vac",
                                      "Proportion vaccinated:",
                                      min = 0,
                                      max = 1,
                                      value = 0.6),
                                 title = "The proportion of the population that have been vaccinated, the number that are vaccinated can be calulated by multiplying the proportion vaccinated by the population. Try to find the vaccination thresold at which an epidemic cannot occur."),
                          tipify(radioButtons("population",
                                              label = "No. of pebbles:",
                                              choices = c(50, 100, 250, 500, 1000),
                                              selected = 100,
                                              inline = TRUE),
                                 title = "How many pebbles do you want to simulate? Does this alter the trend, or does it just alter the epidemic size? Note: A high population will take longer to compute."
                                 ),
                          tipify(radioButtons("simulations",
                                      label = "No. of simulations:",
                                      choices = c(1, 10, 50, 100, 500, 1000),
                                      selected = 10,
                                      inline = TRUE),
                                 title = "How many times to repeat the game. What is the effect of increasing this? Note: A high number of simulations will take longer to compute"
                          ),
                          tipify(selectInput("sumstat", 
                                      "Summary statistic to plot:",
                                      list(`Cumulative no. of pebbles` = 
                                             "`Cumulative no. of pebbles`",
                                           `No. of pebbles` = 
                                             "`No. of pebbles`",
                                           `Percentage (%) of unvaccinated infected` = 
                                             "`Percentage (%) of unvaccinated infected`")
                          ),
                          title = "The cumulative number of pebbles (i.e. the rolling total) gives the clearest picture of the final epidemic size. The number of pebbles (in each generation) shows how the epidemic evolves over time. The percentage of unvaccinated infected allows diseases to be compared more easily."
                          ),
                          tipify(actionButton("play_button", "Simulate", 
                                       style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
                                 title = "What effect does repeating the game with the same parameters have?"
                          ),
                          title = 'Game Parameters', 
                          status = "primary", solidHeader = FALSE,
                          collapsible = TRUE,
                          collapsed = TRUE
                     )),
              column(width = 8,
                     box(width = NULL, 
                         tipify(plotOutput("pebble_plot"),
                                title = "Plot of the simulations of the game, overlayed with the mean and 95% confidence intervals. What effect does varying the parameters have?"),
                     collapsible = TRUE,
                     title = "Plot",
                     status = "primary", 
                     solidHeader = FALSE
                     ),
                     tabBox( width = NULL,
                             title = "Tables",
                             side = "right",
                             tabPanel(title = "Summary Statistics",
                                      id = "tabletab1",
                                      tipify(tableOutput("pebble_table"),
                                             title = "Summary statistics for the pebble game. How does varying the parameters effect these? Do these summary measures match what you see on the plot above?",
                                             placement = "top"
                                      )
                             ),
                             tabPanel(title = "Simulation Data",
                                      id = "tabletab2",
                                      tipify(dataTableOutput("results_table"),
                                             title = "Simulation results from playing the pebble game, with your specified parameters. Download this with the button below and see what patterns you can find.",
                                             placement = "top"
                                      ),
                                      downloadButton('downloadDatatable', 'Download')
                                      )
                     )
                     )
            )
    ),
    tabItem(tabName = "disease_com",
            fluidRow(
              column(width = 4, 
                     box( width = NULL,
                          tipify(sliderInput("r0_prim",
                                      "Primary disease R0:",
                                      min = 1,
                                      max = 50,
                                      value = 3),
                                 title = "The basic reproduction rate (R0) is used to measure the transmission potential of a disease. It is thought of as the number of secondary infections produced by a typical case of an infection in a population that is totally susceptible."
                          ),
                          tipify(sliderInput("r0_sec",
                                      "Secondary disease R0:",
                                      min = 1,
                                      max = 50,
                                      value = 12),
                                 title = "The basic reproduction rate (R0) is used to measure the transmission potential of a disease. It is thought of as the number of secondary infections produced by a typical case of an infection in a population that is totally susceptible."
                          ),
                          tipify(sliderInput("no_in_first_gen_com",
                                      "No. in first generation:",
                                      min = 1,
                                      max = 50,
                                      value = 1),
                                 title = "The number of infected pebbles introduced into the population. Does altering this have any effect on the epidemic dynamics?"),
                          tipify(sliderInput("prop_vac_com",
                                      "Proportion vaccinated:",
                                      min = 0,
                                      max = 1,
                                      value = 0.6),
                                 title = "The proportion of the population that have been vaccinated, the number that are vaccinated can be calulated by multiplying the proportion vaccinated by the population. Try to find the vaccination thresold at which an epidemic cannot occur."),
                          tipify(radioButtons("population_com",
                                      label = "No. of pebbles:",
                                      choices = c(50, 100, 250, 500, 1000),
                                      selected = 100,
                                      inline = TRUE),
                                 title = "How many pebbles do you want to simulate? Does this alter the trend, or does it just alter the epidemic size? Note: A high population will take longer to compute."
                          ),
                          tipify(radioButtons("simulations_com",
                                              label = "No. of simulations:",
                                              choices = c(1, 10, 50, 100, 500, 1000),
                                              selected = 10,
                                              inline = TRUE),
                                 title = "How many times to repeat the game. What is the effect of increasing this? Note: A high number of simulations will take longer to compute"
                          ),
                          tipify(selectInput("sumstat_com", 
                                      "Summary statistic to plot:",
                                      list(`Cumulative no. of pebbles` = 
                                             "`Cumulative no. of pebbles`",
                                           `No. of pebbles` = 
                                             "`No. of pebbles`",
                                           `Percentage (%) of unvaccinated infected` = 
                                             "`Percentage (%) of unvaccinated infected`")
                          ),
                          title = "The cumulative number of pebbles (i.e. the rolling total) gives the clearest picture of the final epidemic size. The number of pebbles (in each generation) shows how the epidemic evolves over time. The percentage of unvaccinated infected allows diseases to be compared more easily."
                          ),
                          tipify(actionButton("compare_button", "Simulate", 
                                       style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
                                 title = "What effect does repeating the game with the same parameters have?"
                          ),
                          title = "Disease Parameters", 
                          status = "primary", solidHeader = FALSE,
                          collapsible = TRUE,
                          collapsed = TRUE
                     )),
              column(width = 8,
                     tabBox(width = NULL, 
                         title = "Plots",
                         side = "right",
                         tabPanel(
                           title = "Comparision",
                           id = "tabletab1",
                           tipify(plotOutput("com_plot"),
                                  title = "Comparision plot of simulations of the game for both diseases, overlayed with the mean and 95% confidence intervals. Compare the difference between the trend line gradients, what does this mean?")
                         ),
                         tabPanel(
                           title = "Primary Disease",
                           id = "tabletab2",
                           tipify(plotOutput("prim_plot"),
                                  title = "Plot of the simulations of the game for the primary disease, overlayed with the mean and 95% confidence intervals. What effect does varying the other parameters have?")
                         ),
                         tabPanel(
                           title = "Secondary Disease",
                           id = "tabletab3",
                           tipify(plotOutput("sec_plot"),
                                  title = "Plot of the simulations of the game for the primary disease, overlayed with the mean and 95% confidence intervals. What effect does varying the other parameters have?")
                           )
                         ),
                     tabBox( width = NULL,
                             title = "Primary Disease",
                             side = "right",
                             tabPanel(title = "Summary Table",
                                      tipify(tableOutput("prim_sum_tab"), 
                                             title = "Summary statistics for the pebble game, played with the primary disease. How does varying the parameters effect these? Do these summary measures match what you see on the plot above and how do they correspond with those from the secondary disease?",
                                             placement = "top"
                                      ),
                                      id = "tabletab1"
                                      ),
                             tabPanel(title = "Simulation Table",
                                      id = "tabletab2",
                                      tipify(dataTableOutput("prim_results_table"),
                                             title = "Simulation results from playing the pebble game with the primary disease, and your specified parameters. Download this with the button below and see what patterns you can find.",
                                             placement = "top"
                                      ),
                                      downloadButton("downloadPrimDatatable", "Download"))
                     ),
                     tabBox( width = NULL,
                             title = "Secondary Disease",
                             side = "right",
                             tabPanel(title = "Summary Table",
                                      tipify(tableOutput("sec_sum_tab"),
                                             title = "Summary statistics for the pebble game, played with the secondary disease. How does varying the parameters effect these? Do these summary measures match what you see on the plot above and how do they correspond with those from the primary disease?",
                                             placement = "top"
                                      ),
                                      id = "tabletab1"
                             ),
                             tabPanel(title = "Simulation Table",
                                      id = "tabletab2",
                                      tipify(dataTableOutput("sec_results_table"),
                                             title = "Simulation results from playing the pebble game with the secondary disease, and your specified parameters. Download this with the button below and see what patterns you can find.",
                                             placement = "top"
                             ),
                                      downloadButton("downloadSecDatatable", "Download")
                             )
                     )
              )
            )
            ),
    tabItem(tabName = "pebble_game_code",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="Simulation Functions",                
                 downloadButton('downloadData1', 'Download'),
                 br(),br(),
                 pre(includeText("pebble_game.R"))
            )
    ),
    tabItem(tabName = "ui",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="UI",
                 downloadButton('downloadData2', 'Download'),
                 br(),br(),
                 pre(includeText("ui.R"))
            )
    ),
    tabItem(tabName = "server",
            box( width = NULL, status = "primary", solidHeader = TRUE, title="Server",
                 downloadButton('downloadData3', 'Download'),
                 br(),br(),
                 pre(includeText("server.R"))
            )
    )
  )
)

dashboardPage(
  dashboardHeader(title = "The Pebble Game"),
  sidebar,
  body
)

Server

Download

#Load packages
library(shiny)
library(shinydashboard)
library(shinyBS)
library(tidyverse)

## Source functions
source("pebble_game.R")

## Stop spurious warnings
options(warn = - 1)

shinyServer(function(input, output) {

  ## Simulation the game
  ## Play the game simulation
  sim_sum <- reactive({
    ## Depend on play button
    input$play_button
    
    ## Sim
    sim <- multi_sim_pebble_game(r0 = input$r0, 
                                 no_in_first_gen = input$no_in_first_gen,
                                 prop_vac = input$prop_vac, 
                                 population = input$population,
                                 simulations = input$simulations) %>%
      summarise_pebble_game_sim(simulations = input$simulations,
                                population = input$population,
                                prop_vac = input$prop_vac)
    
    return(sim)
  })
  
  ## Primary disease simulation
  prim_sim <- reactive({
    ## depends on comparision button press
    input$compare_button
    
    prim_sim <- multi_sim_pebble_game(r0 = input$r0_prim, 
                                 no_in_first_gen = input$no_in_first_gen_com,
                                 prop_vac = input$prop_vac_com, 
                                 population = input$population_com,
                                 simulations = input$simulations_com) %>%
      summarise_pebble_game_sim(simulations = input$simulations_com,
                                population = input$population_com,
                                prop_vac = input$prop_vac_com)
    
    return(prim_sim)
  })
  
  ## Secondary disease simulation
  sec_sim <- reactive({
    ## depends on comparision button press
    input$compare_button
    
    sec_sim <- multi_sim_pebble_game(r0 = input$r0_sec, 
                                 no_in_first_gen = input$no_in_first_gen_com,
                                 prop_vac = input$prop_vac_com, 
                                 population = input$population_com,
                                 simulations = input$simulations_com) %>%
      summarise_pebble_game_sim(simulations = input$simulations_com,
                                population = input$population_com,
                                prop_vac = input$prop_vac_com)
    
    return(sec_sim)
  })
  
  ## serve results table
  ## Play the game simulation
  output$results_table <- renderDataTable({
    sim_sum()
  },
  options = list(
    pageLength = 10)
  )
  
  ##Primary
  output$prim_results_table <- renderDataTable({
    prim_sim()
  },
  options = list(
    pageLength = 10)
  )
  
  ##Secondary
  output$sec_results_table <- renderDataTable({
    sec_sim()
  },
  options = list(
    pageLength = 10)
  )
  
  ## Serve results plot - playing the game
  output$pebble_plot <- renderPlot({
    ## Run simulations, summarise and plot see pebble_game.R
    plot <- sim_sum() %>%
      plot_pebbles(y = input$sumstat)
    
    plot
  })

  ## Serve primary disease plot
  output$prim_plot <- renderPlot({
    ## Run simulations, summarise and plot see pebble_game.R
    plot <- prim_sim() %>%
      plot_pebbles(y = input$sumstat_com)
    
    plot
  })
  ## Serve secondary disease plot
  output$sec_plot <- renderPlot({
    ## Run simulations, summarise and plot see pebble_game.R
    plot <- sec_sim() %>%
      plot_pebbles(y = input$sumstat_com,
                   colour = "firebrick2")
    
    plot
  })
  
  ## Serve results plot for comparing disease
  output$com_plot <- renderPlot({
    ## Bind data
    com_sim <- prim_sim() %>% 
      mutate(Disease = "Primary") %>% 
      bind_rows(sec_sim() %>% 
                  mutate(Disease = "Secondary"))
    ## Run simulations, summarise and plot see pebble_game.R
    plot <- com_sim %>%
      plot_pebbles_compare(y = input$sumstat_com)
    
    plot
  })
  
  ## Summary data tables
  
  ## Play the game
  output$pebble_table <- renderTable({
    ## generate summary df
    sim_sum() %>% summary_table(population = input$population,
                                prop_vac = input$prop_vac
                                )
  })
  
  ## Primary disease
  output$prim_sum_tab <- renderTable({
    ## generate summary df
    prim_sim() %>% summary_table(population = input$population_com,
                                 prop_vac = input$prop_vac_com
    )
  })
  
  ## Secondary disease
  output$sec_sum_tab <- renderTable({
    ## generate summary df
    sec_sim() %>% summary_table(population = input$population_com,
                                prop_vac = input$prop_vac_com
    )
  })
  
  ## Set up downloadbale data
  
  ## Play the game
  output$downloadDatatable <- downloadHandler(filename = "pebble_game_sim_results.csv",
                                              content = function(file) {
                                                write.csv(sim_sum(), file)
                                              }
  )
  
  ## Primary disease
  output$downloadPrimDatatable <- downloadHandler(filename = "pebble_game_prim_disease_sim_results.csv",
                                              content = function(file) {
                                                write.csv(prim_sim(), file)
                                              }
  )
  
  ## Secondary disease
  output$downloadSecDatatable <- downloadHandler(filename = "pebble_game_sec_disease_sim_results.csv",
                                              content = function(file) {
                                                write.csv(sec_sim(), file)
                                              }
  )
  
  
  ## Set up downloadable scripts
  output$downloadData1 <- downloadHandler(filename = "pebble_game.R",
                                          content = function(file) {
                                            file.copy("pebble_game.R", file, overwrite = TRUE)
                                            }
                                          )
  output$downloadData2 <- downloadHandler(filename = "ui.R",
                                          content = function(file) {
                                            file.copy("ui.R", file, overwrite = TRUE)
                                            }
                                          )
  output$downloadData3 <- downloadHandler(filename = "server.R",
                                          content = function(file) {
                                            file.copy("server.R", file, overwrite = TRUE)
                                            }
                                          )
  
})