Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shiny reactive #35

Merged
merged 11 commits into from
Nov 29, 2019
112 changes: 112 additions & 0 deletions R/health-calculations.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Average global mortality from WHO database
get_mortality <- function () {
#x <- read.csv ("../who3/health-econ/who-mortality.csv")
#names (x) <- c ("country", "population", "deaths", "remove")
#x$remove <- NULL
#x <- x [!is.na (x$deaths), ]
#mortality <- mean (x$deaths / x$population)
0.007425708
}

# Mode shift response based entirely on Accra walking statistics
mode_shift_response <- function (mode_incr = 0.01, city_pop, mortality) {
# Accra data for distance walked to market
d_market <- c (0.5, 1.5, 2.5, 4.5, 8.5)
p_market <- c (0.273, 0.212, 0.061, 0.424, 0.03)
d_market <- sum (d_market * p_market)

# Accra data for distance walked to trotro
d_tro <- c (0.25, 0.75, 1.5, 3.5, 7.5)
p_tro <- c (0.832, 0.119, 0.023, 0.005, 0.022)
d_tro <- sum (d_tro * p_tro)

# Estimate of distance walked to work based on relative frequencies of trips
# # to market and trotro
d_work <- (0.474 * d_market + 0.19 * d_tro) / (0.474 + 0.19)

# Accra data for numbers of weekly walking trips
n_walk <- c (5, 15.5, 25.5, 35.5, 50.5, 80.5)
p_walk <- c (0.64, 0.204, 0.062, 0.029, 0.034, 0.007)
n_walk <- 7 * sum (n_walk * p_walk)

# Reference weekly walking distance
d_walk_ref <- (n_walk - 5) * d_tro + 2.5 * 0.474 * d_work + 2.5 * d_market

# Change in daily distance walked to work in response to mode_incr for
# walking
d_work <- ((0.474 * (1 + mode_incr)) * d_market +
(0.19 * (1 + mode_incr)) * d_tro) / (0.474 + 0.19)
# Change in daily distance walked in general in response to mode_incr for
# walking
d_walk <- (n_walk - 5) * (1 + mode_incr) * d_tro +
2.5 * 0.474 * (1 + mode_incr) * d_work +
2.5 * (1 + mode_incr) * d_market

# Overall risk ratio for change in distance walked:
rr <- 0.114 * d_walk / d_walk_ref - 0.114
mortality_here <- city_pop * mortality * rr
data.frame (mode_shift = mode_incr,
dist_ref = d_walk_ref,
dist = d_walk,
increase = d_walk / d_walk_ref - 1,
rr = rr,
d_mortality = mortality_here)
}

get_scenario_results <- function (city = "Accra", has_tram = FALSE) {
nm <- "scenario-results-table.csv"
f <- system.file (nm, package = "upthat")
if (f == "") {
u <- paste0 ("https://github.com/ATFutures/upthat/releases/",
"download/0.0.2/", nm)
path <- dirname (system.file ("net.Rds", package = "upthat"))
download.file (u, destfile = file.path (path, nm))
f <- system.file (nm, package = "upthat")
}
mode_shift <- read.csv (f)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Robinlovelace Note that this function auto-downloads the scenario results into /inst the first time it's run. I think this is a sensible approach, as it takes no time to download, and ensures we only need to keep the one master file updated. Feel free to suggest alternative approaches if you'd prefer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds sensible, extensible and future proof, good thinking 🚀

mode_shift [tolower (mode_shift$City) == tolower (city) &
mode_shift$has_tram == has_tram, ]
}

get_population <- function (city) {
switch (city,
"Accra" = 2.27e6,
"Kathmandu" = 1.74e6)
}


calc_exposure <- function (city = "Accra", has_tram = FALSE) {
# Assume fixed PM2.5 values as for Accra
pm25bg <- 35
pm25max <- 50

mode_shift <- get_scenario_results (city = city, has_tram = has_tram)

# pm25bg modified by reduction in car usage due to mode shift:
car_red <- mode_shift$car / 100
pm25bg_mod <- pm25bg + car_red * (pm25max - pm25bg) / pm25bg
# presume average walking concentrations half way to max value:
pm25walk <- (pm25max + pm25bg_mod) / 2

response <- mode_shift_response (mode_incr = mode_shift$walking / 100,
city_pop = get_population (city),
mortality = get_mortality ())

mode_shift <- cbind (mode_shift, response [, -1])

# average weekly concentration for reference case:
walk_time <- response$dist_ref / 5.3
non_walk_time <- 24 * 7 - walk_time
pm25_ref <- (pm25bg_mod * non_walk_time + pm25walk * walk_time) / (24 * 7)

# modified average weekly concentration for scenario
walk_time <- response$dist / 5.3
non_walk_time <- 24 * 7 - walk_time
pm25_scenario <- (pm25bg_mod * non_walk_time + pm25walk * walk_time) / (24 * 7)
# capped at 50, but all well below here, so can be left as is

d_exposure <- pm25_scenario - pm25_ref
mode_shift$exposure <- get_population (city) *
get_mortality () * d_exposure * 0.07 / 10
return (mode_shift)
}
30 changes: 26 additions & 4 deletions R/server.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ shinyAppServer = function(input, output, session) {
"Found these Rds files: ",
paste0(rds_files_available, collapse = ", ")
)

