diff --git a/.Rbuildignore b/.Rbuildignore index 80904f6d..de8dbdc6 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -17,3 +17,6 @@ README_files/ ^_quarto$ vignettes/ ^LICENSE\.md$ +^cran-comments\.md$ +^CRAN-SUBMISSION$ +#inst/tinytest/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index de0f3b8b..f4273c62 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ SCRATCH ^_quarto$ _quarto + +/.quarto/ diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION new file mode 100644 index 00000000..83d24065 --- /dev/null +++ b/CRAN-SUBMISSION @@ -0,0 +1,3 @@ +Version: 0.1.0 +Date: 2024-06-19 18:17:25 UTC +SHA: 561b24cb0be3549f88efdc7aa527181f7e6b3327 diff --git a/DESCRIPTION b/DESCRIPTION index 71138161..850de674 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,14 +1,16 @@ Package: tinyplot Type: Package Title: Lightweight Extension of the Base R Graphics System -Version: 0.0.5.9008 +Version: 0.1.0 +Date: 2024-06-19 Authors@R: c( person( given = "Grant", family = "McDermott", role = c("aut", "cre"), - email = "gmcd@amazon.com" + email = "gmcd@amazon.com", + comment = c(ORCID = "0000-0001-7883-8573") ), person( given = "Vincent", @@ -32,7 +34,7 @@ Authors@R: ) ) Description: Lightweight extension of the base R graphics system, with support - for automatic legends, facetting, and several other enhancements. + for automatic legends, facets, and various other enhancements. License: Apache License (>= 2) Depends: R (>= 4.0) @@ -54,8 +56,6 @@ Suggests: knitr Encoding: UTF-8 RoxygenNote: 7.3.1 -URL: https://grantmcdermott.com/tinyplot/, - http://grantmcdermott.com/tinyplot/ +URL: https://grantmcdermott.com/tinyplot/ BugReports: https://github.com/grantmcdermott/tinyplot/issues -VignetteBuilder: knitr Roxygen: list(markdown = TRUE) diff --git a/NAMESPACE b/NAMESPACE index 722beb81..be51aed9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,7 @@ S3method(tinyplot,default) S3method(tinyplot,density) S3method(tinyplot,formula) export(draw_legend) +export(get_saved_par) export(plt) export(tinyplot) export(tpar) diff --git a/NEWS.md b/NEWS.md index 94e1e29b..23af2558 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,25 @@ # News -## 0.0.5.9008 (development version) +## 0.1.0 + +Our first CRAN submission! This v0.1.0 release includes the following new +features and updates: License: - Formally switch to Apache 2.0 license. (#141 @grantmcdermott) +Breaking changes: + +- To ensure consistent "dot.case" style for all `tinyplot()` function arguments, +the following two arguments have been renamed (`old` => `new`): + - `par_restore` => `restore.par` (note the change in word order too!) + - `ribbon_alpha` => `ribbon.alpha` + + We don't believe that these two arguments are much used in practice. So + hopefully it will only have a negligible effect on existing `tinyplot` code in + the wild, even though it is a breaking change. (#149 @grantmcdermott) + New features: - Gradient legends are now supported if a continuous variable is passed to @@ -22,7 +36,11 @@ default. Thanks to @zeileis for the suggestion. (#130 @grantmcdermott) automatically vary line widths by group. (#134 @grantmcdermott) - `tpar()` now accepts standard `par()` arguments in addition to the `tinyplot`-specific ones. This allows users to set or query graphical parameters -via a single convenience function, instead having to invoke `tpar` and `par` separately. +via a single convenience function, instead having to invoke `tpar` and `par` +separately. (#140 @grantmcdermott) + - As an aside, `tpar()` has gained some additional parameters for fine-grained + control of global plot defaults, including `grid`, `ribbon.alpha`, and various + `file.*` parameters (see next bullet point). - Users can write plots directly to disk using the new `file` argument, alongside corresponding `width` and `height` arguments for output customization (both of which are defined in inches). For example, @@ -32,9 +50,27 @@ external graphics devices like `png()`, `pdf()`, etc. But it may prove more convenient, since the current global graphics parameters held in `(t)par()` are carried over to the external device too and don't need to be reset. Note that the appropriate device type is determined automatically by the file extension, -which must be one of ".png", ".jpg" (".jpeg"), ".pdf", or ".svg". (#143 +which must be one of ".png", ".jpg" (".jpeg"), ".pdf", or ".svg". +(#143 @grantmcdermott) +- We have a shiny new `tinyplot` logo. (#148 @grantmcdermott) +- The new `get_saved_par()` function can be used to retrieve the `par` settings +from immediately before or immediately after the preceding `tinyplot` call. +This function replaces some older (non-exported) internal functions that +`tinyplot` was using to restore and control `par` environments. But it could +also prove help to end users who are looking for additional ways to restore +`par` settings after the fact. See `?get_saved_par` for some examples. (#152 +@grantmcdermott) +- `tinyplot`/`plt` gaina a new `alpha = ` convenience argument for +adding transparency to plot elements and colours. Example use: +`plt(rnorm(1e3), pch = 19, alpha = 0.3)`. (#129 @grantmcdermott) +- Similar to the preceding news item, transparency can be added to (grouped) +background fill by passing `bg` (or its alias, `fill`) a numeric in the range +`[0,1]`. This feature has the same effect as `bg = "by"` except for the added +transparency. Example use: +`plt(lat ~ long | depth, data = quakes, pch = 21, cex = 2, bg = 0.2)`. (#129 @grantmcdermott) + Bug fixes: - Fixed bug that prevented `tpar(facet.x = ...)` args from being passed forward @@ -56,6 +92,8 @@ CRAN's recommended 5 MB limit. Please note that local testing of the package requires adding the `NOT_CRAN=TRUE` environment variable to your .Renviron file (or, exporting it in your .bashrc/.zshrc/etc. dotfile if you prefer that approach). (#145 @vincentarelbundock & @grantmcdermott) +- Update some test snapshots to match slight changes in the way that R 4.4.0 +calculates `density` grid coords. (#150 @grantmcdermott) ## 0.0.5 diff --git a/R/by_aesthetics.R b/R/by_aesthetics.R index 0601f2ca..0afda208 100755 --- a/R/by_aesthetics.R +++ b/R/by_aesthetics.R @@ -1,6 +1,7 @@ -by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, ordered = NULL) { +by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, ordered = NULL, alpha = NULL) { if (is.null(ordered)) ordered = FALSE + if (is.null(alpha)) alpha = 1 if (is.null(gradient)) gradient = FALSE if (isTRUE(gradient)) { ngrps = 100L @@ -37,8 +38,8 @@ by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, order if (is.null(palette)) { if (ngrps <= length(palette()) && isFALSE(ordered) && isFALSE(gradient)) { - palette_fun = function() palette() # must be function to avoid arg ambiguity - args = list() + palette_fun = function(alpha) adjustcolor(palette(), alpha) # must be function to avoid arg ambiguity + args = list(alpha = alpha) } else { if (ngrps <= 8 && isFALSE(ordered)) { # ngrps < 100 so we know gradient is FALSE too palette = "R4" @@ -58,7 +59,7 @@ by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, order } } - args = list(n = ngrps, palette = palette) + args = list(n = ngrps, palette = palette, alpha = alpha) } } else { @@ -71,7 +72,7 @@ by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, order if (pal_match < 1L) stop("'palette' is ambiguous") palette_fun = palette.colors if (isTRUE(gradient)) { - palette_fun2 = function(n, palette) colorRampPalette(palette.colors(palette = palette))(n) + palette_fun2 = function(n, palette, alpha) colorRampPalette(palette.colors(palette = palette, alpha = alpha))(n) palette_fun = palette_fun2 } } else { @@ -87,7 +88,7 @@ by_col = function(ngrps = 1L, col = NULL, palette = NULL, gradient = NULL, order ) } } - args = list(n = ngrps, palette = palette) + args = list(n = ngrps, palette = palette, alpha = alpha) } else if (class(palette) %in% c("call", "name")) { diff --git a/R/draw_legend.R b/R/draw_legend.R index 29c9ad51..b4bdc02c 100644 --- a/R/draw_legend.R +++ b/R/draw_legend.R @@ -4,17 +4,17 @@ #' outside the plotting area) and drawing of legend. #' #' @md -#' @param legend Legend placement keyword or list, passed down from `tinyplot`. +#' @param legend Legend placement keyword or list, passed down from [tinyplot]. #' @param legend_args Additional legend arguments to be passed to `legend()`. #' @param by_dep The (deparsed) "by" grouping variable name. #' @param lgnd_labs The labels passed to `legend(legend = ...)`. -#' @param type Plotting type(s), passed down from `tinyplot`. -#' @param pch Plotting character(s), passed down from `tinyplot`. -#' @param lty Plotting linetype(s), passed down from `tinyplot`. -#' @param lwd Plotting line width(s), passed down from `tinyplot`. -#' @param col Plotting colour(s), passed down from `tinyplot`. -#' @param bg Plotting character background fill colour(s), passed down from `tinyplot`. -#' @param cex Plotting character expansion(s), passed down from `tinyplot`. +#' @param type Plotting type(s), passed down from [tinyplot]. +#' @param pch Plotting character(s), passed down from [tinyplot]. +#' @param lty Plotting linetype(s), passed down from [tinyplot]. +#' @param lwd Plotting line width(s), passed down from [tinyplot]. +#' @param col Plotting colour(s), passed down from [tinyplot]. +#' @param bg Plotting character background fill colour(s), passed down from [tinyplot]. +#' @param cex Plotting character expansion(s), passed down from [tinyplot]. #' @param gradient Logical indicating whether a continuous gradient swatch #' should be used to represent the colors. #' @param lmar Legend margins (in lines). Should be a numeric vector of the form @@ -26,10 +26,15 @@ #' @param has_sub Logical. Does the plot have a sub-caption. Only used if #' keyword position is "bottom!", in which case we need to bump the legend #' margin a bit further. -#' @param new_plot Should we be calling plot.new internally? +#' @param new_plot Logical. Should we be calling plot.new internally? +#' +#' @returns No return value, called for side effect of producing a(n empty) plot +#' with a legend in the margin. +#' #' @importFrom graphics grconvertX grconvertY rasterImage strwidth #' @importFrom grDevices as.raster recordGraphics #' @importFrom utils modifyList +#' #' @examples #' #' oldmar = par("mar") @@ -225,7 +230,7 @@ draw_legend = function( # requires additional space omar[2] = par("mgp")[1] + 1*par("cex.lab") } - par(mar = omar) ## TEST + par(mar = omar) if (isTRUE(new_plot)) plot.new() @@ -292,13 +297,13 @@ draw_legend = function( ## drawn, otherwise the inset calculation---which is based in the legend ## width---will be off the first time. if (outer_bottom) { - omar[1] = par("mgp")[1] + 1*par("cex.lab") ## TEST - if (isTRUE(has_sub)) omar[1] = omar[1] + 1*par("cex.sub") ## TEST + omar[1] = par("mgp")[1] + 1*par("cex.lab") + if (isTRUE(has_sub)) omar[1] = omar[1] + 1*par("cex.sub") } else { ## For "top!", the logic is slightly different: We don't expand the outer ## margin b/c we need the legend to come underneath the main title. So ## we rather expand the existing inner margin. - ooma[3] = ooma[3] + topmar_epsilon ## TESTING + ooma[3] = ooma[3] + topmar_epsilon par(oma = ooma) } par(mar = omar) diff --git a/R/get_saved_par.R b/R/get_saved_par.R new file mode 100644 index 00000000..be3b1ef0 --- /dev/null +++ b/R/get_saved_par.R @@ -0,0 +1,116 @@ +#' @title Retrieve the saved graphical parameters +#' +#' @description Convenience function for retrieving the graphical parameters +#' (i.e., the full list of `tag = value` pairs held in +#' \code{\link[graphics]{par}}) from either immediately before or +#' immediately after the most recent [tinyplot] call. +#' +#' @param when character. From when should the saved parameters be retrieved? +#' Either "before" (the default) or "after" the preceding `tinyplot` call. +#' +#' @details A potential side-effect of [tinyplot] is that it can change a user's +#' \code{\link[graphics]{par}} settings. For example, it may adjust the inner +#' and outer plot margins to make space for an automatic legend; see +#' [draw_legend]. While it is possible to immediately restore the original +#' \code{\link[graphics]{par}} settings upon exit via the +#' `tinyplot(..., restore.par = TRUE)` argument, this is not the default +#' behaviour. The reason being that we need to preserve the adjusted parameter +#' settings in case users want to add further graphical annotations to their +#' plot (e.g., \code{\link[graphics]{abline}}, \code{\link[graphics]{text}}, +#' etc.) Nevertheless, it may still prove desirable to recall and reset these +#' original graphical parameters after the fact (e.g., once all these extra +#' annotations have been added). That is the purpose of this [get_saved_par] +#' function. +#' +#' Of course, users may prefer to manually capture and reset graphical +#' parameters, as per the standard method described in the +#' \code{\link[graphics]{par}} documentation. For example: +#' +#' ``` +#' op = par(no.readonly = TRUE) # save current par settings +#' # +#' par(op) # reset original pars +#' ``` +#' +#' This standard manual approach may be safer than [get_saved_par] because it +#' offers more precise control. Specifically, the value of [get_saved_par] +#' itself will be reset after ever new [tinyplot] call; i.e. it may inherit an +#' already-changed set of parameters. Users should bear these trade-offs in +#' mind when deciding which approach to use. As a general rule, +#' [get_saved_par] offers the convenience of resetting the original +#' \code{\link[graphics]{par}} settings even if a user forgot to save them +#' beforehand. But one should avoid invoking it after a series of consecutive +#' [tinyplot] calls. +#' +#' Finally, note that users can always call \code{\link[grDevices]{dev.off}} +#' to reset all \code{\link[graphics]{par}} settings to their defaults. +#' +#' @returns A list of \code{\link[graphics]{par}} settings. +#' +#' @examples +#' # +#' # Contrived example where we draw a grouped scatterplot with a legend and +#' # manually add corresponding best fit lines for each group... +#' # +#' +#' # First draw the grouped scatterplot +#' tinyplot(Sepal.Length ~ Petal.Length | Species, iris) +#' +#' # Preserving adjusted par settings is good for adding elements to our plot +#' for (s in levels(iris$Species)) { +#' abline( +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), +#' col = which(levels(iris$Species)==s) +#' ) +#' } +#' +#' # Get saved par from before the preceding tinyplot call (but don't use yet) +#' sp = get_saved_par("before") +#' +#' # Note the changed margins will affect regular plots too, which is probably +#' # not desirable +#' plot(1:10) +#' +#' # Reset the original parameters (could use `par(sp)` here) +#' tpar(sp) +#' # Redraw our simple plot with our corrected right margin +#' plot(1:10) +#' +#' # +#' # Quick example going the other way, "correcting" for par.restore = TRUE... +#' # +#' +#' tinyplot(Sepal.Length ~ Petal.Length | Species, iris, restore.par = TRUE) +#' # Our added best lines will be wrong b/c of misaligned par +#' for (s in levels(iris$Species)) { +#' abline( +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), +#' col = which(levels(iris$Species)==s), lty = 2 +#' ) +#' } +#' # grab the par settings from the _end_ of the preceding tinyplot call to fix +#' tpar(get_saved_par("after")) +#' # now the best lines are correct +#' for (s in levels(iris$Species)) { +#' abline( +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), +#' col = which(levels(iris$Species)==s) +#' ) +#' } +#' +#' # reset again to original saved par settings before exit +#' tpar(sp) +#' +#' @export +get_saved_par <- function(when = c("before", "after")) { + when = match.arg(when) + par_env_name = paste0(".saved_par_", when) + return(get(par_env_name, envir = get(".tinyplot_env", envir = parent.env(environment())))) +} + +# (non-exported) companion function(s) for setting the original pars +set_saved_par <- function(when = c("before", "after"), value) { + when = match.arg(when) + par_env_name = paste0(".saved_par_", when) + assign(par_env_name, value, envir = get(".tinyplot_env", envir = parent.env(environment()))) +} diff --git a/R/tinyplot-package.R b/R/tinyplot-package.R index cd16b1ab..1eef4aa1 100644 --- a/R/tinyplot-package.R +++ b/R/tinyplot-package.R @@ -1,22 +1,4 @@ -#' \code{tinyplot-package} -#' -#' @title tinyplot: Lightweight extension of the base R graphics system, with -#' support for automatic legends, facetting, and several other enhancements. -#' -#' @description The goal of **tinyplot** is to provides a lightweight extension -#' of the base R graphics system with various convenience features, -#' particularly for representing groups with your data. For example, the core -#' `tinyplot()` function (alias: `plt()` with no vowels) makes it easy to plot -#' different categories of a dataset in a single function call and highlight -#' these categories (groups) using modern colour palettes. Coincident with -#' this grouping support, `tinyplot()` also produces automatic legends with -#' scope for further customization. While the package offers several other -#' enhancements like facets, it tries as far as possible to be a drop-in -#' replacement for the equivalent base plotting calls. Users should generally -#' be able to swap a valid `plot()` call with `tinyplot()` without any changes -#' to the expected output. -#' -#' @docType package -#' @aliases tinyplot-package NULL #' @keywords internal -"_PACKAGE" \ No newline at end of file +"_PACKAGE" + +NULL diff --git a/R/tinyplot.R b/R/tinyplot.R index 1b44e2d6..292c8dd7 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -171,35 +171,52 @@ #' @param bg background fill color for the open plot symbols 21:25 (see #' `points.default`), as well as ribbon and area plot types. For the latter #' group---including filled density plots---an automatic alpha transparency -#' adjustment will be applied (see the `ribbon_alpha` argument further below). -#' Users can also supply a special `bg = "by"` convenience argument, in which -#' case the background fill will inherit the automatic group coloring -#' intended for the `col` argument. Note that this grouped inheritance will -#' persist even if the `col` defaults are themselves overridden. For example, -#' `tinyplot(y ~ x | z, data = fakedata, pch = 22, col = "blue", bg = "by")` -#' will yield filled squares with a blue border. +#' adjustment will be applied (see the `ribbon.alpha` argument further below). +#' Users can also supply either one of two special convenience arguments that +#' will cause the background fill to inherit the automatic grouped coloring +#' behaviour of `col`: +#' +#' - `bg = "by"` will insert a background fill that inherits the main color +#' mappings from `col`. +#' - `by = ` (i.e., a numeric in the range `[0,1]`) will insert +#' a background fill that inherits the main color mapping(s) from `col`, but +#' with added alpha-transparency. +#' +#' For both of these convenience arguments, note that the (grouped) `bg` +#' mappings will persist even if the (grouped) `col` defaults are themselves +#' overridden. This can be useful if you want to preserve the grouped palette +#' mappings by background fill but not boundary color, e.g. filled points. See +#' examples. #' @param fill alias for `bg`. If non-NULL values for both `bg` and `fill` are #' provided, then the latter will be ignored in favour of the former. +#' @param alpha a numeric in the range `[0,1]` for adjusting the alpha channel +#' of the color palette, where 0 means transparent and 1 means opaque. Use +#' fractional values, e.g. `0.5` for semi-transparency. #' @param cex character expansion. A numerical vector (can be a single value) #' giving the amount by which plotting characters and symbols should be scaled #' relative to the default. Note that NULL is equivalent to 1.0, while NA #' renders the characters invisible. -#' @param par_restore a logical value indicating whether the `par` settings -#' prior to calling `tinyplot` should be restored on exit. Defaults to FALSE, -#' which makes it possible to add elements to the plot after it has been -#' drawn. However, note the the outer margins of the graphics device may have -#' been altered to make space for the `tinyplot` legend. Users can opt out of -#' this persistent behaviour by setting to TRUE instead. (Another option would -#' be calling `dev.off()` to reset all `par` settings to their defaults.) +#' @param restore.par a logical value indicating whether the +#' \code{\link[graphics]{par}} settings prior to calling `tinyplot` should be +#' restored on exit. Defaults to FALSE, which makes it possible to add +#' elements to the plot after it has been drawn. However, note the the outer +#' margins of the graphics device may have been altered to make space for the +#' `tinyplot` legend. Users can opt out of this persistent behaviour by +#' setting to TRUE instead. See also [get_saved_par] for another option to +#' recover the original \code{\link[graphics]{par}} settings, as well as +#' longer discussion about the trade-offs involved. #' @param subset,na.action,drop.unused.levels arguments passed to `model.frame` #' when extracting the data from `formula` and `data`. #' @param ymin,ymax minimum and maximum coordinates of interval plot types. Only #' used when the `type` argument is one of "pointrange", "errorbar", or #' "ribbon". -#' @param ribbon_alpha numeric factor modifying the opacity alpha of any ribbon -#' shading; typically in `[0, 1]`. Default value is 0.2. Only used when -#' `type = "ribbon"`, or when the `bg` fill argument is specified in a density -#' plot (since filled density plots are converted to ribbon plots internally). +#' @param ribbon.alpha numeric factor modifying the opacity alpha of any ribbon +#' shading; typically in `[0, 1]`. Only used when `type = "ribbon"`, or when +#' the `bg` fill argument is specified in a density plot (since filled density +#' plots are converted to ribbon plots internally). If an an applicable plot +#' type is called but no explicit value is provided, then will default to +#' `tpar("ribbon.alpha")` (i.e., probably `0.2` unless this has been +#' overridden by the user in their global settings.) #' @param add logical. If TRUE, then elements are added to the current plot rather #' than drawing a new plot window. Note that the automatic legend for the #' added elements will be turned off. @@ -233,6 +250,8 @@ #' specified. #' @param ... other graphical parameters. See \code{\link[graphics]{par}} or #' the "Details" section of \code{\link[graphics]{plot}}. +#' +#' @returns No return value, called for side effect of producing a plot. #' #' @details #' Disregarding the enhancements that it supports, `tinyplot` tries as far as @@ -248,25 +267,21 @@ #' @importFrom tools file_ext #' #' @examples -#' -#' # save graphics parameters to restore them later -#' op = tpar() -#' -#' +#' #' #' aq = transform( #' airquality, #' Month = factor(Month, labels = month.abb[unique(Month)]) #' ) #' -#' # tinyplot should be a drop-in replacement for (most) regular plot calls. For -#' # example: +#' # In most cases, `tinyplot` should be a drop-in replacement for regular +#' # `plot` calls. For example: #' -#' par(mfrow = c(1, 2)) +#' op = tpar(mfrow = c(1, 2)) #' plot(0:10, main = "plot") #' tinyplot(0:10, main = "tinyplot") +#' tpar(op) # restore original layout #' -#' # restore graphics parameters -#' par(op) +#' # Aside: `tinyplot::tpar()` is a (near) drop-in replacement for `par()` #' #' # Unlike vanilla plot, however, tinyplot allows you to characterize groups #' # using either the `by` argument or equivalent `|` formula syntax. @@ -282,12 +297,36 @@ #' plt(Temp ~ Day | Month, data = aq) ## shorthand alias #' #' # Use standard base plotting arguments to adjust features of your plot. -#' # For example, change `pch` (plot character) to get filled points. +#' # For example, change `pch` (plot character) to get filled points and `cex` +#' # (character expansion) to increase their size. +#' +#' tinyplot( +#' Temp ~ Day | Month, +#' data = aq, +#' pch = 16, +#' cex = 2 +#' ) +#' +#' # We can add alpha transparency for overlapping points +#' +#' tinyplot( +#' Temp ~ Day | Month, +#' data = aq, +#' pch = 16, +#' cex = 2, +#' alpha = 0.3 +#' ) #' +#' # To get filled points with a common solid background color, use an +#' # appropriate plotting character (21:25) and combine with one of the special +#' # `bg` convenience arguments. #' tinyplot( #' Temp ~ Day | Month, #' data = aq, -#' pch = 16 +#' pch = 21, # use filled circles +#' cex = 2, +#' bg = 0.3, # numeric in [0,1] adds a grouped background fill with transparency +#' col = "black" # override default color mapping; give all points a black border #' ) #' #' # Converting to a grouped line plot is a simple matter of adjusting the @@ -373,7 +412,6 @@ #' # palettes, depending on the number of groups. However, all palettes listed #' # by `palette.pals()` and `hcl.pals()` are supported as convenience strings, #' # or users can supply a valid palette-generating function for finer control -#' # over transparency etc. #' #' tinyplot( #' Temp ~ Day | Month, @@ -383,19 +421,21 @@ #' ) #' #' # It's possible to further customize the look of you plots using familiar -#' # arguments and base plotting theme settings (e.g., via `par`). +#' # arguments and base plotting theme settings (e.g., via `(t)par`). #' #' tpar(family = "HersheySans", las = 1) #' tinyplot( #' Temp ~ Day | Month, #' data = aq, #' type = "b", pch = 16, -#' palette = palette.colors(palette = "tableau", alpha = 0.5), +#' palette = "tableau", alpha = 0.5, #' main = "Daily temperatures by month", #' frame = FALSE, grid = TRUE #' ) #' -#' par(op) # revert original graphics parameters +#' # Note: For more examples and a detailed walkthrough, please see the +#' # introductory tinyplot tutorial available online: +#' # https://grantmcdermott.com/tinyplot/vignettes/intro_tutorial.html #' #' @rdname tinyplot #' @export @@ -434,11 +474,12 @@ tinyplot.default = function( col = NULL, bg = NULL, fill = NULL, + alpha = NULL, cex = 1, - par_restore = FALSE, + restore.par = FALSE, ymin = NULL, ymax = NULL, - ribbon_alpha = 0.2, + ribbon.alpha = NULL, add = FALSE, file = NULL, width = NULL, @@ -499,17 +540,20 @@ tinyplot.default = function( # Save current graphical parameters opar = par(no.readonly = TRUE) - if (par_restore || !is.null(facet)) { + if (restore.par || !is.null(facet)) { if (!is.null(file) || !is.null(width) || !is.null(height)) { opar$new = FALSE # catch for some interfaces } on.exit(par(opar), add = TRUE) } + # set_orig_par(opar) + set_saved_par(when = "before", opar) # catch for adding to existing facet plot # if (!is.null(facet) && isTRUE(add)) par(tpar("last_facet_par")) if (!is.null(facet) && isTRUE(add)) ( - par(get_last_facet_par()) + # par(get_last_facet_par()) + par(get_saved_par(when = "after")) ) # Capture deparsed expressions early, before x, y and by are evaluated @@ -670,25 +714,32 @@ tinyplot.default = function( col = col, palette = substitute(palette), gradient = by_continuous, - ordered = by_ordered + ordered = by_ordered, + alpha = alpha ) if (is.null(bg) && !is.null(fill)) bg = fill + if (!is.null(bg) && length(bg)==1 && is.numeric(bg) && bg>=0 && bg <=1) { + alpha = bg + bg = "by" + } if (!is.null(bg) && length(bg)==1 && bg == "by") { bg = by_col( ngrps = ngrps, col = NULL, palette = substitute(palette), gradient = by_continuous, - ordered = by_ordered + ordered = by_ordered, + alpha = alpha ) } else if (length(bg) != ngrps) { bg = rep(bg, ngrps) } if (type == "ribbon") { + if (is.null(ribbon.alpha)) ribbon.alpha = .tpar[["ribbon.alpha"]] if (!is.null(bg)) { - bg = adjustcolor(bg, ribbon_alpha) + bg = adjustcolor(bg, ribbon.alpha) } else if (!is.null(col)) { - bg = adjustcolor(col, ribbon_alpha) + bg = adjustcolor(col, ribbon.alpha) } } @@ -1329,11 +1380,9 @@ tinyplot.default = function( } - # tidy up before exit - if (!is.null(facet)) { - last_facet_par = par(no.readonly = TRUE) - set_last_facet_par(last_facet_par) - } + # save end pars for possible recall later + apar = par(no.readonly = TRUE) + set_saved_par(when = "after", apar) } @@ -1366,7 +1415,7 @@ tinyplot.formula = function( col = NULL, lty = NULL, lwd = NULL, - par_restore = FALSE, + restore.par = FALSE, formula = NULL, subset = NULL, na.action = NULL, @@ -1544,7 +1593,7 @@ tinyplot.formula = function( col = col, lty = lty, lwd = lwd, - par_restore = par_restore, + restore.par = restore.par, ... ) @@ -1578,7 +1627,7 @@ tinyplot.density = function( lwd = NULL, bg = NULL, fill = NULL, - par_restore = FALSE, + restore.par = FALSE, ... ) { @@ -1750,7 +1799,7 @@ tinyplot.density = function( fill = fill, lty = lty, lwd = lwd, - par_restore = par_restore, + restore.par = restore.par, ... ) diff --git a/R/tpar.R b/R/tpar.R index e8671bf5..6173e6af 100644 --- a/R/tpar.R +++ b/R/tpar.R @@ -1,12 +1,13 @@ -#' @title Set or query graphical parameters +#' @title Set or query graphical parameters #' -#' @description `tpar` extends \code{\link[graphics]{par}}, serving as a drop-in +#' @description Extends \code{\link[graphics]{par}}, serving as a (near) drop-in #' replacement for setting or querying graphical parameters. The key -#' difference is that, beyond supporting the standard group of R graphical -#' parameters, `tpar` also supports additional graphical parameters that are -#' provided by `tinyplot`. Similar to \code{\link[graphics]{par}}, parameters -#' are set by passing appropriate `key = value` argument pairs, and multiple -#' parameters can be set or queried at the same time. +#' differences is that, beyond supporting the standard group of R graphical +#' parameters in \code{\link[graphics]{par}}, `tpar` also supports additional +#' graphical parameters that are provided by `tinyplot`. Similar to +#' \code{\link[graphics]{par}}, parameters are set by passing appropriate +#' `key = value` argument pairs, and multiple parameters can be set or queried +#' at the same time. #' #' @md #' @param ... arguments of the form `key = value`. This includes all of the @@ -14,7 +15,7 @@ #' the `tinyplot`-specific ones described in the 'Graphical Parameters' #' section below. #' -#' @details The `tinyplot`-specfic parameters are saved in an internal +#' @details The `tinyplot`-specific parameters are saved in an internal #' environment called `.tpar` for performance and safety reasons. However, #' they can also be set at package load time via \code{\link[base]{options}}, #' which may prove convenient for users that want to enable different default @@ -24,7 +25,25 @@ #' #' For their part, any "base" graphical parameters are caught dynamically and #' passed on to \code{\link[graphics]{par}} as appropriate. Technically, only -#' parameters that satisify `par(..., no.readonly = TRUE)` are evaluated. +#' parameters that satisfy `par(..., no.readonly = TRUE)` are evaluated. +#' +#' However, note the important distinction: `tpar` only evaluates parameters +#' from \code{\link[graphics]{par}} if they are passed _explicitly_ by the +#' user. This means that `tpar` should not be used to capture the (invisible) +#' state of a user's entire set of graphics parameters, i.e. `tpar()` != +#' `par()`. If you want to capture the _all_ existing graphics settings, then +#' you should rather use `par()` instead. +#' +#' @returns When parameters are set, their previous values are returned in an +#' invisible named list. Such a list can be passed as an argument to `tpar` to +#' restore the parameter values. +#' +#' When just one parameter is queried, the value of that parameter is returned +#' as (atomic) vector. When two or more parameters are queried, their values +#' are returned in a list, with the list names giving the parameters. +#' +#' Note the inconsistency: setting one parameter returns a list, but querying +#' one parameter returns a vector. #' #' @section Additional Graphical Parameters: #' @@ -60,6 +79,9 @@ #' \tab\tab\cr #' \tab\tab\cr #' `lmar` \tab\tab A numeric vector of form `c(inner, outer)` that gives the margin padding, in terms of lines, around the automatic `tinyplot` legend. Defaults to `c(1.0, 0.1)`, where the first number represents the "inner" margin between the legend and the plot region, and the second number represents the "outer" margin between the legend and edge of the graphics device. (Note that an exception for the definition of the "outer" legend margin occurs when the legend placement is `"top!"`, since the legend is placed above the plot region but below the main title. In such cases, the outer margin is relative to the existing gap between the title and the plot region, which is itself determined by `par("mar")[3]`.)\cr +#' \tab\tab\cr +#' \tab\tab\cr +#' `ribbon.alpha` \tab\tab Numeric factor in the range `[0,1]` for modifying the opacity alpha of "ribbon" and "area" (and alike) type plots. Default value is `0.2`.\cr #' } #' #' @importFrom graphics par @@ -88,6 +110,10 @@ #' # Reset back to original values #' tpar(op) #' +#' # Important: tpar() only evalutes parameters that have been passed explicitly +#' # by the user. So it it should not be used to query and set (restore) +#' # parameters that weren't explicitly requested, i.e. tpar() != par(). +#' #' # Note: The tinyplot-specific parameters can also be be set via `options` #' # with a `tinyplot_*` prefix, which can be convenient for enabling #' # different default behaviour at startup time (e.g., via an .Rprofile @@ -100,7 +126,6 @@ tpar = function(...) { facet.col = facet.bg = facet.border = used_par_old = NULL opts = list(...) - # if (length(opts)==1 && (!is.null(names(opts)) && names(opts) != "last_facet_par")) { if (length(opts)==1 && is.null(names(opts))) { if (inherits(opts[[1]], "list") && !is.null(names(opts[[1]]))) { opts = opts[[1]] @@ -118,7 +143,6 @@ tpar = function(...) { } if (length(used_par)) { if (!is.null(nam)) used_par = opts[used_par] - # par(used_par) used_par_old = par(used_par) tpar_old = modifyList(tpar_old, used_par_old, keep.null = TRUE) } @@ -196,6 +220,12 @@ tpar = function(...) { .tpar$lmar = lmar } + if (length(opts$ribbon.alpha)) { + ribbon.alpha = as.numeric(opts$ribbon.alpha) + if (!is.numeric(ribbon.alpha) || ribbon.alpha<0 || ribbon.alpha>1) stop("ribbon.alpha needs to be a numeric in the range [0,1]") + .tpar$ribbon.alpha = ribbon.alpha + } + ## Like par(), we want the return object to be dependent on inputs... # User didn't assign any new values, but may have requested explicit (print @@ -223,12 +253,3 @@ tpar = function(...) { } - -# separate setter and getter functions for .last_facet_par -set_last_facet_par <- function(value) { - assign(".last_facet_par", value, envir = get(".tinyplot_env", envir = parent.env(environment()))) -} -get_last_facet_par <- function() { - return(get(".last_facet_par", envir = get(".tinyplot_env", envir = parent.env(environment())))) -} - diff --git a/R/zzz.R b/R/zzz.R index 4afbf529..03ce58fb 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -21,11 +21,19 @@ .tpar$facet.bg <- if(is.null(getOption("tinyplot_facet.bg"))) NULL else getOption("tinyplot_facet.bg") .tpar$facet.border <- if(is.null(getOption("tinyplot_facet.border"))) NA else getOption("tinyplot_facet.border") + # Plot grid .tpar$grid <- if(is.null(getOption("tinyplot_grid"))) FALSE else as.logical(getOption("tinyplot_grid")) # Legend margin, i.e. gap between the legend and the plot elements .tpar$lmar <- if(is.null(getOption("tinyplot_lmar"))) c(1.0, 0.1) else as.numeric(getOption("tinyplot_lmar")) + # Alpha fill (transparency) default for ribbon and area plots + .tpar$ribbon.alpha <- if(is.null(getOption("tinyplot_ribbon.alpha"))) 0.2 else as.numeric(getOption("tinyplot_ribbon.alpha")) + assign(".tpar", .tpar, envir = tnypltptns) + + assign(".saved_par_before", NULL, envir = get(".tinyplot_env", envir = parent.env(environment()))) + assign(".saved_par_after", NULL, envir = get(".tinyplot_env", envir = parent.env(environment()))) + } \ No newline at end of file diff --git a/README.md b/README.md index ade61b0e..ef6be42a 100644 --- a/README.md +++ b/README.md @@ -17,54 +17,54 @@ version](https://www.r-pkg.org/badges/version/tinyplot.png)](https://CRAN.R-proj A lightweight extension of the base R graphics system, with support for automatic grouping, legends, facets, and various other enhancements. -**tinyplot** is not yet on CRAN, but can be installed from R-universe. +The stable version of **tinyplot** is available on CRAN. ``` r -install.packages("tinyplot", repos = "https://grantmcdermott.r-universe.dev") +install.packages("tinyplot") ``` -Our goal is to submit to CRAN within the first few months of 2024, once -we have settled on some remaining design choices and features support. -You can take a look at the [open -issues](https://github.com/grantmcdermott/tinyplot/issues) to see what’s -currently under consideration. Please feel free to weigh on these if you -have opinions. We want end users to have a say in determining the final -product. +Or, you can grab the latest development version from R-universe. + +``` r +install.packages("tinyplot", repos = "https://grantmcdermott.r-universe.dev") +``` ## Why R users are spoiled for choice when it comes to visualization -frameworks. The options include **ggplot2** (arguably the most important -graphics system of the last decade) and **lattice**, not to mention a -bewildering array of extensions built on top of, around, and in between -these amazing packages. - -As a result, it is perhaps not surprising that the base R graphics -system sometimes gets short shrift. This is unfortunate, because base R -offers very powerful and flexible plotting facilities. Just type -`demo(graphics)` or `demo(persp)` into your R console to get an idea. -Or, take a look at -[these](https://github.com/karoliskoncevicius/tutorial_r_introduction/blob/main/baseplotting.md) -[two](https://quizzical-engelbart-d15a44.netlify.app/2021-2022_m2-data-2_visu-2_practice#1) -excellent tutorials. The downside of this power and flexibility is that -base R plotting can require a fair bit of manual tinkering. A case in -point is plotting grouped data with an appropriate legend. Doing so with -the generic `plot()` function can require several function calls or a -loop, fiddling with your plot regions, and then generating the legend +frameworks. The options, of course, include **lattice** and **ggplot2**; +say nothing of the bewildering array of extensions built around, on top +of, and in between these amazing packages.[^1] + +Given the wealth of options, it is perhaps understandable that even avid +R users can overlook the base R graphics system. This is unfortunate, +because base R offers very powerful and flexible plotting +facilities.[^2] The downside of this power and flexibility is that base +R plotting can require a lot of manual tinkering. A case in point is +plotting grouped data with an appropriate legend. Doing so with the +generic `plot()` function can require several function calls or a loop, +fiddling with your plot regions, and then generating the legend manually. The **tinyplot** package aims to remove this overhead. It provides a -lightweight (zero dependency) extension of the base R graphics system -with various convenience features, particularly for representing grouped -data. For example, the core `tinyplot()` function—or its shorthand alias -`plt()`—makes it easy to plot different groups of a dataset in a single -function call and highlight these groups using modern colour palettes. -Coincident with this grouping support, **tinyplot** also produces -automatic legends with scope for further customization. While the -package offers several other enhancements like facets, it tries as far -as possible to be a drop-in replacement for the equivalent base plotting -function. Users should generally be able to swap a valid `plot()` call -for `tinyplot()` without any changes to the expected output. +lightweight extension of the base R graphics system that preserves the +same core logic and syntax, but with numerous convenience features to +make base R plotting a more user-friendly experience. For example, the +core `tinyplot()` function—or its shorthand alias `plt()`—makes it easy +to plot grouped datasets and generate automatic legends in a single +function call. Or, you can display groups in separate facets without +having to worry about manually setting plot regions. While **tinyplot** +offers these and various other enhancements, it tries as far as possible +to be a drop-in replacement for the equivalent base plotting function. +Users should generally be able to swap out a valid `plot()` call for +`tinyplot()`/`plt()` without any changes to the expected output. + +It is worth highlighting that **tinyplot** depends solely on base R and +that care has been taken to keep its installation size to a minimum. It +may thus provide an attractive and lightweight option for package +developers (and regular R users) who would like to produce convenient +and sophisticated plots, but without incurring any recursive +dependencies. ## Quickstart @@ -95,7 +95,7 @@ aesthetic tweaks: plt( Sepal.Length ~ Petal.Length | Species, data = iris, - palette = "dark", pch = 16, + palette = "dark", pch = 16, grid = TRUE, frame = FALSE ) ``` @@ -136,3 +136,15 @@ Hopefully, these have been enough to pique your interest. Head over to the [intro tutorial](https://grantmcdermott.com/tinyplot/vignettes/intro_tutorial.html) for many more examples, including range plots and customization. + +[^1]: Both **lattice** and **ggplot2** are build on top of the **grid** + package, which was incoporated into the base R distribution way back + in R 2.0.0. **ggplot2**, in particular, is arguably the most + important and influential (high-level) graphics library of the last + two decades, across any programming language. + +[^2]: Just type `demo(graphics)` or `demo(persp)` into your R console to + get an idea. Or, take a look at + [these](https://github.com/karoliskoncevicius/r_notes/blob/main/baseplotting.md) + [two](https://quizzical-engelbart-d15a44.netlify.app/2021-2022_m2-data-2_visu-2_practice#1) + excellent tutorials. diff --git a/README.qmd b/README.qmd index 0a9d1eed..fe44ccdb 100644 --- a/README.qmd +++ b/README.qmd @@ -1,3 +1,6 @@ +--- +format: gfm +--- ```{r, include = FALSE} knitr::opts_chunk$set( @@ -26,47 +29,60 @@ knitr::opts_chunk$set( A lightweight extension of the base R graphics system, with support for automatic grouping, legends, facets, and various other enhancements. -**tinyplot** is not yet on CRAN, but can be installed from R-universe. +The stable version of **tinyplot** is available on CRAN. ``` r -install.packages("tinyplot", repos = "https://grantmcdermott.r-universe.dev") +install.packages("tinyplot") ``` -Our goal is to submit to CRAN within the first few months of 2024, once we have -settled on some remaining design choices and features support. You can take a -look at the [open issues](https://github.com/grantmcdermott/tinyplot/issues) to see -what's currently under consideration. Please feel free to weigh on these if you -have opinions. We want end users to have a say in determining the final product. +Or, you can grab the latest development version from R-universe. + +``` r +install.packages("tinyplot", repos = "https://grantmcdermott.r-universe.dev") +``` ## Why R users are spoiled for choice when it comes to visualization frameworks. The -options include **ggplot2** (arguably the most important graphics -system of the last decade) and **lattice**, not to mention a bewildering array -of extensions built on top of, around, and in between these amazing packages. - -As a result, it is not surprising that the base R graphics system can -sometimes get short shrift. This is unfortunate, because base R offers very -powerful and flexible plotting facilities. Just type `demo(graphics)` or -`demo(persp)` into your R console to get an idea. Or, take a look at -[these](https://github.com/karoliskoncevicius/tutorial_r_introduction/blob/main/baseplotting.md) +options, of course, include **lattice** and **ggplot2**; say nothing of the +bewildering array of extensions built around, on top of, and in between these +amazing packages.^[Both **lattice** and **ggplot2** are build on top of the +**grid** package, which was incoporated into the base R distribution way back in +R 2.0.0. **ggplot2**, in particular, is arguably the most important and +influential (high-level) graphics library of the last two decades, across any +programming language.] + +Given the wealth of options, it is perhaps understandable that even avid R users +can overlook the base R graphics system. This is unfortunate, because base R +offers very powerful and flexible plotting facilities.^[Just type +`demo(graphics)` or `demo(persp)` into your R console to get an idea. Or, take a +look at +[these](https://github.com/karoliskoncevicius/r_notes/blob/main/baseplotting.md) [two](https://quizzical-engelbart-d15a44.netlify.app/2021-2022_m2-data-2_visu-2_practice#1) -excellent tutorials. The downside of this power and flexibility is that base R -plotting can require a fair bit of manual tinkering. A case in point is -plotting grouped data with an appropriate legend. Doing so with the generic -`plot()` function can require several function calls or a loop, fiddling with -your plot regions, and then generating the legend manually. +excellent tutorials.] +The downside of this power and flexibility is that base R plotting can require a +lot of manual tinkering. A case in point is plotting grouped data with an +appropriate legend. Doing so with the generic `plot()` function can require +several function calls or a loop, fiddling with your plot regions, and then +generating the legend manually. The **tinyplot** package aims to remove this overhead. It provides a lightweight -extension of the base R graphics system that comes with various convenience -features, yet relies on no additional dependencies beyond base R itself. For -example, the core `tinyplot()` function—or its shorthand alias -`plt()`—makes it easy to plot different groups of a dataset and generate -an automatic legend in a single function call. While **tinyplot** offers various -other enhancements like facets, additional plot types, etc. it tries as far as -possible to be a drop-in replacement for the equivalent base plotting function. -Users should generally be able to swap a valid `plot()` call for `tinyplot()` -without any changes to the expected output. +extension of the base R graphics system that preserves the same core logic and +syntax, but with numerous convenience features to make base R plotting a more +user-friendly experience. For example, the core `tinyplot()` function---or its +shorthand alias `plt()`---makes it easy to plot grouped datasets and generate +automatic legends in a single function call. Or, you can display groups in +separate facets without having to worry about manually setting plot regions. +While **tinyplot** offers these and various other enhancements, it tries as far +as possible to be a drop-in replacement for the equivalent base plotting +function. Users should generally be able to swap out a valid `plot()` call for +`tinyplot()`/`plt()` without any changes to the expected output. + +It is worth highlighting that **tinyplot** depends solely on base R and that +care has been taken to keep its installation size to a minimum. It may thus +provide an attractive and lightweight option for package developers (and +regular R users) who would like to produce convenient and sophisticated plots, +but without incurring any recursive dependencies. ## Quickstart @@ -94,7 +110,7 @@ same plot with this shorthand alias, plus a few aesthetic tweaks: plt( Sepal.Length ~ Petal.Length | Species, data = iris, - palette = "dark", pch = 16, + palette = "dark", pch = 16, grid = TRUE, frame = FALSE ) ``` @@ -127,4 +143,4 @@ plt( Hopefully, these have been enough to pique your interest. Head over to the [intro tutorial](https://grantmcdermott.com/tinyplot/vignettes/intro_tutorial.html) -for many more examples, including range plots and customization. \ No newline at end of file +for many more examples, including range plots and customization. diff --git a/cran-comments.md b/cran-comments.md new file mode 100644 index 00000000..86a774d7 --- /dev/null +++ b/cran-comments.md @@ -0,0 +1,65 @@ +## Overview + +This is a resubmission that addresses several action items requested by the CRAN +team after our first submission in April. While we have directly resolved most +of the CRAN requests, we wish to highlight two issues that require some +additional context: + +1. We were asked to provide DOI links to methods references in our Description. +However, we not have any appropriate references, given that this is a conceptually +simple graphics extension package. + +2. In addition to ensuring that all Examples restore the user's original `par` +settings upon completion (which we have addressed), we were asked to ensure that +a user's `par` settings are immediately restored upon exiting our main +`tinyplot` function. However, this more stringent requirement would negate a +main feature of the function---and the **tinyplot** package at large---since, +for example, we need to adjust `par` settings to add legends outside of the plot +margin. Restoring `par` settings by default would mean that users could no +longer add elements like `abline` to a newly created tinyplot in a safe +or consistent way, since the underlying coordinate system has been reverted. +After some back and forth with Prof. Kurt Hornik (see email correspondence with +Achim Zeileis), we understand that this requirement is at least partially +motivated by a lack of precedence. We have thus taken the following steps to +motivate, safeguard, and document the default **tinyplot** behaviour with +respect to `par`: + + - Users can immediately restore their original `par` settings directly by + invoking the `tinyplot(..., restore.par = TRUE)` argument. + + - If users need to revert `par` settings after the fact---i.e. after a + tinyplot has already been drawn---then we provide an additional + `get_saved_par()` convenience function for doing so. This function retrieves + the state of the user's `par` settings from immediately before the preceding + `tinyplot()` call, which are automatically saved in a hidden environment + variable, and can then be used to restore `par` from this original state. + The `?get_saved_par` help documentation provides several examples, as well + as a detailed explanation of our rationale (need) for persisting `par` + settings by default to ensure a consistent user experience. We have + similarly documented steps to revert or control `par` settings in the help + documentation of other **tinyplot** functions. + +Again, we realise that we are in somewhat uncharted waters here without obvious +precedent. But we hope these additional functions and our explicit documentation +will meet the CRAN requirements. We are happy to discuss further with the CRAN +team if that would prove helpful. + +Original submission notes: + +- This is a new package that provides a lightweight extension of the base R +graphics system (including automatic legends for grouped data, facets, etc.) + +- We run a comprehensive test suite as part of our CI development workflow on +GitHub, which includes hundreds of test snapshots (i.e., SVG images). However, +we have removed these tests from our CRAN submission since their volume results +in a large install tarball, beyond CRAN's recommend size limits. + +## Test environments +Local: Arch Linux +GitHub Actions (ubuntu-22.04): release, devel + +## R CMD check results + +0 errors | 0 warnings | 1 note + +* This is a new release. diff --git a/inst/tinytest/_tinysnapshot/aesthetics_by_fill.svg b/inst/tinytest/_tinysnapshot/aesthetics_by_fill.svg new file mode 100644 index 00000000..94f7f6c6 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/aesthetics_by_fill.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + +Month +5 +6 +7 +8 +9 + + + + + + + +Day +Temp + + + + + + + + + + +0 +5 +10 +15 +20 +25 +30 + + + + + +60 +70 +80 +90 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/aesthetics_by_fill_alpha.svg b/inst/tinytest/_tinysnapshot/aesthetics_by_fill_alpha.svg new file mode 100644 index 00000000..6620558f --- /dev/null +++ b/inst/tinytest/_tinysnapshot/aesthetics_by_fill_alpha.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + +Month +5 +6 +7 +8 +9 + + + + + + + +Day +Temp + + + + + + + + + + +0 +5 +10 +15 +20 +25 +30 + + + + + +60 +70 +80 +90 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/density_factor.svg b/inst/tinytest/_tinysnapshot/density_factor.svg index 4c65bf35..85ad5612 100644 --- a/inst/tinytest/_tinysnapshot/density_factor.svg +++ b/inst/tinytest/_tinysnapshot/density_factor.svg @@ -55,21 +55,21 @@ 3.5 4.0 4.5 - + - - - - - - + + + + + + 0.0 -0.2 -0.4 -0.6 -0.8 -1.0 -1.2 +0.2 +0.4 +0.6 +0.8 +1.0 +1.2 @@ -78,8 +78,8 @@ - - - + + + diff --git a/inst/tinytest/_tinysnapshot/density_fill.svg b/inst/tinytest/_tinysnapshot/density_fill.svg index be74d1d9..c2b43128 100644 --- a/inst/tinytest/_tinysnapshot/density_fill.svg +++ b/inst/tinytest/_tinysnapshot/density_fill.svg @@ -55,21 +55,21 @@ 3.5 4.0 4.5 - + - - - - - - + + + + + + 0.0 -0.2 -0.4 -0.6 -0.8 -1.0 -1.2 +0.2 +0.4 +0.6 +0.8 +1.0 +1.2 @@ -78,11 +78,11 @@ - - - - - - + + + + + + diff --git a/inst/tinytest/_tinysnapshot/density_legend_bottom.svg b/inst/tinytest/_tinysnapshot/density_legend_bottom.svg index 97553741..0abd7de8 100644 --- a/inst/tinytest/_tinysnapshot/density_legend_bottom.svg +++ b/inst/tinytest/_tinysnapshot/density_legend_bottom.svg @@ -46,17 +46,17 @@ 20 30 40 - - - - - - -0.00 -0.02 -0.04 -0.06 -0.08 + + + + + + +0.00 +0.02 +0.04 +0.06 +0.08 @@ -65,7 +65,7 @@ - - + + diff --git a/inst/tinytest/_tinysnapshot/density_nogroups.svg b/inst/tinytest/_tinysnapshot/density_nogroups.svg index 54f65b9a..a5e495df 100644 --- a/inst/tinytest/_tinysnapshot/density_nogroups.svg +++ b/inst/tinytest/_tinysnapshot/density_nogroups.svg @@ -33,23 +33,23 @@ 20 30 40 - + - - - - - - - + + + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 -0.06 -0.07 +0.01 +0.02 +0.03 +0.04 +0.05 +0.06 +0.07 @@ -58,6 +58,6 @@ - + diff --git a/inst/tinytest/_tinysnapshot/density_numeric.svg b/inst/tinytest/_tinysnapshot/density_numeric.svg index 356279ad..447fd9a7 100644 --- a/inst/tinytest/_tinysnapshot/density_numeric.svg +++ b/inst/tinytest/_tinysnapshot/density_numeric.svg @@ -47,17 +47,17 @@ 20 30 40 - - - - - - -0.00 -0.02 -0.04 -0.06 -0.08 + + + + + + +0.00 +0.02 +0.04 +0.06 +0.08 @@ -66,7 +66,7 @@ - - + + diff --git a/inst/tinytest/_tinysnapshot/density_type_factor.svg b/inst/tinytest/_tinysnapshot/density_type_factor.svg index 89559990..4273539b 100644 --- a/inst/tinytest/_tinysnapshot/density_type_factor.svg +++ b/inst/tinytest/_tinysnapshot/density_type_factor.svg @@ -54,21 +54,21 @@ 3.5 4.0 4.5 - + - - - - - - + + + + + + 0.0 -0.2 -0.4 -0.6 -0.8 -1.0 -1.2 +0.2 +0.4 +0.6 +0.8 +1.0 +1.2 @@ -77,8 +77,8 @@ - - - + + + diff --git a/inst/tinytest/_tinysnapshot/density_type_fill.svg b/inst/tinytest/_tinysnapshot/density_type_fill.svg index f2e2ad5e..df8b0f92 100644 --- a/inst/tinytest/_tinysnapshot/density_type_fill.svg +++ b/inst/tinytest/_tinysnapshot/density_type_fill.svg @@ -54,21 +54,21 @@ 3.5 4.0 4.5 - + - - - - - - + + + + + + 0.0 -0.2 -0.4 -0.6 -0.8 -1.0 -1.2 +0.2 +0.4 +0.6 +0.8 +1.0 +1.2 @@ -77,11 +77,11 @@ - - - - - - + + + + + + diff --git a/inst/tinytest/_tinysnapshot/density_type_nogroups.svg b/inst/tinytest/_tinysnapshot/density_type_nogroups.svg index 15d7a0ae..52354831 100644 --- a/inst/tinytest/_tinysnapshot/density_type_nogroups.svg +++ b/inst/tinytest/_tinysnapshot/density_type_nogroups.svg @@ -32,23 +32,23 @@ 20 30 40 - + - - - - - - - + + + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 -0.06 -0.07 +0.01 +0.02 +0.03 +0.04 +0.05 +0.06 +0.07 @@ -57,6 +57,6 @@ - + diff --git a/inst/tinytest/_tinysnapshot/density_type_numeric.svg b/inst/tinytest/_tinysnapshot/density_type_numeric.svg index 0551cbd9..cb12f148 100644 --- a/inst/tinytest/_tinysnapshot/density_type_numeric.svg +++ b/inst/tinytest/_tinysnapshot/density_type_numeric.svg @@ -46,17 +46,17 @@ 20 30 40 - - - - - - -0.00 -0.02 -0.04 -0.06 -0.08 + + + + + + +0.00 +0.02 +0.04 +0.06 +0.08 @@ -65,7 +65,7 @@ - - + + diff --git a/inst/tinytest/_tinysnapshot/facet_density.svg b/inst/tinytest/_tinysnapshot/facet_density.svg index 05919557..8f0c7b4a 100644 --- a/inst/tinytest/_tinysnapshot/facet_density.svg +++ b/inst/tinytest/_tinysnapshot/facet_density.svg @@ -47,15 +47,15 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 4 @@ -83,15 +83,15 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 6 @@ -119,27 +119,27 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 8 - + - + - + diff --git a/inst/tinytest/_tinysnapshot/facet_density_by.svg b/inst/tinytest/_tinysnapshot/facet_density_by.svg index e1d14c68..d2eb21a9 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_by.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_by.svg @@ -57,15 +57,15 @@ 25 30 35 - - - - - -0.0 -0.1 -0.2 -0.3 + + + + + +0.0 +0.1 +0.2 +0.3 4 @@ -91,15 +91,15 @@ 25 30 35 - - - - - -0.0 -0.1 -0.2 -0.3 + + + + + +0.0 +0.1 +0.2 +0.3 6 @@ -125,36 +125,36 @@ 25 30 35 - - - - - -0.0 -0.1 -0.2 -0.3 + + + + + +0.0 +0.1 +0.2 +0.3 8 - + - + - + - + - + - + diff --git a/inst/tinytest/_tinysnapshot/facet_density_by_equal.svg b/inst/tinytest/_tinysnapshot/facet_density_by_equal.svg index cc9059ea..eb9ac359 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_by_equal.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_by_equal.svg @@ -61,15 +61,15 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 4 @@ -97,15 +97,15 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 6 @@ -133,21 +133,21 @@ 25 30 35 - + - - - + + + 0.00 -0.05 -0.10 -0.15 +0.05 +0.10 +0.15 8 - + @@ -156,7 +156,7 @@ - + @@ -165,7 +165,7 @@ - + diff --git a/inst/tinytest/_tinysnapshot/facet_density_fancy.svg b/inst/tinytest/_tinysnapshot/facet_density_fancy.svg index 18f2d32a..00becdf7 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_fancy.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_fancy.svg @@ -59,15 +59,15 @@ 25 30 35 - + - - - + + + 0.0 -0.1 -0.2 -0.3 +0.1 +0.2 +0.3 4 @@ -80,12 +80,12 @@ - + - - - - + + + + @@ -120,12 +120,12 @@ - + - - - - + + + + @@ -160,36 +160,36 @@ - + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/inst/tinytest/_tinysnapshot/facet_density_fancy_formula.svg b/inst/tinytest/_tinysnapshot/facet_density_fancy_formula.svg index 5f8efb0c..612cb233 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_fancy_formula.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_fancy_formula.svg @@ -59,15 +59,15 @@ 25 30 35 - + - - - + + + 0.0 -0.1 -0.2 -0.3 +0.1 +0.2 +0.3 4 @@ -80,12 +80,12 @@ - + - - - - + + + + @@ -120,12 +120,12 @@ - + - - - - + + + + @@ -160,36 +160,36 @@ - + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/inst/tinytest/_tinysnapshot/facet_density_formula.svg b/inst/tinytest/_tinysnapshot/facet_density_formula.svg index 8e1486d9..f7c792b7 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_formula.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_formula.svg @@ -42,19 +42,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 cold:calm @@ -76,19 +76,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 hot:calm @@ -110,19 +110,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 cold:windy @@ -144,34 +144,34 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 hot:windy - + - + - + - + diff --git a/inst/tinytest/_tinysnapshot/facet_density_grid.svg b/inst/tinytest/_tinysnapshot/facet_density_grid.svg index cae34699..e7239647 100644 --- a/inst/tinytest/_tinysnapshot/facet_density_grid.svg +++ b/inst/tinytest/_tinysnapshot/facet_density_grid.svg @@ -42,19 +42,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 cold @@ -76,19 +76,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 hot @@ -112,19 +112,19 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 @@ -144,34 +144,34 @@ 50 100 150 - + - - - - - + + + + + 0.00 -0.01 -0.02 -0.03 -0.04 -0.05 +0.01 +0.02 +0.03 +0.04 +0.05 windy - + - + - + - + diff --git a/inst/tinytest/_tinysnapshot/palette_alpha.svg b/inst/tinytest/_tinysnapshot/palette_alpha.svg new file mode 100644 index 00000000..76a1f67d --- /dev/null +++ b/inst/tinytest/_tinysnapshot/palette_alpha.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + +Species +setosa +versicolor +virginica + + + + + + + +Petal.Length +Sepal.Length + + + + + + + + + + +1 +2 +3 +4 +5 +6 +7 + + + + + + + + + +4.5 +5.0 +5.5 +6.0 +6.5 +7.0 +7.5 +8.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/par_restore_FALSE.svg b/inst/tinytest/_tinysnapshot/restore_par_FALSE.svg similarity index 100% rename from inst/tinytest/_tinysnapshot/par_restore_FALSE.svg rename to inst/tinytest/_tinysnapshot/restore_par_FALSE.svg diff --git a/inst/tinytest/_tinysnapshot/par_restore_TRUE.svg b/inst/tinytest/_tinysnapshot/restore_par_TRUE.svg similarity index 100% rename from inst/tinytest/_tinysnapshot/par_restore_TRUE.svg rename to inst/tinytest/_tinysnapshot/restore_par_TRUE.svg diff --git a/inst/tinytest/_tinysnapshot/par_restore_bottom.svg b/inst/tinytest/_tinysnapshot/restore_par_bottom.svg similarity index 100% rename from inst/tinytest/_tinysnapshot/par_restore_bottom.svg rename to inst/tinytest/_tinysnapshot/restore_par_bottom.svg diff --git a/inst/tinytest/test-README.R b/inst/tinytest/test-README.R index 72f13c43..6462d61c 100644 --- a/inst/tinytest/test-README.R +++ b/inst/tinytest/test-README.R @@ -117,23 +117,20 @@ f = function() { } expect_snapshot_plot(f, label = "readme_pointrange") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.2") { - f = function() { - tpar(pch = 16, family = "HersheySans") - - tinyplot( - Temp ~ Day | Month, - data = aq, - type = "b", - palette = palette.colors(palette = "Tableau 10", alpha = 0.5), - main = "Daily temperatures by month", - frame = FALSE, grid = TRUE - ) - } - expect_snapshot_plot(f, label = "readme_hershey_plus") +f = function() { + tpar(pch = 16, family = "HersheySans") + + tinyplot( + Temp ~ Day | Month, + data = aq, + type = "b", + # palette = palette.colors(palette = "Tableau 10", alpha = 0.5), + palette = "Tableau 10", alpha = 0.5, + main = "Daily temperatures by month", + frame = FALSE, grid = TRUE + ) } +expect_snapshot_plot(f, label = "readme_hershey_plus") # diff --git a/inst/tinytest/test-aesthetics.R b/inst/tinytest/test-aesthetics.R index 951b1bc8..a3972573 100755 --- a/inst/tinytest/test-aesthetics.R +++ b/inst/tinytest/test-aesthetics.R @@ -42,6 +42,14 @@ expect_snapshot_plot(f, label = "aesthetics_by_type_l") f = function() tinyplot(Temp ~ Day | Month, data = aq, type = "b", pch = "by", lty = "by", lwd = "by", col = "black") expect_snapshot_plot(f, label = "aesthetics_by_nocol") +# fill = "by" (with border colour override) +f = function() tinyplot(Temp ~ Day | Month, data = aq, pch = 21, cex = 2, fill = "by", col = "black") +expect_snapshot_plot(f, label = "aesthetics_by_fill") + +# fill = "" (with border colour override) +f = function() tinyplot(Temp ~ Day | Month, data = aq, pch = 21, cex = 2, fill = 0.5, col = "black") +expect_snapshot_plot(f, label = "aesthetics_by_fill_alpha") + # inherit global par f = function() { par(pch = 16) diff --git a/inst/tinytest/test-density.R b/inst/tinytest/test-density.R index da5e28ac..f67e3a51 100644 --- a/inst/tinytest/test-density.R +++ b/inst/tinytest/test-density.R @@ -1,12 +1,10 @@ source("helpers.R") using("tinysnapshot") -## Sidestep test fails due to new (R 4.4.0) density grid value calculations. +## Avoid test fails on older R versions (pre 4.4.0) due to slight change in +## density grid value calculations. ## https://bugs.r-project.org/show_bug.cgi?id=18337 -exit_if_not(getRversion() <= "4.3.3") -## Note: Once 4.4.0 is released we can either generate some new plots or -## test with something like: -# f = function() tinyplot(density(mtcars$mpg, old.coords=TRUE)) +exit_if_not(getRversion() >= "4.4.0") mtcars$am = as.factor(mtcars$am) diff --git a/inst/tinytest/test-facet.R b/inst/tinytest/test-facet.R index 4b49e4fb..cb0b723a 100644 --- a/inst/tinytest/test-facet.R +++ b/inst/tinytest/test-facet.R @@ -3,7 +3,7 @@ using("tinysnapshot") mtcars$am = as.factor(mtcars$am) -op = tpar() +op = par() # ## simple scatterplot cases first @@ -112,9 +112,7 @@ f = function() { } expect_snapshot_plot(f, label = "facet_by") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.3") { +if (getRversion() >= "4.4.0") { f = function() { with( mtcars, @@ -235,9 +233,7 @@ f = function() { expect_snapshot_plot(f, label = "facet_ribbon_by") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.3") { +if (getRversion() <= "4.4.0") { f = function() { with( mtcars2, @@ -274,12 +270,10 @@ if (getRversion() <= "4.3.3") { # restore original par settings tpar(op) -## Sidestep test fails due to new (R 4.4.0) density grid value calculations. +## Avoid test fails on older R versions (pre 4.4.0) due to slight change in +## density grid value calculations. ## https://bugs.r-project.org/show_bug.cgi?id=18337 -exit_if_not(getRversion() <= "4.3.3") -## Note: Once 4.4.0 is released we can either generate some new plots or -## test with something like: -# f = function() tinyplot(density(mtcars$mpg, old.coords=TRUE)) +exit_if_not(getRversion() >= "4.4.0") f = function() { with( @@ -317,9 +311,8 @@ f = function() { } expect_snapshot_plot(f, label = "facet_density_by") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.2") { + +if (getRversion() >= "4.4.0") { f = function() { with( mtcars, @@ -376,9 +369,8 @@ f = function() { } expect_snapshot_plot(f, label = "facet_2x2_formula") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.2") { + +if (getRversion() <= "4.4.0") { f = function() { tinyplot( ~ mpg | am, mtcars, @@ -409,9 +401,7 @@ f = function() { expect_snapshot_plot(f, label = "facet_grid") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -if (getRversion() <= "4.3.3") { +if (getRversion() <= "4.4.0") { f = function() { tinyplot( mpg ~ wt | factor(gear), data = mtcars, diff --git a/inst/tinytest/test-misc.R b/inst/tinytest/test-misc.R index c6dbec34..98eee179 100644 --- a/inst/tinytest/test-misc.R +++ b/inst/tinytest/test-misc.R @@ -2,42 +2,42 @@ source("helpers.R") using("tinysnapshot") f = function() { - tpar(mfrow = c(1, 2)) + op = tpar(mfrow = c(1, 2)) plot(Temp ~ Day, data = airquality, log = "x") tinyplot(Temp ~ Day, data = airquality, log = "x") + tpar(op) } expect_snapshot_plot(f, label = "arg_log_x") f = function() { - tpar(mfrow = c(1, 2)) + op = tpar(mfrow = c(1, 2)) plot(Temp ~ Day, data = airquality, log = "y") tinyplot(Temp ~ Day, data = airquality, log = "y") + tpar(op) } expect_snapshot_plot(f, label = "arg_log_y") f = function() { - tpar(mfrow = c(1, 2)) + op = tpar(mfrow = c(1, 2)) plot(Temp ~ Day, data = airquality, log = "xy") tinyplot(Temp ~ Day, data = airquality, log = "xy") + tpar(op) } expect_snapshot_plot(f, label = "arg_log_xy") f = function() { - tpar(mfrow = c(1, 2)) + op = tpar(mfrow = c(1, 2)) plot(Temp ~ Day, data = airquality, log = "yx") tinyplot(Temp ~ Day, data = airquality, log = "yx") + tpar(op) } expect_snapshot_plot(f, label = "arg_log_yx") -## Sidestep test fails due to new (R 4.4.0) density grid value calculations. ## https://bugs.r-project.org/show_bug.cgi?id=18337 -exit_if_not(getRversion() <= "4.3.3") -## Note: Once 4.4.0 is released we can either generate some new plots or -## test with something like: -# f = function() tinyplot(..., old.coords=TRUE)) +# exit_if_not(getRversion() >= "4.4.0") f = function() { - tpar(mfrow = c(1, 1)) + op = tpar(mfrow = c(1, 1)) m = transform(mtcars, cyl = factor(cyl)) pred = predict(lm(mpg ~ wt + cyl, m), interval = "confidence") m = cbind(m, pred) @@ -49,5 +49,6 @@ f = function() { m, tinyplot(wt, mpg, by = cyl, pch = 16, add = TRUE) ) + tpar(op) } expect_snapshot_plot(f, label = "addTRUE") \ No newline at end of file diff --git a/inst/tinytest/test-palette.R b/inst/tinytest/test-palette.R index 5c363ad9..f0c2ccfa 100644 --- a/inst/tinytest/test-palette.R +++ b/inst/tinytest/test-palette.R @@ -51,6 +51,17 @@ f = function() { } expect_error(f()) +# Test alpha transparency arg +f = function() { + tinyplot( + Sepal.Length ~ Petal.Length | Species, iris, + pch = 19, + palette = "tableau", + alpha = 0.5 + ) +} +expect_snapshot_plot(f, label = "palette_alpha") + # Test function f = function() { tinyplot( diff --git a/inst/tinytest/test-par_restore.R b/inst/tinytest/test-restore_par.R similarity index 59% rename from inst/tinytest/test-par_restore.R rename to inst/tinytest/test-restore_par.R index 9e41c904..d87cb230 100644 --- a/inst/tinytest/test-par_restore.R +++ b/inst/tinytest/test-restore_par.R @@ -1,12 +1,13 @@ source("helpers.R") using("tinysnapshot") -## Skip failing test in R devel due to some minor esoteric difference coming up -## in R 4.4.0. Can revert once it reaches release for local testing. -exit_if_not(getRversion() <= "4.3.3") +# ## Avoid test fails on older R versions (pre 4.4.0) due to slight change in +# ## density grid value calculations. +# ## https://bugs.r-project.org/show_bug.cgi?id=18337 +# exit_if_not(getRversion() >= "4.4.0") -op = tpar() +op = par(no.readonly = TRUE) f1 = function() { tinyplot( @@ -16,7 +17,7 @@ f1 = function() { ) points(6,3, pch = 17, col = "hotpink", cex = 1.5) } -expect_snapshot_plot(f1, label = "par_restore_bottom") +expect_snapshot_plot(f1, label = "restore_par_bottom") f2 = function() { tinyplot( @@ -28,10 +29,10 @@ f2 = function() { lines(lowess(mtcars[["wt"]], mtcars[["mpg"]])) plot(1:10) } -expect_snapshot_plot(f2, label = "par_restore_FALSE") +expect_snapshot_plot(f2, label = "restore_par_FALSE") -# restore original par settings and then rerun with par_restore=TRUE -tpar(op) +# restore original par settings and then rerun with restore.par=TRUE +par(op) f3 = function() { tinyplot( @@ -39,9 +40,9 @@ f3 = function() { pch = 19, grid = grid(), legend = legend("right!", title = "How many cylnders do you have?"), - par_restore = TRUE + restore.par = TRUE ) lines(lowess(mtcars[["wt"]], mtcars[["mpg"]])) plot(1:10) } -expect_snapshot_plot(f3, label = "par_restore_TRUE") +expect_snapshot_plot(f3, label = "restore_par_TRUE") diff --git a/man/draw_legend.Rd b/man/draw_legend.Rd index 24e00060..000fa629 100644 --- a/man/draw_legend.Rd +++ b/man/draw_legend.Rd @@ -23,7 +23,7 @@ draw_legend( ) } \arguments{ -\item{legend}{Legend placement keyword or list, passed down from \code{tinyplot}.} +\item{legend}{Legend placement keyword or list, passed down from \link{tinyplot}.} \item{legend_args}{Additional legend arguments to be passed to \code{legend()}.} @@ -31,19 +31,19 @@ draw_legend( \item{lgnd_labs}{The labels passed to \code{legend(legend = ...)}.} -\item{type}{Plotting type(s), passed down from \code{tinyplot}.} +\item{type}{Plotting type(s), passed down from \link{tinyplot}.} -\item{pch}{Plotting character(s), passed down from \code{tinyplot}.} +\item{pch}{Plotting character(s), passed down from \link{tinyplot}.} -\item{lty}{Plotting linetype(s), passed down from \code{tinyplot}.} +\item{lty}{Plotting linetype(s), passed down from \link{tinyplot}.} -\item{lwd}{Plotting line width(s), passed down from \code{tinyplot}.} +\item{lwd}{Plotting line width(s), passed down from \link{tinyplot}.} -\item{col}{Plotting colour(s), passed down from \code{tinyplot}.} +\item{col}{Plotting colour(s), passed down from \link{tinyplot}.} -\item{bg}{Plotting character background fill colour(s), passed down from \code{tinyplot}.} +\item{bg}{Plotting character background fill colour(s), passed down from \link{tinyplot}.} -\item{cex}{Plotting character expansion(s), passed down from \code{tinyplot}.} +\item{cex}{Plotting character expansion(s), passed down from \link{tinyplot}.} \item{gradient}{Logical indicating whether a continuous gradient swatch should be used to represent the colors.} @@ -59,7 +59,11 @@ for which the default values are \code{c(1.0, 0.1)}.} keyword position is "bottom!", in which case we need to bump the legend margin a bit further.} -\item{new_plot}{Should we be calling plot.new internally?} +\item{new_plot}{Logical. Should we be calling plot.new internally?} +} +\value{ +No return value, called for side effect of producing a(n empty) plot +with a legend in the margin. } \description{ Internal function used to calculate the placement of (including diff --git a/man/figures/README-quickstart2-1.png b/man/figures/README-quickstart2-1.png index d91ee9eb..524fdb33 100644 Binary files a/man/figures/README-quickstart2-1.png and b/man/figures/README-quickstart2-1.png differ diff --git a/man/figures/README-quickstart3-1.png b/man/figures/README-quickstart3-1.png index e4527d66..be9edd7c 100644 Binary files a/man/figures/README-quickstart3-1.png and b/man/figures/README-quickstart3-1.png differ diff --git a/man/figures/README-quickstart4-1.png b/man/figures/README-quickstart4-1.png index a98f899f..ab9eb45a 100644 Binary files a/man/figures/README-quickstart4-1.png and b/man/figures/README-quickstart4-1.png differ diff --git a/man/figures/README-quickstart5-1.png b/man/figures/README-quickstart5-1.png index ed53420d..6c5b230c 100644 Binary files a/man/figures/README-quickstart5-1.png and b/man/figures/README-quickstart5-1.png differ diff --git a/man/get_saved_par.Rd b/man/get_saved_par.Rd new file mode 100644 index 00000000..49b16ec5 --- /dev/null +++ b/man/get_saved_par.Rd @@ -0,0 +1,113 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/get_saved_par.R +\name{get_saved_par} +\alias{get_saved_par} +\title{Retrieve the saved graphical parameters} +\usage{ +get_saved_par(when = c("before", "after")) +} +\arguments{ +\item{when}{character. From when should the saved parameters be retrieved? +Either "before" (the default) or "after" the preceding \code{tinyplot} call.} +} +\value{ +A list of \code{\link[graphics]{par}} settings. +} +\description{ +Convenience function for retrieving the graphical parameters +(i.e., the full list of \code{tag = value} pairs held in +\code{\link[graphics]{par}}) from either immediately before or +immediately after the most recent \link{tinyplot} call. +} +\details{ +A potential side-effect of \link{tinyplot} is that it can change a user's +\code{\link[graphics]{par}} settings. For example, it may adjust the inner +and outer plot margins to make space for an automatic legend; see +\link{draw_legend}. While it is possible to immediately restore the original +\code{\link[graphics]{par}} settings upon exit via the +\code{tinyplot(..., restore.par = TRUE)} argument, this is not the default +behaviour. The reason being that we need to preserve the adjusted parameter +settings in case users want to add further graphical annotations to their +plot (e.g., \code{\link[graphics]{abline}}, \code{\link[graphics]{text}}, +etc.) Nevertheless, it may still prove desirable to recall and reset these +original graphical parameters after the fact (e.g., once all these extra +annotations have been added). That is the purpose of this \link{get_saved_par} +function. + +Of course, users may prefer to manually capture and reset graphical +parameters, as per the standard method described in the +\code{\link[graphics]{par}} documentation. For example: + +\if{html}{\out{
}}\preformatted{op = par(no.readonly = TRUE) # save current par settings +# +par(op) # reset original pars +}\if{html}{\out{
}} + +This standard manual approach may be safer than \link{get_saved_par} because it +offers more precise control. Specifically, the value of \link{get_saved_par} +itself will be reset after ever new \link{tinyplot} call; i.e. it may inherit an +already-changed set of parameters. Users should bear these trade-offs in +mind when deciding which approach to use. As a general rule, +\link{get_saved_par} offers the convenience of resetting the original +\code{\link[graphics]{par}} settings even if a user forgot to save them +beforehand. But one should avoid invoking it after a series of consecutive +\link{tinyplot} calls. + +Finally, note that users can always call \code{\link[grDevices]{dev.off}} +to reset all \code{\link[graphics]{par}} settings to their defaults. +} +\examples{ +# +# Contrived example where we draw a grouped scatterplot with a legend and +# manually add corresponding best fit lines for each group... +# + +# First draw the grouped scatterplot +tinyplot(Sepal.Length ~ Petal.Length | Species, iris) + +# Preserving adjusted par settings is good for adding elements to our plot +for (s in levels(iris$Species)) { + abline( + lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), + col = which(levels(iris$Species)==s) + ) +} + +# Get saved par from before the preceding tinyplot call (but don't use yet) +sp = get_saved_par("before") + +# Note the changed margins will affect regular plots too, which is probably +# not desirable +plot(1:10) + +# Reset the original parameters (could use `par(sp)` here) +tpar(sp) +# Redraw our simple plot with our corrected right margin +plot(1:10) + +# +# Quick example going the other way, "correcting" for par.restore = TRUE... +# + +tinyplot(Sepal.Length ~ Petal.Length | Species, iris, restore.par = TRUE) +# Our added best lines will be wrong b/c of misaligned par +for (s in levels(iris$Species)) { + abline( + lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), + col = which(levels(iris$Species)==s), lty = 2 + ) +} +# grab the par settings from the _end_ of the preceding tinyplot call to fix +tpar(get_saved_par("after")) +# now the best lines are correct +for (s in levels(iris$Species)) { + abline( + lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), + col = which(levels(iris$Species)==s) + ) +} + +# reset again to original saved par settings before exit +tpar(sp) + +} diff --git a/man/tinyplot-package.Rd b/man/tinyplot-package.Rd index bf9a0826..e7fa9dc3 100644 --- a/man/tinyplot-package.Rd +++ b/man/tinyplot-package.Rd @@ -3,36 +3,22 @@ \docType{package} \name{tinyplot-package} \alias{tinyplot-package} -\title{tinyplot: Lightweight extension of the base R graphics system, with -support for automatic legends, facetting, and several other enhancements.} +\title{tinyplot: Lightweight Extension of the Base R Graphics System} \description{ -The goal of \strong{tinyplot} is to provides a lightweight extension -of the base R graphics system with various convenience features, -particularly for representing groups with your data. For example, the core -\code{tinyplot()} function (alias: \code{plt()} with no vowels) makes it easy to plot -different categories of a dataset in a single function call and highlight -these categories (groups) using modern colour palettes. Coincident with -this grouping support, \code{tinyplot()} also produces automatic legends with -scope for further customization. While the package offers several other -enhancements like facets, it tries as far as possible to be a drop-in -replacement for the equivalent base plotting calls. Users should generally -be able to swap a valid \code{plot()} call with \code{tinyplot()} without any changes -to the expected output. -} -\details{ -\code{tinyplot-package} +\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} + +Lightweight extension of the base R graphics system, with support for automatic legends, facets, and various other enhancements. } \seealso{ Useful links: \itemize{ \item \url{https://grantmcdermott.com/tinyplot/} - \item \url{http://grantmcdermott.com/tinyplot/} \item Report bugs at \url{https://github.com/grantmcdermott/tinyplot/issues} } } \author{ -\strong{Maintainer}: Grant McDermott \email{gmcd@amazon.com} +\strong{Maintainer}: Grant McDermott \email{gmcd@amazon.com} (\href{https://orcid.org/0000-0001-7883-8573}{ORCID}) Authors: \itemize{ diff --git a/man/tinyplot.Rd b/man/tinyplot.Rd index fb0e384e..11e47a91 100644 --- a/man/tinyplot.Rd +++ b/man/tinyplot.Rd @@ -38,11 +38,12 @@ tinyplot(x, ...) col = NULL, bg = NULL, fill = NULL, + alpha = NULL, cex = 1, - par_restore = FALSE, + restore.par = FALSE, ymin = NULL, ymax = NULL, - ribbon_alpha = 0.2, + ribbon.alpha = NULL, add = FALSE, file = NULL, width = NULL, @@ -71,7 +72,7 @@ tinyplot(x, ...) col = NULL, lty = NULL, lwd = NULL, - par_restore = FALSE, + restore.par = FALSE, formula = NULL, subset = NULL, na.action = NULL, @@ -102,7 +103,7 @@ tinyplot(x, ...) lwd = NULL, bg = NULL, fill = NULL, - par_restore = FALSE, + restore.par = FALSE, ... ) @@ -307,38 +308,57 @@ features are deferred to some other graphical parameter (i.e., passing the \item{bg}{background fill color for the open plot symbols 21:25 (see \code{points.default}), as well as ribbon and area plot types. For the latter group---including filled density plots---an automatic alpha transparency -adjustment will be applied (see the \code{ribbon_alpha} argument further below). -Users can also supply a special \code{bg = "by"} convenience argument, in which -case the background fill will inherit the automatic group coloring -intended for the \code{col} argument. Note that this grouped inheritance will -persist even if the \code{col} defaults are themselves overridden. For example, -\code{tinyplot(y ~ x | z, data = fakedata, pch = 22, col = "blue", bg = "by")} -will yield filled squares with a blue border.} +adjustment will be applied (see the \code{ribbon.alpha} argument further below). +Users can also supply either one of two special convenience arguments that +will cause the background fill to inherit the automatic grouped coloring +behaviour of \code{col}: +\itemize{ +\item \code{bg = "by"} will insert a background fill that inherits the main color +mappings from \code{col}. +\item \verb{by = } (i.e., a numeric in the range \verb{[0,1]}) will insert +a background fill that inherits the main color mapping(s) from \code{col}, but +with added alpha-transparency. +} + +For both of these convenience arguments, note that the (grouped) \code{bg} +mappings will persist even if the (grouped) \code{col} defaults are themselves +overridden. This can be useful if you want to preserve the grouped palette +mappings by background fill but not boundary color, e.g. filled points. See +examples.} \item{fill}{alias for \code{bg}. If non-NULL values for both \code{bg} and \code{fill} are provided, then the latter will be ignored in favour of the former.} +\item{alpha}{a numeric in the range \verb{[0,1]} for adjusting the alpha channel +of the color palette, where 0 means transparent and 1 means opaque. Use +fractional values, e.g. \code{0.5} for semi-transparency.} + \item{cex}{character expansion. A numerical vector (can be a single value) giving the amount by which plotting characters and symbols should be scaled relative to the default. Note that NULL is equivalent to 1.0, while NA renders the characters invisible.} -\item{par_restore}{a logical value indicating whether the \code{par} settings -prior to calling \code{tinyplot} should be restored on exit. Defaults to FALSE, -which makes it possible to add elements to the plot after it has been -drawn. However, note the the outer margins of the graphics device may have -been altered to make space for the \code{tinyplot} legend. Users can opt out of -this persistent behaviour by setting to TRUE instead. (Another option would -be calling \code{dev.off()} to reset all \code{par} settings to their defaults.)} +\item{restore.par}{a logical value indicating whether the +\code{\link[graphics]{par}} settings prior to calling \code{tinyplot} should be +restored on exit. Defaults to FALSE, which makes it possible to add +elements to the plot after it has been drawn. However, note the the outer +margins of the graphics device may have been altered to make space for the +\code{tinyplot} legend. Users can opt out of this persistent behaviour by +setting to TRUE instead. See also \link{get_saved_par} for another option to +recover the original \code{\link[graphics]{par}} settings, as well as +longer discussion about the trade-offs involved.} \item{ymin, ymax}{minimum and maximum coordinates of interval plot types. Only used when the \code{type} argument is one of "pointrange", "errorbar", or "ribbon".} -\item{ribbon_alpha}{numeric factor modifying the opacity alpha of any ribbon -shading; typically in \verb{[0, 1]}. Default value is 0.2. Only used when -\code{type = "ribbon"}, or when the \code{bg} fill argument is specified in a density -plot (since filled density plots are converted to ribbon plots internally).} +\item{ribbon.alpha}{numeric factor modifying the opacity alpha of any ribbon +shading; typically in \verb{[0, 1]}. Only used when \code{type = "ribbon"}, or when +the \code{bg} fill argument is specified in a density plot (since filled density +plots are converted to ribbon plots internally). If an an applicable plot +type is called but no explicit value is provided, then will default to +\code{tpar("ribbon.alpha")} (i.e., probably \code{0.2} unless this has been +overridden by the user in their global settings.)} \item{add}{logical. If TRUE, then elements are added to the current plot rather than drawing a new plot window. Note that the automatic legend for the @@ -383,6 +403,9 @@ should not be specified in the same call.} \item{subset, na.action, drop.unused.levels}{arguments passed to \code{model.frame} when extracting the data from \code{formula} and \code{data}.} } +\value{ +No return value, called for side effect of producing a plot. +} \description{ Enhances the base \code{\link[graphics]{plot}} function. Supported features include automatic legends and facets for grouped data, additional plot types, @@ -397,25 +420,21 @@ out existing \code{plot} calls for \code{tinyplot} (or its shorthand alias \code without causing unexpected changes to the output. } \examples{ - -# save graphics parameters to restore them later -op = tpar() - - +#' aq = transform( airquality, Month = factor(Month, labels = month.abb[unique(Month)]) ) -# tinyplot should be a drop-in replacement for (most) regular plot calls. For -# example: +# In most cases, `tinyplot` should be a drop-in replacement for regular +# `plot` calls. For example: -par(mfrow = c(1, 2)) +op = tpar(mfrow = c(1, 2)) plot(0:10, main = "plot") tinyplot(0:10, main = "tinyplot") +tpar(op) # restore original layout -# restore graphics parameters -par(op) +# Aside: `tinyplot::tpar()` is a (near) drop-in replacement for `par()` # Unlike vanilla plot, however, tinyplot allows you to characterize groups # using either the `by` argument or equivalent `|` formula syntax. @@ -431,12 +450,36 @@ tinyplot(Temp ~ Day | Month, data = aq) ## formula method plt(Temp ~ Day | Month, data = aq) ## shorthand alias # Use standard base plotting arguments to adjust features of your plot. -# For example, change `pch` (plot character) to get filled points. +# For example, change `pch` (plot character) to get filled points and `cex` +# (character expansion) to increase their size. + +tinyplot( + Temp ~ Day | Month, + data = aq, + pch = 16, + cex = 2 +) + +# We can add alpha transparency for overlapping points + +tinyplot( + Temp ~ Day | Month, + data = aq, + pch = 16, + cex = 2, + alpha = 0.3 +) +# To get filled points with a common solid background color, use an +# appropriate plotting character (21:25) and combine with one of the special +# `bg` convenience arguments. tinyplot( Temp ~ Day | Month, data = aq, - pch = 16 + pch = 21, # use filled circles + cex = 2, + bg = 0.3, # numeric in [0,1] adds a grouped background fill with transparency + col = "black" # override default color mapping; give all points a black border ) # Converting to a grouped line plot is a simple matter of adjusting the @@ -522,7 +565,6 @@ tinyplot( # palettes, depending on the number of groups. However, all palettes listed # by `palette.pals()` and `hcl.pals()` are supported as convenience strings, # or users can supply a valid palette-generating function for finer control -# over transparency etc. tinyplot( Temp ~ Day | Month, @@ -532,18 +574,20 @@ tinyplot( ) # It's possible to further customize the look of you plots using familiar -# arguments and base plotting theme settings (e.g., via `par`). +# arguments and base plotting theme settings (e.g., via `(t)par`). tpar(family = "HersheySans", las = 1) tinyplot( Temp ~ Day | Month, data = aq, type = "b", pch = 16, - palette = palette.colors(palette = "tableau", alpha = 0.5), + palette = "tableau", alpha = 0.5, main = "Daily temperatures by month", frame = FALSE, grid = TRUE ) -par(op) # revert original graphics parameters +# Note: For more examples and a detailed walkthrough, please see the +# introductory tinyplot tutorial available online: +# https://grantmcdermott.com/tinyplot/vignettes/intro_tutorial.html } diff --git a/man/tpar.Rd b/man/tpar.Rd index 38a8b25c..7cde1771 100644 --- a/man/tpar.Rd +++ b/man/tpar.Rd @@ -12,17 +12,30 @@ parameters typically supported by \code{\link[graphics]{par}}, as well as the \code{tinyplot}-specific ones described in the 'Graphical Parameters' section below.} } +\value{ +When parameters are set, their previous values are returned in an +invisible named list. Such a list can be passed as an argument to \code{tpar} to +restore the parameter values. + +When just one parameter is queried, the value of that parameter is returned +as (atomic) vector. When two or more parameters are queried, their values +are returned in a list, with the list names giving the parameters. + +Note the inconsistency: setting one parameter returns a list, but querying +one parameter returns a vector. +} \description{ -\code{tpar} extends \code{\link[graphics]{par}}, serving as a drop-in +Extends \code{\link[graphics]{par}}, serving as a (near) drop-in replacement for setting or querying graphical parameters. The key -difference is that, beyond supporting the standard group of R graphical -parameters, \code{tpar} also supports additional graphical parameters that are -provided by \code{tinyplot}. Similar to \code{\link[graphics]{par}}, parameters -are set by passing appropriate \code{key = value} argument pairs, and multiple -parameters can be set or queried at the same time. +differences is that, beyond supporting the standard group of R graphical +parameters in \code{\link[graphics]{par}}, \code{tpar} also supports additional +graphical parameters that are provided by \code{tinyplot}. Similar to +\code{\link[graphics]{par}}, parameters are set by passing appropriate +\code{key = value} argument pairs, and multiple parameters can be set or queried +at the same time. } \details{ -The \code{tinyplot}-specfic parameters are saved in an internal +The \code{tinyplot}-specific parameters are saved in an internal environment called \code{.tpar} for performance and safety reasons. However, they can also be set at package load time via \code{\link[base]{options}}, which may prove convenient for users that want to enable different default @@ -32,7 +45,14 @@ take a \verb{tinyplot_*} prefix, e.g. For their part, any "base" graphical parameters are caught dynamically and passed on to \code{\link[graphics]{par}} as appropriate. Technically, only -parameters that satisify \code{par(..., no.readonly = TRUE)} are evaluated. +parameters that satisfy \code{par(..., no.readonly = TRUE)} are evaluated. + +However, note the important distinction: \code{tpar} only evaluates parameters +from \code{\link[graphics]{par}} if they are passed \emph{explicitly} by the +user. This means that \code{tpar} should not be used to capture the (invisible) +state of a user's entire set of graphics parameters, i.e. \code{tpar()} != +\code{par()}. If you want to capture the \emph{all} existing graphics settings, then +you should rather use \code{par()} instead. } \section{Additional Graphical Parameters}{ @@ -69,6 +89,9 @@ parameters that satisify \code{par(..., no.readonly = TRUE)} are evaluated. \tab\tab\cr \tab\tab\cr \code{lmar} \tab\tab A numeric vector of form \code{c(inner, outer)} that gives the margin padding, in terms of lines, around the automatic \code{tinyplot} legend. Defaults to \code{c(1.0, 0.1)}, where the first number represents the "inner" margin between the legend and the plot region, and the second number represents the "outer" margin between the legend and edge of the graphics device. (Note that an exception for the definition of the "outer" legend margin occurs when the legend placement is \code{"top!"}, since the legend is placed above the plot region but below the main title. In such cases, the outer margin is relative to the existing gap between the title and the plot region, which is itself determined by \code{par("mar")[3]}.)\cr +\tab\tab\cr +\tab\tab\cr +\code{ribbon.alpha} \tab\tab Numeric factor in the range \verb{[0,1]} for modifying the opacity alpha of "ribbon" and "area" (and alike) type plots. Default value is \code{0.2}.\cr } } @@ -95,6 +118,10 @@ tinyplot(mpg ~ wt, data = mtcars, facet = ~am) # Reset back to original values tpar(op) +# Important: tpar() only evalutes parameters that have been passed explicitly +# by the user. So it it should not be used to query and set (restore) +# parameters that weren't explicitly requested, i.e. tpar() != par(). + # Note: The tinyplot-specific parameters can also be be set via `options` # with a `tinyplot_*` prefix, which can be convenient for enabling # different default behaviour at startup time (e.g., via an .Rprofile diff --git a/vignettes/intro_tutorial.Rmd b/vignettes/intro_tutorial.Rmd index b3099ef4..df25c5a8 100644 --- a/vignettes/intro_tutorial.Rmd +++ b/vignettes/intro_tutorial.Rmd @@ -105,7 +105,8 @@ For example, change `pch` (plot character) to get filled points. ```{r pch_16} tinyplot( Temp ~ Day | Month, data = aq, - pch = 16 + pch = 16, + cex = 2 ) ``` @@ -135,6 +136,20 @@ tinyplot( ) ``` +The `"by"` convenience argument is also available for mapping group colours to +background fill `bg` (alias `fill`). One use case is to override the grouped +border colours for filled plot characters and instead pass them through the +background fill. + +```{r} +tinyplot( + Temp ~ Day | Month, data = aq, + pch = 21, # use filled circles + col = "black", # override automatic group (border) colours of points + fill = "by" # use background fill by group instead +) +``` + ## Colours On the subject of group colours, the default palette should adjust automatically @@ -167,8 +182,21 @@ tinyplot( ``` Beyond these convenience strings, users can also supply a valid -palette-generating function for finer control over alpha transparency, colour -order, and so forth. We'll see a demonstration of this further below. +palette-generating function for finer control and additional options.^[For +example, if you have installed the **ggsci** package +([link][https://nanx.me/ggsci/index.html]) then you could use +`palette = ggsci::pal_npg()` to generate a palette consistent with those used by +the Nature Publishing Group.] You can also use the `alpha` argument to adjust +the (alpha) transparency of your colours: + +```{r} +tinyplot( + Temp ~ Day | Month, data = aq, + pch = 19, cex = 2, + palette = "tableau", + alpha = 0.3 +) +``` To underscore what we said earlier, colours are inherited from the user's current palette. So these can also be set globally, just as they can for the @@ -220,16 +248,32 @@ with( ) ``` -Finally, note that gradient legends are also supported for continuous grouping -variables. Gradient legends can be customized in a similar vein to the discrete -legends that we have seen so far (keyword positioning, palette choice, alpha -transparency, etc.) But here is a simple example that demonstrates the default -behaviour. +The examples that we have seen thus far are all based on discrete grouping +variables. However, please note that **tinyplot** also supports continuous +grouping variables, which automatically yield gradient legends. ```{r legend_gradient} tinyplot(Temp ~ Wind | Ozone, data = aq, pch = 19) ``` +Gradient legends (and plots) can be customized in an identical manner to +discrete legends by adjusting the keyword positioning, palette choice, alpha +transparency etc. Here is a quick adaptation of the previous plot to +demonstrate. Note that here we pass a special convenience argument to +`bg`/`fill`; if it detects a numeric in the range of `[0, 1]`, then it +automatically inherits the grouped colour mappings but with added transparency. + +```{r legend_gradient2} +tinyplot( + Temp ~ Wind | Ozone, data = aq, + pch = 21, # use filled plot character + cex = 2, + col = "black", # override automatic (grouped) border colour of points + fill = 0.5, # use background fill instead with added alpha transparency +) +``` + + ## Interval plots `tinyplot` adds supports for interval plots via the `"pointrange"`, `"errorbar"`, @@ -401,14 +445,14 @@ op = tpar( tinyplot( Temp ~ Day | Month, data = aq, type = "b", - palette = palette.colors(palette = "tableau", alpha = 0.5), + alpha = 0.5, main = "Daily temperatures by month" ) ``` -(For access to a wider array of fonts, you might consider the +_Note: For access to a much wider variety of fonts, you might consider the **showtext** package -([link](https://cran.r-project.org/web/packages/showtext/vignettes/introduction.html)).) +([link](https://cran.r-project.org/web/packages/showtext/vignettes/introduction.html))._ At the risk of repeating ourselves, the use of `(t)par` in the previous example again underscores the correspondence with the base graphics system. Because