diff --git a/modules/Visualization/R/plot_extreme_probs.R b/modules/Visualization/R/plot_extreme_probs.R index 7397898246957832d52ed89f1d019f0dcc94340d..5669efd85017d8ecde94449260c7417f28298397 100644 --- a/modules/Visualization/R/plot_extreme_probs.R +++ b/modules/Visualization/R/plot_extreme_probs.R @@ -208,7 +208,13 @@ plot_extreme_probs <- function(recipe, fcst, indices = var, drop = 'selected') dim_dots <- dim(var_dots) - var_dots <- as.numeric(var_dots >= 0) + if (recipe$Analysis$Workflow$Visualization$dots_on_points == "significant") { + var_dots <- as.numeric(var_dots <= 0) + dots_caption <- "Dots indicate negative RPSS" + } else { # "non-significant" + var_dots <- as.numeric(var_dots > 0) + dots_caption <- "Dots indicate positive RPSS" + } dim(var_dots) <- dim_dots } else { var_dots <- NULL @@ -284,7 +290,7 @@ plot_extreme_probs <- function(recipe, fcst, fun <- VizEquiMap base_args <- list(data = NULL, dots = NULL, mask = NULL, lon = longitude, lat = latitude, - dot_symbol = 20, title_scale = 0.6, + dot_symbol = 4, title_scale = 0.6, font.main = 2, margin_scale = c(1, 5, 5, 5), filled.continents = F, brks = brks, cols = cols, bar_label_digits = 4, bar_label_scale = 1.5, @@ -306,7 +312,7 @@ plot_extreme_probs <- function(recipe, fcst, lon_dim = 'longitude', lat_dim = 'latitude', target_proj = target_proj, drawleg = 'bar', style = 'point', brks = brks, cols = cols, - dot_size = 0.2, dot_symbol = 47, + dot_size = 0.2, dot_symbol = 4, col_inf = cols_1[1], col_sup = cols_2[length(cols_2)]) } @@ -361,7 +367,7 @@ plot_extreme_probs <- function(recipe, fcst, "Reference: ", recipe$Analysis$Datasets$Reference, " [", recipe$Analysis$Time$hcst_start, " - ", recipe$Analysis$Time$hcst_end, "]", - "\n", " ") + "\n", if (!is.null(dots)) dots_caption else " ") # Modify base arguments base_args[[1]] <- i_var_fcst[i, , ] if (is.null(attributes(fcst$attrs$time_bounds))) { diff --git a/modules/Visualization/R/plot_forecast_map.R b/modules/Visualization/R/plot_forecast_map.R index e86800c10d783510dc6324c74840df3492983443..7ba2e88201bf8cad332bcdf1be7a6786390315ce 100644 --- a/modules/Visualization/R/plot_forecast_map.R +++ b/modules/Visualization/R/plot_forecast_map.R @@ -159,7 +159,13 @@ plot_forecast_map <- function(recipe, fcst, mask = NULL, dots = NULL, indices = var, drop = 'selected') dim_dots <- dim(var_dots) - var_dots <- as.numeric(var_dots <= 0) + if (recipe$Analysis$Workflow$Visualization$dots_on_points == "significant") { + var_dots <- as.numeric(var_dots <= 0) + dots_caption <- "Dots indicate negative RPSS" + } else { # "non-significant" + var_dots <- as.numeric(var_dots > 0) + dots_caption <- "Dots indicate positive RPSS" + } dim(var_dots) <- dim_dots } else { var_dots <- NULL @@ -231,7 +237,7 @@ plot_forecast_map <- function(recipe, fcst, mask = NULL, dots = NULL, fun <- VizEquiMap base_args <- list(data = NULL, dots = NULL, mask = NULL, lon = longitude, lat = latitude, - dot_symbol = 20, title_scale = 0.7, + dot_symbol = 4, title_scale = 0.7, font.main = 2, margin_scale = c(3, 5, 5, 5), bar_extra_margin = rep(0.9, 4), filled.continents = F, brks = brks, cols = cols, @@ -251,7 +257,7 @@ plot_forecast_map <- function(recipe, fcst, mask = NULL, dots = NULL, lon_dim = 'longitude', lat_dim = 'latitude', target_proj = target_proj, drawleg = 'bar', style = 'point', brks = brks, cols = cols, - dot_size = 0.2, dot_symbol = 47) + dot_size = 0.2, dot_symbol = 4) } output_configuration <- output_conf[[projection]]$forecast_map base_args[names(output_configuration)] <- output_configuration @@ -303,7 +309,8 @@ plot_forecast_map <- function(recipe, fcst, mask = NULL, dots = NULL, "%d-%m-%Y"), "\n", forecast_time_caption, "\n", "Reference: ", recipe$Analysis$Datasets$Reference, "\n", - "Units: ", units) + "Units: ", units, "\n", + if (!is.null(dots)) dots_caption else " ") # Modify base arguments base_args[[1]] <- i_var_fcst[i, , ] if (is.null(attributes(fcst$attrs$time_bounds))) { diff --git a/modules/Visualization/R/plot_metrics.R b/modules/Visualization/R/plot_metrics.R index 6392609cb00cce0a3afe46f6da13ecab479d4492..43b012ddb6405ba84eb2cdbe30717f17193c3496 100644 --- a/modules/Visualization/R/plot_metrics.R +++ b/modules/Visualization/R/plot_metrics.R @@ -302,7 +302,7 @@ plot_metrics <- function(recipe, data_cube, metrics, data = asplit(metric, MARGIN = 1), lon = longitude, lat = latitude, special_args = metric_significance, - dot_symbol = 20, toptitle = toptitle, + dot_symbol = 4, toptitle = toptitle, title_scale = 0.6, titles = titles, filled.continents = FALSE, brks = brks, cols = cols, col_inf = col_inf, col_sup = col_sup, @@ -338,7 +338,7 @@ plot_metrics <- function(recipe, data_cube, metrics, fun <- VizEquiMap base_args <- list(data = NULL, dots = NULL, lon = longitude, lat = latitude, - dot_symbol = 20, dot_size = 1, + dot_symbol = 4, dot_size = 1, title_scale = 0.6, filled.continents = F, brks = brks, cols = cols, col_inf = col_inf, col_sup = col_sup, @@ -363,7 +363,7 @@ plot_metrics <- function(recipe, data_cube, metrics, target_proj = target_proj, drawleg = 'bar', style = 'point', dots = NULL, brks = brks, cols = cols, col_inf = col_inf, col_sup = col_sup, - units = units, dot_size = 0.2, dot_symbol = 47) + units = units, dot_size = 0.2, dot_symbol = 4) } output_configuration <- output_conf[[projection]]$skill_metrics base_args[names(output_configuration)] <- output_configuration @@ -482,11 +482,23 @@ plot_metrics <- function(recipe, data_cube, metrics, } else { if (significance == 'dots') { if (projection != 'cylindrical_equidistant') { - base_args[[10]] <- metric_significance[[i]][[1]] + if (recipe$Analysis$Workflow$Visualization$dots_on_points == "significant") { + base_args[[10]] <- metric_significance[[i]][[1]] + dots_caption <- paste0("Dots indicate statistical significance", "\n") + } else { # "non-significant" + base_args[[10]] <- 1 - base_args[[10]] + dots_caption <- paste0("Dots indicate statistical non-significance", "\n") + } } else { # The position of arguments in base_args requires this cond # so VizEquiMap plots dots when requested - base_args[[2]] <- metric_significance[[i]][[1]] + if (recipe$Analysis$Workflow$Visualization$dots_on_points == "significant") { + base_args[[2]] <- metric_significance[[i]][[1]] + dots_caption <- paste0("Dots indicate statistical significance", "\n") + } else { + base_args[[2]] <- 1 - base_args[[2]] + dots_caption <- paste0("Dots indicate statistical non-significance", "\n") + } } sign_file_label <- '_dots' } else if (significance == 'mask') { @@ -494,7 +506,7 @@ plot_metrics <- function(recipe, data_cube, metrics, sign_file_label <- '_mask' } } - significance_caption <- "\n alpha = 0.05" + significance_caption <- "alpha = 0.05" } else { significance_caption <- NULL sign_file_label <- NULL @@ -503,7 +515,8 @@ plot_metrics <- function(recipe, data_cube, metrics, base_args[['caption']] <- paste0("Nominal start date: ", nominal_startdate_caption, "\n", forecast_time_caption, "\n", - "Reference: ", recipe$Analysis$Datasets$Reference, + "Reference: ", recipe$Analysis$Datasets$Reference, "\n", + if (significance == 'dots') dots_caption, significance_caption) fileout <- paste0(outfile, "_ft", forecast_time, diff --git a/modules/Visualization/R/plot_most_likely_terciles_map.R b/modules/Visualization/R/plot_most_likely_terciles_map.R index 3f8a41b813169d3da66f1415690e160832e38237..14406085fe924b61dcb3d19b8d3ba819c4b5ce50 100644 --- a/modules/Visualization/R/plot_most_likely_terciles_map.R +++ b/modules/Visualization/R/plot_most_likely_terciles_map.R @@ -159,10 +159,17 @@ plot_most_likely_terciles <- function(recipe, indices = var, drop = 'selected') dim_dots <- dim(var_dots) - var_dots <- as.numeric(var_dots <= 0) + if (recipe$Analysis$Workflow$Visualization$dots_on_points == "significant") { + var_dots <- as.numeric(var_dots <= 0) + dots_caption <- "Dots indicate negative RPSS" + } else { # "non-significant" + var_dots <- as.numeric(var_dots > 0) + dots_caption <- "Dots indicate positive RPSS" + } dim(var_dots) <- dim_dots } else { var_dots <- NULL + dots_caption <- NULL } # Plot title labels look different depending on horizon and aggregation @@ -350,6 +357,12 @@ plot_most_likely_terciles <- function(recipe, tmp$bar_titles <- NULL tmp$nmap <- NULL tmp$var_limits <- NULL + if (i_bar == 1) { + if (!is.null(dots_caption)) { + mtext(dots_caption, side = 1, line = 12, at = NA, adj = 0, + cex = 0.9, col = "black") + } + } if (length(cb_info$brks[[i_bar]]) > 2) { # plot colorbar as normal do.call(ColorBar, tmp) diff --git a/modules/Visualization/Visualization.R b/modules/Visualization/Visualization.R index 8c50be4585a4cb943918a2839284caec716d6486..6fab018e518b5a12e2d4f23473c0f444c24b7988 100644 --- a/modules/Visualization/Visualization.R +++ b/modules/Visualization/Visualization.R @@ -25,7 +25,7 @@ Visualization <- function(recipe, skill_metrics = NULL, statistics = NULL, probabilities = NULL, - significance = F, + significance = FALSE, output_conf = NULL, logo = NULL) { # Try to produce and save several basic plots. @@ -85,6 +85,11 @@ Visualization <- function(recipe, recipe$Analysis$Workflow$Visualization$multi_panel <- FALSE } + # Set default dotting of non-significant grid points if not specified + if (is.null(recipe$Analysis$Workflow$Visualization$dots_on_points)) { + recipe$Analysis$Workflow$Visualization$dots_on_points <- "non-significant" + } + # Warning if significance parameter not included in function call if (!missing(significance) && !is.null(recipe$Analysis$Workflow$Visualization$significance)) { if (significance != recipe$Analysis$Workflow$Visualization$significance) { @@ -144,7 +149,7 @@ Visualization <- function(recipe, } } - # Plot forecast ensemble mean + # Plot forecast map if ("forecast_map" %in% plots) { if (!is.null(data$fcst)) { if (is.null(recipe$Analysis$Workflow$Visualization$mask_ens)) { @@ -174,11 +179,11 @@ Visualization <- function(recipe, c('both', TRUE)) { if (is.null(skill_metrics)) { error(recipe$Run$logger, - paste0("For the forecast ensemble mean plot, skill_metrics ", + paste0("For the forecast map plot, skill_metrics ", "needs to be provided to be masked.")) } else if (!('enscorr' %in% names(skill_metrics))) { error(recipe$Run$logger, - paste0("For the forecast ensemble mean plot, enscor metric ", + paste0("For the forecast map plot, enscor metric ", "needs to be provided to be masked.")) } else { plot_forecast_map(recipe, data$fcst, @@ -193,11 +198,11 @@ Visualization <- function(recipe, if (recipe$Analysis$Workflow$Visualization$dots %in% c('both', TRUE)) { if (is.null(skill_metrics)) { error(recipe$Run$logger, - paste0("For the forecast ensemble mean plot, skill_metrics ", + paste0("For the forecast map plot, skill_metrics ", "needs to be provided for the dots.")) } else if (!('enscorr' %in% names(skill_metrics))) { error(recipe$Run$logger, - paste0("For the forecast ensemble mean plot, enscor metric ", + paste0("For the forecast map plot, enscor metric ", "needs to be provided for the dots.")) } else { plot_forecast_map(recipe, data$fcst, @@ -211,7 +216,7 @@ Visualization <- function(recipe, } ## End loop over methods } else { error(recipe$Run$logger, - paste0("The forecast ensemble mean plot has been requested, but ", + paste0("The forecast map plot has been requested, but ", "there is no fcst element in 'data'.")) } } diff --git a/recipe_template.yml b/recipe_template.yml index 8df187122fcf4673e66ee75175fecb6e86dde55e..c948cb847ece016b1e9d715a0285f64dbdb7d3b6 100644 --- a/recipe_template.yml +++ b/recipe_template.yml @@ -148,8 +148,9 @@ Analysis: multi_panel: yes # Multi-panel plot or single-panel plots. Default is 'no/false'. (Optional, bool) projection: 'cylindrical_equidistant' # Options: 'cylindrical_equidistant', 'robinson', 'lambert_europe'. Default is cylindrical equidistant. (Optional, str) significance: 'dots' # Type of mask for statistical significance. Options are 'dots', and yes/no. 'dots'. 'mask' and 'both' options are not available for projections other than cylindrical_equidistant. - mask_terciles: no # Whether to dot or mask the non-significant points by rpss in the most likely tercile plot. yes/true, no/false or 'both'. Default is no/false. (Optional, str) - dots_terciles: yes # Whether to dot the non-significant by rpss in the most likely tercile plot. yes/true, no/false or 'both'. Default is no/false. (Optional, str) + mask_terciles: no # Whether to mask the non-significant points by rpss in the most likely tercile plot. yes/true, no/false or 'both'. Default is no/false. (Optional, str) + dots_terciles: yes # Whether to dot the non-significant points by rpss in the most likely tercile plot. yes/true, no/false or 'both'. Default is no/false. (Optional, str) + dots_on_points: "non-significant" # Which grid points to dot, if dots are requested. Either "significant" or "non-significant". mask_ens: no # Whether to mask the non-significant points by rpss in the forecast ensemble mean plot. yes/true, no/false or 'both'. Default is no/false. (Optional, str) shapefile: # path to a shapefile (*.shp) to include in the plots. Only available for the cylindrical equidistant projection. (Optional, str) logo: tools/BSC_logo_95.jpg # path to a logo (*.png or *.jpg/jpeg) to include in the plots. (Optional, str)