Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Suggests:
knitr
Config/Needs/website: altdoc (>= 0.7.2), future.apply
Encoding: UTF-8
RoxygenNote: 7.3.3
URL: https://grantmcdermott.com/tinyplot/
BugReports: https://github.com/grantmcdermott/tinyplot/issues
Roxygen: list(markdown = TRUE)
Config/roxygen2/version: 8.0.0
13 changes: 13 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,22 @@ where the formatting is also better._

### New features

- The `grid` argument (and `tpar("grid")`) now accepts character strings to
control axis-specific grids at different resolutions. Uppercase letters
(`"X"`, `"Y"`, `"XY"`) draw grid lines at the standard tick positions, while
lowercase letters (`"x"`, `"y"`, `"xy"`) draw a finer grid with additional
lines at the midpoints between ticks. Thanks to @zeileis for the suggestion.
(#578 @grantmcdermott)
- New `"dynamic"` theme that now serves as the foundation for all other dynamic
(tiny)themes. (#549 @grantmcdermott)

### Bug fixes

- Fixed `grid = grid()` not drawing grid lines on all facets. That said, logical
or character inputs (e.g., `grid = TRUE`, `grid = "xy"`) remain the more
idiomatic way to generate a background grid in `tinyplot`.
(#193 @grantmcdermott)

## v0.6.1

### Aesthetic changes
Expand Down
9 changes: 9 additions & 0 deletions R/assertions.R
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@ assert_length = function(x, len = 1, null.ok = FALSE, name = as.character(substi
}
}

assert_grid = function(x, null.ok = FALSE, name = as.character(substitute(x))) {
if (is.null(x) && isTRUE(null.ok)) return(invisible(TRUE))
if (is.logical(x) && length(x) == 1) return(invisible(TRUE))
valid_strings = c("x", "y", "X", "Y", "xy", "xY", "Xy", "XY")
if (is.character(x) && length(x) == 1 && x %in% valid_strings) return(invisible(TRUE))
msg = sprintf("`%s` must be a logical flag or a character string combining x/X and/or y/Y (e.g., \"xy\", \"XY\", \"xY\")", name)
stop(msg, call. = FALSE)
}

assert_logical = function(x, null.ok = FALSE, name = as.character(substitute(x))) {
if (is.null(x) && isTRUE(null.ok)) {
return(invisible(TRUE))
Expand Down
62 changes: 41 additions & 21 deletions R/facet.R
Original file line number Diff line number Diff line change
Expand Up @@ -514,34 +514,54 @@ draw_facet_window = function(

# panel grid lines
if (is.null(grid)) grid = get_tpar("grid", tpar_list = tpars)
if (!is.null(grid)) {
if (is.logical(grid)) {
## If grid is TRUE create a default grid. Rather than just calling the default grid()
## abline(... = pretty(extendrange(...)), ...) is used. Reason: pretty() is generic
## and works better for axes based on date/time classes. Exception: For axes in logs,
## resort to using grid() which is likely better handled there.
if (isTRUE(grid)) {
gnx = gny = NULL
if (!is.null(grid) && !isFALSE(grid)) {
gcol = get_tpar("grid.col", tpar_list = tpars)
glty = get_tpar("grid.lty", tpar_list = tpars)
glwd = get_tpar("grid.lwd", tpar_list = tpars)

if (isTRUE(grid)) {
draw_x = draw_y = TRUE
fine_x = fine_y = FALSE
} else if (is.character(grid)) {
draw_x = grepl("x", grid, fixed = TRUE) || grepl("X", grid, fixed = TRUE)
draw_y = grepl("y", grid, fixed = TRUE) || grepl("Y", grid, fixed = TRUE)
fine_x = grepl("x", grid, fixed = TRUE)
fine_y = grepl("y", grid, fixed = TRUE)
} else {
eval(grid) # issue #193
draw_x = draw_y = FALSE
}

if (draw_x || draw_y) {

if (draw_x) {
if (!is.null(xaxb)) {
abline(v = xaxb, col = get_tpar("grid.col", tpar_list = tpars), lty = get_tpar("grid.lty", tpar_list = tpars), lwd = get_tpar("grid.lwd", tpar_list = tpars))
gnx = NA
} else if (!any(c(par("xlog"), type == "boxplot"))) {
xg = xaxb
} else {
xg = if (!inherits(x, c("POSIXt", "Date"))) axTicks(side = 1) else axTicksDateTime(side = 1, x = x)
abline(v = xg, col = get_tpar("grid.col", tpar_list = tpars), lty = get_tpar("grid.lty", tpar_list = tpars), lwd = get_tpar("grid.lwd", tpar_list = tpars))
gnx = NA
}
if (fine_x && !par("xlog") && length(xg) >= 2L) {
xg = as.numeric(xg)
half = (xg[2L] - xg[1L]) / 2
xg = seq(xg[1L] - half, xg[length(xg)] + half, by = half)
}
abline(v = xg, col = gcol, lty = glty, lwd = glwd)
}

if (draw_y) {
if (!is.null(yaxb)) {
abline(h = yaxb, col = get_tpar("grid.col", tpar_list = tpars), lty = get_tpar("grid.lty", tpar_list = tpars), lwd = get_tpar("grid.lwd", tpar_list = tpars))
gny = NA
} else if (!any(c(par("ylog"), type == "boxplot"))) {
yg = yaxb
} else {
yg = if (!inherits(y, c("POSIXt", "Date"))) axTicks(side = 2) else axTicksDateTime(side = 2, x = x)
abline(h = yg, col = get_tpar("grid.col", tpar_list = tpars), lty = get_tpar("grid.lty", tpar_list = tpars), lwd = get_tpar("grid.lwd", tpar_list = tpars))
gny = NA
}
grid(nx = gnx, ny = gny, col = get_tpar("grid.col", tpar_list = tpars), lty = get_tpar("grid.lty", tpar_list = tpars), lwd = get_tpar("grid.lwd", tpar_list = tpars))
if (fine_y && !par("ylog") && length(yg) >= 2L) {
yg = as.numeric(yg)
half = (yg[2L] - yg[1L]) / 2
yg = seq(yg[1L] - half, yg[length(yg)] + half, by = half)
}
abline(h = yg, col = gcol, lty = glty, lwd = glwd)
}
} else {
grid

}
}

Expand Down
19 changes: 16 additions & 3 deletions R/tinyplot.R
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,15 @@
#' the plot. Can also use `frame` as an acceptable argument alias.
#' The default is to draw a frame if both axis types (set via `axes`, `xaxt`,
#' or `yaxt`) include axis lines.
#' @param grid argument for plotting a background panel grid, one of either:
#' - a logical (i.e., `TRUE` to draw the grid), or
#' @param grid argument for plotting a background panel grid, one of:
#' - a logical (i.e., `TRUE` to draw the grid on both axes).
#' - a character string controlling which axes get grid lines and at what
#' resolution. Uppercase letters (`"X"`, `"Y"`, `"XY"`) draw grid lines at
#' the standard axis tick positions (with the latter equivalent to `TRUE`),
#' while lowercase letters (`"x"`, `"y"`, `"xy"`) draw a finer grid with
#' additional lines at the midpoints between ticks. (Note: the finer grid
#' has no effect on log-scale axes, since tick positions already include
#' intermediate values.)
#' - a panel grid plotting function like `grid()`.
#' Note that this argument replaces the `panel.first` and `panel.last`
#' arguments from base `plot()` and tries to make the process more seamless
Expand Down Expand Up @@ -653,6 +660,12 @@ tinyplot.default = function(
par_first = get_saved_par("first")
if (is.null(par_first)) set_saved_par("first", par())

# Validate grid only for simple values; skip for unevaluated calls like grid()
# which are passed as language objects from tinyplot.formula via substitute(). (#193)
if (!is.null(grid) && !is.call(grid)) {
assert_grid(grid, null.ok = TRUE, name = "grid")
}

# save for tinyplot_add()
assert_logical(add)
if (!add) {
Expand Down Expand Up @@ -1580,7 +1593,7 @@ tinyplot.formula = function(
axes = axes,
frame.plot = frame.plot,
asp = asp,
grid = grid,
grid = substitute(grid), # issue #193
legend_args = legend_args,
pch = pch,
col = col,
Expand Down
4 changes: 2 additions & 2 deletions R/tpar.R
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
#' * `grid.col`: Character or (integer) numeric that specifies the color of the panel grid lines. Defaults to `"lightgray"`.
#' * `grid.lty`: Character or (integer) numeric that specifies the line type of the panel grid lines. Defaults to `"dotted"`.
#' * `grid.lwd`: Non-negative numeric giving the line width of the panel grid lines. Defaults to `1`.
#' * `grid`: Logical indicating whether a background panel grid should be added to plots automatically. Defaults to `NULL`, which is equivalent to `FALSE`.
#' * `grid`: Logical or character indicating whether a background panel grid should be added to plots automatically. Defaults to `NULL`, which is equivalent to `FALSE`. In addition to logical values, a character string can be used to control axis-specific grids: uppercase letters (`"X"`, `"Y"`, `"XY"`) draw grid lines at the standard axis tick positions (equivalent to `TRUE`), while lowercase letters (`"x"`, `"y"`, `"xy"`) draw a finer grid with additional lines at the midpoints between ticks.
#' * `lmar`: 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)`. The inner margin is the gap between the legend and the plot region, and the outer margin is the gap between the legend and the edge of the graphics device.
#' * `palette.qualitative`: Palette for qualitative colors. See the `palette` argument in `?tinyplot`.
#' * `palette.sequential`: Palette for sequential colors. See the `palette` argument in `?tinyplot`.
Expand Down Expand Up @@ -276,7 +276,7 @@ assert_tpar = function(.tpar) {
assert_numeric(.tpar[["lmar"]], len = 2, null.ok = TRUE, name = "lmar")
assert_numeric(.tpar[["ribbon.alpha"]], len = 1, lower = 0, upper = 1, null.ok = TRUE, name = "ribbon.alpha")
assert_numeric(.tpar[["grid.lwd"]], len = 1, lower = 0, null.ok = TRUE, name = "grid.lwd")
assert_flag(.tpar[["grid"]], null.ok = TRUE, name = "grid")
assert_grid(.tpar[["grid"]], null.ok = TRUE, name = "grid")
assert_numeric(.tpar[["file.res"]], len = 1, lower = 0, null.ok = TRUE, name = "file.res")
assert_numeric(.tpar[["file.height"]], len = 1, lower = 0, null.ok = TRUE, name = "file.height")
assert_numeric(.tpar[["file.width"]], len = 1, lower = 0, null.ok = TRUE, name = "file.width")
Expand Down
12 changes: 6 additions & 6 deletions inst/tinytest/_tinysnapshot/flip_boxplot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading