From 22cc3ac7875ca779487c0ab3f3f119c1446f1309 Mon Sep 17 00:00:00 2001 From: ARIADNA BATALLA FERRES Date: Wed, 25 Jun 2025 12:24:36 +0200 Subject: [PATCH 1/4] Update ColorBarContinuous.R to match esviz version --- .../Visualization/R/tmp/ColorBarContinuous.R | 197 ++++++++++-------- 1 file changed, 112 insertions(+), 85 deletions(-) diff --git a/modules/Visualization/R/tmp/ColorBarContinuous.R b/modules/Visualization/R/tmp/ColorBarContinuous.R index b7727ba0..ccbb634a 100644 --- a/modules/Visualization/R/tmp/ColorBarContinuous.R +++ b/modules/Visualization/R/tmp/ColorBarContinuous.R @@ -45,7 +45,7 @@ #' colorbar. Takes by default an approximation of a value that yields a #' readable tick arrangement (extreme breaks always ticked). If set to 0 or #' lower, no labels are drawn. See the code of the function for details or -#' use 'extra_labels' for customized tick arrangements. +#' use 'bar_extra_labels' for customized tick arrangements. #'@param bar_limits Vector of two numeric values with the extremes of the #' range of values represented in the colour bar. If 'var_limits' go beyond #' this interval, the drawing of triangle extremes is triggered at the @@ -82,7 +82,7 @@ #' parameter is set by default to ClimPalette(). #'@param plot Logical value indicating whether to only compute its breaks and #' colours (FALSE) or to also draw it on the current device (TRUE). -#'@param draw_ticks Whether to draw ticks for the labels along the colour bar +#'@param draw_bar_ticks Whether to draw ticks for the labels along the colour bar #' (TRUE) or not (FALSE). TRUE by default. Disregarded if 'plot = FALSE'. #'@param draw_separators Whether to draw black lines in the borders of each of #' the colour rectancles of the colour bar (TRUE) or not (FALSE). FALSE by @@ -91,24 +91,29 @@ #' colour bar, if drawn at all. Takes 1 by default (rectangle triangle #' proportional to the thickness of the colour bar). Disregarded if #' 'plot = FALSE'. -#'@param extra_labels Numeric vector of extra labels to draw along axis of +#'@param bar_extra_labels Numeric vector of extra labels to draw along axis of #' the colour bar. The number of provided decimals will be conserved. #' Disregarded if 'plot = FALSE'. +#'@param extra_labels Deprecated. Use 'bar_extra_labels' instead. #'@param title Title to draw on top of the colour bar, most commonly with the #' units of the represented field in the neighbour figures. Empty by default. #'@param title_scale Scale factor for the 'title' of the colour bar. #' Takes 1 by default. -#'@param label_scale Scale factor for the labels of the colour bar. +#'@param bar_label_scale Scale factor for the labels of the colour bar. #' Takes 1 by default. -#'@param tick_scale Scale factor for the length of the ticks of the labels +#'@param label_scale Deprecated. Use 'bar_label_scale' instead. +#'@param bar_tick_scale Scale factor for the length of the ticks of the labels #' along the colour bar. Takes 1 by default. -#'@param extra_margin Extra margins to be added around the colour bar, +#'@param tick_scale Deprecated. Use 'bar_tick_scale' instead. +#'@param bar_extra_margin Extra margins to be added around the colour bar, #' in the format c(y1, x1, y2, x2). The units are margin lines. Takes #' rep(0, 4) by default. -#'@param label_digits Number of significant digits to be displayed in the +#'@param extra_margin Deprecated. Use 'bar_extra_margin' instead. +#'@param bar_label_digits Number of significant digits to be displayed in the #' labels of the colour bar, usually to avoid too many decimal digits #' overflowing the figure region. This does not have effect over the labels -#' provided in 'extra_labels'. Takes 4 by default. +#' provided in 'bar_extra_labels'. Takes 4 by default. +#'@param label_digits Deprecated. Use 'bar_label_digits' instead. #'@param ... Arguments to be passed to the method. Only accepts the following #' graphical parameters:\cr adj ann ask bg bty cex.lab cex.main cex.sub cin #' col.axis col.lab col.main col.sub cra crt csi cxy err family fg fig fin @@ -144,20 +149,22 @@ #'@import utils #'@export ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, - subsampleg = NULL, bar_limits = NULL, var_limits = NULL, - triangle_ends = NULL, col_inf = NULL, col_sup = NULL, - color_fun = ClimPalette(), plot = TRUE, - draw_ticks = TRUE, draw_separators = FALSE, - triangle_ends_scale = 1, extra_labels = NULL, - title = NULL, title_scale = 1, - label_scale = 1, tick_scale = 1, - extra_margin = rep(0, 4), label_digits = 4, ...) { + subsampleg = NULL, bar_limits = NULL, var_limits = NULL, + triangle_ends = NULL, col_inf = NULL, col_sup = NULL, + color_fun = ClimPalette(), plot = TRUE, + draw_bar_ticks = TRUE, draw_separators = FALSE, + triangle_ends_scale = 1, bar_extra_labels = NULL, + extra_labels = NULL, title = NULL, title_scale = 1, + bar_label_scale = 1, label_scale = NULL, + bar_tick_scale = 1, tick_scale = NULL, + bar_extra_margin = rep(0, 4), extra_margin = NULL, + bar_label_digits = 4, label_digits = NULL, ...) { # Required checks if ((is.null(brks) || length(brks) < 2) && is.null(bar_limits) && is.null(var_limits)) { stop("At least one of 'brks' with the desired breaks, 'bar_limits' or ", "'var_limits' must be provided to generate the colour bar.") } - + # Check brks if (!is.null(brks)) { if (!is.numeric(brks)) { @@ -170,14 +177,14 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, brks <- reorder$x } } - + # Check bar_limits if (!is.null(bar_limits)) { if (!(all(is.na(bar_limits) | is.numeric(bar_limits)) && (length(bar_limits) == 2))) { stop("Parameter 'bar_limits' must be a vector of two numeric elements or NAs.") } } - + # Check var_limits if (!is.null(var_limits)) { if (!(is.numeric(var_limits) && (length(var_limits) == 2))) { @@ -188,7 +195,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, stop("Parameter 'var_limits' must not contain infinite values.") } } - + # Check cols if (!is.null(cols)) { if (!is.character(cols)) { @@ -197,12 +204,12 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, stop("Parameter 'cols' must contain valid colour identifiers.") } } - + # Check color_fun if (!is.function(color_fun)) { stop("Parameter 'color_fun' must be a colour-generator function.") } - + # Check integrity among brks, bar_limits and var_limits if (is.null(brks) || (length(brks) < 2)) { if (is.null(brks)) { @@ -249,21 +256,21 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, stop("Parameters 'brks' and 'bar_limits' are inconsistent.") } } - + # Check col_inf if (!is.null(col_inf)) { if (!.IsColor(col_inf)) { stop("Parameter 'col_inf' must be a valid colour identifier.") } } - + # Check col_sup if (!is.null(col_sup)) { if (!.IsColor(col_sup)) { stop("Parameter 'col_sup' must be a valid colour identifier.") } } - + # Check triangle_ends if (!is.null(triangle_ends) && (!is.logical(triangle_ends) || length(triangle_ends) != 2)) { stop("Parameter 'triangle_ends' must be a logical vector with two elements.") @@ -293,16 +300,16 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, if (plot && !is.null(var_limits)) { if ((bar_limits[1] > var_limits[1]) && !triangle_ends[1]) { warning("There are variable values smaller than the lower limit ", - "of the colour bar and the lower triangle end has been ", - "disabled. These will be painted in the colour for NA values.") + "of the colour bar and the lower triangle end has been ", + "disabled. These will be painted in the colour for NA values.") } if ((bar_limits[2] < var_limits[2]) && !triangle_ends[2]) { warning("There are variable values greater than the higher limit ", - "of the colour bar and the higher triangle end has been ", - "disabled. These will be painted in the colour for NA values.") + "of the colour bar and the higher triangle end has been ", + "disabled. These will be painted in the colour for NA values.") } } - + # Generate colours if needed if (is.null(cols)) { cols <- color_fun(length(brks) - 1 + sum(triangle_ends)) @@ -319,25 +326,29 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, } else if ((length(cols) != (length(brks) - 1))) { stop("Incorrect number of 'brks' and 'cols'. There must be one more break than the number of colours.") } - + # Check vertical if (!is.logical(vertical)) { stop("Parameter 'vertical' must be TRUE or FALSE.") } - - # Check extra_labels - if (is.null(extra_labels)) { - extra_labels <- numeric(0) + + # Check bar_extra_labels + if (missing(bar_extra_labels) && !missing(extra_labels)) { + warning("The parameter 'extra_labels' is deprecated. Use 'bar_extra_labels' instead.") + bar_extra_labels <- extra_labels } - if (!is.numeric(extra_labels)) { - stop("Parameter 'extra_labels' must be numeric.") + if (is.null(bar_extra_labels)) { + bar_extra_labels <- numeric(0) + } + if (!is.numeric(bar_extra_labels)) { + stop("Parameter 'bar_extra_labels' must be numeric.") } else { - if (any(extra_labels > bar_limits[2]) || any(extra_labels < bar_limits[1])) { - stop("Parameter 'extra_labels' must not contain ticks beyond the color bar limits.") + if (any(bar_extra_labels > bar_limits[2]) || any(bar_extra_labels < bar_limits[1])) { + stop("Parameter 'bar_extra_labels' must not contain ticks beyond the color bar limits.") } } - extra_labels <- sort(extra_labels) - + bar_extra_labels <- sort(bar_extra_labels) + # Check subsampleg primes <- function(x) { # Courtesy of Chase. See http://stackoverflow.com/questions/6424856/r-function-for-returning-all-factors @@ -358,7 +369,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, } if (subsampleg > (length(brks) - 1) / 4) { subsampleg <- max(1, round(length(brks) / 4)) - extra_labels <- c(extra_labels, bar_limits[2]) + bar_extra_labels <- c(bar_extra_labels, bar_limits[2]) added_final_tick <- TRUE if ((length(brks) - 1) %% subsampleg < (length(brks) - 1) / 4 / 2) { remove_final_tick <- TRUE @@ -372,27 +383,27 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, if ((subsampleg) < 1) { draw_labels <- FALSE } - + # Check plot if (!is.logical(plot)) { stop("Parameter 'plot' must be logical.") } - + # Check draw_separators if (!is.logical(draw_separators)) { stop("Parameter 'draw_separators' must be logical.") } - + # Check triangle_ends_scale if (!is.numeric(triangle_ends_scale)) { stop("Parameter 'triangle_ends_scale' must be numeric.") } - - # Check draw_ticks - if (!is.logical(draw_ticks)) { - stop("Parameter 'draw_ticks' must be logical.") + + # Check draw_bar_ticks + if (!is.logical(draw_bar_ticks)) { + stop("Parameter 'draw_bar_ticks' must be logical.") } - + # Check title if (is.null(title)) { title <- '' @@ -400,38 +411,54 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, if (!is.character(title)) { stop("Parameter 'title' must be a character string.") } - + # Check title_scale if (!is.numeric(title_scale)) { stop("Parameter 'title_scale' must be numeric.") } - - # Check label_scale - if (!is.numeric(label_scale)) { - stop("Parameter 'label_scale' must be numeric.") + + # Check bar_label_scale + if (missing(bar_label_scale) && !missing(label_scale)) { + warning("The parameter 'label_scale' is deprecated. Use 'bar_label_scale' instead.") + bar_label_scale <- label_scale + } + if (!is.numeric(bar_label_scale)) { + stop("Parameter 'bar_label_scale' must be numeric.") + } + + # Check bar_tick_scale + if (missing(bar_tick_scale) && !missing(tick_scale)) { + warning("The parameter 'tick_scale' is deprecated. Use 'bar_tick_scale' instead.") + bar_tick_scale <- tick_scale + } + if (!is.numeric(bar_tick_scale)) { + stop("Parameter 'bar_tick_scale' must be numeric.") + } + + # Check bar_extra_margin + if (missing(bar_extra_margin) && !missing(extra_margin)) { + warning("The parameter 'extra_margin' is deprecated. Use 'bar_extra_margin' instead.") + bar_extra_margin <- extra_margin } - - # Check tick_scale - if (!is.numeric(tick_scale)) { - stop("Parameter 'tick_scale' must be numeric.") + if (!is.numeric(bar_extra_margin) || length(bar_extra_margin) != 4) { + stop("Parameter 'bar_extra_margin' must be a numeric vector of length 4.") } - - # Check extra_margin - if (!is.numeric(extra_margin) || length(extra_margin) != 4) { - stop("Parameter 'extra_margin' must be a numeric vector of length 4.") + + # Check bar_label_digits + if (missing(bar_label_digits) && !missing(label_digits)) { + warning("The parameter 'label_digits' is deprecated. Use 'bar_label_digits' instead.") + bar_label_digits <- label_digits } - - # Check label_digits - if (!is.numeric(label_digits)) { - stop("Parameter 'label_digits' must be numeric.") + if (!is.numeric(bar_label_digits)) { + stop("Parameter 'bar_label_digits' must be numeric.") } - label_digits <- round(label_digits) - + bar_label_digits <- round(bar_label_digits) + # Process the user graphical parameters that may be passed in the call ## Graphical parameters to exclude excludedArgs <- c("cex", "cex.axis", "col", "lab", "las", "mar", "mgp", "new", "ps") userArgs <- .FilterUserGraphicArgs(excludedArgs, ...) - + # # Plotting colorbar # ~~~~~~~~~~~~~~~~~~~ @@ -448,29 +475,29 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, if (vertical) { figure_size <- rev(figure_size) } -# pannel_to_redraw <- par('mfg') -# .SwitchToFigure(pannel_to_redraw[1], pannel_to_redraw[2]) + # pannel_to_redraw <- par('mfg') + # .SwitchToFigure(pannel_to_redraw[1], pannel_to_redraw[2]) # Load the user parameters par(new = TRUE) par(userArgs) # Set up color bar plot region margins <- c(0.0, 0, 0.0, 0) cex_title <- 1 * title_scale - cex_labels <- 0.9 * label_scale - cex_ticks <- -0.3 * tick_scale + cex_labels <- 0.9 * bar_label_scale + cex_ticks <- -0.3 * bar_tick_scale spaceticklab <- max(-cex_ticks, 0) if (vertical) { margins[1] <- margins[1] + (1.2 * cex_labels * 3 + spaceticklab) * cs - margins <- margins + extra_margin[c(4, 1:3)] * cs + margins <- margins + bar_extra_margin[c(4, 1:3)] * cs } else { margins[1] <- margins[1] + (1.2 * cex_labels * 1 + spaceticklab) * cs - margins <- margins + extra_margin * cs + margins <- margins + bar_extra_margin * cs } if (title != '') { margins[3] <- margins[3] + (1.0 * cex_title) * cs } margins[3] <- margins[3] + sqrt(figure_size[2] / (margins[1] + margins[3])) * - figure_size[2] / 6 * ifelse(title != '', 0.5, 0.8) + figure_size[2] / 6 * ifelse(title != '', 0.5, 0.8) # Set side margins margins[2] <- margins[2] + figure_size[1] / 16 margins[4] <- margins[4] + figure_size[1] / 16 @@ -511,7 +538,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, # try and error par(mai = margins, mgp = c(0, cex_labels / 2 + spaceticklab - - cex_labels / 4 * (3 / cex_labels - 1), 0), + - cex_labels / 4 * (3 / cex_labels - 1), 0), las = 1) d <- 1 image(1:ncols, 1, t(t(1:ncols)), axes = FALSE, col = cols, @@ -535,7 +562,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, lines(right_triangle$x, right_triangle$y) } par(xpd = FALSE) - + # Put the separators if (vertical) { if (draw_separators) { @@ -565,7 +592,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, # Put the ticks plot_range <- length(brks) - 1 var_range <- tail(brks, 1) - head(brks, 1) - extra_labels_at <- ((extra_labels - head(brks, 1)) / var_range) * plot_range + 0.5 + bar_extra_labels_at <- ((bar_extra_labels - head(brks, 1)) / var_range) * plot_range + 0.5 at <- seq(1, length(brks), subsampleg) labels <- brks[at] # Getting rid of next-to-last tick if too close to last one @@ -573,13 +600,13 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, at <- at[-length(at)] labels <- labels[-length(labels)] } - labels <- signif(labels, label_digits) + labels <- signif(labels, bar_label_digits) if (added_final_tick) { - extra_labels[length(extra_labels)] <- signif(tail(extra_labels, 1), label_digits) + bar_extra_labels[length(bar_extra_labels)] <- signif(tail(bar_extra_labels, 1), bar_label_digits) } at <- at - 0.5 - at <- c(at, extra_labels_at) - labels <- c(labels, extra_labels) + at <- c(at, bar_extra_labels_at) + labels <- c(labels, bar_extra_labels) tick_reorder <- sort(at, index.return = TRUE) at <- tick_reorder$x if (draw_labels) { @@ -587,7 +614,7 @@ ColorBarContinuous <- function(brks = NULL, cols = NULL, vertical = TRUE, } else { labels <- FALSE } - axis(d, at = at, tick = draw_ticks, labels = labels, cex.axis = cex_labels, tcl = cex_ticks) + axis(d, at = at, tick = draw_bar_ticks, labels = labels, cex.axis = cex_labels, tcl = cex_ticks) par(saved_pars) } invisible(list(brks = brks, cols = cols, col_inf = col_inf, col_sup = col_sup)) -- GitLab From aa4dc5ec3d2f3f08d37e070e3b8f1fed90f3a4b2 Mon Sep 17 00:00:00 2001 From: ARIADNA BATALLA FERRES Date: Wed, 25 Jun 2025 12:25:30 +0200 Subject: [PATCH 2/4] Update VizEquiMap.R to match esviz version --- modules/Visualization/R/tmp/VizEquiMap.R | 261 ++++++++++++----------- 1 file changed, 135 insertions(+), 126 deletions(-) diff --git a/modules/Visualization/R/tmp/VizEquiMap.R b/modules/Visualization/R/tmp/VizEquiMap.R index 6fef1036..f3855901 100644 --- a/modules/Visualization/R/tmp/VizEquiMap.R +++ b/modules/Visualization/R/tmp/VizEquiMap.R @@ -10,7 +10,7 @@ #'include continents, oceans, and lakes. This plot function is compatible with #'figure layouts if colour bar is disabled. #' -#'@param var Array with the values at each cell of a grid on a regular +#'@param data Array with the values at each cell of a grid on a regular #' rectangular or gaussian grid. The array is expected to have two #' dimensions: c(latitude, longitude). Longitudes can be in ascending or #' descending order and latitudes in any order. It can contain NA values @@ -19,20 +19,21 @@ #' this alternative is not appropriate for square arrays. It is allowed that #' the positions of the longitudinal and latitudinal coordinate dimensions #' are interchanged. +#'@param var Deprecated. Use 'data' instead. #'@param lon Numeric vector of longitude locations of the cell centers of the -#' grid of 'var', in ascending or descending order (same as 'var'). Expected +#' grid of 'data', in ascending or descending order (same as 'data'). Expected #' to be regularly spaced, within either of the ranges [-180, 180] or #' [0, 360]. Data for two adjacent regions split by the limits of the #' longitude range can also be provided, e.g. \code{lon = c(0:50, 300:360)} -#' ('var' must be provided consitently). +#' ('data' must be provided consitently). #'@param lat Numeric vector of latitude locations of the cell centers of the -#' grid of 'var', in any order (same as 'var'). Expected to be from a regular +#' grid of 'data', in any order (same as 'data'). Expected to be from a regular #' rectangular or gaussian grid, within the range [-90, 90]. #'@param varu Array of the zonal component of wind/current/other field with -#' the same dimensions as 'var'. It is allowed that the positions of the +#' the same dimensions as 'data'. It is allowed that the positions of the #' longitudinal and latitudinal coordinate dimensions are interchanged. #'@param varv Array of the meridional component of wind/current/other field -#' with the same dimensions as 'var'. It is allowed that the positions of the +#' with the same dimensions as 'data'. It is allowed that the positions of the #' longitudinal and latitudinal coordinate dimensions are interchanged. #'@param toptitle Top title of the figure, scalable with parameter #' 'title_scale'. @@ -43,18 +44,18 @@ #' manipulation functions like \code{paste()} or \code{paste0()}, using #' \code{"\n"} to indicate line breaks. #'@param units Title at the top of the colour bar, most commonly the units of -#' the variable provided in parameter 'var'. +#' the variable provided in parameter 'data'. #'@param brks,cols,bar_limits,triangle_ends Usually only providing 'brks' is #' enough to generate the desired colour bar. These parameters allow to #' define n breaks that define n - 1 intervals to classify each of the values -#' in 'var'. The corresponding grid cell of a given value in 'var' will be +#' in 'data'. The corresponding grid cell of a given value in 'data' will be #' coloured in function of the interval it belongs to. These parameters are #' sent to \code{ColorBar()} to generate the breaks and colours. Additional #' colours for values beyond the limits of the colour bar are also generated #' and applied to the plot if 'bar_limits' or 'brks' and 'triangle_ends' are #' properly provided to do so. See ?ColorBar for a full explanation. #'@param col_inf,col_sup,colNA Colour identifiers to colour the values in -#' 'var' that go beyond the extremes of the colour bar and to colour NA +#' 'data' that go beyond the extremes of the colour bar and to colour NA #' values, respectively. 'colNA' takes attr(cols, 'na_color') if available by #' default, where cols is the parameter 'cols' if provided or the vector of #' colors returned by 'color_fun'. If not available, it takes 'pink' by @@ -70,7 +71,7 @@ #' parameters to control the visual aspect of the drawn colour bar (3/3). #' See ?ColorBar for a full explanation. #'@param square Logical value to choose either to draw a coloured square for -#' each grid cell in 'var' (TRUE; default) or to draw contour lines and fill +#' each grid cell in 'data' (TRUE; default) or to draw contour lines and fill #' the spaces in between with colours (FALSE). In the latter case, #' 'filled.continents' will take the value FALSE if not specified. #'@param filled.continents Colour to fill in drawn projected continents. @@ -94,7 +95,7 @@ #' location of the shape. The default value is NULL. #'@param shapefile_color Line color of the shapefile. #'@param shapefile_lwd Line width of the shapefile. The default value is 1. -#'@param contours Array of same dimensions as 'var' to be added to the plot +#'@param contours Array of same dimensions as 'data' to be added to the plot #' and displayed with contours. Parameter 'brks2' is required to define the #' magnitude breaks for each contour curve. Disregarded if 'square = FALSE'. #' It is allowed that the positions of the longitudinal and latitudinal @@ -111,8 +112,8 @@ #' contour labels or not. The default value is TRUE. #'@param contour_label_scale Scale factor for the superimposed labels when #' drawing contour levels. -#'@param dots Array of same dimensions as 'var' or with dimensions -#' c(n, dim(var)), where n is the number of dot/symbol layers to add to the +#'@param dots Array of same dimensions as 'data' or with dimensions +#' c(n, dim(data)), where n is the number of dot/symbol layers to add to the #' plot. A value of TRUE at a grid cell will draw a dot/symbol on the #' corresponding square of the plot. By default all layers provided in 'dots' #' are plotted with dots, but a symbol can be specified for each of the @@ -126,7 +127,7 @@ #'@param dot_size Scale factor for the dots/symbols to be plotted, specified #' in 'dots'. If a single value is specified, it will be applied to all #' layers in 'dots'. Takes 1 by default. -#'@param mask An array with the same dimensions as 'var' of [0, 1] or logical +#'@param mask An array with the same dimensions as 'data' of [0, 1] or logical #' indicating the grids to not plot data. The value 0 or FALSE is the point not #' to be plotted. #'@param mask_color Color of the mask. The default value is 'white'. @@ -184,6 +185,31 @@ #'@param vertical TRUE/FALSE for vertical/horizontal colour bar. Default is #' FALSE. Parameters 'width' and 'height' might need to be modified to #' accommodate the vertical colour bar. +#'@param include_lower_boundary Logical value indicating whether to include +#' the minimum value of the field. Takes TRUE by default. +#'@param include_upper_boundary Logical value indicating whether to include +#' the maximum value of the field. Takes TRUE by default. +#'@param hatching_mask Logical or binary (0/1) array with two named dimensions: +#' c(latitude, longitude). Hatching is applied to grid cells where +#' 'hatching_mask' is TRUE (or 1). Arrays with dimensions c(longitude, latitude) +#' are also accepted, but the resulting hatching may appear transposed. To +#' ensure correct alignment with the map, provide 'data'. The function will +#' compare the dimension order of 'hatching_mask' and 'data', and automatically +#' transpose 'hatching_mask' if the latitude and longitude dimensions appear to +#' be reversed. +#'@param hatching_density The density of shading lines, in lines per inch. A +#' zero value of density means no shading nor filling, whereas negative values +#' and NA suppress shading (and so allow color filling). NULL means that no +#' shading lines are drawn. Default is 10. +#'@param hatching_angle The slope of shading lines, given as an angle in degrees +#' (counter-clockwise). Default is 45. +#'@param hatching_color Color of the hatching lines. Default is +#' \code{"#252525"}. +#'@param hatching_lwd The line width, a positive number. The interpretation is +#' device-specific, and some devices do not implement line widths less than +#' one. Default is 0.5. +#'@param hatching_cross A logical value indicating crosshatching. If TRUE, adds +#' a second set of lines in the opposite angle. Default is FALSE. #'@param boxlim Limits of a box to be added to the plot, in degrees: #' c(x1, y1, x2, y2). A list with multiple box specifications can also be #' provided. @@ -203,40 +229,15 @@ #'@param fileout File where to save the plot. If not specified (default) a #' graphics device will pop up. Extensions allowed: eps/ps, jpeg, png, pdf, #' bmp and tiff. -#'@param width File width, in the units specified in the parameter size_units +#'@param width File width, in the units specified in the parameter 'size_units' #' (inches by default). Takes 8 by default. #'@param height File height, in the units specified in the parameter -#' size_units (inches by default). Takes 5 by default. +#' 'size_units' (inches by default). Takes 5 by default. #'@param size_units Units of the size of the device (file or window) to plot #' in. Inches ('in') by default. See ?Devices and the creator function of #' the corresponding device. #'@param res Resolution of the device (file or window) to plot in. See #' ?Devices and the creator function of the corresponding device. -#'@param include_lower_boundary Logical value indicating whether to include -#' the minimum value of the field. Takes TRUE by default. -#'@param include_upper_boundary Logical value indicating whether to include -#' the maximum value of the field. Takes TRUE by default. -#'@param hatching_mask Logical or binary (0/1) array with two named dimensions: -#' c(latitude, longitude). Hatching is applied to grid cells where -#' 'hatching_mask' is TRUE (or 1). Arrays with dimensions c(longitude, latitude) -#' are also accepted, but the resulting hatching may appear transposed. To -#' ensure correct alignment with the map, provide 'data'. The function will -#' compare the dimension order of 'hatching_mask' and 'data', and automatically -#' transpose 'hatching_mask' if the latitude and longitude dimensions appear to -#' be reversed. -#'@param hatching_density The density of shading lines, in lines per inch. A -#' zero value of density means no shading nor filling, whereas negative values -#' and NA suppress shading (and so allow color filling). NULL means that no -#' shading lines are drawn. Default is 10. -#'@param hatching_angle The slope of shading lines, given as an angle in degrees -#' (counter-clockwise). Default is 45. -#'@param hatching_color Color of the hatching lines. Default is -#' \code{"#252525"}. -#'@param hatching_lwd The line width, a positive number. The interpretation is -#' device-specific, and some devices do not implement line widths less than -#' one. Default is 0.5. -#'@param hatching_cross A logical value indicating crosshatching. If TRUE, adds -#' a second set of lines in the opposite angle. Default is FALSE. #'@param \dots Arguments to be passed to the method. Only accepts the following #' graphical parameters:\cr #' adj ann ask bg bty cex.sub cin col.axis col.lab col.main col.sub cra crt @@ -266,11 +267,11 @@ #' \dontrun{ #'ano <- s2dv::Ano_CrossValid(map_temp$exp, map_temp$obs, memb = FALSE, #' dat_dim = c('dat', 'member'), memb_dim = 'member') -#'var <- s2dv::MeanDims(ano$exp, "member") +#'data <- s2dv::MeanDims(ano$exp, "member") #'lats <- attr(map_temp$exp, "Variables")$common$lat #'lons <- attr(map_temp$exp, "Variables")$common$lon #' -#'VizEquiMap(var[1, 1, 1, 1, , ], lon = lons, lat = lats, +#'VizEquiMap(data[1, 1, 1, 1, , ], lon = lons, lat = lats, #' toptitle = 'Near-surface temperature anomaly, Nov. 2000', #' filled.continents = FALSE, title_scale = 0.7, #' caption = paste0("This is a test caption.", "\n", @@ -279,9 +280,9 @@ #'@import graphics maps utils #'@importFrom grDevices dev.cur dev.new dev.off gray #'@importFrom stats cor -#' @importFrom s2dv InsertDim +#'@importFrom s2dv InsertDim #'@export -VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, +VizEquiMap <- function(data, lon, lat, varu = NULL, varv = NULL, toptitle = NULL, sizetit = NULL, caption = NULL, units = NULL, brks = NULL, cols = NULL, bar_limits = NULL, triangle_ends = NULL, col_inf = NULL, col_sup = NULL, @@ -308,16 +309,17 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, draw_separators = FALSE, triangle_ends_scale = 1, bar_label_digits = 4, bar_label_scale = 1, units_scale = 1, bar_tick_scale = 1, - bar_extra_margin = rep(0, 4), + bar_extra_margin = rep(0, 4), + include_lower_boundary = TRUE, + include_upper_boundary = TRUE, hatching_mask = NULL, + hatching_density = 10, hatching_angle = 45, + hatching_color = "#252525", hatching_lwd = 0.5, + hatching_cross = FALSE, boxlim = NULL, boxcol = 'purple2', boxlwd = 5, margin_scale = rep(1, 4), title_scale = 1, caption_size = 0.8, numbfig = NULL, fileout = NULL, width = 8, height = 5, size_units = 'in', - res = 100, include_lower_boundary = TRUE, - include_upper_boundary = TRUE, hatching_mask = NULL, - hatching_density = 10, hatching_angle = 45, - hatching_color = "#252525", hatching_lwd = 0.5, - hatching_cross = FALSE, ...) { + res = 100, var = NULL, ...) { # Process the user graphical parameters that may be passed in the call ## Graphical parameters to exclude excludedArgs <- c("cex", "cex.axis", "cex.lab", "cex.main", "col", "din", "fig", "fin", "lab", "las", "lty", "lwd", "mai", "mar", "mgp", "new", "oma", "ps", "tck") @@ -336,59 +338,66 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, stop("Parameters 'lon' and 'lat' must be numeric vectors.") } - # Check var - if (is.null(var)) { - stop("Parameter 'var' cannot be NULL.") + # Check data + if (missing(data) || is.null(data)) { + if (!is.null(var)) { + data <- var + warning("The parameter 'var' is deprecated. Use 'data' instead.") + } else { + stop("Parameter 'data' cannot be NULL.") + } + } else if (!is.null(var)) { + warning("The parameter 'var' is deprecated. 'data' will be used instead.") } - if (!is.array(var)) { - stop("Parameter 'var' must be a numeric array.") + if (!is.array(data)) { + stop("Parameter 'data' must be a numeric array.") } transpose <- FALSE - if (!is.null(names(dim(var)))) { - if (any(names(dim(var)) %in% .KnownLonNames()) && - any(names(dim(var)) %in% .KnownLatNames())) { - lon_dim <- names(dim(var))[names(dim(var)) %in% .KnownLonNames()] - lat_dim <- names(dim(var))[names(dim(var)) %in% .KnownLatNames()] + if (!is.null(names(dim(data)))) { + if (any(names(dim(data)) %in% .KnownLonNames()) && + any(names(dim(data)) %in% .KnownLatNames())) { + lon_dim <- names(dim(data))[names(dim(data)) %in% .KnownLonNames()] + lat_dim <- names(dim(data))[names(dim(data)) %in% .KnownLatNames()] } else { - names(dim(var)) <- NULL + names(dim(data)) <- NULL lat_dim <- NULL lon_dim <- NULL - warning("Dimension names of 'var' doesn't correspond to any coordinates names supported by s2dv package.") + warning("Dimension names of 'data' doesn't correspond to any coordinates names supported by s2dv package.") } } else { lon_dim <- NULL lat_dim <- NULL - warning("Parameter 'var' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the corresponding coordinates dimensions.") + warning("Parameter 'data' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the corresponding coordinates dimensions.") } - if (length(dim(var)) > 2) { + if (length(dim(data)) > 2) { if (!is.null(lon_dim) & !is.null(lat_dim)) { - dimnames <- names(dim(var)) - dim(var) <- dim(var)[which((dimnames == lon_dim | dimnames == lat_dim | dim(var) != 1))] + dimnames <- names(dim(data)) + dim(data) <- dim(data)[which((dimnames == lon_dim | dimnames == lat_dim | dim(data) != 1))] } else { - if (all(dim(var) == 1)) { - dim(var) <- c(1, 1) - } else if (length(dim(var)[which(dim(var) > 1)]) == 2) { - var <- drop(var) - } else if (length(dim(var)[which(dim(var) > 1)]) == 1) { - dim(var) <- c(dim(var)[which(dim(var) > 1)], 1) + if (all(dim(data) == 1)) { + dim(data) <- c(1, 1) + } else if (length(dim(data)[which(dim(data) > 1)]) == 2) { + data <- drop(data) + } else if (length(dim(data)[which(dim(data) > 1)]) == 1) { + dim(data) <- c(dim(data)[which(dim(data) > 1)], 1) } } } - if (length(dim(var)) != 2) { - stop("Parameter 'var' must be a numeric array with two dimensions.") + if (length(dim(data)) != 2) { + stop("Parameter 'data' must be a numeric array with two dimensions.") } - if ((dim(var)[1] == length(lon) && dim(var)[2] == length(lat)) || - (dim(var)[2] == length(lon) && dim(var)[1] == length(lat))) { - if (dim(var)[2] == length(lon) && dim(var)[1] == length(lat)) { + if ((dim(data)[1] == length(lon) && dim(data)[2] == length(lat)) || + (dim(data)[2] == length(lon) && dim(data)[1] == length(lat))) { + if (dim(data)[2] == length(lon) && dim(data)[1] == length(lat)) { if (length(lon) == length(lat)) { - if (is.null(names(dim(var)))) { - warning("Parameter 'var' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the first and second dimensions.") + if (is.null(names(dim(data)))) { + warning("Parameter 'data' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the first and second dimensions.") } else { - if (names(dim(var)[1]) == lat_dim) { + if (names(dim(data)[1]) == lat_dim) { transpose <- TRUE } } @@ -397,17 +406,17 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } } } else { - stop("Parameters 'lon' and 'lat' must have as many elements as the number of cells along longitudes and latitudes in the input array 'var'.") + stop("Parameters 'lon' and 'lat' must have as many elements as the number of cells along longitudes and latitudes in the input array 'data'.") } - if (!is.null(names(dim(var)))) { - if (names(dim(var)[1]) == lon_dim) { + if (!is.null(names(dim(data)))) { + if (names(dim(data)[1]) == lon_dim) { if (transpose) { - stop("Coordinates dimensions of 'var' doesn't correspond to lat or lon.") + stop("Coordinates dimensions of 'data' doesn't correspond to lat or lon.") } - } else if (names(dim(var)[2]) == lon_dim) { + } else if (names(dim(data)[2]) == lon_dim) { if (!transpose) { - stop("Coordinates dimensions of 'var' doesn't correspond to lat or lon.") + stop("Coordinates dimensions of 'data' doesn't correspond to lat or lon.") } } } @@ -416,13 +425,13 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, # with dimensions c(lon, lat). if (transpose) { - var <- t(var) + data <- t(data) } transpose <- FALSE - names(dim(var)) <- c(lon_dim, lat_dim) - dims <- dim(var) + names(dim(data)) <- c(lon_dim, lat_dim) + dims <- dim(data) # Check varu and varv if (!is.null(varu) && !is.null(varv)) { @@ -450,9 +459,9 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } else { if (!is.null(names(dim(varu)))) { if (!(lon_dim %in% names(dim(varu)) && lat_dim %in% names(dim(varu)))) { - stop("Parameters 'varu' and 'varv' must have same dimension names as 'var'.") - } else if (dim(varu)[lon_dim] != dim(var)[lon_dim] || dim(varu)[lat_dim] != dim(var)[lat_dim]) { - stop("Parameters 'varu' and 'varv' must have same dimensions as 'var'.") + stop("Parameters 'varu' and 'varv' must have same dimension names as 'data'.") + } else if (dim(varu)[lon_dim] != dim(data)[lon_dim] || dim(varu)[lat_dim] != dim(data)[lat_dim]) { + stop("Parameters 'varu' and 'varv' must have same dimensions as 'data'.") } } else { warning("Parameters 'varu' and 'varv' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the corresponding coordinates dimensions.") @@ -503,9 +512,9 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } else { if (!is.null(names(dim(contours)))) { if (!(lon_dim %in% names(dim(contours)) && lat_dim %in% names(dim(contours)))) { - stop("Parameters 'contours' must have same dimension names as 'var'.") - } else if (dim(contours)[lon_dim] != dim(var)[lon_dim] || dim(contours)[lat_dim] != dim(var)[lat_dim]) { - stop("Parameters 'contours' must have same dimensions as 'var'.") + stop("Parameters 'contours' must have same dimension names as 'data'.") + } else if (dim(contours)[lon_dim] != dim(data)[lon_dim] || dim(contours)[lat_dim] != dim(data)[lat_dim]) { + stop("Parameters 'contours' must have same dimensions as 'data'.") } } else { warning("Parameters 'contours' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the corresponding coordinates dimensions.") @@ -580,37 +589,37 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, stop("Parameter 'vertical' must be TRUE or FALSE.") } - tmp <- .create_var_limits(data = var, brks = brks, + tmp <- .create_var_limits(data = data, brks = brks, bar_limits = bar_limits, drawleg = drawleg) var_limits <- tmp$var_limits drawleg <- tmp$drawleg # Check: brks, cols, subsampleg, bar_limits, color_fun, bar_extra_labels, draw_bar_ticks - # draw_separators, triangle_ends_scale, label_scale, units, units_scale, + # draw_separators, triangle_ends_scale, bar_label_scale, units, units_scale, # bar_label_digits # Build: brks, cols, bar_limits, col_inf, col_sup colorbar <- ColorBarContinuous(brks, cols, vertical = vertical, subsampleg, bar_limits, var_limits, triangle_ends, col_inf, col_sup, color_fun, FALSE, - extra_labels = bar_extra_labels, draw_ticks = draw_bar_ticks, + bar_extra_labels = bar_extra_labels, draw_bar_ticks = draw_bar_ticks, draw_separators = draw_separators, triangle_ends_scale = triangle_ends_scale, - label_scale = bar_label_scale, title = units, - title_scale = units_scale, tick_scale = bar_tick_scale, - extra_margin = bar_extra_margin, label_digits = bar_label_digits) + bar_label_scale = bar_label_scale, title = units, + title_scale = units_scale, bar_tick_scale = bar_tick_scale, + bar_extra_margin = bar_extra_margin, bar_label_digits = bar_label_digits) brks <- colorbar$brks cols <- colorbar$cols col_inf <- colorbar$col_inf col_sup <- colorbar$col_sup bar_limits <- c(head(brks, 1), tail(brks, 1)) - # Adjust 'var' values according to 'include_lower_boundary' and 'include_upper_boundary'. + # Adjust 'data' values according to 'include_lower_boundary' and 'include_upper_boundary'. # This adjustment ensures that, by default, values at the lower limit of the color bars ('brks[1]') are included. # Refer to issue #15 in the esviz GitLab for more details. if (include_lower_boundary) { - var[var == head(brks, 1)] <- head(brks, 1) + head(diff(brks), 1)/10 + data[data == head(brks, 1)] <- head(brks, 1) + head(diff(brks), 1)/10 } if (!include_upper_boundary) { - var[var == tail(brks, 1)] <- tail(brks, 1) + tail(diff(brks), 1)/10 + data[data == tail(brks, 1)] <- tail(brks, 1) + tail(diff(brks), 1)/10 } # Check colNA @@ -739,7 +748,7 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, if (is.null(contours)) { if (!square) { brks2 <- brks - contours <- var + contours <- data } } else { ll <- signif(min(contours, na.rm = TRUE), 2) @@ -787,9 +796,9 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } else { if (!is.null(names(dim(dots)))) { if (!(lon_dim %in% names(dim(dots)) && lat_dim %in% names(dim(dots)))) { - stop("Parameters 'dots' must have same dimension names as 'var'.") - } else if (dim(dots)[lon_dim] != dim(var)[lon_dim] || dim(dots)[lat_dim] != dim(var)[lat_dim]) { - stop("Parameters 'dots' must have same dimensions as 'var'.") + stop("Parameters 'dots' must have same dimension names as 'data'.") + } else if (dim(dots)[lon_dim] != dim(data)[lon_dim] || dim(dots)[lat_dim] != dim(data)[lat_dim]) { + stop("Parameters 'dots' must have same dimensions as 'data'.") } } else { warning("Parameters 'dots' should have dimension names. Coordinates 'lon' and 'lat' have been assigned into the corresponding coordinates dimensions.") @@ -813,7 +822,7 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } } } else { - stop("Parameter 'dots' must have same number of longitudes and latitudes as 'var'.") + stop("Parameter 'dots' must have same number of longitudes and latitudes as 'data'.") } if (transpose) { @@ -848,14 +857,14 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, if (!is.null(mask)) { mask <- drop(mask) if (!is.array(mask) || any(!names(dim(mask)) %in% c(lon_dim, lat_dim))) { - stop("Parameter 'mask' must have two dimensions named as the longitude and latitude dimensions in 'var'.") + stop("Parameter 'mask' must have two dimensions named as the longitude and latitude dimensions in 'data'.") } else { - if (!identical(names(dim(mask)), names(dim(var)))) { - mask <- aperm(mask, match(names(dim(mask)), names(dim(var)))) + if (!identical(names(dim(mask)), names(dim(data)))) { + mask <- aperm(mask, match(names(dim(mask)), names(dim(data)))) } } - if (!identical(dim(mask), dim(var))) { - stop("Parameter 'mask' must have the same dimensions as 'var'.") + if (!identical(dim(mask), dim(data))) { + stop("Parameter 'mask' must have the same dimensions as 'data'.") } else if (is.numeric(mask)) { if (all(mask %in% c(0, 1))) { mask <- array(as.logical(mask), dim = dim(mask)) @@ -882,7 +891,7 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, if (!is.null(hatching_mask)) { hatching_mask <- drop(hatching_mask) if (!is.array(hatching_mask) || any(!names(dim(hatching_mask)) %in% c(lon_dim, lat_dim))) { - stop("Parameter 'hatching_mask' must have two dimensions named as the longitude and latitude dimensions in 'var'.") + stop("Parameter 'hatching_mask' must have two dimensions named as the longitude and latitude dimensions in 'data'.") } } @@ -1218,18 +1227,18 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, # If lat and lon are both regular-spaced, "useRaster = TRUE" can avoid # artifact white lines on the figure. If not, useRaster has to be FALSE (default) tryCatch({ - image(lonb$x, latb$x, var[lonb$ix, latb$ix], + image(lonb$x, latb$x, data[lonb$ix, latb$ix], col = c(col_inf_image, cols, col_sup_image), breaks = c(-.Machine$double.xmax, brks, .Machine$double.xmax), axes = FALSE, xlab = "", ylab = "", add = TRUE, useRaster = TRUE) }, error = function(x) { - image(lonb$x, latb$x, var[lonb$ix, latb$ix], + image(lonb$x, latb$x, data[lonb$ix, latb$ix], col = c(col_inf_image, cols, col_sup_image), breaks = c(-.Machine$double.xmax, brks, .Machine$double.xmax), axes = FALSE, xlab = "", ylab = "", add = TRUE) }) } else { - .filled.contour(lonb$x, latb$x, var[lonb$ix, latb$ix], + .filled.contour(lonb$x, latb$x, data[lonb$ix, latb$ix], levels = c(.Machine$double.xmin, brks, .Machine$double.xmax), col = c(col_inf_image, cols, col_sup_image)) } @@ -1252,13 +1261,13 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # if (!is.null(dots)) { - data_avail <- !is.na(var) + data_avail <- !is.na(data) for (counter in 1:(dim(dots)[1])) { points <- which(dots[counter, , ] & data_avail, arr.ind = TRUE) points(lon[points[, 1]], lat[points[, 2]], pch = dot_symbol[counter], - cex = dot_size[counter] * 3 / sqrt(sqrt(length(var))), - lwd = dot_size[counter] * 3 / sqrt(sqrt(length(var)))) + cex = dot_size[counter] * 3 / sqrt(sqrt(length(data))), + lwd = dot_size[counter] * 3 / sqrt(sqrt(length(data)))) } } @@ -1267,7 +1276,7 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, # ~~~~~~~~~~~~~~~~~ # if (!is.null(hatching_mask)) { - Hatching(hatching_mask = hatching_mask, lat = lat, lon = lon, data = var, + Hatching(hatching_mask = hatching_mask, lat = lat, lon = lon, data = data, hatching_density = hatching_density, hatching_angle = hatching_angle, hatching_color = hatching_color, hatching_lwd = hatching_lwd, @@ -1486,11 +1495,11 @@ VizEquiMap <- function(var, lon, lat, varu = NULL, varv = NULL, } ColorBarContinuous(brks, cols, vertical = vertical, subsampleg, bar_limits, var_limits, triangle_ends, col_inf = col_inf, col_sup = col_sup, - extra_labels = bar_extra_labels, draw_ticks = draw_bar_ticks, + bar_extra_labels = bar_extra_labels, draw_bar_ticks = draw_bar_ticks, draw_separators = draw_separators, title = units, title_scale = units_scale, triangle_ends_scale = triangle_ends_scale, - label_scale = bar_label_scale, tick_scale = bar_tick_scale, - extra_margin = bar_extra_margin, label_digits = bar_label_digits) + bar_label_scale = bar_label_scale, bar_tick_scale = bar_tick_scale, + bar_extra_margin = bar_extra_margin, bar_label_digits = bar_label_digits) } # If the graphic was saved to file, close the connection with the device -- GitLab From 9a5f2c612671f86a98f462d1d6d92cba3d7dc9db Mon Sep 17 00:00:00 2001 From: ARIADNA BATALLA FERRES Date: Wed, 25 Jun 2025 12:26:13 +0200 Subject: [PATCH 3/4] Update PlotCombinedMap.R to match esviz version --- modules/Visualization/R/tmp/PlotCombinedMap.R | 179 +++++++++++------- 1 file changed, 107 insertions(+), 72 deletions(-) diff --git a/modules/Visualization/R/tmp/PlotCombinedMap.R b/modules/Visualization/R/tmp/PlotCombinedMap.R index e4d6d7f3..f80fdfcf 100644 --- a/modules/Visualization/R/tmp/PlotCombinedMap.R +++ b/modules/Visualization/R/tmp/PlotCombinedMap.R @@ -27,23 +27,33 @@ #'@param map_dim Optional name for the dimension of 'maps' along which the #' multiple maps are arranged. Only applies when 'maps' is provided as a #' 3-dimensional array. Takes the value 'map' by default. -#'@param brks Colour levels to be sent to PlotEquiMap. This parameter is +#'@param brks Colour levels to be sent to VizEquiMap. This parameter is #' optional and adjusted automatically by the function. -#'@param cols List of vectors of colours to be sent to PlotEquiMap for the +#'@param cols List of vectors of colours to be sent to VizEquiMap for the #' colour bar of each map. This parameter is optional and adjusted #' automatically by the function (up to 5 maps). The colours provided for each #' colour bar will be automatically interpolated to match the number of breaks. #' Each item in this list can be named, and the name will be used as title for #' the corresponding colour bar (equivalent to the parameter 'bar_titles'). +#'@param bar_limits A numeric vector of 2 indicating the range of color bar. +#' The default is NULL, and the function will decide the range automatically. +#'@param triangle_ends A logical vector of two indicating if the lower and upper +#' triangles of the color bar should be plotted. The default is +#' c(FALSE, FALSE). +#'@param col_inf A character string of recognized color name or code indicating +#' the color of the lower triangle of the color bar. The default is NULL. +#'@param col_sup A character string of recognized color name or code indicating +#' the color of the upper triangle of the color bar. The default is NULL. #'@param col_unknown_map Colour to use to paint the grid cells for which a map #' is not possible to be chosen according to 'map_select_fun' or for those #' values that go beyond 'display_range'. Takes the value 'white' by default. #'@param mask Optional numeric array with dimensions (latitude, longitude), with #' values in the range [0, 1], indicating the opacity of the mask over each #' grid point. Cells with a 0 will result in no mask, whereas cells with a 1 -#' will result in a totally opaque superimposed pixel coloured in 'col_mask'. -#'@param col_mask Colour to be used for the superimposed mask (if specified in +#' will result in a totally opaque superimposed pixel coloured in 'mask_color'. +#'@param mask_color Colour to be used for the superimposed mask (if specified in #' 'mask'). Takes the value 'grey' by default. +#'@param col_mask Deprecated. Use 'mask_color' instead. #'@param dots Array of same dimensions as 'var' or with dimensions #' c(n, dim(var)), where n is the number of dot/symbol layers to add to the #' plot. A value of TRUE at a grid cell will draw a dot/symbol on the @@ -52,20 +62,23 @@ #' layers via the parameter 'dot_symbol'. #'@param bar_titles Optional vector of character strings providing the titles to #' be shown on top of each of the colour bars. -#'@param legend_scale Scale factor for the size of the colour bar labels. Takes +#'@param bar_label_scale Scale factor for the size of the colour bar labels. Takes #' 1 by default. #'@param cex_bar_titles Scale factor for the sizes of the bar titles. Takes 1.5 #' by default. -#'@param plot_margin Numeric vector of length 4 for the margin sizes in the -#' following order: bottom, left, top, and right. If not specified, use the -#' default of par("mar"), c(5.1, 4.1, 4.1, 2.1). Used as 'margin_scale' in -#' s2dv::PlotEquiMap. +#'@param margin_scale Numeric vector of length 4 for the margin sizes in the +#' following order: bottom, left, top, and right. If not specified (NULL), the +#' default of par("mar"), c(5.1, 4.1, 4.1, 2.1), is used. Default is NULL. +#'@param plot_margin Deprecated. Use 'margin_scale' instead. +#'@param bar_extra_margin A numeric vector of 4 indicating the extra margins to +#' be added around the color bar, in the format c(y1, x1, y2, x2). The units +#' are margin lines. The default values are c(2, 0, 2, 0). #'@param fileout File where to save the plot. If not specified (default) a #' graphics device will pop up. Extensions allowed: eps/ps, jpeg, png, pdf, bmp #' and tiff -#'@param width File width, in the units specified in the parameter size_units +#'@param width File width, in the units specified in the parameter 'size_units' #' (inches by default). Takes 8 by default. -#'@param height File height, in the units specified in the parameter size_units +#'@param height File height, in the units specified in the parameter 'size_units' #' (inches by default). Takes 5 by default. #'@param size_units Units of the size of the device (file or window) to plot in. #' Inches ('in') by default. See ?Devices and the creator function of the @@ -81,10 +94,10 @@ #'@param return_leg A logical value indicating if the color bars information #' should be returned by the function. If TRUE, the function doesn't plot the #' color bars but still creates the layout with color bar areas, and the -#' arguments for GradientCatsColorBar() or ColorBar() will be returned. It is -#' convenient for users to adjust the color bars manually. The default is -#' FALSE, the color bars will be plotted directly. -#'@param ... Additional parameters to be passed on to \code{PlotEquiMap}. +#' arguments for GradientCatsColorBar() or ColorBarContinuous() will be +#' returned. It is convenient for users to adjust the color bars manually. The +#' default is FALSE, the color bars will be plotted directly. +#'@param ... Additional parameters to be passed on to \code{VizEquiMap}. #' #'@examples #'# Simple example @@ -115,34 +128,34 @@ #' width = 14, height = 10) #'} #' -#'@seealso \code{PlotCombinedMap} and \code{PlotEquiMap} -#' -#'@importFrom s2dv PlotEquiMap ColorBar +#'@seealso \code{PlotCombinedMap} and \code{VizEquiMap} +#' +#'@import utils #'@importFrom maps map #'@importFrom graphics box image layout mtext par plot.new #'@importFrom grDevices adjustcolor bmp colorRampPalette dev.cur dev.new dev.off #' hcl jpeg pdf png postscript svg tiff #'@export PlotCombinedMap <- function(maps, lon, lat, - map_select_fun, display_range, - map_dim = 'map', - brks = NULL, cols = NULL, - bar_limits = NULL, triangle_ends = c(F, F), col_inf = NULL, col_sup = NULL, - col_unknown_map = 'white', - mask = NULL, col_mask = 'grey', - dots = NULL, - bar_titles = NULL, legend_scale = 1, - cex_bar_titles = 1.5, - plot_margin = NULL, bar_extra_margin = c(2, 0, 2, 0), - fileout = NULL, width = 8, height = 5, - size_units = 'in', res = 100, drawleg = T, return_leg = FALSE, - ...) { + map_select_fun, display_range, + map_dim = 'map', + brks = NULL, cols = NULL, + bar_limits = NULL, triangle_ends = c(FALSE, FALSE), + col_inf = NULL, col_sup = NULL, + col_unknown_map = 'white', + mask = NULL, mask_color = 'grey', col_mask = NULL, + dots = NULL, + bar_titles = NULL, bar_label_scale = 1, + cex_bar_titles = 1.5, margin_scale = NULL, + plot_margin = NULL, bar_extra_margin = c(2, 0, 2, 0), + fileout = NULL, width = 8, height = 5, + size_units = 'in', res = 100, drawleg = T, + return_leg = FALSE, ...) { args <- list(...) - + # If there is any filenames to store the graphics, process them # to select the right device if (!is.null(fileout)) { - .SelectDevice <- utils::getFromNamespace(".SelectDevice", "s2dv") deviceInfo <- .SelectDevice(fileout = fileout, width = width, height = height, units = size_units, res = res) saveToFile <- deviceInfo$fun @@ -270,12 +283,12 @@ PlotCombinedMap <- function(maps, lon, lat, subsampleg = NULL, bar_limits = bar_limits, var_limits = var_limits_maps, triangle_ends = triangle_ends, col_inf = col_inf, col_sup = col_sup, plot = FALSE, draw_separators = TRUE, - bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = legend_scale * 1.5, + bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = bar_label_scale * 1.5, extra_margin = bar_extra_margin) - # Check legend_scale - if (!is.numeric(legend_scale)) { - stop("Parameter 'legend_scale' must be numeric.") + # Check bar_label_scale + if (!is.numeric(bar_label_scale)) { + stop("Parameter 'bar_label_scale' must be numeric.") } # Check col_unknown_map @@ -283,9 +296,13 @@ PlotCombinedMap <- function(maps, lon, lat, stop("Parameter 'col_unknown_map' must be a character string.") } - # Check col_mask - if (!is.character(col_mask)) { - stop("Parameter 'col_mask' must be a character string.") + # Check mask_color + if (missing(mask_color) && !missing(col_mask)) { + warning("The parameter 'col_mask' is deprecated. Use 'mask_color' instead.") + mask_color <- col_mask + } + if (!is.character(mask_color)) { + stop("Parameter 'mask_color' must be a character string.") } # Check mask @@ -301,6 +318,7 @@ PlotCombinedMap <- function(maps, lon, lat, stop("Parameter 'mask' must have dimensions c(lat, lon).") } } + # Check dots if (!is.null(dots)) { if (length(dim(dots)) != 2) { @@ -311,12 +329,27 @@ PlotCombinedMap <- function(maps, lon, lat, stop("Parameter 'mask' must have dimensions c(lat, lon).") } } - + + # Check margin_scale + if (missing(margin_scale) && !missing(plot_margin)) { + warning("The parameter 'plot_margin' is deprecated. Use 'margin_scale' instead.") + margin_scale <- plot_margin + } + if (!is.null(margin_scale)) { + if (!is.numeric(margin_scale) || length(margin_scale) != 4) { + stop("Parameter 'margin_scale' must be a numeric vector of length 4: c(bottom, left, top, right).") + } + } + #---------------------- # Identify the most likely map #---------------------- + #TODO: Consider col_inf + if (!is.null(colorbar$col_inf[[1]])) { + warning("Lower triangle is not supported now. Please contact maintainer if you have this need.") + } if (!is.null(colorbar$col_sup[[1]])) { - + brks_norm <- vector('list', length = nmap) range_width <- vector('list', length = nmap) slightly_tune_val <- vector('list', length = nmap) @@ -339,7 +372,7 @@ PlotCombinedMap <- function(maps, lon, lat, res <- res + 1 - slightly_tune_val[[res_ind]] } else { res <- res + ((map_select_fun(x) - colorbar$brks[[res_ind]][1]) / - range_width[[res_ind]] * ((length(brks_norm[[res_ind]]) - 2) / (length(brks_norm[[res_ind]]) - 1))) + range_width[[res_ind]] * ((length(brks_norm[[res_ind]]) - 2) / (length(brks_norm[[res_ind]]) - 1))) if (map_select_fun(x) == colorbar$brks[[res_ind]][1]) { res <- res + slightly_tune_val[[res_ind]] } @@ -351,15 +384,16 @@ PlotCombinedMap <- function(maps, lon, lat, } res }) - + } else { - + brks_norm <- vector('list', length = nmap) - range_width <- display_range[2] - display_range[1] #vector('list', length = nmap) + range_width <- vector('list', length = nmap) slightly_tune_val <- vector('list', length = nmap) for (ii in 1:nmap) { brks_norm[[ii]] <- seq(0, 1, length.out = length(colorbar$brks[[ii]])) slightly_tune_val[[ii]] <- brks_norm[[ii]][2] / (length(brks_norm[[ii]]) * 2) + range_width[[ii]] <- diff(range(colorbar$brks[[ii]])) } ml_map <- apply(maps, c(lat_dim, lon_dim), function(x) { if (any(is.na(x))) { @@ -367,14 +401,15 @@ PlotCombinedMap <- function(maps, lon, lat, } else { res <- which(x == map_select_fun(x)) if (length(res) > 0) { - res <- res[1] + res <- res_ind <- res[1] if (map_select_fun(x) < display_range[1] || - map_select_fun(x) > display_range[2]) { + map_select_fun(x) > display_range[2]) { res <- -0.5 } else { - res <- res + (map_select_fun(x) - display_range[1]) / range_width - if (map_select_fun(x) == display_range[1]) { - res <- res + slightly_tune_val + res <- res + ((map_select_fun(x) - colorbar$brks[[res_ind]][1]) / + range_width[[res_ind]]) + if (map_select_fun(x) == colorbar$brks[[res_ind]][1]) { + res <- res + slightly_tune_val[[res_ind]] } } } else { @@ -384,7 +419,7 @@ PlotCombinedMap <- function(maps, lon, lat, res }) } - + nlat <- length(lat) nlon <- length(lon) @@ -413,18 +448,18 @@ PlotCombinedMap <- function(maps, lon, lat, dev.new(units = size_units, res = res, width = width, height = height) } #NOTE: I think plot.new() is not necessary in any case. -# plot.new() + # plot.new() #TODO: Don't hardcoded. Let users decide. par(font.main = 1) # If colorbars need to be plotted, re-define layout. if (drawleg) { layout(matrix(c(rep(1, nmap),2:(nmap + 1)), 2, nmap, byrow = TRUE), heights = c(6, 1.5)) } - + #---------------------- - # Set colors and breaks and then PlotEquiMap + # Set colors and breaks and then VizEquiMap #---------------------- - if (!is.null(colorbar$col_sup[[1]])) { + if (!is.null(colorbar$col_sup[[1]])) { tcols <- c(col_unknown_map, colorbar$cols[[1]], colorbar$col_sup[[1]]) tbrks <- c(-1, brks_norm[[1]] + rep(1, each = length(brks_norm[[1]]))) for (k in 2:nmap) { @@ -439,14 +474,14 @@ PlotCombinedMap <- function(maps, lon, lat, tbrks <- c(tbrks, brks_norm[[k]] + rep(k, each = length(brks_norm[[k]]))) } } - - if (is.null(plot_margin)) { - plot_margin <- c(5, 4, 4, 2) + 0.1 # default of par()$mar + + if (is.null(margin_scale)) { + margin_scale <- c(5, 4, 4, 2) + 0.1 # default of par()$mar } - - PlotEquiMap(var = ml_map, lon = lon, lat = lat, - brks = tbrks, cols = tcols, drawleg = FALSE, - filled.continents = FALSE, dots = dots, margin_scale = plot_margin, ...) + + VizEquiMap(var = ml_map, lon = lon, lat = lat, + brks = tbrks, cols = tcols, drawleg = FALSE, + filled.continents = FALSE, dots = dots, margin_scale = margin_scale, ...) #---------------------- # Add overplot on top @@ -460,9 +495,9 @@ PlotCombinedMap <- function(maps, lon, lat, lon[(wher + 1):dims_mask[2]] <- lon[(wher + 1):dims_mask[2]] - 360 } lonb <- sort(lon, index.return = TRUE) - + cols_mask <- sapply(seq(from = 0, to = 1, length.out = 10), - function(x) adjustcolor(col_mask, alpha.f = x)) + function(x) adjustcolor(mask_color, alpha.f = x)) image(lonb$x, latb$x, t(mask)[lonb$ix, latb$ix], axes = FALSE, col = cols_mask, breaks = seq(from = 0, to = 1, by = 0.1), @@ -490,7 +525,7 @@ PlotCombinedMap <- function(maps, lon, lat, old_mar[3] <- old_mar[3] - (2 * size_title + 1) par(mar = old_mar) } - + if (drawleg & !return_leg) { GradientCatsColorBar(nmap = dim(maps)[map_dim], brks = colorbar$brks, cols = colorbar$cols, vertical = FALSE, @@ -498,15 +533,15 @@ PlotCombinedMap <- function(maps, lon, lat, var_limits = var_limits_maps, triangle_ends = triangle_ends, col_inf = colorbar$col_inf, col_sup = colorbar$col_sup, plot = TRUE, draw_separators = TRUE, - bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = legend_scale * 1.5, + bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = bar_label_scale * 1.5, extra_margin = bar_extra_margin) } - + if (!return_leg) { # If the graphic was saved to file, close the connection with the device if (!is.null(fileout)) dev.off() } - + if (return_leg) { tmp <- list(nmap = dim(maps)[map_dim], brks = colorbar$brks, cols = colorbar$cols, vertical = FALSE, @@ -514,12 +549,12 @@ PlotCombinedMap <- function(maps, lon, lat, var_limits = var_limits_maps, triangle_ends = triangle_ends, col_inf = colorbar$col_inf, col_sup = colorbar$col_sup, plot = TRUE, draw_separators = TRUE, - bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = legend_scale * 1.5, + bar_titles = bar_titles, title_scale = cex_bar_titles, label_scale = bar_label_scale * 1.5, extra_margin = bar_extra_margin) + warning("The device is not off yet. Use dev.off() after plotting the color bars.") return(tmp) #NOTE: The device is not off! Can keep plotting the color bars. } - + } - -- GitLab From 82c46af7515a84bd9a29e098b8467a12b721f935 Mon Sep 17 00:00:00 2001 From: ARIADNA BATALLA FERRES Date: Wed, 25 Jun 2025 12:26:41 +0200 Subject: [PATCH 4/4] Update PlotRobinson.R to match esviz version --- modules/Visualization/R/tmp/PlotRobinson.R | 402 +++++++++++---------- 1 file changed, 221 insertions(+), 181 deletions(-) diff --git a/modules/Visualization/R/tmp/PlotRobinson.R b/modules/Visualization/R/tmp/PlotRobinson.R index 67ca034d..adff5674 100644 --- a/modules/Visualization/R/tmp/PlotRobinson.R +++ b/modules/Visualization/R/tmp/PlotRobinson.R @@ -4,7 +4,7 @@ #'plot the map. The target projection must be a valid CRS string, preferrably be #'EPSG or ESRI code; check \link[sf]{st_crs} for more explanation. This function #'is mainly tested for Robinson projection (ESRI:54030), but it can work with -#'other projection types in theory.\n +#'other projection types in theory.\cr #'The map can be plotted by points or polygon. A legend can be plotted as either #'a color bar or a discrete ggplot legend. Dots can be drawn on top of the data, #'which can be used for significance test. A mask can be added to not plot the @@ -21,17 +21,19 @@ #' of ascending or descending order. #'@param lon_dim A character string indicating the longitude dimension name in #' 'data'. If it is NULL, the function tries to find the name in -#' \code{s2dv:::.KnownLonNames}. The default value is NULL. +#' \code{esviz:::.KnownLonNames}. The default value is NULL. #'@param lat_dim A character string indicating the latitude dimension name in #' 'data'. If it is NULL, the function tries to find the name in -#' \code{s2dv:::.KnownLatNames}. The default value is NULL. +#' \code{esviz:::.KnownLatNames}. The default value is NULL. #'@param target_proj A character string indicating the target projection. It -#' should be a valid crs string. The default projection is Robinson -#' (ESRI:54030). Note that the character string may work differently depending -#' on PROJ and GDAL module version. -#'@param legend A character string indicating the legend style. It can be 's2dv' -#' (color bar by \code{ColorBar()}), 'ggplot2' (discrete legend by ggplot2), or -#' NULL (no legend), +#' should be a valid crs string. The default projection is Robinson: +#' "ESRI:54030". Note that the character string may work differently depending +#' on PROJ and GDAL module version. If package version 'sf' is lower than +#' "1.0.10" and an error appears regarding the target crs, you can try with +#' numeric crs (e.g. target_proj = 54030). +#'@param drawleg A character string indicating the legend style. It can be +#' 'bar' (color bar by \code{ColorBarContinuous()}), 'ggplot2' (discrete legend +#' by ggplot2), or FALSE (no legend). The default value is 'bar'. #'@param style A character string indicating the plotting style. It can be #' 'point' or 'polygon'. The default value is 'point'. Note that 'polygon' may #' be time- and memory-consuming for global or high-resolution data. @@ -46,23 +48,24 @@ #' define n breaks that define n - 1 intervals to classify each of the values #' in 'data'. The corresponding grid cell of a given value in 'data' will be #' colored in function of the interval it belongs to. These parameters are -#' sent to \code{ColorBar()} to generate the breaks and colours. Additional -#' colours for values beyond the limits of the colour bar are also generated -#' and applied to the plot if 'bar_limits' or 'brks' and 'triangle_ends' are -#' properly provided to do so. See ?ColorBar for a full explanation. +#' sent to \code{ColorBarContinuous()} to generate the breaks and colours. +#' Additional colors for values beyond the limits of the colour bar are also +#' generated and applied to the plot if 'bar_limits' or 'brks' and +#' 'triangle_ends' are properly provided to do so. See ?ColorBarContinuous for +#' a full explanation. #'@param col_inf,col_sup,colNA Colour identifiers to color the values that #' excess the extremes of the color bar and to color NAs, respectively. 'colNA' #' takes attr(cols, 'na_color') if available by default, where cols is the #' parameter 'cols' if provided or the vector of colors returned by #' 'color_fun'. 'col_inf' and 'col_sup' will take the value of 'colNA' if not -#' specified. See ?ColorBar for a full explanation. +#' specified. See ?ColorBarContinuous for a full explanation. #'@param color_fun,bar_extra_margin Set of #' parameters to control the visual aspect of the drawn colour bar -#' (1/3). See ?ColorBar for a full explanation. +#' (1/3). See ?ColorBarContinuous for a full explanation. #'@param vertical A logical value indicating the direction of colorbar if -#' parameter 'legend' is 's2dv'. The default value is TRUE. +#' parameter 'drawleg' is 'bar'. The default value is TRUE. #'@param toptitle A character string of the top title of the figure, scalable -#' with parameter 'title_size'. +#' with parameter 'title_scale'. #'@param caption A character string of the caption located at left-bottom of the #' plot. #'@param units A character string of the data units, which is the title of the @@ -72,11 +75,16 @@ #' cannot exceed 180 degrees. #'@param point_size A number of the size of the data points if "style = 'point'". #' The default is 'auto' and the function tries to find the appropriate size. -#'@param title_size A number of the size of the top title. The default is 16. -#'@param dots_size A number of the size of the dots. The default is 0.5. -#'@param dots_shape A number indicating the dot shape recognized by parameter +#'@param title_scale A number of the size of the top title. The default is 16. +#'@param title_size Deprecated. Use 'title_scale' instead. +#'@param dot_size A number of the size of the dots. The default is 0.5. +#'@param dots_size Deprecated. Use 'dot_size' instead. +#'@param dot_symbol A number indicating the dot shape recognized by parameter #' 'shape' in \code{geom_point()}. -#'@param coastlines_width A number indicating the width of the coastlines. +#'@param dots_shape Deprecated. Use 'dot_symbol' instead. +#'@param coast_width A number indicating the width of the coastlines. Default is +#' 0.3. +#'@param coastlines_width Deprecated. Use 'coast_width' instead. #'@param fileout A character string of the path to save the plot. If not #' specified (default), a graphic device will pop up. The extension should be #' accepted by \code{ggsave()}. @@ -94,37 +102,43 @@ #'@return A map plot with speficied projection, either in pop-up window or a #' saved file. #' -#'@examples -#'data <- array(rep(seq(-10, 10, length.out = 181), 360) + rnorm(360), +#'@examples +#'data <- array(rep(seq(-10, 10, length.out = 181), 360) + rnorm(360), #' dim = c(lat = 181, lon = 360)) #'dots <- data #'dots[which(dots < 4 & dots > -4)] <- 0 #'dots[which(dots != 0)] <- 1 -#'PlotRobinson(data, lon = 0:359, lat = -90:90, dots = dots, -#' brks = seq(-10, 10, length.out = 11), -#' toptitle = 'synthetic example', vertical = F, -#' caption = 'Robinson Global\ns2dv::PlotRobinson example', -#' bar_extra_margin = c(0, 1, 0, 1), width = 8, height = 6) -#'PlotRobinson(data, lon = 0:359, lat = -90:90, mask = dots, legend = 'ggplot2', -#' target_proj = "+proj=moll", brks = seq(-10, 10, length.out = 11), -#' color_fun = clim.palette("purpleorange"), colNA = 'green', -#' toptitle = 'synthetic example', -#' caption = 'Mollweide Global\ns2dv::PlotRobinson example', -#' width = 8, height = 6) -#' -#'@import sf ggplot2 rnaturalearth cowplot +#' \dontrun{ +#'PlotRobinson(data, lon = 0:359, lat = -90:90, dots = dots, +#' brks = seq(-10, 10, length.out = 11), +#' toptitle = 'synthetic example', vertical = FALSE, +#' caption = 'Robinson Projection', +#' bar_extra_margin = c(0, 1, 0, 1), width = 8, height = 6) +#'PlotRobinson(data, lon = 0:359, lat = -90:90, mask = dots, drawleg = 'ggplot2', +#' target_proj = "+proj=moll", brks = seq(-10, 10, length.out = 11), +#' color_fun = ClimPalette("purpleorange"), colNA = 'green', +#' toptitle = 'synthetic example', caption = 'Mollweide Projection', +#' width = 8, height = 6) +#' } +#'@import sf ggplot2 rnaturalearth cowplot utils +#'@importFrom dplyr mutate group_by summarise +#'@importFrom ClimProjDiags Subset +#'@importFrom rlang .data #'@export -PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, - target_proj = 54030, legend = 's2dv', style = 'point', - dots = NULL, mask = NULL, brks = NULL, cols = NULL, bar_limits = NULL, - triangle_ends = NULL, col_inf = NULL, col_sup = NULL, colNA = NULL, - color_fun = clim.palette(), bar_extra_margin = c(3.5, 0, 3.5, 0), vertical = TRUE, - toptitle = NULL, caption = NULL, units = NULL, crop_coastlines = NULL, - point_size = "auto", title_size = 10, dots_size = 0.2, - dots_shape = 47, coastlines_width = 0.3, - fileout = NULL, width = 8, height = 5, size_units = "in", - res = 300) { - +PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, + target_proj = NULL, drawleg = 'bar', style = 'point', + dots = NULL, mask = NULL, brks = NULL, cols = NULL, + bar_limits = NULL, triangle_ends = NULL, col_inf = NULL, + col_sup = NULL, colNA = NULL, color_fun = ClimPalette(), + bar_extra_margin = rep(0, 4), vertical = TRUE, + toptitle = NULL, caption = NULL, units = NULL, + crop_coastlines = NULL, point_size = "auto", + title_scale = 16, title_size = NULL, dot_size = 0.5, + dots_size = NULL, dot_symbol = 47, dots_shape = NULL, + coast_width = 0.3, coastlines_width = NULL, + fileout = NULL, width = 8, height = 4, + size_units = "in", res = 300) { + # Sanity check # data data <- drop(data) @@ -140,7 +154,7 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, } } if (is.unsorted(lon)) { - .warning("Parameter 'lon' should be sorted to guarantee the correct result.") + warning("Parameter 'lon' should be sorted to guarantee the correct result.") } # lat, lat_dim if (is.null(lat_dim)) { @@ -158,7 +172,10 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, if (length(lat) != dims[lat_dim]) { stop("Length of parameter 'lat' should match latitude dimension in 'data'.") } - data <- s2dv::Reorder(data, c(lon_dim, lat_dim)) + + # Reorder data + data <- aperm(data, match(names(dim(data)), c(lon_dim, lat_dim))) + # Make lat always from 90 to -90 sort_lat <- FALSE if (!is.unsorted(lat)) { @@ -166,25 +183,28 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, data <- ClimProjDiags::Subset(data, along = lat_dim, indices = seq(length(lat), 1, -1)) sort_lat <- TRUE } - + # original_proj: it can only be regular grid now original_proj <- st_crs(4326) - # tartget_proj + # target_proj if (is.null(target_proj)) { - stop("Parameter 'target_proj' cannot be NULL.") - } else { - target_proj_tmp <- st_crs(target_proj) - if (is.na(target_proj_tmp)) { - .warning(paste0("Try ESRI code: ESRI:", target_proj)) - target_proj <- st_crs(paste0("ESRI:", target_proj)) + if (packageVersion("sf") < "1.0.10") { + target_proj <- 54030 } else { - target_proj <- target_proj_tmp + target_proj <- "ESRI:54030" } } - - # legend - if (!is.null(legend) && (!legend %in% c('s2dv', 'ggplot2'))) { - stop("Parameter 'legend' must be NULL, ggplot2 or s2dv.") + target_proj_tmp <- st_crs(target_proj) + if (is.na(target_proj_tmp)) { + warning(paste0("Try ESRI code: ESRI:", target_proj)) + target_proj <- st_crs(paste0("ESRI:", target_proj)) + } else { + target_proj <- target_proj_tmp + } + + # drawleg + if (!drawleg %in% c('bar', 'ggplot2', FALSE)) { + stop("Parameter 'drawleg' must be FALSE, 'ggplot2' or 'bar'.") } # style if (!style %in% c('point', 'polygon') || length(style) != 1) { @@ -195,17 +215,17 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, if ((abs(diff(range(lon))) > 350 & abs(diff(range(lat))) > 175) | (prod(dim(data)) >= (180 * 360))) { if (!isTRUE(utils::askYesNo("The region seems to be global and style 'polygon' is chosen. It may be time- and memory-consuming to plot the map. Are you sure that you want to continue?"))) { - return(invisible()) + return(invisible()) } } } # dots if (!is.null(dots)) { dots <- drop(dots) - if (any(!names(dim(dots)) %in% c(lon_dim, lat_dim))) { + if (!is.array(dots) || any(!names(dim(dots)) %in% c(lon_dim, lat_dim))) { stop("Parameter 'dots' must have two dimensions named as longitude and latitude dimensions in 'data'.") } else { - dots <- Reorder(dots, c(lon_dim, lat_dim)) + dots <- aperm(dots, match(names(dim(dots)), c(lon_dim, lat_dim))) } if (!identical(dim(dots), dim(data))) { stop("Parameter 'dots' must have the same dimensions as 'data'.") @@ -226,10 +246,10 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, # mask if (!is.null(mask)) { mask <- drop(mask) - if (any(!names(dim(mask)) %in% c(lon_dim, lat_dim))) { + if (!is.array(mask) || any(!names(dim(mask)) %in% c(lon_dim, lat_dim))) { stop("Parameter 'mask' must have two dimensions named as longitude and latitude dimensions in 'data'.") } else { - mask <- Reorder(mask, c(lon_dim, lat_dim)) + mask <- aperm(mask, match(names(dim(mask)), c(lon_dim, lat_dim))) } if (!identical(dim(mask), dim(data))) { stop("Parameter 'mask' must have the same dimensions as 'data'.") @@ -249,38 +269,31 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, stop("Parameter 'mask' must be a logical or numerical array.") } } - + # Check title_scale + if (missing(title_scale) && !missing(title_size)) { + warning("The parameter 'title_size' is deprecated. Use 'title_scale' instead.") + title_scale <- title_size + } + if (!is.numeric(title_scale) || length(title_scale) != 1) { + stop("Parameter 'title_scale' must be a single numerical value.") + } + + tmp <- .create_var_limits(data = data, brks = brks, + bar_limits = bar_limits, drawleg = drawleg) + var_limits <- tmp$var_limits + drawleg <- tmp$drawleg + # Color bar ## Check: brks, cols, bar_limits, color_fun, bar_extra_margin, units ## Build: brks, cols, bar_limits, col_inf, col_sup - if (!all(is.na(data))) { - var_limits <- c(min(data[!is.infinite(data)], na.rm = TRUE), - max(data[!is.infinite(data)], na.rm = TRUE)) - } else { - warning("All the data are NAs. The map will be filled with colNA.") - if (!is.null(brks) && length(brks) > 1) { - #NOTE: var_limits be like this to avoid warnings from ColorBar - var_limits <- c(min(brks, na.rm = TRUE) + diff(brks)[1], - max(brks, na.rm = TRUE)) - } else if (!is.null(bar_limits)) { - var_limits <- c(bar_limits[1] + 0.01, bar_limits[2]) - } else { - var_limits <- c(-0.5, 0.5) # random range since colorbar is not going to be plotted - if (!is.null(legend)) { - legend <- NULL - warning("All data are NAs. Color bar won't be drawn. If you want to have ", - "color bar still, define parameter 'brks' or 'bar_limits'.") - } - } - } - colorbar <- ColorBar(brks = brks, cols = cols, vertical = vertical, subsampleg = NULL, - bar_limits = bar_limits, var_limits = var_limits, triangle_ends = triangle_ends, - col_inf = col_inf, col_sup = col_sup, color_fun = color_fun, - plot = FALSE, draw_ticks = TRUE, draw_separators = FALSE, - triangle_ends_scale = 1, extra_labels = NULL, - title = units, title_scale = 1, # units_scale - label_scale = 1, tick_scale = 1, #bar_tick_scale - extra_margin = bar_extra_margin, label_digits = 4) + colorbar <- ColorBarContinuous(brks = brks, cols = cols, vertical = vertical, subsampleg = NULL, + bar_limits = bar_limits, var_limits = var_limits, triangle_ends = triangle_ends, + col_inf = col_inf, col_sup = col_sup, color_fun = color_fun, + plot = FALSE, draw_bar_ticks = TRUE, draw_separators = FALSE, + triangle_ends_scale = 1, bar_extra_labels = NULL, + title = units, title_scale = 1, # units_scale + bar_label_scale = 1, bar_tick_scale = 1, + bar_extra_margin = bar_extra_margin, bar_label_digits = 4) brks <- colorbar$brks cols <- colorbar$cols col_inf <- colorbar$col_inf @@ -316,26 +329,52 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, stop("Parameter 'crop_coastlines' needs to have names 'latmax', 'latmin', 'lonmax', 'lonmin'.") } } - + # point_size if (point_size == 'auto') { # 360x181 with default setting, 0.05 point_size <- round(0.05 * (360 * 181) / (length(lon) * length(lat)), 2) } else if (!is.numeric(point_size)) { - stop("Parameter 'point_size' must be a number.") - } - # - -#================================================================= - - # Adapt s2dv ColorBar parameters to ggplot plot - # If legend is NULL, still tune with s2dv legend way - if (is.null(legend) || legend == 's2dv') { + stop("Parameter 'point_size' must be a numerical value.") + } + + # dot_symbol + if (missing(dot_symbol) && !missing(dots_shape)) { + warning("The parameter 'dots_shape' is deprecated. Use 'dot_symbol' instead.") + dot_symbol <- dots_shape + } + if (!is.numeric(dot_symbol)) { + stop("Parameter 'dot_symbol' must be a numerical value.") + } + + # dot_size + if (missing(dot_size) && !missing(dots_size)) { + warning("The parameter 'dots_size' is deprecated. Use 'dot_size' instead.") + dot_size <- dots_size + } + if (!is.numeric(dot_size)) { + stop("Parameter 'dot_size' must be a numerical value.") + } + + # coast_width + if (missing(coast_width) && !missing(coastlines_width)) { + warning("The parameter 'coastlines_width' is deprecated. Use 'coast_width' instead.") + coast_width <- coastlines_width + } + if (!is.numeric(coast_width)) { + stop("Parameter 'coast_width' must be a numerical value.") + } + + #================================================================= + + # Adapt ColorBarContinuous parameters to ggplot plot + # If drawleg is FALSE, still tune with bar legend way + if (isFALSE(drawleg) || drawleg == 'bar') { # the colorbar triangle color. If it is NULL (no triangle plotted), use colNA col_inf_image <- ifelse(is.null(col_inf), colNA, col_inf) col_sup_image <- ifelse(is.null(col_sup), colNA, col_sup) cols_ggplot <- c(col_inf_image, cols, col_sup_image) - + # Add triangles to brks brks_ggplot <- brks if (var_limits[2] > tail(brks, 1)) { @@ -348,19 +387,20 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, } else { brks_ggplot <- c(brks[1] - diff(brks[1:2]), brks_ggplot) } - + } else { # ggplot2 legend brks_ggplot <- brks cols_ggplot <- cols } - + # Build data dataframe lonlat_df <- data.frame(lon = rep(as.vector(lon), length(lat)), lat = sort(rep(as.vector(lat), length(lon)), decreasing = TRUE)) data_df <- lonlat_df %>% dplyr::mutate(dat = as.vector(data)) - + lonlat_df_ori <- NULL + # Remove the points where mask = FALSE if (!is.null(mask)) { # Save original lonlat_df to plot with expected region @@ -368,7 +408,7 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, lonlat_df_ori <- st_transform(lonlat_df_ori, crs = target_proj) lonlat_df_ori <- as.data.frame(st_coordinates(lonlat_df_ori)) names(lonlat_df_ori) <- c('long', 'lat') - + if (sort_lat) { mask <- ClimProjDiags::Subset(mask, along = lat_dim, indices = seq(length(lat), 1, -1)) } @@ -378,14 +418,14 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, data_df <- data_df[mask_df$mask == TRUE, ] lonlat_df <- data_df[, 1:2] } - + #NOTE: if target_proj = "ESRI:54030", Nord3v2 has different behavior from hub and ws!! data_df <- st_as_sf(data_df, coords = c("lon", "lat"), crs = original_proj) data_df <- st_transform(data_df, crs = target_proj) data_df <- data_df %>% dplyr::mutate(long = st_coordinates(data_df)[, 1], lat = st_coordinates(data_df)[, 2]) - + # Re-project dots if (!is.null(dots)) { if (sort_lat) { @@ -394,29 +434,29 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, dots_df <- data.frame(lon = rep(as.vector(lon), length(lat)), lat = sort(rep(as.vector(lat), length(lon)), decreasing = TRUE), dot = as.vector(dots)) - + dots_df <- st_as_sf(dots_df, coords = c("lon", "lat"), crs = original_proj) dots_df <- st_transform(dots_df, crs = target_proj) dots_df <- dots_df %>% dplyr::mutate(long = st_coordinates(dots_df)[, 1], lat = st_coordinates(dots_df)[, 2]) - dots_df <- subset(dots_df, dot == FALSE) + dots_df <- dplyr::filter(dots_df, .data$dot == FALSE) } - + # coastlines coastlines <- rnaturalearth::ne_coastline(scale = "medium", returnclass = "sf") ## crop the coastlines to the desired range if (!is.null(crop_coastlines)) { suppressWarnings({ - coastlines <- st_crop(coastlines, - xmin = as.numeric(crop_coastlines['lonmin']), - xmax = as.numeric(crop_coastlines['lonmax']), - ymin = as.numeric(crop_coastlines['latmin']), - ymax = as.numeric(crop_coastlines['latmax'])) + coastlines <- st_crop(coastlines, + xmin = as.numeric(crop_coastlines['lonmin']), + xmax = as.numeric(crop_coastlines['lonmax']), + ymin = as.numeric(crop_coastlines['latmin']), + ymax = as.numeric(crop_coastlines['latmax'])) }) } coastlines <- st_transform(coastlines, crs = target_proj) - + if (style == 'polygon') { # Calculate polygon points from regular lat/lon #NOTE: The original grid must be regular grid with same space @@ -435,14 +475,14 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, # To prevent out-of-global lat lat_poly[which(lat_poly > 90)] <- 90 lat_poly[which(lat_poly < -90)] <- -90 - + lonlat_df <- data.frame(lon = lon_poly, lat = lat_poly) # Transfer lon/lat to projection proj_lonlat <- st_as_sf(lonlat_df, coords = c("lon", "lat"), crs = original_proj) #NOTE: if target_proj = "ESRI:54030", on Nord3v2, st_transform has lon and lat swapped! proj_lonlat <- st_transform(proj_lonlat, crs = target_proj) lonlat_df_proj <- st_coordinates(proj_lonlat) - + # Use id to create groups for each polygon ids <- factor(paste0("id_", 1:dim(data_df)[1])) values <- data.frame(id = ids, @@ -453,63 +493,63 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, datapoly <- merge(values, positions, by = "id") datapoly <- st_as_sf(datapoly, coords = c("x", "y"), crs = target_proj) datapoly <- datapoly %>% - dplyr::group_by(id) %>% - dplyr::summarise() %>% #NOTE: VERY SLOW if plot global - dplyr::mutate(value = values[order(values$id), ]$value) %>% - st_cast("POLYGON") %>% - st_convex_hull() # maintain outer polygen (no bowtie shape) + dplyr::group_by(.data$id) %>% + dplyr::summarise() %>% #NOTE: VERY SLOW if plot global + dplyr::mutate(value = values[order(values$id), ]$value) %>% + st_cast("POLYGON") %>% + st_convex_hull() # maintain outer polygen (no bowtie shape) } - + # Plots if (style == 'polygon') { res_p <- ggplot(data = data_df) + #NOTE: must be data_df? - geom_sf(data = datapoly, - aes(col = cut(value, breaks = brks_ggplot, include.lowest = T), - fill = cut(value, breaks = brks_ggplot, include.lowest = T))) + geom_sf(data = datapoly, + aes(col = cut(.data$value, breaks = brks_ggplot, include.lowest = T), + fill = cut(.data$value, breaks = brks_ggplot, include.lowest = T))) } else if (style == 'point') { res_p <- ggplot(data = data_df) + - geom_point(aes(x = long, y = lat, - col = cut(dat, breaks = brks_ggplot, include.lowest = T)), - #NOTE: These two lines make point size vary with lat - #size = point_size / (data_df$lat / min(data_df$lat))) + - #size = (sort(rep(as.vector(lat), length(lon))) / max(lat)) * point_size) + - size = point_size) - } - + geom_point(aes(x = .data$long, y = .data$lat, + col = cut(.data$dat, breaks = brks_ggplot, include.lowest = T)), + #NOTE: These two lines make point size vary with lat + #size = point_size / (data_df$lat / min(data_df$lat))) + + #size = (sort(rep(as.vector(lat), length(lon))) / max(lat)) * point_size) + + size = point_size) + } + if (is.null(lonlat_df_ori)) { coord_sf_lim <- c(range(data_df$long), range(data_df$lat)) } else { coord_sf_lim <- c(range(lonlat_df_ori$long), range(lonlat_df_ori$lat)) } res_p <- res_p + - geom_sf(data = coastlines, colour ='black', size = coastlines_width) + - # Remove background grid and lat/lon label; add white background - theme_void() + theme(plot.background = element_rect(fill = 'white', colour = 'white')) + - # crop the projection - coord_sf(xlim = coord_sf_lim[1:2], ylim = coord_sf_lim[3:4], - expand = TRUE, datum = target_proj) - + geom_sf(data = coastlines, colour ='black', size = coast_width) + + # Remove background grid and lat/lon label; add white background + theme_void() + theme(plot.background = element_rect(fill = 'white', colour = 'white')) + + # crop the projection + coord_sf(xlim = coord_sf_lim[1:2], ylim = coord_sf_lim[3:4], + expand = TRUE, datum = target_proj) + if (!is.null(dots)) { - res_p <- res_p + geom_point(data = dots_df, aes(x = long, y = lat), - shape = dots_shape, size = dots_size) - #NOTE: This line makes point size vary with lat - #size = dots_size / (dots_df$lat / min(dots_df$lat))) + res_p <- res_p + geom_point(data = dots_df, aes(x = .data$long, y = .data$lat), + shape = dot_symbol, size = dot_size) + #NOTE: This line makes point size vary with lat + #size = dot_size / (dots_df$lat / min(dots_df$lat))) } - - if (identical(legend, 'ggplot2')) { + + if (identical(drawleg, 'ggplot2')) { if (style == 'polygon') { - res_p <- res_p + scale_colour_manual(values = cols_ggplot, - aesthetics = c("colour", "fill"), - drop = FALSE, na.value = colNA) + - guides(fill = guide_legend(title = units, override.aes = list(size = 1)), - color = "none") - } else if (style == 'point') { - res_p <- res_p + scale_colour_manual(values = cols_ggplot, - drop = FALSE, na.value = colNA) + - guides(colour = guide_legend(title = units, override.aes = list(size = 1))) - } - - } else { # s2dv or NULL + res_p <- res_p + scale_colour_manual(values = cols_ggplot, + aesthetics = c("colour", "fill"), + drop = FALSE, na.value = colNA) + + guides(fill = guide_legend(title = units, override.aes = list(size = 1)), + color = "none") + } else if (style == 'point') { + res_p <- res_p + scale_colour_manual(values = cols_ggplot, + drop = FALSE, na.value = colNA) + + guides(colour = guide_legend(title = units, override.aes = list(size = 1))) + } + + } else { # bar or NULL if (style == 'polygon') { res_p <- res_p + scale_colour_manual(values = cols_ggplot, aesthetics = c("colour", "fill"), @@ -521,32 +561,32 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, # Remove ggplot legend res_p <- res_p + theme(legend.position = "none", plot.margin = margin(0.5, 0, 0, 0, 'cm')) } - + if (!is.null(toptitle)) { res_p <- res_p + ggtitle(toptitle) + - theme(plot.title = element_text(size = title_size, hjust = 0.5, vjust = 3)) + theme(plot.title = element_text(size = title_scale, hjust = 0.5, vjust = 3)) } if (!is.null(caption)) { res_p <- res_p + labs(caption = caption) + theme(plot.caption = element_text(hjust = 0, vjust = 1, margin = margin(0, 0, 0, 0, 'cm'))) } - - # s2dv legend fun to put in cowplot::plot_grid - if (identical(legend, 's2dv')) { + + # bar legend fun to put in cowplot::plot_grid + if (identical(drawleg, 'bar')) { fun_legend <- function() { if (vertical) { par(mar = c(7.1, 2.2, 7.1, 3.1), mgp = c(3, 1, 0)) } else { par(mar = c(1.1, 1.2, 0.1, 1.1), mgp = c(3, 1, 0)) } - ColorBar(brks = brks, cols = cols, vertical = vertical, subsampleg = NULL, - bar_limits = bar_limits, var_limits = var_limits, triangle_ends = triangle_ends, - col_inf = col_inf, col_sup = col_sup, color_fun = color_fun, - plot = TRUE, draw_ticks = TRUE, draw_separators = FALSE, - triangle_ends_scale = 1, extra_labels = NULL, - title = units, title_scale = 1, # units_scale - label_scale = 1, tick_scale = 1, #bar_tick_scale - extra_margin = bar_extra_margin, label_digits = 4) + ColorBarContinuous(brks = brks, cols = cols, vertical = vertical, subsampleg = NULL, + bar_limits = bar_limits, var_limits = var_limits, triangle_ends = triangle_ends, + col_inf = col_inf, col_sup = col_sup, color_fun = color_fun, + plot = TRUE, draw_bar_ticks = TRUE, draw_separators = FALSE, + triangle_ends_scale = 1, bar_extra_labels = NULL, + title = units, title_scale = 1, # units_scale + bar_label_scale = 1, bar_tick_scale = 1, + bar_extra_margin = bar_extra_margin, bar_label_digits = 4) } if (vertical) { res_p <- cowplot::plot_grid(res_p, fun_legend, rel_widths = c(6, 1)) @@ -555,7 +595,7 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, } res_p <- res_p + theme(plot.background = element_rect(fill = "white", colour = "white")) } - + if (!is.null(fileout)) { ext <- regmatches(fileout, regexpr("[a-zA-Z0-9]*$", fileout)) ggsave(fileout, res_p, width = width, height = height, dpi = res, units = size_units, @@ -564,6 +604,6 @@ PlotRobinson <- function(data, lon, lat, lon_dim = NULL, lat_dim = NULL, dev.new(units = size_units, res = res, width = width, height = height) res_p } - + } -- GitLab