From 94b4c99b63d76fcc15c6b7e681fb338bb886772b Mon Sep 17 00:00:00 2001 From: Samuel Buis Date: Fri, 19 Jun 2026 17:06:28 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Improve=20handling=20of=20=E2=80=9Csuccessi?= =?UTF-8?q?ve=20situations=E2=80=9D=20in=20dynamic=20plots=20and=20add=20a?= =?UTF-8?q?utomatic=20multiline=20title=20wrapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Propagate the 'successive' argument through the plotting dispatcher and specific plot functions to support contiguous/successive situations. Implement add_vertical_lines(df_data, successive, p) to draw vertical separators and make_multiline_title(title, max_char) to split long titles across lines for "successive situations" Update many plot_dynamic_* function signatures to accept 'successive', call add_vertical_lines, and use the multiline title helper. --- R/generic_plotting.R | 14 +++--- R/specific_plotting_dynamic.R | 91 +++++++++++++++++++++++++++++------ man/specific_dynamic_plots.Rd | 24 +++++++-- 3 files changed, 103 insertions(+), 26 deletions(-) diff --git a/R/generic_plotting.R b/R/generic_plotting.R index c407d235..006e9541 100644 --- a/R/generic_plotting.R +++ b/R/generic_plotting.R @@ -186,22 +186,22 @@ plot_situations <- function(..., obs = NULL, obs_sd = NULL, p[[i]] <- switch(item_case, # Dynamic plots: "mixture_versions_overlap" = - plot_dynamic_mixture_versions_overlap(sim_situation, i, + plot_dynamic_mixture_versions_overlap(sim_situation, i, successive, title = plot_title ), "mixture_versions_no_overlap" = - plot_dynamic_mixture_versions(sim_situation, i, title = plot_title), + plot_dynamic_mixture_versions(sim_situation, i, successive, title = plot_title), "mixture_no_versions_overlap" = - plot_dynamic_mixture_overlap(sim_situation, i, title = plot_title), - "mixture_no_versions_no_overlap" = plot_dynamic_mixture(sim_situation, i, + plot_dynamic_mixture_overlap(sim_situation, i, successive, title = plot_title), + "mixture_no_versions_no_overlap" = plot_dynamic_mixture(sim_situation, i, successive, title = plot_title ), "non_mixture_versions_overlap" = - plot_dynamic_versions_overlap(sim_situation, i, title = plot_title), + plot_dynamic_versions_overlap(sim_situation, i, successive, title = plot_title), "non_mixture_versions_no_overlap" = - plot_dynamic_versions(sim_situation, i, title = plot_title), + plot_dynamic_versions(sim_situation, i, successive, title = plot_title), "non_mixture_no_versions_overlap" = - plot_dynamic_overlap(sim_situation, i, title = plot_title), + plot_dynamic_overlap(sim_situation, i, successive, title = plot_title), "non_mixture_no_versions_no_overlap" = plot_dynamic(sim_situation, i, successive, title = plot_title), diff --git a/R/specific_plotting_dynamic.R b/R/specific_plotting_dynamic.R index 7e1d8b80..65f24822 100644 --- a/R/specific_plotting_dynamic.R +++ b/R/specific_plotting_dynamic.R @@ -45,17 +45,12 @@ #' NULL - #' @keywords internal +#' @description Add vertical lines between situations in case of successive situations. #' @rdname specific_dynamic_plots -plot_dynamic <- function(df_data, sit, successive, title = NULL) { - p <- ggplot2::ggplot( - df_data, - ggplot2::aes(x = .data$Date) - ) + - ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + - ggplot2::facet_wrap(~ .data$var, scales = "free_y") - +#' @param p A ggplot to modify` +#' @return A ggplot object with vertical lines added if successive situations are provided. +add_vertical_lines <- function(df_data, successive, p) { if (!is.null(successive)) { dates <- unique(df_data$succession_date) dates_vlines <- as.POSIXct(dates, tz = "UTC") @@ -66,6 +61,52 @@ plot_dynamic <- function(df_data, sit, successive, title = NULL) { color = "black" ) } + return(p) +} + +#' @keywords internal +#' @description Make a multiline title for a ggplot object, splitting the title into multiple lines (for successive situations only) if it exceeds a certain character limit. +#' @rdname specific_dynamic_plots +#' @param title A character string representing the title to be split into multiple lines. +#' @param max_char An integer specifying the maximum number of characters per line. Default is 80 +#' @return A character string with newline characters inserted to create a multiline title. +make_multiline_title <- function(title, max_char = 120) { + + labels <- strsplit(title, " \\| ")[[1]] + + lines <- character() + current <- labels[1] + + if (length(labels) > 1) { + for (lab in labels[-1]) { + + candidate <- paste(current, lab, sep = " | ") + + if (nchar(candidate) <= max_char) { + current <- candidate + } else { + lines <- c(lines, paste0(current, " ...")) + current <- lab + } + } + } + + lines <- c(lines, current) + + paste(lines, collapse = "\n") +} + +#' @keywords internal +#' @rdname specific_dynamic_plots +plot_dynamic <- function(df_data, sit, successive, title = NULL) { + p <- ggplot2::ggplot( + df_data, + ggplot2::aes(x = .data$Date) + ) + + ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + + ggplot2::facet_wrap(~ .data$var, scales = "free_y") + + p <- add_vertical_lines(df_data, successive, p) if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point(ggplot2::aes(y = .data$Observed), na.rm = TRUE) @@ -81,12 +122,13 @@ plot_dynamic <- function(df_data, sit, successive, title = NULL) { ) } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) return(p) } -plot_dynamic_mixture <- function(df_data, sit, title = NULL) { +plot_dynamic_mixture <- function(df_data, sit, successive, title = NULL) { p <- ggplot2::ggplot( df_data, ggplot2::aes( @@ -97,6 +139,7 @@ plot_dynamic_mixture <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$var, scales = "free_y") + p <- add_vertical_lines(df_data, successive, p) if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point(ggplot2::aes(y = .data$Observed), na.rm = TRUE) @@ -113,13 +156,14 @@ plot_dynamic_mixture <- function(df_data, sit, title = NULL) { } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) + ggplot2::labs(colour = "Plant") return(p) } -plot_dynamic_mixture_overlap <- function(df_data, sit, title = NULL) { +plot_dynamic_mixture_overlap <- function(df_data, sit, successive, title = NULL) { p <- ggplot2::ggplot( df_data, ggplot2::aes( @@ -132,6 +176,8 @@ plot_dynamic_mixture_overlap <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$group_var, scales = "free") + p <- add_vertical_lines(df_data, successive, p) + if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point( ggplot2::aes( @@ -156,6 +202,7 @@ plot_dynamic_mixture_overlap <- function(df_data, sit, title = NULL) { } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) + ggplot2::guides( @@ -167,7 +214,7 @@ plot_dynamic_mixture_overlap <- function(df_data, sit, title = NULL) { return(p) } -plot_dynamic_versions <- function(df_data, sit, title = NULL) { +plot_dynamic_versions <- function(df_data, sit, successive, title = NULL) { df_data$Observed_Legend <- "Observed Value" p <- ggplot2::ggplot( df_data, @@ -176,6 +223,8 @@ plot_dynamic_versions <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$var, scales = "free") + p <- add_vertical_lines(df_data, successive, p) + if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point( ggplot2::aes(y = .data$Observed, shape = .data$Observed_Legend), @@ -196,6 +245,7 @@ plot_dynamic_versions <- function(df_data, sit, title = NULL) { } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) + ggplot2::guides( @@ -208,7 +258,7 @@ plot_dynamic_versions <- function(df_data, sit, title = NULL) { return(p) } -plot_dynamic_overlap <- function(df_data, sit, title = NULL) { +plot_dynamic_overlap <- function(df_data, sit, successive, title = NULL) { p <- ggplot2::ggplot( df_data, ggplot2::aes(x = .data$Date, colour = .data$var) @@ -216,6 +266,8 @@ plot_dynamic_overlap <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$group_var, scales = "free") + p <- add_vertical_lines(df_data, successive, p) + if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::labs(shape = "Variable") + @@ -235,13 +287,14 @@ plot_dynamic_overlap <- function(df_data, sit, title = NULL) { ) } } + title <- make_multiline_title(title) p <- p + ggplot2::labs(colour = "Variable") + ggplot2::ggtitle(title) return(p) } -plot_dynamic_mixture_versions_overlap <- function(df_data, sit, title = NULL) { +plot_dynamic_mixture_versions_overlap <- function(df_data, sit, successive, title = NULL) { stop( "Too many cases to consider at a time: mixture + versions + overlap. ", "Please use only a maximum of two combinations of: ", @@ -250,7 +303,7 @@ plot_dynamic_mixture_versions_overlap <- function(df_data, sit, title = NULL) { } -plot_dynamic_versions_overlap <- function(df_data, sit, title = NULL) { +plot_dynamic_versions_overlap <- function(df_data, sit, successive, title = NULL) { p <- ggplot2::ggplot( df_data, ggplot2::aes( @@ -261,6 +314,8 @@ plot_dynamic_versions_overlap <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$group_var, scales = "free") + p <- add_vertical_lines(df_data, successive, p) + if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point( ggplot2::aes(y = .data$Observed, colour = .data$var), @@ -279,6 +334,7 @@ plot_dynamic_versions_overlap <- function(df_data, sit, title = NULL) { } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) + ggplot2::labs(colour = "Variable", linetype = "Version") @@ -286,7 +342,7 @@ plot_dynamic_versions_overlap <- function(df_data, sit, title = NULL) { return(p) } -plot_dynamic_mixture_versions <- function(df_data, sit, title = NULL) { +plot_dynamic_mixture_versions <- function(df_data, sit, successive, title = NULL) { p <- ggplot2::ggplot( df_data, ggplot2::aes( @@ -298,6 +354,8 @@ plot_dynamic_mixture_versions <- function(df_data, sit, title = NULL) { ggplot2::geom_line(ggplot2::aes(y = .data$Simulated)) + ggplot2::facet_wrap(~ .data$var, scales = "free") + p <- add_vertical_lines(df_data, successive, p) + if ("Observed" %in% colnames(df_data)) { p <- p + ggplot2::geom_point( ggplot2::aes(y = .data$Observed), @@ -314,6 +372,7 @@ plot_dynamic_mixture_versions <- function(df_data, sit, title = NULL) { ) } } + title <- make_multiline_title(title) p <- p + ggplot2::ggtitle(title) + ggplot2::labs( diff --git a/man/specific_dynamic_plots.Rd b/man/specific_dynamic_plots.Rd index d2134509..28b1ea99 100644 --- a/man/specific_dynamic_plots.Rd +++ b/man/specific_dynamic_plots.Rd @@ -2,32 +2,50 @@ % Please edit documentation in R/specific_plotting_dynamic.R \name{specific_dynamic_plots} \alias{specific_dynamic_plots} +\alias{add_vertical_lines} +\alias{make_multiline_title} \alias{plot_dynamic} \title{Specific functions to generate dynamic plots} \usage{ +add_vertical_lines(df_data, successive, p) + +make_multiline_title(title, max_char = 120) + plot_dynamic(df_data, sit, successive, title = NULL) } \arguments{ \item{df_data}{A named list of data frame including the data to plot (one df per situation)} -\item{sit}{The name of the situation to plot} - \item{successive}{A list of lists containing the situations to be represented as a contiguous sequence} -\item{title}{The plot title (optional, NULL by default)} +\item{p}{A ggplot to modify`} + +\item{title}{A character string representing the title to be split into multiple lines.} + +\item{max_char}{An integer specifying the maximum number of characters per line. Default is 80} + +\item{sit}{The name of the situation to plot} } \value{ A ggplot object A list of ggplot objects + +A ggplot object with vertical lines added if successive situations are provided. + +A character string with newline characters inserted to create a multiline title. } \description{ Generate dynamic plots for the different cases handled in CroPlotR (plant mixture, plot several simulation results on same graph, ...) as specified by the different arguments. + +Add vertical lines between situations in case of successive situations. + +Make a multiline title for a ggplot object, splitting the title into multiple lines (for successive situations only) if it exceeds a certain character limit. } \details{ List of the different specific functions: From 96690886f2142d14c767166fa002301cd15badcf Mon Sep 17 00:00:00 2001 From: sbuis Date: Fri, 19 Jun 2026 15:14:17 +0000 Subject: [PATCH 2/2] Style code (GHA) --- R/specific_plotting_dynamic.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/R/specific_plotting_dynamic.R b/R/specific_plotting_dynamic.R index 65f24822..0599efcc 100644 --- a/R/specific_plotting_dynamic.R +++ b/R/specific_plotting_dynamic.R @@ -71,7 +71,6 @@ add_vertical_lines <- function(df_data, successive, p) { #' @param max_char An integer specifying the maximum number of characters per line. Default is 80 #' @return A character string with newline characters inserted to create a multiline title. make_multiline_title <- function(title, max_char = 120) { - labels <- strsplit(title, " \\| ")[[1]] lines <- character() @@ -79,7 +78,6 @@ make_multiline_title <- function(title, max_char = 120) { if (length(labels) > 1) { for (lab in labels[-1]) { - candidate <- paste(current, lab, sep = " | ") if (nchar(candidate) <= max_char) {