-
Notifications
You must be signed in to change notification settings - Fork 0
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
Plot Step Ahead Projection function #2
Conversation
- from the example-complex-scenario-hub. "example_worfklow.Rmd"
- add `use_median_as_point` parameter - force forecast_data as "model_output_df" - fix input of plotly function - update plot if no "point" value
to show or not the output plot
- output for 1 model_id in ens_name (truth data and fix error by default) - return plot_model object
- allow none, one or multiple intervals - adapt transparency
- fix opacity - reorganize function (create internal functions) - add top_layer parameter
- hover text format for interactive plot - fix visible binding for global variable
Thank you for the feedback, I implemented the required changes except for the example files. I am not sure what would be the best solution here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am basically fine with the content of this PR as is. My final requests are:
- some investigation into why the plotly figure heights are so tall and ideally fixing this so by default they are lower
- adding at least some unit tests to the code
I do think we should enforce the unit tests piece prior to merging in the current PR, even though the functionality appears to be there. I don't have the time to do this now, but I would be happy at a future time to help brainstorm a list of possible tests that could be put in place here. E.g. one that came to me on this latest re-review is making sure we throw an error if the column specified by x_col_name argument is not a date.
Found this generally very clear and easy to follow. I find the attached plot (faceted by model) a bit confusing, with the legend only showing the one model (the first panel). In the interactive plotly, if you then click to not display the model, only the first panel projection disappears (pictured). I would propose to have the default of this plot to not have a legend, but not sure exactly how to set this up practically (tricky with the option default being true for other plots). Another option might be to allow each of the panels to still be a different colour so the legend corresponds to something meaningful? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made a number of comments but most are just suggestions. Overall I found nothing critical to resolve but think following some suggestions might make the code easier to follow and reason about.
Also might be a good idea to run styler::tidyverse_style()
on any R/*.R
and testthat/*.R
script to make them more readable.
- `example_round1.csv`: example of model output for a round associated with the | ||
origin date: "2021-03-07" (called "round 1"), target: "incident case", for the | ||
US national level, from the | ||
[example-complex-scenario-hub](https://github.com/Infectious-Disease-Modeling-Hubs/example-complex-scenario-hub). The data set also contains an ensemble calculated by applying the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we answered this on slack. While the idea is generally good, in some packages we don't need a full example hub so to keep package sizes as small as possible, I think it is acceptable to only include small and specific test materials to the functionality being tested.
R/plot_step_ahead_model_output.R
Outdated
#' @param all_ens a list with two data frame: one for plain lines, | ||
#' one for ribbons plotting (in a wide format) for a unique `model_id` value | ||
#' associated with specific color (`ens_color`). NULL is no specific layout | ||
#' required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm struggling a little to understand the difference between all_plot
and all_ens
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's mostly the same format. all_ens
is only non NULL when the parameter to set the ensemble to a specific color and contains the data associated with the model_id designated as "ensemble". In this case, the model_id will be excluded from the all_plot object. I split them because they have slightly different plotting parameters and it was easy to set it like this.
However, I am happy to re-think in a future version and make it easier to understand (same as the idea to "modularize" the lapply
/if
part of the code)
R/plot_step_ahead_model_output.R
Outdated
subplot <- lapply(facet_value, function(x) { | ||
# Data preparation | ||
df_point <- all_plot$median[which(all_plot$median[[facet]] == x), ] | ||
df_ribbon <- all_plot[names(all_plot) %in% intervals] | ||
df_ribbon <- setNames(lapply(df_ribbon, function(df_rib) { | ||
df_rib[which(df_rib[[facet]] == x), ] | ||
}), names(df_ribbon)) | ||
if (!is.null(all_ens)) { | ||
df_point_ens <- all_ens$median[which(all_ens$median[[facet]] == x), ] | ||
df_ribbon_ens <- all_ens[names(all_ens) %in% intervals] | ||
df_ribbon_ens <- setNames(lapply(df_ribbon_ens, function(df_rib) { | ||
df_rib[which(df_rib[[facet]] == x), ] | ||
}), names(df_ribbon_ens)) | ||
} | ||
if (plot_truth & facet %in% colnames(truth_data)) { | ||
truth_data <- truth_data[which(truth_data[[facet]] == x), ] | ||
} | ||
|
||
# Plot | ||
if (x == facet_value[1]) { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point, df_ribbon, plot_truth, truth_data, | ||
opacity = fill_transparency, top_layer = top_layer, | ||
interactive = TRUE, fill_by = fill_by, x_col_name = x_col_name, | ||
x_truth_col_name = x_truth_col_name) | ||
} else if (facet == fill_by) { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point, df_ribbon, plot_truth, truth_data, | ||
opacity = fill_transparency, top_layer = top_layer, | ||
show_truth_legend = FALSE, interactive = TRUE, | ||
fill_by = fill_by, x_col_name = x_col_name, | ||
x_truth_col_name = x_truth_col_name) | ||
} else { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point, df_ribbon, plot_truth, truth_data, | ||
opacity = fill_transparency, showlegend = FALSE, | ||
top_layer = top_layer, show_truth_legend = FALSE, | ||
interactive = TRUE, fill_by = fill_by, x_col_name = x_col_name, | ||
x_truth_col_name = x_truth_col_name) | ||
} | ||
# Ensemble color | ||
if (!is.null(all_ens)) { | ||
if (x == facet_value[1]) { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point_ens, df_ribbon_ens, FALSE, truth_data, | ||
line_color = ens_color, opacity = fill_transparency, | ||
top_layer = top_layer, interactive = TRUE, fill_by = fill_by, | ||
x_col_name = x_col_name, x_truth_col_name = x_truth_col_name) | ||
} else if (facet == fill_by) { | ||
if (facet == "model_id" & ens_name == x) { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point_ens, df_ribbon_ens, TRUE, truth_data, | ||
line_color = ens_color, opacity = fill_transparency, | ||
top_layer = top_layer, show_truth_legend = FALSE, | ||
interactive = TRUE, fill_by = fill_by, x_col_name = x_col_name, | ||
x_truth_col_name = x_truth_col_name) | ||
} | ||
} else { | ||
plot_model <- simple_model_plot( | ||
plot_model, df_point_ens, df_ribbon_ens, FALSE, truth_data, | ||
line_color = ens_color, opacity = fill_transparency, | ||
showlegend = FALSE, top_layer = top_layer, | ||
show_truth_legend = FALSE, interactive = TRUE, fill_by = fill_by, | ||
x_col_name = x_col_name, x_truth_col_name = x_truth_col_name) | ||
} | ||
} | ||
if (!is.null(facet_title)) { | ||
if (grepl("top", facet_title)) { | ||
y_title <- 1 | ||
y_anchor <- "top" | ||
} else if (grepl("bottom", facet_title)) { | ||
y_title <- 0 | ||
y_anchor <- "bottom" | ||
} | ||
if (grepl("left", facet_title)) { | ||
x_title <- 0 | ||
x_anchor <- "left" | ||
} else if (grepl("right", facet_title)) { | ||
x_title <- 1 | ||
x_anchor <- "right" | ||
} | ||
plot_model <- plotly::layout( | ||
plot_model, | ||
annotations = list(x = x_title, y = y_title, xref = "paper", | ||
yref = "paper", xanchor = x_anchor, | ||
yanchor = y_anchor, showarrow = FALSE, text = x)) | ||
} | ||
return(plot_model) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section is quite nested and hard to follow. I wonder if some of it can be modularised and pulled out into smaller more concise functions?
Also although the unnamed function called in lapply
only has x
as an argument, there are a lot of objects used from the function environment which also make it a bit confusing and hard to follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, it will take me some time to test and implement. I am happy to think about it for a future version.
Co-authored-by: Anna Krystalli <annakrystalli@googlemail.com>
plot_step_ahead_forecasts()
function (create plot_step_ahead_forecasts() #1)Still to do:
TRUE
returns Plotly object, but returns ggplot2 type object when set toFALSE
.