Skip to content

Commit 77d7e5e

Browse files
authored
Merge pull request #73 from cmu-delphi/shinyExtra
feat: lineplot, parameter tables
2 parents 806119b + 4ae4fb5 commit 77d7e5e

File tree

1 file changed

+69
-17
lines changed

1 file changed

+69
-17
lines changed

app.R

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,41 @@ load_forecast_data_raw <- function(forecaster) {
5151
# Have loading function use the cache.
5252
load_forecast_data <- memoise::memoise(load_forecast_data_raw, cache = cache)
5353

54+
#' create a data table for the shiny plot of the forecasters present
55+
#' @description
56+
prepare_forecaster_table <- function(selected_forecasters) {
57+
forecasters <- tar_read(forecaster_params_grid) %>%
58+
select(-id) %>%
59+
mutate(across(where(is.list), map, `%||%`, c(0, 7, 14))) %>%
60+
mutate(lags = paste(lags, sep = ",")) %>%
61+
group_by(parent_id) %>%
62+
mutate(ahead = toString(unique(ahead))) %>%
63+
ungroup() %>%
64+
distinct(parent_id, .keep_all = TRUE) %>%
65+
rename(name = parent_id) %>%
66+
select(name, everything())
67+
forecasters$present <- map_vec(paste0("score_", forecasters$name), \(x) x %in% selected_forecasters)
68+
return(forecasters)
69+
}
70+
71+
#' create a data table for the shiny plot of the ensembles present
72+
#' @description
73+
prepare_ensemble_table <- function(selected_forecasters) {
74+
forecasters <- tar_read(ensemble_forecasters) %>%
75+
select(-id) %>%
76+
group_by(parent_id) %>%
77+
mutate(ahead = toString(unique(ahead))) %>%
78+
ungroup() %>%
79+
distinct(parent_id, .keep_all = TRUE) %>%
80+
rename(name = parent_id) %>%
81+
mutate(ensemble_params = paste(ensemble_params, sep = ",")) %>%
82+
mutate(forecaster_ids = paste(forecaster_ids, sep = ",")) %>%
83+
select(name, everything()) %>%
84+
select(-forecasters)
85+
print(selected_forecasters)
86+
forecasters$present <- map_vec(paste0("ensemble_score_", forecasters$name), \(x) x %in% selected_forecasters)
87+
return(forecasters)
88+
}
5489
#### Adapted from shiny-eval.R from cmu-delphi/hospitalization-forecaster
5590

5691
shinyApp(
@@ -125,10 +160,22 @@ shinyApp(
125160
multiple = TRUE,
126161
selected = c("as", "gu", "mp", "vi")
127162
),
163+
selectInput("excluded_aheads",
164+
"Exclude aheads:",
165+
choices = 1:28,
166+
multiple = TRUE
167+
)
128168
),
129169
mainPanel(
130-
plotlyOutput("main_plot", height = "90em"),
131-
width=8
170+
verticalLayout(
171+
plotlyOutput("main_plot", height = "90em"),
172+
h2("forecaster name -> parameters"),
173+
#textOutput("forecaster_param_title"),
174+
dataTableOutput("forecaster_table"),
175+
h2("ensemble name -> parameters"),
176+
dataTableOutput("ensemble_table")
177+
),
178+
width = 8
132179
)
133180
)
134181
)
@@ -137,24 +184,27 @@ shinyApp(
137184
filtered_scorecards_reactive <- reactive({
138185
agg_forecasters <- unique(c(input$selected_forecasters, input$baseline))
139186
if (length(agg_forecasters) == 0 ||
140-
all(agg_forecasters == "" | is.null(agg_forecasters) | is.na(agg_forecasters))
187+
all(agg_forecasters == "" | is.null(agg_forecasters) | is.na(agg_forecasters))
141188
) {
142189
return(data.frame())
143190
}
144191

145192
processed_evaluations_internal <- lapply(agg_forecasters, function(forecaster) {
146-
load_forecast_data(forecaster) %>>%
193+
load_forecast_data(forecaster) %>>%
147194
filter(
148195
.data$forecast_date %>>% between(.env$input$selected_forecast_date_range[[1L]], .env$input$selected_forecast_date_range[[2L]]),
149196
.data$target_end_date %>>% between(.env$input$selected_target_end_date_range[[1L]], .env$input$selected_target_end_date_range[[2L]]),
150-
!.data$geo_value %in% c(.env$input$excluded_geo_values, "us")
197+
!.data$geo_value %in% c(.env$input$excluded_geo_values, "us"),
198+
!.data$ahead %in% .env$input$excluded_aheads
151199
)
152-
}) %>%
200+
}) %>%
153201
bind_rows()
154202
})
155203
output$main_plot <- renderPlotly({
156204
input_df <- filtered_scorecards_reactive()
157-
if (nrow(input_df) == 0) { return() }
205+
if (nrow(input_df) == 0) {
206+
return()
207+
}
158208

159209
# Normalize by baseline scores. This is not relevant for coverage, which is compared
160210
# to the nominal confidence level.
@@ -184,7 +234,7 @@ shinyApp(
184234

185235
x_tick_angle <- list(tickangle = -30)
186236
facet_x_tick_angles <- setNames(rep(list(x_tick_angle), 10), paste0("xaxis", 1:10))
187-
scale_type <- ifelse(input$facets_share_scale, "fixed", "free_y" )
237+
scale_type <- ifelse(input$facets_share_scale, "fixed", "free_y")
188238

189239
input_df %>>%
190240
# Aggregate scores over all geos
@@ -208,13 +258,9 @@ shinyApp(
208258
),
209259
na.rm = TRUE
210260
)) %>>%
211-
# Use scatterplot or lines depending on the x var. Also, if the range
212-
# of obs by forecaster is too wide, plot using points instead of
213-
# lines.
261+
# Use scatterplot or lines depending on the x var.
214262
{
215-
if (input$x_var %in% c(input$facet_vars, "geo_value", "forecaster", "ahead") || range(plot.df[["n"]]) %>>% {
216-
.[[2L]] > 1.2 * .[[1L]]
217-
}) {
263+
if (input$x_var %in% c(input$facet_vars, "geo_value", "forecaster", "ahead")) {
218264
. + geom_point(aes(size = n)) + expand_limits(size = 0)
219265
} else {
220266
. + geom_line()
@@ -228,9 +274,15 @@ shinyApp(
228274
} else {
229275
facet_grid(as.formula(paste0(input$facet_vars[[1L]], " ~ ", paste(collapse = " + ", input$facet_vars[-1L]))), scales = scale_type)
230276
}) %>>%
231-
ggplotly() %>>%
232-
{inject(layout(., hovermode = "x unified", legend = list(orientation = "h", title = list(text = "forecaster")), xaxis = x_tick_angle, !!!facet_x_tick_angles))}
233-
277+
ggplotly() %>>% {
278+
inject(layout(., hovermode = "x unified", legend = list(orientation = "h", title = list(text = "forecaster")), xaxis = x_tick_angle, !!!facet_x_tick_angles))
279+
}
234280
})
281+
output$forecaster_table <- renderDataTable(
282+
prepare_forecaster_table(input$selected_forecasters)
283+
)
284+
output$ensemble_table <- renderDataTable(
285+
prepare_ensemble_table(input$selected_forecasters)
286+
)
235287
}
236288
)

0 commit comments

Comments
 (0)