ggplot2::theme_set (ggplot2::theme_minimal ())

output$mymap = mapdeck::renderMapdeck({
mapdeck::mapdeck(style = "mapbox://styles/mapbox/light-v10")
})
Expand All @@ -59,7 +62,7 @@ shinyAppServer = function(input, output, session) {
message("Reading this matching file: ", matching_file)
net <<- readRDS(matching_file)
net$layer = net$flow
plot_layer(net, input$layer, update_view = TRUE)
plot_map(net, input$layer, update_view = TRUE)
}
)

Expand All @@ -77,7 +80,7 @@ shinyAppServer = function(input, output, session) {
net$layer = net$flow
}
}
plot_layer(net, input$layer, update_view = FALSE)
plot_map(net, input$layer, update_view = FALSE)
}
)

Expand All @@ -93,12 +96,21 @@ shinyAppServer = function(input, output, session) {
net$layer = net$flow
}
}
plot_layer(net, input$layer, update_view = TRUE)
plot_map(net, input$layer, update_view = TRUE)
}
)

x <- reactive ({
g <- plot_chart (city = input$city_sc)
return (g)
})
output$plot = renderPlot ({
print (x ())
})

}

plot_layer = function(net, leg_title, update_view = FALSE) {
plot_map = function(net, leg_title, update_view = FALSE) {
net$width = 100 * net$layer / max(net$layer, na.rm = TRUE)
cols = rgb(colourvalues::get_palette("inferno"), maxColorValue = 255)
variables = seq(min(net$layer), max(net$layer), length.out = 5)
Expand Down Expand Up @@ -126,3 +138,13 @@ plot_layer = function(net, leg_title, update_view = FALSE) {
layer_id = "mylayer"
)
}

plot_chart = function (city) {
x <- calc_exposure (city = city, has_tram = FALSE)
x$mortality_reduction <- x$d_mortality - x$exposure
ggplot2::ggplot (x, ggplot2::aes (x = bus_stops_per_1000,
y = mortality_reduction)) +
ggplot2::geom_point () +
ggplot2::geom_smooth (method = "lm") +
ggplot2::theme (axis.title.y = ggplot2::element_text (angle = 90))
}
37 changes: 23 additions & 14 deletions R/ui.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@
#' @import shiny
#' @import leaflet
#' @export
shinyAppUI = fluidPage(
shiny::titlePanel("Urban Planning and Transport Health Assessment Tool (upthat)"),
column(12, shiny::htmlOutput("app_info")),
column(width = 3,
selectInput("city", label = "City", choices = c("Accra", "Kathmandu", "Bristol", "NYC")),
selectInput("mode", label = "Mode of transport", choices = c("Walk", "Cycle", "Ebike", "Escooter", "Fly")),
selectInput("layer", label = "Layer", choices = c("pedestrian flow", "exposure")),
sliderInput("bus", "Number of bus stops added per 1,000", min = 0, max = 10, value = 1),
sliderInput("obs", "Investment (US $ millions):", min = 0, max = 50, value = 0.5, step = 0.1)
shinyAppUI = navbarPage("Urban Planning and Transport Health Assessment Tool (upthat)",
tabPanel("Maps",
column(12, shiny::htmlOutput("app_info")),
column(width = 3,
selectInput("city", label = "City", choices = c("Accra", "Kathmandu", "Bristol", "NYC")),
selectInput("mode", label = "Mode of transport", choices = c("Walk", "Cycle", "Ebike", "Escooter", "Fly")),
selectInput("layer", label = "Layer", choices = c("pedestrian flow", "exposure")),
sliderInput("bus", "Number of bus stops added per 1,000", min = 0, max = 10, value = 1),
sliderInput("obs", "Investment (US $ millions):", min = 0, max = 50, value = 0.5, step = 0.1)
),
column(width = 9,
mapdeck::mapdeckOutput ("mymap")
),
p(),
actionButton("recalc", "Zoom to city extent")
),
column(width = 9,
mapdeck::mapdeckOutput ("mymap")
),
p(),
actionButton("recalc", "Zoom to city extent")
tabPanel("Scenarios",
column(width=3,
selectInput("city_sc", label = "City", choices = c("Accra", "Kathmandu", "Bristol", "NYC"))
),
column(width=9,
plotOutput("plot")
)
)
)