Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types: abline, hline, vline #249

Merged
merged 9 commits into from
Nov 13, 2024
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
3 changes: 3 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ export(plt_add)
export(tinyplot)
export(tinyplot_add)
export(tpar)
export(type_abline)
export(type_area)
export(type_boxplot)
export(type_errorbar)
export(type_function)
export(type_glm)
export(type_hist)
export(type_histogram)
export(type_hline)
export(type_jitter)
export(type_lines)
export(type_lm)
Expand All @@ -30,6 +32,7 @@ export(type_ribbon)
export(type_segments)
export(type_spineplot)
export(type_spline)
export(type_vline)
importFrom(grDevices,adjustcolor)
importFrom(grDevices,as.raster)
importFrom(grDevices,col2rgb)
Expand Down
18 changes: 12 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Breaking changes:
plot type) should no longer be passed via `...` in the main plotting function.
Instead, these additional arguments must now be passed explicitly as part of the
corresponding `type_*()` function in the `type` argument. So, for example, you
should now use `plt(Nile, type = type_histogram(breaks = 30))` instead of
`plt(Nile, type = "histogram", breaks = 30)` if you wanted to adjust the number
should now use `tinyplot(Nile, type = type_histogram(breaks = 30))` instead of
`tinyplot(Nile, type = "histogram", breaks = 30)` if you wanted to adjust the number
of breaks. More details are provided below and also in the new dedicated
[Plot types vignette](https://grantmcdermott.com/tinyplot/vignettes/types.html).
The essential idea is that shortcut character types (here: `"histogram"`) all
Expand All @@ -23,7 +23,7 @@ behaviour by passing appropriate arguments. We're sorry to introduce a breaking
change, but this new approach should ensure that users have better control of
how their plots behave, and avoids guesswork on our side.
- `ribbon.alpha` is deprecated in `tinyplot()`. Use the `alpha` argument of the
`type_ribbon()` function instead: `plt(..., type = type_ribbon(alpha = 0.5))`
`type_ribbon()` function instead: `tinyplot(..., type = type_ribbon(alpha = 0.5))`

New features:

Expand All @@ -35,6 +35,12 @@ types enable a variety of additional features. (#222 @vincentarelbundock)
- `type_lm()` (shortcut: `"lm"`)
- `type_loess()` (shortcut: `"loess"`)
- `type_spline()` (shortcut: `"spline"`)
- New function-based types
- `type_abline()`: line with intercept and slope
- `type_hline()`: horizontal line
- `type_vline()`: verticla line
- `type_function()` arbitrary function.
- `type_spineplot()` (shortcut: `"spineplot"`) type for producing spine
- `type_function()` can trace arbitrary functions.
- New `type_spineplot()` (shortcut: `"spineplot"`) type for producing spine
plots and spinograms. These are modified versions of a histogram or mosaic
Expand All @@ -49,11 +55,11 @@ types enable a variety of additional features. (#222 @vincentarelbundock)
on the website.)
- The new `flip` argument allows for easily flipping (swapping) the orientation
of the x and y axes. This should work regardless of plot type, e.g.
`plt(~Sepal.Length | Species, data = iris, type = "density", flip = TRUE)`.
`tinyplot(~Sepal.Length | Species, data = iris, type = "density", flip = TRUE)`.
(#216 @grantmcdermott)
- `tpar()` gains additional `grid.col`, `grid.lty`, and `grid.lwd` arguments for
fine-grained control over the appearance of the default panel grid when
`plt(..., grid = TRUE)` is called. (#237 @grantmcdermott)
`tinyplot(..., grid = TRUE)` is called. (#237 @grantmcdermott)
- The new `tinyplot_add()` (alias: `plt_add()`) convenience function allows
easy layering of plots without having to specify repeat arguments. (#246
@vincentarelbundock)
Expand Down Expand Up @@ -229,7 +235,7 @@ adding transparency to plot elements and colours. Example use:
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
`tinyplot(lat ~ long | depth, data = quakes, pch = 21, cex = 2, bg = 0.2)`. (#129
@grantmcdermott)


Expand Down
17 changes: 17 additions & 0 deletions R/assertions.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ assert_choice = function(x, choice, null.ok = FALSE, name = as.character(substit
stop(msg, call. = FALSE)
}

check_true = function(x, null.ok = FALSE) {
if (is.null(x) && isTRUE(null.ok)) {
return(invisible(TRUE))
}
if (isTRUE(x)) {
return(invisible(TRUE))
}
return(FALSE)
}

assert_true = function(x, null.ok = FALSE, name = as.character(substitute(x))) {
msg = sprintf("`%s` must be true.", name)
if (!isTRUE(check_true(x, null.ok = null.ok))) {
stop(msg, call. = FALSE)
}
}

check_string = function(x, null.ok = FALSE) {
if (is.null(x) && isTRUE(null.ok)) {
return(invisible(TRUE))
Expand Down
79 changes: 79 additions & 0 deletions R/type_abline.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#' Add straight lines to a plot
#'
#' @inheritParams graphics::abline
#' @inheritParams tinyplot
#' @examples
#' mod = lm(mpg ~ hp, data = mtcars)
#' y = mtcars$mpg
#' yhat = predict(mod)
#' tinyplot(y, yhat, xlim = c(0, 40), ylim = c(0, 40))
#' tinyplot_add(type = type_abline(a = 0, b = 1))
#' @export
type_abline = function(a = 0, b = 1, col = NULL, lty = NULL, lwd = NULL) {
data_abline = function(datapoints, ...) {
if (nrow(datapoints) == 0) {
msg = "`type_abline() only works on existing plots with x and y data points."
stop(msg, call. = FALSE)
}
return(list())
}
draw_abline = function() {
fun = function(ifacet, data_facet, icol, ilty, ilwd, ...) {
nfacets = length(data_facet)

if (length(a) == 1) {
a = rep(a, nfacets)
} else if (length(a) != nfacets) {
msg = "Length of 'a' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (length(b) == 1) {
b = rep(b, nfacets)
} else if (length(b) != nfacets) {
msg = "Length of 'b' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(col)) {
col = icol
}
if (length(col) == 1) {
col = rep(col, nfacets)
} else if (length(col) != nfacets) {
msg = "Length of 'col' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lty)) {
lty = if (!is.null(ilty)) ilty else 1
}
if (length(lty) == 1) {
lty = rep(lty, nfacets)
} else if (length(lty) != nfacets) {
msg = "Length of 'lty' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lwd)) {
lwd = if (!is.null(ilwd)) ilwd else 1
}
if (length(lwd) == 1) {
lwd = rep(lwd, nfacets)
} else if (length(lwd) != nfacets) {
msg = "Length of 'lwd' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

abline(a = a[ifacet], b = b[ifacet], col = col[ifacet], lty = lty[ifacet], lwd = lwd[ifacet])
}
return(fun)
}
out = list(
draw = draw_abline(),
data = data_abline,
name = "abline"
)
class(out) = "tinyplot_type"
return(out)
}
70 changes: 70 additions & 0 deletions R/type_hline.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#' Trace a horizontal line on the plot
#'
#' @param h y-value(s) for horizontal line(s). Numeric of length 1 or equal to the number of facets.
#' @inheritParams graphics::abline
#' @inheritParams tinyplot
#' @examples
#' tinyplot(mpg ~ hp | factor(cyl), facet = ~ factor(cyl), data = mtcars)
#' tinyplot_add(type = type_hline(h = 12, col = "pink", lty = 3, lwd = 3))
#' @export
type_hline = function(h = 0, col = NULL, lty = NULL, lwd = NULL) {
data_hline = function(datapoints, ...) {
if (nrow(datapoints) == 0) {
msg = "`type_hline() only works on existing plots with x and y data points."
stop(msg, call. = FALSE)
}
return(list())
}
draw_hline = function() {
fun = function(ifacet, data_facet, icol, ilty, ilwd, ...) {
nfacets = length(data_facet)

if (length(h) == 1) {
h = rep(h, nfacets)
} else if (length(h) != nfacets) {
msg = "Length of 'h' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(col)) {
col = icol
}
if (length(col) == 1) {
col = rep(col, nfacets)
} else if (length(col) != nfacets) {
msg = "Length of 'col' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lty)) {
lty = if (!is.null(ilty)) ilty else 1
}
if (length(lty) == 1) {
lty = rep(lty, nfacets)
} else if (length(lty) != nfacets) {
msg = "Length of 'lty' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lwd)) {
lwd = if (!is.null(ilwd)) ilwd else 1
}
if (length(lwd) == 1) {
lwd = rep(lwd, nfacets)
} else if (length(lwd) != nfacets) {
msg = "Length of 'lwd' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

abline(h = h[ifacet], col = col[ifacet], lty = lty[ifacet], lwd = lwd[ifacet])
}
return(fun)
}
out = list(
draw = draw_hline(),
data = data_hline,
name = "hline"
)
class(out) = "tinyplot_type"
return(out)
}
77 changes: 77 additions & 0 deletions R/type_vline.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#' Trace a vertical line on the plot
#'
#' @param v x-value(s) for vertical line(s). Numeric of length 1 or equal to the number of facets.
#' @inheritParams tinyplot
#' @examples
#' tinyplot(mpg ~ hp, data = mtcars)
#' tinyplot_add(type = type_vline(150))
#'
#' # facet-specify location and colors
#' cols = c("black", "green", "orange")
#' tinyplot(mpg ~ hp | factor(cyl), facet = ~ factor(cyl), data = mtcars, col = cols)
#' tinyplot_add(type = type_vline(
#' v = c(100, 150, 200), col = cols, lty = 3, lwd = 3
#' ))
#' @export
type_vline = function(v = 0, col = "black", lty = 1, lwd = 1) {
assert_numeric(v)
data_vline = function(datapoints, ...) {
if (nrow(datapoints) == 0) {
msg = "`type_vline() only works on existing plots with x and y data points."
stop(msg, call. = FALSE)
}
return(list())
}
draw_vline = function() {
fun = function(ifacet, data_facet, icol, ilty, ilwd, ...) {
nfacets = length(data_facet)

if (length(v) == 1) {
v = rep(v, nfacets)
} else if (length(v) != nfacets) {
msg = "Length of 'v' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(col)) {
col = icol
}
if (length(col) == 1) {
col = rep(col, nfacets)
} else if (length(col) != nfacets) {
msg = "Length of 'col' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lty)) {
lty = if (!is.null(ilty)) ilty else 1
}
if (length(lty) == 1) {
lty = rep(lty, nfacets)
} else if (length(lty) != nfacets) {
msg = "Length of 'lty' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

if (is.null(lwd)) {
lwd = if (!is.null(ilwd)) ilwd else 1
}
if (length(lwd) == 1) {
lwd = rep(lwd, nfacets)
} else if (length(lwd) != nfacets) {
msg = "Length of 'lwd' must be 1 or equal to the number of facets"
stop(msg, call. = FALSE)
}

abline(v = v[ifacet], col = col[ifacet], lty = lty[ifacet], lwd = lwd[ifacet])
}
return(fun)
}
out = list(
draw = draw_vline(),
data = data_vline,
name = "vline"
)
class(out) = "tinyplot_type"
return(out)
}
20 changes: 14 additions & 6 deletions altdoc/quarto_website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ website:
file: vignettes/types.qmd
- text: Gallery
file: vignettes/gallery.qmd
# - section: $ALTDOC_MAN_BLOCK
- section: Reference
contents:
- section: Plotting functions
Expand All @@ -36,12 +35,15 @@ website:
file: man/draw_legend.qmd
- section: Plot types
contents:
#
- section: Shapes
contents:
- text: type_area, type_ribbon
- text: type_area
file: man/type_ribbon.qmd
- text: type_errorbar, type_pointrange
- text: type_ribbon
file: man/type_ribbon.qmd
- text: type_errorbar
file: man/type_errorbar.qmd
- text: type_pointrange
file: man/type_errorbar.qmd
- text: type_lines
file: man/type_lines.qmd
Expand All @@ -55,7 +57,6 @@ website:
file: man/type_rect.qmd
- text: type_segments
file: man/type_segments.qmd
#
- section: Visualizations
contents:
- text: type_boxplot
Expand All @@ -66,7 +67,14 @@ website:
file: man/type_jitter.qmd
- text: type_spineplot
file: man/type_spineplot.qmd
#
- section: Functions
contents:
- text: type_abline
file: man/type_abline.qmd
- text: type_hline
file: man/type_hline.qmd
- text: type_vline
file: man/type_vline.qmd
- section: Models
contents:
- text: type_glm
Expand Down
Loading
Loading