|
| 1 | +#' @title Retrieve the saved graphical parameters |
| 2 | +#' |
| 3 | +#' @description Convenience function for retrieving the graphical parameters |
| 4 | +#' (i.e., the full list of `tag = value` pairs held in |
| 5 | +#' \code{\link[graphics]{par}}) from either immediately before or |
| 6 | +#' immediately after the most recent [tinyplot] call. |
| 7 | +#' |
| 8 | +#' @param when character. From when should the saved parameters be retrieved? |
| 9 | +#' Either "before" (the default) or "after" the preceding `tinyplot` call. |
| 10 | +#' |
| 11 | +#' @details A potential side-effect of [tinyplot] is that it can change a user's |
| 12 | +#' \code{\link[graphics]{par}} settings. For example, it may adjust the inner |
| 13 | +#' and outer plot margins to make space for an automatic legend; see |
| 14 | +#' [draw_legend]. While it is possible to immediately restore the original |
| 15 | +#' \code{\link[graphics]{par}} settings upon exit via the |
| 16 | +#' `tinyplot(..., restore.par = TRUE)` argument, this is not the default |
| 17 | +#' behaviour. The reason being that we need to preserve the adjusted parameter |
| 18 | +#' settings in case users want to add further graphical annotations to their |
| 19 | +#' plot (e.g., \code{\link[graphics]{abline}}, \code{\link[graphics]{text}}, |
| 20 | +#' etc.) Nevertheless, it may still prove desirable to recall and reset these |
| 21 | +#' original graphical parameters after the fact (e.g., once all these extra |
| 22 | +#' annotations have been added). That is the purpose of this [get_saved_par] |
| 23 | +#' function. |
| 24 | +#' |
| 25 | +#' Of course, users may prefer to manually capture and reset graphical |
| 26 | +#' parameters, as per the standard method described in the |
| 27 | +#' \code{\link[graphics]{par}} documentation. For example: |
| 28 | +#' |
| 29 | +#' ``` |
| 30 | +#' op = par(no.readonly = TRUE) # save current par settings |
| 31 | +#' # <do lots of (tiny)plotting> |
| 32 | +#' par(op) # reset original pars |
| 33 | +#' ``` |
| 34 | +#' |
| 35 | +#' This standard manual approach may be safer than [get_saved_par] because it |
| 36 | +#' offers more precise control. Specifically, the value of [get_saved_par] |
| 37 | +#' itself will be reset after ever new [tinyplot] call; i.e. it may inherit an |
| 38 | +#' already-changed set of parameters. Users should bear these trade-offs in |
| 39 | +#' mind when deciding which approach to use. As a general rule, |
| 40 | +#' [get_saved_par] offers the convenience of resetting the original |
| 41 | +#' \code{\link[graphics]{par}} settings even if a user forgot to save them |
| 42 | +#' beforehand. But one should avoid invoking it after a series of consecutive |
| 43 | +#' [tinyplot] calls. |
| 44 | +#' |
| 45 | +#' Finally, note that users can always call \code{\link[grDevices]{dev.off}} |
| 46 | +#' to reset all \code{\link[graphics]{par}} settings to their defaults. |
| 47 | +#' |
| 48 | +#' @returns A list of \code{\link[graphics]{par}} settings. |
| 49 | +#' |
| 50 | +#' @examples |
| 51 | +#' # |
| 52 | +#' # Contrived example where we draw a grouped scatterplot with a legend and |
| 53 | +#' # manually add corresponding best fit lines for each group... |
| 54 | +#' # |
| 55 | +#' |
| 56 | +#' # First draw the grouped scatterplot |
| 57 | +#' tinyplot(Sepal.Length ~ Petal.Length | Species, iris) |
| 58 | +#' |
| 59 | +#' # Preserving adjusted par settings is good for adding elements to our plot |
| 60 | +#' for (s in levels(iris$Species)) { |
| 61 | +#' abline( |
| 62 | +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), |
| 63 | +#' col = which(levels(iris$Species)==s) |
| 64 | +#' ) |
| 65 | +#' } |
| 66 | +#' |
| 67 | +#' # Get saved par from before the preceding tinyplot call (but don't use yet) |
| 68 | +#' sp = get_saved_par("before") |
| 69 | +#' |
| 70 | +#' # Note the changed margins will affect regular plots too, which is probably |
| 71 | +#' # not desirable |
| 72 | +#' plot(1:10) |
| 73 | +#' |
| 74 | +#' # Reset the original parameters (could use `par(sp)` here) |
| 75 | +#' tpar(sp) |
| 76 | +#' # Redraw our simple plot with our corrected right margin |
| 77 | +#' plot(1:10) |
| 78 | +#' |
| 79 | +#' # |
| 80 | +#' # Quick example going the other way, "correcting" for par.restore = TRUE... |
| 81 | +#' # |
| 82 | +#' |
| 83 | +#' tinyplot(Sepal.Length ~ Petal.Length | Species, iris, restore.par = TRUE) |
| 84 | +#' # Our added best lines will be wrong b/c of misaligned par |
| 85 | +#' for (s in levels(iris$Species)) { |
| 86 | +#' abline( |
| 87 | +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), |
| 88 | +#' col = which(levels(iris$Species)==s), lty = 2 |
| 89 | +#' ) |
| 90 | +#' } |
| 91 | +#' # grab the par settings from the _end_ of the preceding tinyplot call to fix |
| 92 | +#' tpar(get_saved_par("after")) |
| 93 | +#' # now the best lines are correct |
| 94 | +#' for (s in levels(iris$Species)) { |
| 95 | +#' abline( |
| 96 | +#' lm(Sepal.Length ~ Petal.Length, iris, subset = Species==s), |
| 97 | +#' col = which(levels(iris$Species)==s) |
| 98 | +#' ) |
| 99 | +#' } |
| 100 | +#' |
| 101 | +#' # reset again to original saved par settings before exit |
| 102 | +#' tpar(sp) |
| 103 | +#' |
| 104 | +#' @export |
| 105 | +get_saved_par <- function(when = c("before", "after")) { |
| 106 | + when = match.arg(when) |
| 107 | + par_env_name = paste0(".saved_par_", when) |
| 108 | + return(get(par_env_name, envir = get(".tinyplot_env", envir = parent.env(environment())))) |
| 109 | +} |
| 110 | + |
| 111 | +# (non-exported) companion function(s) for setting the original pars |
| 112 | +set_saved_par <- function(when = c("before", "after"), value) { |
| 113 | + when = match.arg(when) |
| 114 | + par_env_name = paste0(".saved_par_", when) |
| 115 | + assign(par_env_name, value, envir = get(".tinyplot_env", envir = parent.env(environment()))) |
| 116 | +} |
0 commit comments