| Title: | Lightweight Extension of the Base R Graphics System |
|---|---|
| Description: | Lightweight extension of the base R graphics system, with support for automatic legends, facets, themes, and various other enhancements. |
| Authors: | Grant McDermott [aut, cre] (ORCID: <https://orcid.org/0000-0001-7883-8573>), Vincent Arel-Bundock [aut] (ORCID: <https://orcid.org/0000-0003-1995-6531>), Achim Zeileis [aut] (ORCID: <https://orcid.org/0000-0003-0918-3766>), Etienne Bacher [ctb], Miura Meng [ctb] (ORCID: <https://orcid.org/0009-0004-1522-1997>) |
| Maintainer: | Grant McDermott <[email protected]> |
| License: | Apache License (>= 2) |
| Version: | 0.8.0 |
| Built: | 2026-09-28 01:04:40 UTC |
| Source: | https://github.com/grantmcdermott/tinyplot |
Main exported function for drawing legends. Supports:
Inner and outer positioning (with "!" suffix)
Discrete and continuous (gradient) legends
Automatic margin adjustment
draw_legend( legend = NULL, legend_args = NULL, by_dep = NULL, lgnd_labs = NULL, labeller = NULL, type = NULL, pch = NULL, lty = NULL, lwd = NULL, col = NULL, bg = NULL, cex = NULL, gradient = FALSE, lmar = NULL, has_sub = FALSE, has_cap = FALSE, cap_text = NULL, new_plot = TRUE, draw = TRUE, soma_target = NULL, dynmar_title_mar = NULL, type_hints = NULL )draw_legend( legend = NULL, legend_args = NULL, by_dep = NULL, lgnd_labs = NULL, labeller = NULL, type = NULL, pch = NULL, lty = NULL, lwd = NULL, col = NULL, bg = NULL, cex = NULL, gradient = FALSE, lmar = NULL, has_sub = FALSE, has_cap = FALSE, cap_text = NULL, new_plot = TRUE, draw = TRUE, soma_target = NULL, dynmar_title_mar = NULL, type_hints = NULL )
legend |
Legend placement keyword or list, passed down from tinyplot. |
legend_args |
Additional legend arguments to be passed to
|
by_dep |
The (deparsed) "by" grouping variable name. |
lgnd_labs |
The labels passed to |
labeller |
Function, character keyword, or dictionary (named vector or
list) for formatting or relabelling the labels ( |
type |
Plotting type(s), passed down from tinyplot. |
pch |
Plotting character(s), passed down from tinyplot. |
lty |
Plotting linetype(s), passed down from tinyplot. |
lwd |
Plotting line width(s), passed down from tinyplot. |
col |
Plotting colour(s), passed down from tinyplot. |
bg |
Plotting character background fill colour(s), passed down from tinyplot. |
cex |
Plotting character expansion(s), passed down from tinyplot. |
gradient |
Logical indicating whether a continuous gradient swatch should be used to represent the colors. |
lmar |
Legend margins (in lines). Should be a numeric vector of the form
|
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. |
has_cap |
Logical. Does the plot have a caption. Only used if keyword position is "bottom!", in which case we need to bump the legend margin a bit further. |
cap_text |
Character. The caption text to draw below the legend when position is "bottom!". Ignored otherwise. |
new_plot |
Logical. Should we be calling plot.new internally? |
draw |
Logical. If |
soma_target |
Numeric. Shared outer margin target (in lines) for
multi-legend alignment. If |
dynmar_title_mar |
Numeric or |
type_hints |
Optional named list of semantic behaviour properties that a
plot type declares for itself (e.g. |
No return value, called for side effect of producing a(n empty) plot with a legend in the margin.
oldmar = par("mar") draw_legend( legend = "right!", ## default (other options incl, "left(!)", ""bottom(!)", etc.) legend_args = list(title = "Key", bty = "o"), lgnd_labs = c("foo", "bar"), type = "p", pch = 21:22, col = 1:2 ) # The legend is placed in the outer margin... box("figure", col = "cyan", lty = 4) # ... and the plot is proportionally adjusted against the edge of this # margin. box("plot") # You can add regular plot objects per normal now plot.window(xlim = c(1,10), ylim = c(1,10)) points(1:10) points(10:1, pch = 22, col = "red") axis(1); axis(2) # etc. # Important: A side effect of draw_legend is that the inner margins have been # adjusted. (Here: The right margin, since we called "right!" above.) par("mar") # To reset you should call `dev.off()` or just reset manually. par(mar = oldmar) # Note that the inner and outer margin of the legend itself can be set via # the `lmar` argument. (This can also be set globally via # `tpar(lmar = c(inner, outer))`.) draw_legend( legend_args = list(title = "Key", bty = "o"), lgnd_labs = c("foo", "bar"), type = "p", pch = 21:22, col = 1:2, lmar = c(0, 0.1) ## set inner margin to zero ) box("figure", col = "cyan", lty = 4) par(mar = oldmar) # Continuous (gradient) legends are also supported draw_legend( legend = "right!", legend_args = list(title = "Key"), lgnd_labs = LETTERS[1:5], col = hcl.colors(5), gradient = TRUE ## enable gradient legend ) par(mar = oldmar)oldmar = par("mar") draw_legend( legend = "right!", ## default (other options incl, "left(!)", ""bottom(!)", etc.) legend_args = list(title = "Key", bty = "o"), lgnd_labs = c("foo", "bar"), type = "p", pch = 21:22, col = 1:2 ) # The legend is placed in the outer margin... box("figure", col = "cyan", lty = 4) # ... and the plot is proportionally adjusted against the edge of this # margin. box("plot") # You can add regular plot objects per normal now plot.window(xlim = c(1,10), ylim = c(1,10)) points(1:10) points(10:1, pch = 22, col = "red") axis(1); axis(2) # etc. # Important: A side effect of draw_legend is that the inner margins have been # adjusted. (Here: The right margin, since we called "right!" above.) par("mar") # To reset you should call `dev.off()` or just reset manually. par(mar = oldmar) # Note that the inner and outer margin of the legend itself can be set via # the `lmar` argument. (This can also be set globally via # `tpar(lmar = c(inner, outer))`.) draw_legend( legend_args = list(title = "Key", bty = "o"), lgnd_labs = c("foo", "bar"), type = "p", pch = 21:22, col = 1:2, lmar = c(0, 0.1) ## set inner margin to zero ) box("figure", col = "cyan", lty = 4) par(mar = oldmar) # Continuous (gradient) legends are also supported draw_legend( legend = "right!", legend_args = list(title = "Key"), lgnd_labs = LETTERS[1:5], col = hcl.colors(5), gradient = TRUE ## enable gradient legend ) par(mar = oldmar)
Convenience function for retrieving the graphical parameters
(i.e., the full list of tag = value pairs held in
par) from either immediately before or
immediately after the most recent tinyplot call.
get_saved_par(when = c("before", "after", "first"))get_saved_par(when = c("before", "after", "first"))
when |
character. From when should the saved parameters be retrieved?
Either "before" (the default) or "after" the preceding |
A potential side-effect of tinyplot is that it can change a user's
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
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., abline, 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
par documentation. For example:
op = par(no.readonly = TRUE) # save current par settings # <do lots of (tiny)plotting> 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
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 dev.off
to reset all par settings to their defaults.
A list of par settings.
# # 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)# # 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)
Objects of class recordedtinyplot are returned by
tinyplot(..., record = TRUE). They are a thin wrapper around
recordPlot—thus conferring the same replay
functionality—but with the initializing plot call and state added, so that
recorded (tiny)plots play nicely with tinyplot_add() and
friends.
## S3 method for class 'recordedtinyplot' print(x, ...) ## S3 method for class 'recordedtinyplot' str(object, ...)## S3 method for class 'recordedtinyplot' print(x, ...) ## S3 method for class 'recordedtinyplot' str(object, ...)
x |
a |
... |
further arguments passed to |
object |
a |
Recording requires a device whose display list is enabled (see
dev.control); without one there is nothing to
record and the returned plot will replay blank. Interactive devices—the
plot pane of an IDE, say—typically enable it by default, whereas
file-based devices (png, pdf, svg, ...) do not. tinyplot() enables
it for any device that it opens itself via the file argument, and warns
if the current device is not recording.
Printing a recorded plot—either explicitly with print(), or simply by
evaluating it at the console—is what restores the initializing call, so
that a subsequent tinyplot_add() layers onto it. Calling
replayPlot() on the object instead redraws it
just as it would any other recording, but leaves the current plot context
untouched; layering after that route targets whichever plot was drawn last.
This class is experimental, as is the record argument that produces it.
print() replays the plot and returns x invisibly.
recordPlot and
replayPlot, which this class wraps and defers to
for the actual recording and replaying.
dev.control for enabling a device's display list,
without which there is nothing to record.
## Not run: p = tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, record = TRUE) tinyplot(1:10) # some other plot p # replay, restoring plot context tinyplot_add(type = "lm") # layers onto p, not onto the 1:10 plot ## End(Not run)## Not run: p = tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, record = TRUE) tinyplot(1:10) # some other plot p # replay, restoring plot context tinyplot_add(type = "lm") # layers onto p, not onto the 1:10 plot ## End(Not run)
Function for formatting label appearance, e.g. axis
ticks labels. This is what the top-level xaxl and yaxl arguments
from tinyplot ultimately get passed to.
tinylabel(x, labeller = NULL, na.ignore = TRUE, na.rm = TRUE)tinylabel(x, labeller = NULL, na.ignore = TRUE, na.rm = TRUE)
x |
a numeric or character vector |
labeller |
how the labels should be relabelled or reformatted. One of:
Note that an unnamed character vector of length greater than one is an
error, rather than a positional replacement of the labels. Such a vector
cannot be distinguished from a formatting keyword when |
na.ignore |
logical indicating whether the labelling function should
ignore |
na.rm |
logical indicating whether |
a character vector of the same length as x with the transformed
labels.
x = 1e4 tinylabel(x, "comma") tinylabel(x, ",") # same tinylabel(x, "$") # or "dollar" # a named vector acts as a dictionary: matched entries are replaced and the # rest are left alone tinylabel(c("setosa", "versicolor"), c(setosa = "SET")) # invoke tinylabel from a parent tinyplot call... # => x/yaxl for adjusting axes tick labels # => legend = list(labeller = ...) for adjusting the legend labels s77 = transform(data.frame(state.x77), Illiteracy = Illiteracy / 100) tinyplot(Life.Exp ~ Income | Illiteracy, data = s77, xaxl = '$', legend = list(labeller = '%')) # log example (combined with axis scaling) tinyplot(x = 10^c(10:0), y = 0:10, type = "b", log = "x", xaxl = "log") # combine with `x/yaxb` to adjust the actual tick marks ("break points") # at the same time tinyplot(x = 10^c(10:0), y = 0:10, type = "b", log = "x", xaxl = "log", xaxb = 10^c(1,3,5,7,9)) # ## custom function examples ## example I: date formatting dat = data.frame( date = seq(as.Date("2000/1/1"), by = "month", length.out = 12), trend = 1:12 + rnorm(12, sd = 1) ) tinyplot(trend ~ date, data = dat, xaxl = function(x) format(x, "%b, %Y")) ## example II: string wrapping # create a "vectorised" version of `base::strwrap` that breaks long # strings into new lines every 18 characters strwrap18 = function(x) sapply( strwrap(x, width = 18, simplify = FALSE), paste, collapse = "\n" ) # now demonstrate on a dataset with long y-tick labels dat2 = data.frame( x = rep(rnorm(100), 3), y = c( "tinyplot is a lightweight extension of the base R graphics system.", "R is a language for statistical computing.", "Data visualization is an essential skill." ) ) tinyplot(y ~ x, data = dat2, type = "j", yaxl = strwrap18, theme = "bw") # use theme for horizontal labels + dynamic marginx = 1e4 tinylabel(x, "comma") tinylabel(x, ",") # same tinylabel(x, "$") # or "dollar" # a named vector acts as a dictionary: matched entries are replaced and the # rest are left alone tinylabel(c("setosa", "versicolor"), c(setosa = "SET")) # invoke tinylabel from a parent tinyplot call... # => x/yaxl for adjusting axes tick labels # => legend = list(labeller = ...) for adjusting the legend labels s77 = transform(data.frame(state.x77), Illiteracy = Illiteracy / 100) tinyplot(Life.Exp ~ Income | Illiteracy, data = s77, xaxl = '$', legend = list(labeller = '%')) # log example (combined with axis scaling) tinyplot(x = 10^c(10:0), y = 0:10, type = "b", log = "x", xaxl = "log") # combine with `x/yaxb` to adjust the actual tick marks ("break points") # at the same time tinyplot(x = 10^c(10:0), y = 0:10, type = "b", log = "x", xaxl = "log", xaxb = 10^c(1,3,5,7,9)) # ## custom function examples ## example I: date formatting dat = data.frame( date = seq(as.Date("2000/1/1"), by = "month", length.out = 12), trend = 1:12 + rnorm(12, sd = 1) ) tinyplot(trend ~ date, data = dat, xaxl = function(x) format(x, "%b, %Y")) ## example II: string wrapping # create a "vectorised" version of `base::strwrap` that breaks long # strings into new lines every 18 characters strwrap18 = function(x) sapply( strwrap(x, width = 18, simplify = FALSE), paste, collapse = "\n" ) # now demonstrate on a dataset with long y-tick labels dat2 = data.frame( x = rep(rnorm(100), 3), y = c( "tinyplot is a lightweight extension of the base R graphics system.", "R is a language for statistical computing.", "Data visualization is an essential skill." ) ) tinyplot(y ~ x, data = dat2, type = "j", yaxl = strwrap18, theme = "bw") # use theme for horizontal labels + dynamic margin
Enhances the base plot function. Supported features
include automatic legends and facets for grouped data, additional plot types,
theme customization, and so on. Users can call either tinyplot(), or its
shorthand alias plt().
tinyplot(x, ...) ## Default S3 method: tinyplot( x = NULL, y = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, weights = NULL, labels = NULL, by = NULL, facet = NULL, facet.args = NULL, data = NULL, type = NULL, legend = NULL, main = NULL, sub = NULL, cap = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), xlim = NULL, ylim = NULL, axes = TRUE, xaxt = NULL, yaxt = NULL, xaxs = NULL, xpad = NULL, yaxs = NULL, ypad = NULL, xaxb = NULL, yaxb = NULL, xaxl = NULL, yaxl = NULL, xaxr = NULL, yaxr = NULL, las = NULL, log = "", flip = FALSE, frame.plot = NULL, grid = NULL, palette = NULL, pch = NULL, lty = NULL, lwd = NULL, col = NULL, bg = NULL, fill = NULL, alpha = NULL, cex = NULL, add = FALSE, draw = NULL, empty = FALSE, restore.par = FALSE, file = NULL, width = NULL, height = NULL, record = NULL, asp = NA, theme = NULL, ... ) ## S3 method for class 'formula' tinyplot( x = NULL, data = parent.frame(), facet = NULL, facet.args = NULL, type = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, weights = NULL, labels = NULL, xlim = NULL, ylim = NULL, main = NULL, sub = NULL, cap = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE, frame.plot = NULL, asp = NA, grid = NULL, pch = NULL, col = NULL, lty = NULL, lwd = NULL, restore.par = FALSE, formula = NULL, subset = NULL, na.action = NULL, drop.unused.levels = TRUE, ... ) ## S3 method for class 'density' tinyplot(x = NULL, type = c("l", "area"), ...) plt(x, ...)tinyplot(x, ...) ## Default S3 method: tinyplot( x = NULL, y = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, weights = NULL, labels = NULL, by = NULL, facet = NULL, facet.args = NULL, data = NULL, type = NULL, legend = NULL, main = NULL, sub = NULL, cap = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), xlim = NULL, ylim = NULL, axes = TRUE, xaxt = NULL, yaxt = NULL, xaxs = NULL, xpad = NULL, yaxs = NULL, ypad = NULL, xaxb = NULL, yaxb = NULL, xaxl = NULL, yaxl = NULL, xaxr = NULL, yaxr = NULL, las = NULL, log = "", flip = FALSE, frame.plot = NULL, grid = NULL, palette = NULL, pch = NULL, lty = NULL, lwd = NULL, col = NULL, bg = NULL, fill = NULL, alpha = NULL, cex = NULL, add = FALSE, draw = NULL, empty = FALSE, restore.par = FALSE, file = NULL, width = NULL, height = NULL, record = NULL, asp = NA, theme = NULL, ... ) ## S3 method for class 'formula' tinyplot( x = NULL, data = parent.frame(), facet = NULL, facet.args = NULL, type = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, weights = NULL, labels = NULL, xlim = NULL, ylim = NULL, main = NULL, sub = NULL, cap = NULL, xlab = NULL, ylab = NULL, ann = par("ann"), axes = TRUE, frame.plot = NULL, asp = NA, grid = NULL, pch = NULL, col = NULL, lty = NULL, lwd = NULL, restore.par = FALSE, formula = NULL, subset = NULL, na.action = NULL, drop.unused.levels = TRUE, ... ) ## S3 method for class 'density' tinyplot(x = NULL, type = c("l", "area"), ...) plt(x, ...)
x, y
|
the x and y arguments provide the x and y coordinates for the
plot. Any reasonable way of defining the coordinates is acceptable; most
likely the names of existing vectors or columns of data frames. See the
'Examples' section below, or the function
|
... |
other graphical parameters. If |
xmin, xmax, ymin, ymax
|
minimum and maximum coordinates of relevant area
or interval plot types. Only used when the |
weights |
an optional numeric vector of observation weights, of the same
length as the number of |
labels |
an optional vector of text labels for use with |
by |
grouping variable(s). The default behaviour is for groups to be
represented in the form of distinct colours, which will also trigger an
automatic legend. (See |
facet |
the faceting variable(s) that you want arrange separate plot windows by. Can be specified in various ways:
|
facet.args |
an optional list of arguments for controlling faceting
behaviour. (Ignored if
|
data |
a data.frame (or list) from which the variables in formula should be taken. A matrix is converted to a data frame. |
type |
character string or call to a
|
legend |
one of the following options:
|
main |
a main title for the plot, see also |
sub |
a subtitle for the plot. |
cap |
a caption for the plot, drawn at the bottom. Useful for
annotations like data sources. Best paired with a dynamic
|
xlab |
a label for the x axis, defaults to a description of x. |
ylab |
a label for the y axis, defaults to a description of y. |
ann |
a logical value indicating whether the default annotation (title and x and y axis labels) should appear on the plot. |
xlim |
the x limits (x1, x2) of the plot. Note that x1 > x2 is allowed
and leads to a reversed axis (although see the
|
ylim |
the y limits of the plot. Accepts the same input forms as |
axes |
logical or character. Should axes be drawn ( |
xaxt, yaxt
|
character specifying the type of x-axis and y-axis,
respectively. See |
xaxs, yaxs
|
character specifying the style of the interval calculation
used for the x-axis and y-axis, respectively. See
|
xpad, ypad
|
numeric specifying how much padding, as a fraction of the
data range, should be added to each end of the axes. If
|
xaxb, yaxb
|
numeric vector (or character vector, if appropriate) giving
the break points at which the axis tick-marks are to be drawn. Break points
outside the range of the data will be ignored if the associated axis
variable is categorical, or an explicit |
xaxl, yaxl
|
a function, character keyword, or dictionary (named vector
or list) for formatting or (re)labelling the x- or y-axis tick labels.
Passed to |
xaxr, yaxr
|
numeric giving the rotation of the x- or y-axis tick labels,
in degrees counter-clockwise; |
las |
numeric in |
log |
a character string which contains |
flip |
logical. Should the plot orientation be flipped, so that the y-axis is on the horizontal plane and the x-axis is on the vertical plane? Default is FALSE. |
frame.plot |
a logical indicating whether a box should be drawn around
the plot. Can also use |
grid |
argument for plotting a background panel grid, one of:
|
palette |
one of the following options:
|
pch |
plotting "character", i.e., symbol to use. Character, integer, or
vector of length equal to the number of categories in the |
lty |
line type. Character, integer, or vector of length equal to the
number of categories in the |
lwd |
line width. Numeric scalar or vector of length equal to the
number of categories in the |
col |
plotting color. Character, integer, or vector of length equal to
the number of categories in the |
bg |
background fill color for the open plot symbols 21:25 (see
For both of these convenience arguments, note that the (grouped) |
fill |
alias for |
alpha |
a numeric in the range |
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
|
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. See also tinyplot_add, which provides a convenient wrapper around this functionality for layering on top of an existing plot without having to repeat arguments. |
draw |
a function that draws directly on the plot canvas (before |
empty |
logical indicating whether the interior plot region should be
left empty. The default is |
restore.par |
a logical value indicating whether the
|
file |
character string giving the file path for writing a plot to disk.
If specified, the plot will not be displayed interactively, but rather sent
to the appropriate external graphics device (i.e.,
|
width |
numeric giving the plot width in inches. Together with |
height |
numeric giving the plot height in inches. Same considerations as
|
record |
(experimental) a logical value indicating whether the plot
should be recorded and returned as a replayable
Note that recording requires a device with an enabled display list (see
|
asp |
the y/xy/x aspect ratio, see |
theme |
keyword string (e.g. |
formula |
a |
subset, na.action, drop.unused.levels
|
arguments passed to |
Disregarding the enhancements that it supports, tinyplot tries as far as
possible to mimic the behaviour and syntax logic of the original base
plot function. Users should therefore be able to swap
out existing plot calls for tinyplot (or its shorthand alias plt),
without causing unexpected changes to the output.
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object, which
can be replayed later; see recordedtinyplot.
aq = transform( airquality, Month = factor(Month, labels = month.abb[unique(Month)]) ) # In most cases, `tinyplot` should be a drop-in replacement for regular # `plot` calls. For example: op = tpar(mfrow = c(1, 2)) plot(0:10, main = "plot") tinyplot(0:10, main = "tinyplot") tpar(op) # restore original layout # 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. with(aq, tinyplot(Day, Temp, by = Month)) ## atomic method tinyplot(Temp ~ Day | Month, data = aq) ## formula method # (Notice that we also get an automatic legend.) # You can also use the equivalent shorthand `plt()` alias if you'd like to # save on a few keystrokes 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 and `cex` # (character expansion) to increase their size. tinyplot( Temp ~ Day | Month, data = aq, pch = 16, cex = 2 ) # Use the special "by" convenience keyword if you would like to map these # aesthetic features over groups too (i.e., in addition to the default # colour grouping) tinyplot( Temp ~ Day | Month, data = aq, pch = "by", cex = "by" ) # 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`/`fill` convenience arguments. tinyplot( Temp ~ Day | Month, data = aq, 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 ) # Aside: For "bubble" plots, pass an appropriate vector to the `cex` arg. # This can be useful for depicting an additional dimension of the data (here: # Wind). tinyplot( Temp ~ Day | Month, data = aq, pch = 21, cex = aq$Wind, # map character size to another feature in the data bg = 0.3, col = "black" ) # Converting to a grouped line plot is a simple matter of adjusting the # `type` argument. tinyplot( Temp ~ Day | Month, data = aq, type = "l" ) # Similarly for other plot types, including some additional ones provided # directly by tinyplot, e.g. density plots or internal plots (ribbons, # pointranges, etc.) tinyplot( ~ Temp | Month, data = aq, type = "density", fill = "by" ) # Facet plots are supported too. Facets can be drawn on their own... tinyplot( Temp ~ Day, facet = ~Month, data = aq, type = "area", main = "Temperatures by month" ) # ... or combined/contrasted with the by (colour) grouping. aq = transform(aq, Summer = Month %in% c("Jun", "Jul", "Aug")) tinyplot( Temp ~ Day | Summer, facet = ~Month, data = aq, type = "area", palette = "dark2", main = "Temperatures by month and season" ) # Customize facets by passing a list of options to the companion `facet.args` # argument. For example, here we arrange the facets in a single row and also # turn off the inner axes labels to reduce redundancy. tinyplot( Temp ~ Day | Summer, facet = ~Month, facet.args = list(nrow = 1, axes = "outer"), data = aq, type = "area", palette = "dark2", main = "Temperatures by month and season" ) # Use a two-sided formula to arrange the facet windows in a fixed grid. # LHS -> facet rows; RHS -> facet columns aq$hot = aq$Temp >= 75 aq$windy = aq$Wind >= 15 tinyplot( Temp ~ Day, facet = windy ~ hot, facet.args = list(prefix = TRUE), # optional data = aq ) # (Note: The optional `prefix = TRUE` argument prepends the facet variable # names to the strip titles, making for a more informative display here.) # To add common elements to each facet, use the `draw` argument tinyplot( Temp ~ Day, facet = windy ~ hot, facet.args = list(prefix = TRUE), data = aq, draw = abline(h = 75, lty = 2, col = "hotpink") ) # The (automatic) legend position and look can be customized using # appropriate arguments. Note the trailing "!" in the `legend` position # argument below. This tells `tinyplot` to place the legend _outside_ the plot # area. tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = legend("bottom!", title = "Month of the year", bty = "o") ) # Use legend = "direct" to place text labels at the last point of each # group's data, coloured to match. Best suited to line-based plots with # x-sorted data, where "last" corresponds to "rightmost". The right # margin is automatically expanded to fit the labels. Pairs well with # dynamic themes for tighter margins overall. tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = "direct", theme = "clean2" ) # Use `nudge_x/y`` to manually adjust label positions, or `repel` to # auto-separate overlapping labels: tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = legend("direct", nudge_y = c(May = -1, Jun = 2)), # legend = legend("direct", repel = TRUE), # another option theme = "clean2" ) # The default group colours are inherited from either the "R4" or "Viridis" # 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 tinyplot( Temp ~ Day | Month, data = aq, type = "l", palette = "tableau" ) # It's possible to customize the look of your plots by setting graphical # parameters (e.g., via `(t)par`)... But a more convenient way is to just use # built-in themes (see `?tinytheme`). tinyplot( Temp ~ Day | Month, data = aq, type = "b", alpha = 0.5, main = "Daily temperatures by month", sub = "Brought to you by tinyplot", cap = "Source: Base R airquality dataset", theme = "clean2" ) # For more examples and a detailed walkthrough, please see the introductory # tinyplot tutorial available online: # https://grantmcdermott.com/tinyplot/vignettes/introduction.htmlaq = transform( airquality, Month = factor(Month, labels = month.abb[unique(Month)]) ) # In most cases, `tinyplot` should be a drop-in replacement for regular # `plot` calls. For example: op = tpar(mfrow = c(1, 2)) plot(0:10, main = "plot") tinyplot(0:10, main = "tinyplot") tpar(op) # restore original layout # 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. with(aq, tinyplot(Day, Temp, by = Month)) ## atomic method tinyplot(Temp ~ Day | Month, data = aq) ## formula method # (Notice that we also get an automatic legend.) # You can also use the equivalent shorthand `plt()` alias if you'd like to # save on a few keystrokes 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 and `cex` # (character expansion) to increase their size. tinyplot( Temp ~ Day | Month, data = aq, pch = 16, cex = 2 ) # Use the special "by" convenience keyword if you would like to map these # aesthetic features over groups too (i.e., in addition to the default # colour grouping) tinyplot( Temp ~ Day | Month, data = aq, pch = "by", cex = "by" ) # 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`/`fill` convenience arguments. tinyplot( Temp ~ Day | Month, data = aq, 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 ) # Aside: For "bubble" plots, pass an appropriate vector to the `cex` arg. # This can be useful for depicting an additional dimension of the data (here: # Wind). tinyplot( Temp ~ Day | Month, data = aq, pch = 21, cex = aq$Wind, # map character size to another feature in the data bg = 0.3, col = "black" ) # Converting to a grouped line plot is a simple matter of adjusting the # `type` argument. tinyplot( Temp ~ Day | Month, data = aq, type = "l" ) # Similarly for other plot types, including some additional ones provided # directly by tinyplot, e.g. density plots or internal plots (ribbons, # pointranges, etc.) tinyplot( ~ Temp | Month, data = aq, type = "density", fill = "by" ) # Facet plots are supported too. Facets can be drawn on their own... tinyplot( Temp ~ Day, facet = ~Month, data = aq, type = "area", main = "Temperatures by month" ) # ... or combined/contrasted with the by (colour) grouping. aq = transform(aq, Summer = Month %in% c("Jun", "Jul", "Aug")) tinyplot( Temp ~ Day | Summer, facet = ~Month, data = aq, type = "area", palette = "dark2", main = "Temperatures by month and season" ) # Customize facets by passing a list of options to the companion `facet.args` # argument. For example, here we arrange the facets in a single row and also # turn off the inner axes labels to reduce redundancy. tinyplot( Temp ~ Day | Summer, facet = ~Month, facet.args = list(nrow = 1, axes = "outer"), data = aq, type = "area", palette = "dark2", main = "Temperatures by month and season" ) # Use a two-sided formula to arrange the facet windows in a fixed grid. # LHS -> facet rows; RHS -> facet columns aq$hot = aq$Temp >= 75 aq$windy = aq$Wind >= 15 tinyplot( Temp ~ Day, facet = windy ~ hot, facet.args = list(prefix = TRUE), # optional data = aq ) # (Note: The optional `prefix = TRUE` argument prepends the facet variable # names to the strip titles, making for a more informative display here.) # To add common elements to each facet, use the `draw` argument tinyplot( Temp ~ Day, facet = windy ~ hot, facet.args = list(prefix = TRUE), data = aq, draw = abline(h = 75, lty = 2, col = "hotpink") ) # The (automatic) legend position and look can be customized using # appropriate arguments. Note the trailing "!" in the `legend` position # argument below. This tells `tinyplot` to place the legend _outside_ the plot # area. tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = legend("bottom!", title = "Month of the year", bty = "o") ) # Use legend = "direct" to place text labels at the last point of each # group's data, coloured to match. Best suited to line-based plots with # x-sorted data, where "last" corresponds to "rightmost". The right # margin is automatically expanded to fit the labels. Pairs well with # dynamic themes for tighter margins overall. tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = "direct", theme = "clean2" ) # Use `nudge_x/y`` to manually adjust label positions, or `repel` to # auto-separate overlapping labels: tinyplot( Temp ~ Day | Month, data = aq, type = "l", legend = legend("direct", nudge_y = c(May = -1, Jun = 2)), # legend = legend("direct", repel = TRUE), # another option theme = "clean2" ) # The default group colours are inherited from either the "R4" or "Viridis" # 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 tinyplot( Temp ~ Day | Month, data = aq, type = "l", palette = "tableau" ) # It's possible to customize the look of your plots by setting graphical # parameters (e.g., via `(t)par`)... But a more convenient way is to just use # built-in themes (see `?tinytheme`). tinyplot( Temp ~ Day | Month, data = aq, type = "b", alpha = 0.5, main = "Daily temperatures by month", sub = "Brought to you by tinyplot", cap = "Source: Base R airquality dataset", theme = "clean2" ) # For more examples and a detailed walkthrough, please see the introductory # tinyplot tutorial available online: # https://grantmcdermott.com/tinyplot/vignettes/introduction.html
tinyplot
This convenience function grabs the preceding tinyplot call and updates it
with any new arguments that have been explicitly provided by the user. It
then injects add=TRUE and evaluates the updated call, thereby drawing a new
layer on top of the existing plot. plt_add() is a shorthand alias for
tinyplot_add().
tinyplot_add(...) plt_add(...)tinyplot_add(...) plt_add(...)
... |
All named arguments override arguments from the previous calls.
Arguments not supplied to tinyplot_add remain unchanged from the previous
call. Arguments are captured unevaluated and spliced into the updated call,
so those that rely on non-standard evaluation against |
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object, which
can be replayed later; see recordedtinyplot.
tinyplot_add() layers new elements on top of the existing plot. The
complementary, top-level tinyplot(..., draw = <>) argument works in the
opposite direction: it layers underneath the main plot elements.
However, note that draw is fully generic—it accepts any drawing or
annotation expression—and this includes tinyplot_add() itself. Passing
draw = tinyplot_add(...) thus yields a regular tinyplot layer, inheriting
from the enclosing call in the usual way, but drawn below the main elements
rather than above them. See Examples.
tinyplot_add() works reliably only when adding to a plot originally
created using the tinyplot.formula method with a valid data argument.
We cannot guarantee correct behavior if the original plot was created with
the atomic tinyplot.default method, due to potential environment
mismatches. (An exception is when the original plot arguments—x, y,
etc.—are located in the global environment.)
Automatic legends for the added elements will be turned off.
# ## Basic use tinyplot(Sepal.Width ~ Sepal.Length | Species, facet = ~Species, data = iris) tinyplot_add(type = "lm") ## or : plt_add(type = "lm") ## the previous line is equivalent to (but much more convenient than) ## re-writing the full call with the new type and `add=TRUE`: # tinyplot(Sepal.Width ~ Sepal.Length | Species, # facet = ~Species, # data = iris, # type = "lm", # add = TRUE) ## arguments relying on non-standard evaluation (e.g. `subset`) work too: tinyplot(mpg ~ wt, data = mtcars) tinyplot_add(subset = cyl == 4, col = "red", pch = 16) # ## add(ing) vs draw(ing) dat = data.frame(x = 1:3, y = 0) ## the `draw` argument layers *underneath* the main plot elements... tinyplot( y ~ x, data = dat, pch = 19, cex = 10, draw = abline(h = 0, lwd = 4, col = "hotpink") ) ## ... whereas `tinyplot_add()` layers *on top*. tinyplot(y ~ x, data = dat, pch = 19, cex = 10) tinyplot_add(type = type_hline(0), lwd = 4, col = "hotpink") ## combine = best of both worlds? Since `draw` is generic, we can hand it ## `tinyplot_add()` directly. The line is drawn as a regular tinyplot layer, ## but underneath once more. This is especially useful for, say. flipped ## plots since correct axes inheritance is preserved. (Note that a plain ## `abline(h = 0)` is not flip-aware) tinyplot( y ~ x, data = dat, pch = 19, cex = 10, flip = TRUE, draw = tinyplot_add(type = type_hline(0), lwd = 4, col = "hotpink") )# ## Basic use tinyplot(Sepal.Width ~ Sepal.Length | Species, facet = ~Species, data = iris) tinyplot_add(type = "lm") ## or : plt_add(type = "lm") ## the previous line is equivalent to (but much more convenient than) ## re-writing the full call with the new type and `add=TRUE`: # tinyplot(Sepal.Width ~ Sepal.Length | Species, # facet = ~Species, # data = iris, # type = "lm", # add = TRUE) ## arguments relying on non-standard evaluation (e.g. `subset`) work too: tinyplot(mpg ~ wt, data = mtcars) tinyplot_add(subset = cyl == 4, col = "red", pch = 16) # ## add(ing) vs draw(ing) dat = data.frame(x = 1:3, y = 0) ## the `draw` argument layers *underneath* the main plot elements... tinyplot( y ~ x, data = dat, pch = 19, cex = 10, draw = abline(h = 0, lwd = 4, col = "hotpink") ) ## ... whereas `tinyplot_add()` layers *on top*. tinyplot(y ~ x, data = dat, pch = 19, cex = 10) tinyplot_add(type = type_hline(0), lwd = 4, col = "hotpink") ## combine = best of both worlds? Since `draw` is generic, we can hand it ## `tinyplot_add()` directly. The line is drawn as a regular tinyplot layer, ## but underneath once more. This is especially useful for, say. flipped ## plots since correct axes inheritance is preserved. (Note that a plain ## `abline(h = 0)` is not flip-aware) tinyplot( y ~ x, data = dat, pch = 19, cex = 10, flip = TRUE, draw = tinyplot_add(type = type_hline(0), lwd = 4, col = "hotpink") )
Convenience interface for visualizing
array objects with tinyplot. Extends the
tinyplot.matrix conventions to arrays with up to four
dimensions, by mapping the higher dimensions to facets.
## S3 method for class 'array' tinyplot( x, type = NULL, legend = NULL, facet = NULL, xlab = NULL, ylab = NULL, xy = NULL, ... )## S3 method for class 'array' tinyplot( x, type = NULL, legend = NULL, facet = NULL, xlab = NULL, ylab = NULL, xy = NULL, ... )
x |
an object of class |
type |
plot type passed on to |
legend |
specification passed on to |
facet |
must be |
xlab, ylab
|
axis labels passed on to |
xy |
which dimension (if any) holds x/y pairs; see Details. The default
|
... |
further arguments passed to |
The first two dimensions of the array are treated exactly like the
rows and columns of a matrix; see tinyplot.matrix. By default,
that means the values are plotted against the (first dimension) row index,
with a separate by group for each element of the second dimension.
Higher dimensions are then mapped to facets:
1D arrays are treated as a single-column matrix, i.e. a simple index
plot. If a y variable is also supplied, e.g. tinyplot(tapply(...), y),
then the array is instead treated as a plain x vector.
2D arrays are matrices, and hence dispatch to
tinyplot.matrix.
3D arrays are faceted by the third dimension (i.e., a "facet wrap").
4D arrays are faceted by the third and fourth dimensions, as the rows and columns of a "facet grid", respectively.
Arrays with more than four dimensions are not supported. Subset or reshape them first.
Dimension names are used to label the groups, facets, and axis ticks, while
the names of the dimnames (if any) are used as the axis, legend, and facet
titles. To assign the dimensions to different roles, rearrange them first
with aperm.
x/y pairs. Arrays often hold a stack of matrices, one per variable,
e.g. the hip and knee angles of the gait data (Time x Subject x
Variable). If an array of three or more dimensions has exactly one
length-2 dimension besides the first, then its two slices are plotted
against each other, as x and y. Each of the remaining dimensions then
shifts down a role:
The first dimension becomes by, and orders the points along each path.
It is kept numeric where possible (its dimnames, e.g. times, or else its
index), so that each path is drawn as a line with a colour gradient. If
the dimnames are not numeric, then the groups are discrete and drawn as
points instead.
The second dimension becomes a facet wrap (e.g. one panel per subject).
The third dimension (if any) makes this a facet grid, as its columns.
Control this via the xy argument. Tile and heatmap types are exempt,
since they need the array values as their fill.
Note that contingency tables created by table (e.g.,
HairEyeColor or Titanic) are of class "table" and hence do not
dispatch to this method.
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object, which
can be replayed later; see recordedtinyplot.
# 3D array: facet wrap by the third dimension sims = array( cumsum(rnorm(20 * 3 * 4)), dim = c(20, 3, 4), dimnames = list(NULL, paste("Series", 1:3), paste("Run", 1:4)) ) tinyplot(sims, type = "l") # 4D array: facet grid by the third and fourth dimensions sims4 = array( rnorm(20 * 3 * 2 * 2), dim = c(20, 3, 2, 2), dimnames = list( time = NULL, series = paste0("s", 1:3), model = c("A", "B"), scenario = c("low", "high") ) ) tinyplot(sims4, type = "b", facet.args = list(prefix = TRUE)) # tile/heatmap types lay out each 2D slice as a grid tinyplot(sims4[1:5, , , ], type = "heatmap", theme = "heatmap") # x/y pairs: a length-2 dimension is plotted as x vs y # (e.g., hip vs knee angle through the gait cycle, coloured by time and # faceted by boy) gait9 = gait[, 1:9, ] # take a subset for demonstration tinyplot(gait9) # all boys in a single panel instead tinyplot(gait9, facet = FALSE) # ... or in the background of each boy's own panel tinyplot( gait9, draw = tinyplot(gait9, col = "lightgray", facet = FALSE, add = TRUE) ) # opt out of x/y pairs, to plot the angles against time instead tinyplot(gait9, type = "l", xy = FALSE, legend = FALSE)# 3D array: facet wrap by the third dimension sims = array( cumsum(rnorm(20 * 3 * 4)), dim = c(20, 3, 4), dimnames = list(NULL, paste("Series", 1:3), paste("Run", 1:4)) ) tinyplot(sims, type = "l") # 4D array: facet grid by the third and fourth dimensions sims4 = array( rnorm(20 * 3 * 2 * 2), dim = c(20, 3, 2, 2), dimnames = list( time = NULL, series = paste0("s", 1:3), model = c("A", "B"), scenario = c("low", "high") ) ) tinyplot(sims4, type = "b", facet.args = list(prefix = TRUE)) # tile/heatmap types lay out each 2D slice as a grid tinyplot(sims4[1:5, , , ], type = "heatmap", theme = "heatmap") # x/y pairs: a length-2 dimension is plotted as x vs y # (e.g., hip vs knee angle through the gait cycle, coloured by time and # faceted by boy) gait9 = gait[, 1:9, ] # take a subset for demonstration tinyplot(gait9) # all boys in a single panel instead tinyplot(gait9, facet = FALSE) # ... or in the background of each boy's own panel tinyplot( gait9, draw = tinyplot(gait9, col = "lightgray", facet = FALSE, add = TRUE) ) # opt out of x/y pairs, to plot the angles against time instead tinyplot(gait9, type = "l", xy = FALSE, legend = FALSE)
Convenience interface for visualizing
data.frame objects with tinyplot.
## S3 method for class 'data.frame' tinyplot(x, formula = NULL, by = NULL, labs = FALSE, frames = FALSE, ...) tinypairs(x, by = NULL, labs = FALSE, frames = FALSE, ...)## S3 method for class 'data.frame' tinyplot(x, formula = NULL, by = NULL, labs = FALSE, frames = FALSE, ...) tinypairs(x, by = NULL, labs = FALSE, frames = FALSE, ...)
x |
an object of class |
formula |
a |
by |
(pairs-case only) optional grouping variable. Either 1) a character
string giving a column name in |
labs |
(pairs-case only) logical indicating whether the axes labels
(titles) for each sub-plot in the pairs-style case should be shown. Default
is |
frames |
(pairs-case only) logical indicating whether each sub-plot should
be framed by a box. Default is |
... |
further arguments passed to |
This is a convenience function for plotting data frames with
or without a formula. The case with the formula mainly facilitates
using tinyplot() in combination with pipes. The case without
formula provides a quick way of plotting the variables in a data frame:
a single variable, a pair of variables, or a
pairs-style grid of all variable combinations for
3 or more variables. The latter can be called directly (also for less than
3 variables) via tinypairs().
Note that, unlike a base pairs plot, these
tinyplot variants (deliberately) produce a histogram for the univariate
cases along the grid diagonal.
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object; see
recordedtinyplot. The exception is the pairs-style case
(more than two columns), which draws a grid of sub-plots and always
returns NULL.
## using tinyplot() with data frames tinyplot(cars) tinyplot(iris, Sepal.Length ~ Petal.Width | Species) tinyplot( as.data.frame(UCBAdmissions), Admit ~ Gender, facet = 1 ~ Dept, weights = Freq ) ## note that this also enables usage with pipes (in R >= 4.1.0) such as # cars |> tinyplot() # iris |> tinyplot(Sepal.Length ~ Petal.Width | Species) # UCBAdmissions |> # as.data.frame() |> # tinyplot(Admit ~ Gender, facet = 1 ~ Dept, weights = Freq) # etc. ## pairs-style display for data frames with 3 or more variables ## (works best with a theme) tinytheme("clean2") tinyplot(iris) ## pass `by` arg to group the pairs display (legend is suppressed) ## here, we also add optional frames around the individual sub-plots tinyplot(iris, by = "Species", frames = TRUE) ## another option (but assumes objects of equal length) tinyplot(iris[, 1:4], by = iris$Species, frames = TRUE) ## tinypairs can also create 2x2 pairs display tinypairs(iris[, c(3, 1)], by = iris$Species) tinytheme() ## reset theme## using tinyplot() with data frames tinyplot(cars) tinyplot(iris, Sepal.Length ~ Petal.Width | Species) tinyplot( as.data.frame(UCBAdmissions), Admit ~ Gender, facet = 1 ~ Dept, weights = Freq ) ## note that this also enables usage with pipes (in R >= 4.1.0) such as # cars |> tinyplot() # iris |> tinyplot(Sepal.Length ~ Petal.Width | Species) # UCBAdmissions |> # as.data.frame() |> # tinyplot(Admit ~ Gender, facet = 1 ~ Dept, weights = Freq) # etc. ## pairs-style display for data frames with 3 or more variables ## (works best with a theme) tinytheme("clean2") tinyplot(iris) ## pass `by` arg to group the pairs display (legend is suppressed) ## here, we also add optional frames around the individual sub-plots tinyplot(iris, by = "Species", frames = TRUE) ## another option (but assumes objects of equal length) tinyplot(iris[, 1:4], by = iris$Species, frames = TRUE) ## tinypairs can also create 2x2 pairs display tinypairs(iris[, c(3, 1)], by = iris$Species) tinytheme() ## reset theme
Convenience interface for visualizing
matrix objects with tinyplot.
## S3 method for class 'matrix' tinyplot( x, type = NULL, legend = NULL, facet = NULL, xlab = NULL, ylab = NULL, ... )## S3 method for class 'matrix' tinyplot( x, type = NULL, legend = NULL, facet = NULL, xlab = NULL, ylab = NULL, ... )
x |
an object of class |
type |
plot type passed on to |
legend |
specification passed on to |
facet |
specification of |
xlab, ylab
|
axis labels passed on to |
... |
further arguments passed to |
Internally the matrix is converted to long form and visualized as a
scatter (or other type) of each column's values against their row index.
Each column is mapped to a separate by category, so a matrix with
multiple columns produces a grouped plot. Optionally, it can also be
faceted via facet = "by". This mirrors the base R
matplot convention of plotting the columns of a
matrix against the row numbers. If the matrix has column names, these are
used as the group (and legend) labels. Single-column matrices are drawn as
a simple index plot with no grouping or legend.
The "tile" and "heatmap" types are an exception, since the matplot
convention makes little sense for them. Instead the matrix is laid out as a
grid—columns along the x-axis, rows along the y-axis—with the matrix
values supplied as the fill. The y-axis is reversed so that the first row
sits at the top, matching how one reads a matrix (cf.
heatmap and image); pass an
explicit ylim to override. Both axis
titles are suppressed, since the dimnames already label the ticks, and so
is the legend, since the fill merely re-encodes the matrix's own values.
Pass an explicit legend (or xlab/ylab) to override either. See
Examples.
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object, which
can be replayed later; see recordedtinyplot.
# basic use tinyplot(VADeaths) tinyplot(VADeaths, type = "b") tinyplot(VADeaths, type = "b", legend = "direct", theme = "socviz") tinyplot(VADeaths, type = "b", legend = FALSE, facet = "by", theme = "socviz") # digression: equivalent "o" plot to an example in `?matplot` sines = outer(1:20, 1:4, function(x, y) sin(x / 20 * pi * y)) tinyplot(sines, type = "o", pch = "by", lty = "by", col = rainbow(ncol(sines))) # back to VADeaths running example, we can pass down other types too... # heatmap tinyplot(VADeaths, type = "heatmap", theme = "heatmap", col = "white") # barplot(s) tinyplot(VADeaths, type = "barplot", beside = TRUE) tinyplot(t(VADeaths), type = "barplot", beside = TRUE) tinyplot(VADeaths, type = "barplot", facet = "by", legend = FALSE)# basic use tinyplot(VADeaths) tinyplot(VADeaths, type = "b") tinyplot(VADeaths, type = "b", legend = "direct", theme = "socviz") tinyplot(VADeaths, type = "b", legend = FALSE, facet = "by", theme = "socviz") # digression: equivalent "o" plot to an example in `?matplot` sines = outer(1:20, 1:4, function(x, y) sin(x / 20 * pi * y)) tinyplot(sines, type = "o", pch = "by", lty = "by", col = rainbow(ncol(sines))) # back to VADeaths running example, we can pass down other types too... # heatmap tinyplot(VADeaths, type = "heatmap", theme = "heatmap", col = "white") # barplot(s) tinyplot(VADeaths, type = "barplot", beside = TRUE) tinyplot(t(VADeaths), type = "barplot", beside = TRUE) tinyplot(VADeaths, type = "barplot", facet = "by", legend = FALSE)
Convenience interface for visualizing ts
(time series) objects with tinyplot.
## S3 method for class 'ts' tinyplot( x, facet, type = "l", facet.args = list(free = TRUE), xlab = NULL, ylab = NA, ... )## S3 method for class 'ts' tinyplot( x, facet, type = "l", facet.args = list(free = TRUE), xlab = NULL, ylab = NA, ... )
x |
an object of class |
facet |
specification of |
type, facet.args, xlab, ylab, ...
|
further arguments passed to |
Internally the time series object is converted to a long
data frame with columns Time (time index), Value (observations),
and Series (factor with column labels). Depending on the settings
of facet this data frame is visualized either with the formula
Value ~ Time or Value ~ Time | Series. See the facet argument
description for more details and the Examples below for some illustrations.
An exception is made if the user explicitly supplies a distribution type
argument (i.e, one of "histogram", "density", "boxplot", "violin",
"qq", "ridge", or "rug"). These summarize the series values and
ignore the time index, so they are visualized with the one-sided
formula ~ Value (or ~ Value | Series for multivariate series). This
preserves base-R-compatible behaviour such as
tinyplot(Nile, type = "histogram").
By default, no return value; called for the side effect of producing
a plot. If record = TRUE (or globally via tpar(record = TRUE)), the
plot is instead returned invisibly as a "recordedtinyplot" object, which
can be replayed later; see recordedtinyplot.
## univariate series tinyplot(Nile) # exception: expicitly passing a distribution type on a univariate series # still triggers the corresponding transformation tinyplot(Nile, type = "histogram") ## multivariate series (generally, these also look better with a theme) tinytheme("clean2") tinyplot(EuStockMarkets) ## faceted, free scales, same color tinyplot(EuStockMarkets, facet.args = NULL) ## faceted, same scale, same color tinyplot(EuStockMarkets, facet = "by") ## faceted, free scales, diff colors tinyplot(EuStockMarkets, facet = NULL) ## single frame, diff colors ## further variations tinyplot(EuStockMarkets, facet = NULL, legend = list("direct", repel = TRUE)) tinyplot(EuStockMarkets, facet = "by", facet.args = NULL) tinyplot(EuStockMarkets, facet.args = list(free = TRUE, ncol = 1)) ## pass additional tinyplot args through `...` for further customization tinyplot(EuStockMarkets, facet.args = NULL, type = "area", xlab = NA, yaxl = ",", main = "European stock indices") tinytheme() ## reset## univariate series tinyplot(Nile) # exception: expicitly passing a distribution type on a univariate series # still triggers the corresponding transformation tinyplot(Nile, type = "histogram") ## multivariate series (generally, these also look better with a theme) tinytheme("clean2") tinyplot(EuStockMarkets) ## faceted, free scales, same color tinyplot(EuStockMarkets, facet.args = NULL) ## faceted, same scale, same color tinyplot(EuStockMarkets, facet = "by") ## faceted, free scales, diff colors tinyplot(EuStockMarkets, facet = NULL) ## single frame, diff colors ## further variations tinyplot(EuStockMarkets, facet = NULL, legend = list("direct", repel = TRUE)) tinyplot(EuStockMarkets, facet = "by", facet.args = NULL) tinyplot(EuStockMarkets, facet.args = list(free = TRUE, ncol = 1)) ## pass additional tinyplot args through `...` for further customization tinyplot(EuStockMarkets, facet.args = NULL, type = "area", xlab = NA, yaxl = ",", main = "European stock indices") tinytheme() ## reset
tinyplot
The tinytheme function sets or resets the theme for plots created with
tinyplot. Themes control the appearance of plots, such as text alignment,
font styles, axis labels, and even dynamic margin adjustment to reduce
whitespace.
tinytheme( theme = c("default", "basic", "dynamic", "clean", "clean2", "bw", "linedraw", "classic", "minimal", "ipsum", "ipsum2", "dark", "socviz", "broadsheet", "nber", "web", "heatmap", "ridge", "ridge2", "tufte", "float", "void"), ..., register = NULL )tinytheme( theme = c("default", "basic", "dynamic", "clean", "clean2", "bw", "linedraw", "classic", "minimal", "ipsum", "ipsum2", "dark", "socviz", "broadsheet", "nber", "web", "heatmap", "ridge", "ridge2", "tufte", "float", "void"), ..., register = NULL )
theme |
A character string specifying the name of the theme to apply. Themes are arranged in an approximate hierarchy, adding or subtracting elements in the order presented below. Note that several themes are dynamic, in the sense that they attempt to reduce whitespace in a way that is responsive to the length of axes labels, tick marks, etc. These dynamic plots are marked with an asterisk (*) below.
|
... |
Named arguments to override specific theme settings. These
arguments are passed to |
register |
Optional character string. If provided, the theme (with any
|
Sets a list of graphical parameters using tpar()
Persistent vs. ephemeral themes. Calling tinytheme("<theme>") triggers
a persistent theme, which will be applied to all subsequent graphics (incl.
base plot). To reset the theme to your default settings, call tinytheme()
without arguments. Alternatively, invoke the tinyplot(..., theme = <theme>)
argument for an ephemeral theme that is automatically reset at the end of the
plot call.
# Set a persistent theme
tinytheme("clean")
tinyplot(1:10) # uses "clean"
tinyplot(10:1) # still uses "clean"
tinytheme() # reset to default
# Use an ephemeral theme for a single plot (incl. added components)
tinyplot(1:10, theme = "dark") # uses "dark" ephemerally
tinyplot_add(type = "S") # same plot, so retains theme
tinyplot(10:1) # new plot, so back to default
Custom overrides. To customize a theme's parameters (e.g., mar, las,
etc.), either pass them directly as additional args to
tinytheme(<theme>, ...) or as a list arguments to
tinyplot(..., theme = list(<theme>, ...)).
Please note that passing overrides through tpar() or par() won't work,
because themes work by installing a persistent hook, which means that an
active theme will override any subsequent calls for parameters that the theme
controls.
# Do this
tinytheme("clean", mar = c(5, 5, 2, 2))
<some plot>
# Or this (ephemeral version)
tinyplot(..., theme = list("clean", mar = c(5, 5, 2, 2)))
# Don't do this (the theme hook will overwrite your changes)
tinytheme("clean")
tpar(mar = c(5, 5, 2, 2))
<some plot>
Spacing primitives. Dynamic themes compute mgp (margin line positions)
automatically from two spacing primitives, rather than requiring users to
reason about how mar, mgp, and tcl combine:
gap.axis: the gap in margin lines between the tick tip and the near edge
of the tick label. Default 0.2.
gap.lab: the gap in margin lines between the far edge of the tick label
and the near edge of the axis title. Default 1.0.
These primitives scale automatically with cex.axis and cex.lab, so the
visible spacing between elements remains constant regardless of text size.
To adjust spacing, pass them as overrides:
# Tighter spacing between tick labels and axis titles
tinytheme("clean", gap.lab = 0.5)
# More room between ticks and tick labels
tinytheme("clean", gap.axis = 0.5)
If you supply an explicit mgp value, it is used as-is and the primitives
are ignored.
The function returns nothing. It is called for its side effects.
tpar which does the heavy lifting under the hood;
tinytheme_get() for retrieving the name of the active theme;
tinytheme_list() for listing the names of all available themes;
tinytheme_register() for registering custom named themes.
# Reusable plot function p = function() tinyplot( lat ~ long | depth, data = quakes, main = "Earthquakes off Fiji", sub = "Data courtesy of the Harvard PRIM-H project" ) p() # Set a theme tinytheme("dark") p() # A set theme is persistent and will apply to subsequent plots tinyplot(0:10) # Try a different theme tinytheme("clean") p() # Customize the theme by overriding default settings tinytheme("clean", adj.xlab = 1, adj.ylab = 1, cex.lab = 0.75, cex.axis = 0.9, font.sub = 3, gap.axis = 0, gap.lab = 0.5, tcl = -0.1) p() # Another custom theme example, including a different font tinytheme("bw", font.main = 2, col.axis = "darkcyan", family = "HersheyScript") p() # Aside: One or two specialized themes are only meant for certain plot types tinytheme("ridge2") tinyplot(I(cut(lat, 10)) ~ depth, data = quakes, type = "ridge") # Reset the theme tinytheme() p() # For an ephemeral theme, use `tinyplot(..., theme = <theme>)` directly tinyplot(0:10, theme = "clean", main = "This theme is ephemeral") tinyplot(10:0, main = "See, no more theme") # Customize an ephemeral theme by passing arguments as a list tinyplot(0:10, main = "Custom", theme = list("clean", grid.col = "hotpink")) # Themes showcase ## We'll use a slightly more intricate plot (long y-axis labs and facets) ## to demonstrate dynamic margin adjustment etc. thms = eval(formals(tinytheme)$theme) for (thm in thms) { tinytheme(thm) tinyplot( I(Sepal.Length*1e4) ~ Petal.Length | Species, facet = "by", data = iris, yaxl = ",", main = paste0('tinytheme("', thm, '")'), sub = "A subtitle", cap = "A caption" ) box("outer", lty = 2) } # Reset tinytheme()# Reusable plot function p = function() tinyplot( lat ~ long | depth, data = quakes, main = "Earthquakes off Fiji", sub = "Data courtesy of the Harvard PRIM-H project" ) p() # Set a theme tinytheme("dark") p() # A set theme is persistent and will apply to subsequent plots tinyplot(0:10) # Try a different theme tinytheme("clean") p() # Customize the theme by overriding default settings tinytheme("clean", adj.xlab = 1, adj.ylab = 1, cex.lab = 0.75, cex.axis = 0.9, font.sub = 3, gap.axis = 0, gap.lab = 0.5, tcl = -0.1) p() # Another custom theme example, including a different font tinytheme("bw", font.main = 2, col.axis = "darkcyan", family = "HersheyScript") p() # Aside: One or two specialized themes are only meant for certain plot types tinytheme("ridge2") tinyplot(I(cut(lat, 10)) ~ depth, data = quakes, type = "ridge") # Reset the theme tinytheme() p() # For an ephemeral theme, use `tinyplot(..., theme = <theme>)` directly tinyplot(0:10, theme = "clean", main = "This theme is ephemeral") tinyplot(10:0, main = "See, no more theme") # Customize an ephemeral theme by passing arguments as a list tinyplot(0:10, main = "Custom", theme = list("clean", grid.col = "hotpink")) # Themes showcase ## We'll use a slightly more intricate plot (long y-axis labs and facets) ## to demonstrate dynamic margin adjustment etc. thms = eval(formals(tinytheme)$theme) for (thm in thms) { tinytheme(thm) tinyplot( I(Sepal.Length*1e4) ~ Petal.Length | Species, facet = "by", data = iris, yaxl = ",", main = paste0('tinytheme("', thm, '")'), sub = "A subtitle", cap = "A caption" ) box("outer", lty = 2) } # Reset tinytheme()
Returns the name of the tinytheme that is currently in
effect. Handy for saving a theme and restoring it later, or for querying
the active theme programmatically.
tinytheme_get()tinytheme_get()
A thin convenience wrapper around the "tinytheme" entry of
tpar. The difference is that it always returns a plain character
string, including in a session where no theme has been set yet (where
tpar("tinytheme") returns NULL rather than "default"). Use tpar
if you want the full set of underlying theme settings, rather than just
the name.
Note that a theme passed to the tinyplot(..., theme =) argument is
ephemeral: it is reset on exit, so it is only visible to
tinytheme_get() from inside that same call (e.g. via draw).
A character string naming the active theme.
tinytheme, tinytheme_register, tpar
# no theme set yet tinytheme_get() # save the current theme, switch, then restore it afterwards otheme = tinytheme_get() tinytheme("classic") tinytheme_get() tinyplot(mpg ~ wt, data = mtcars) tinytheme(otheme) # back to where we started tinytheme_get()# no theme set yet tinytheme_get() # save the current theme, switch, then restore it afterwards otheme = tinytheme_get() tinytheme("classic") tinytheme_get() tinyplot(mpg ~ wt, data = mtcars) tinytheme(otheme) # back to where we started tinytheme_get()
tinytheme_register() registers a custom theme so it can be used by name
with tinytheme() or tinyplot(..., theme = ). Custom themes inherit from
a base theme and apply user-specified overrides. Registered themes are
session-scoped: they persist across plots but not across R sessions. To make
a custom theme permanently available, register it in your .Rprofile.
tinytheme_list() returns the names of all available themes (built-in and
registered).
tinytheme_unregister() removes a previously registered theme from the
registry. Does not reset an active theme.
tinytheme_register(name, theme = "default", ...) tinytheme_list() tinytheme_unregister(name)tinytheme_register(name, theme = "default", ...) tinytheme_list() tinytheme_unregister(name)
name |
Character string. The name for your custom theme. Cannot clash
with or overwrite a built-in theme name ( |
theme |
Character string or list. The base theme to inherit from. If a
string, it must reference a built-in or previously-registered theme. If a
list, it is used directly as the base definition. Default is |
... |
Named arguments to override specific theme settings. These are
the same parameters accepted by |
tinytheme_register() returns the theme definition list (invisibly).
tinytheme_list() returns a named list with character vectors builtin
and registered. tinytheme_unregister() returns NULL (invisibly).
# Register a custom theme based on "float" but with a grid tinytheme_register("float2", theme = "float", grid = TRUE) # Use it tinyplot(1:5, theme = "float2") # List all themes tinytheme_list() # Unregister tinytheme_unregister("float2")# Register a custom theme based on "float" but with a grid tinytheme_register("float2", theme = "float", grid = TRUE) # Use it tinyplot(1:5, theme = "float2") # List all themes tinytheme_list() # Unregister tinytheme_unregister("float2")
Extends par, serving as a (near) drop-in
replacement for setting or querying graphical parameters. The key
differences is that, beyond supporting the standard group of R graphical
parameters in par, tpar also supports additional
graphical parameters that are provided by tinyplot. Similar to
par, parameters are set by passing appropriate
key = value argument pairs, and multiple parameters can be set or queried
at the same time.
tpar(..., hook = FALSE)tpar(..., hook = FALSE)
... |
arguments of the form |
hook |
Logical. If |
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 options,
which may prove convenient for users that want to enable different default
behaviour at startup (e.g., through an .Rprofile file). These options all
take a tinyplot_* prefix, e.g.
options(tinyplot_grid = TRUE, tinyplot_facet.bg = "grey90").
For their part, any "base" graphical parameters are caught dynamically and
passed on to par as appropriate. Technically, only
parameters that satisfy par(..., no.readonly = TRUE) are evaluated.
However, note the important distinction: tpar only evaluates parameters
from 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.
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.
adj.cap: Numeric value between 0 and 1 controlling the alignment of the plot caption. Defaults to 0.5 (centered) for the default theme, and 1 (right-aligned) for all other themes.
adj.xlab: Numeric value between 0 and 1 controlling the alignment of the x-axis label.
adj.ylab: Numeric value between 0 and 1 controlling the alignment of the y-axis label.
cairo: Logical indicating whether cairo_pdf should be used when writing plots to PDF. If FALSE, then pdf will be used instead, with implications for embedding (non-standard) fonts. Only used if tinyplot(..., file = "<filename>.pdf") is called. Defaults to the value of capabilities("cairo").
cex.cap: Numeric expansion factor for the plot caption text. Defaults to 1 for the default, basic, and dynamic themes, and 0.8 for clean/classic and their descendants.
cex.xaxs, cex.yaxs: Numeric expansion factors for the x- and y-axis tick labels, respectively. Both default to NULL, whereby the shared cex.axis value is used instead (which in turn falls back to par("cex.axis")). Set one of them to size a single axis' tick labels independently of the other, e.g. cex.yaxs to shrink a long list of category names on the y-axis without also shrinking the x-axis. Compare cex.xlab and cex.ylab, which do the same for the axis titles.
col.cap: Character specifying the colour of the plot caption. Defaults to "black".
col.xaxs, col.yaxs: Characters (or integers) specifying the colour of the x- and y-axis tick labels, respectively. Both default to NULL, whereby the shared col.axis value is used instead.
col.default: Default colour for single-group displays (i.e. plots without a by grouping). Can be NULL, a length-1 character colour, or a length-1 numeric index into palette.qualitative. Defaults to NULL, in which case the first colour of the active qualitative palette is used (or base palette()[1], typically black, if no theme is set). A character value sets the single-group colour independently of the multi-group palette. A numeric value i selects the ith colour of palette.qualitative as the single-group default; a negative index additionally drops that colour from the palette used for grouped plots. For example, col.default = -1 paired with palette.qualitative = "Okabe-Ito" uses black (the leading palette colour) for single-group plots and an Okabe-Ito-minus-black palette for grouped plots, avoiding the need to maintain a separate "no-black" palette.
font.cap: Integer specifying the font face for the plot caption (1 = plain, 2 = bold, 3 = italic, 4 = bold italic). Defaults to 1.
line.cap: Numeric specifying the margin line on which to draw the caption. If NULL (default), computed automatically based on the available bottom margin.
dynmar: Logical indicating whether tinyplot should attempt dynamic adjustment of margins to reduce whitespace and/or account for spacing of text elements (e.g., long horizontal y-axis labels). Note that this parameter is tightly coupled to internal tinythemes() logic and should not be adjusted manually unless you really know what you are doing or don't mind risking unintended consequences to your plot.
facet.axes: Character string controlling which facets draw their own axes: "all" (each facet), "outer" (only facets on the outer edge of the facet grid, dropping redundant interior axes), or "none". Defaults to NULL, whereby the choice is inferred from whether the plot is framed (see the axes argument of facet.args). Equivalent to setting tinyplot(..., facet.args = list(axes = X)), but globally, which also makes it available to themes.
facet.drop: Logical indicating whether facet levels that no observation uses should be dropped, rather than drawing an empty panel. Defaults to FALSE. Equivalent to setting tinyplot(..., facet.args = list(drop = X)), but globally, which also makes it available to themes.
facet.drop.levels: Logical indicating whether each free facet (facet.args = list(free = TRUE)) should keep only the categories of a categorical axis that it actually uses, re-levelled as if that panel's data had been passed through factor() on its own. Defaults to FALSE, i.e. every panel shows the full set of categories. Equivalent to setting tinyplot(..., facet.args = list(drop.levels = X)), but globally, which also makes it available to themes.
facet.bg: Character or integer specifying the facet background colour. If an integer, will correspond to the user's default colour palette (see palette). Passed to rect. Defaults to NULL (none).
facet.border: Character or integer specifying the facet border colour. If an integer, will correspond to the user's default colour palette (see palette). Passed to rect. Defaults to NA (none).
facet.cex: Expansion factor for facet titles. Defaults to 1.
facet.col: Character or integer specifying the facet text colour. If an integer, will correspond to the user's default global colour palette (see palette). Defaults to NULL, which is equivalent to "black".
facet.font: An integer corresponding to the desired font face for facet titles. For most font families and graphics devices, one of four possible values: 1 (regular), 2 (bold), 3 (italic), or 4 (bold italic). Defaults to NULL, which is equivalent to 1 (i.e., regular).
facet.labeller: A formatting function (or tinylabel convenience string, e.g. "percent") applied to the facet titles, or a list of them (or a character vector of convenience strings), optionally named for the facet variables they apply to, for formatting each facet variable differently. Note that this per-variable naming claims the same slot that a tinylabel dictionary would, so a dictionary has to be nested inside it, e.g. facet.labeller = list(Species = c(setosa = "SET")). Defaults to NULL (no formatting). Applied to the underlying facet values, i.e. before any facet.prefix name is added. Equivalent to setting tinyplot(..., facet.args = list(labeller = X)), but globally.
facet.prefix: Logical or character controlling whether facet titles are prefixed with their variable name, e.g. "vs = 0" rather than just "0". TRUE uses the variable name(s), while a character string—or a vector or list of them, one element per facet variable, optionally named for the variables they apply to—supplies custom name(s) instead. Defaults to NULL, which is equivalent to FALSE (no prefix). Equivalent to setting tinyplot(..., facet.args = list(prefix = X)), but globally.
facet.sep: Character string separating the individual variables of a multi-variable facet title, e.g. "\n" to stack them on separate lines. Ignored for single-variable facets. Defaults to NULL, i.e. the ":" that the variables were combined with, or ", " if they are prefixed via facet.prefix (above). Equivalent to setting tinyplot(..., facet.args = list(sep = X)), but globally.
file.height: Numeric specifying the height (in inches) of any plot that is written to disk using the tinyplot(..., file = X) argument. Defaults to 7.
file.res: Numeric specifying the resolution (in dots per square inch) of any plot that is written to disk in bitmap format (i.e., PNG or JPEG) using the tinyplot(..., file = X) argument. Defaults to 300.
file.width: Numeric specifying the width (in inches) of any plot that is written to disk using the tinyplot(..., file = X) argument. Defaults to 7.
fmar: A numeric vector of form c(b,l,t,r) for controlling the (base) margin padding, in terms of lines, between the individual facets in a faceted plot. Defaults to c(1,1,1,1). If more than three facets are detected, the fmar parameter is scaled by 0.75 to reduce excess whitespace. For 2x2 plots, the padding better matches the cex expansion logic of base graphics.
gap.main: Numeric giving the gap (in margin lines) from the main title baseline to the element below it (plot box when no subtitle; subtitle top when subtitle is present). Only used when dynmar = TRUE. Defaults to 0.7.
gap.sub: Numeric giving the gap (in margin lines) from the subtitle baseline to the plot box. Only used when dynmar = TRUE and side.sub = 3. Defaults to 0.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 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.
lty.xaxs, lty.yaxs: Line types for the x- and y-axis lines, respectively. Both default to NULL, whereby the shared lty.axis value is used instead.
lwd.xaxs, lwd.yaxs: Line widths for the x- and y-axis lines, respectively. Both default to NULL, whereby the shared lwd.axis value is used instead.
palette.qualitative: Palette for qualitative colors. See the palette argument in ?tinyplot.
palette.sequential: Palette for sequential colors. See the palette argument in ?tinyplot.
record: (experimental) Logical indicating whether tinyplot() should record plots and return them as replayable recordedtinyplot objects. Defaults to NULL, which is equivalent to FALSE. Setting to TRUE allows for assignment and later recall, e.g. myplot = tinyplot(...); myplot. Sets the default for the record argument of tinyplot(), which takes precedence. Note that recording requires a device with an enabled display list (see dev.control). Most interactive devices enable this behaviour by default, whereas file-based devices do not. However tinyplot() automatically enables it for any device that it opens itself via file, and further emits a warning if the current device is not recording.
ribbon.alpha: Numeric factor in the range [0,1] for modifying the opacity alpha of "ribbon" and "area" type plots. Default value is 0.2.
xpad, ypad: Numeric specifying how much padding, as a fraction of the data range, should be added to each end of the x- and y-axis, respectively. Both default to NULL, in which case an automatic heuristic applies: a numeric axis inherits from x/yaxs (usually 4% padding on each end), whereas a categorical axis with point-like glyphs and few unique categories instead gets 25% of the gap between interior tick marks. Sets the default for the xpad and ypad arguments of tinyplot(), which take precedence and where the heuristic is described in full.
xaxr, yaxr: Numeric giving the rotation of the x- and y-axis tick labels, in degrees counter-clockwise; NULL (the default) leaves them unrotated. Unlike las, which is limited to the four right angles, any angle is permitted. Setting one overrides las for that axis alone, leaving the other axis under las as usual, and 0 (or any multiple of 360) counts as no rotation at all. Sets the default for the xaxr and yaxr arguments of tinyplot(), which take precedence. Two caveats follow from tinyplot drawing rotated labels itself rather than deferring to base axis(). First, margins are only resized to fit them under a theme with dynmar = TRUE (see tinytheme); under the default theme the margins are left alone, so a long rotated label will be clipped unless you widen mar yourself. Second, rotated labels do not inherit the thinning that axis() applies via gap.axis, so they start to overlap once the spacing between ticks falls below line height / sin(srt).
graphics::par which tpar builds on top of. get_saved_par
is a convenience function for retrieving graphical parameters at different
stages of a tinyplot call (and used for internal accounting purposes).
tinytheme allows users to easily set a group of graphics parameters
in a single function call, according to a variety of predefined themes.
tinytheme_get returns the name of the currently active theme.
# Return a list of existing base and tinyplot graphic params tpar("las", "pch", "facet.bg", "facet.cex", "grid") # Simple facet plot with these default values tinyplot(mpg ~ wt, data = mtcars, facet = ~am) # Set params to something new. Similar to graphics::par(), note that we save # the existing values at the same time by assigning to an object. op = tpar( las = 1, pch = 2, facet.bg = "grey90", facet.cex = 2, grid = TRUE ) # Re-plot with these new params tinyplot(mpg ~ wt, data = mtcars, facet = ~am) # Reset back to original values tpar(op) # Important: tpar() only evaluates 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 # file). Example: # options(tinyplot_grid = TRUE, tinyplot_facet.bg = "grey90")# Return a list of existing base and tinyplot graphic params tpar("las", "pch", "facet.bg", "facet.cex", "grid") # Simple facet plot with these default values tinyplot(mpg ~ wt, data = mtcars, facet = ~am) # Set params to something new. Similar to graphics::par(), note that we save # the existing values at the same time by assigning to an object. op = tpar( las = 1, pch = 2, facet.bg = "grey90", facet.cex = 2, grid = TRUE ) # Re-plot with these new params tinyplot(mpg ~ wt, data = mtcars, facet = ~am) # Reset back to original values tpar(op) # Important: tpar() only evaluates 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 # file). Example: # options(tinyplot_grid = TRUE, tinyplot_facet.bg = "grey90")
These functions add straight line(s) through the current plot.
type_abline(a = 0, b = 1) type_hline(h = 0) type_vline(v = 0)type_abline(a = 0, b = 1) type_hline(h = 0) type_vline(v = 0)
a, b
|
the intercept (default: |
h |
y-value(s) for horizontal line(s). Numeric of length 1, or equal to the number of groups or number of facets (or the product thereof). |
v |
x-value(s) for vertical line(s). Numeric of length 1, or equal to the number of groups or number of facets (or the product thereof). |
While type_abline, type_hline, and type_vline can be called in a base
plot layer, we expect that they will typically be called as subsequent
layers via tinyplot_add.
Line parameters always refer to the original (pre-flip) variables. So, if
flip = TRUE, then type_hline() draws vertical line(s) at the given y
value(s), type_vline() draws horizontal line(s) at the given x value(s),
and type_abline() draws the line with the axes swapped.
The recycling behaviour of the line parameters (i.e., a, b, h, or v)
is adaptive, depending on whether by or facet grouping is detected. While
this leads to different recycling scenarios, the underlying code logic
follows sensible heuristics designed to match user expectations.
Parameter lengths must equal one of four options:
Single value (i.e., length = 1), i.e. simplest case where the same line is
applied uniformly across all groups and facets. Uses the default user colour
(e.g. "black", or tpar("palette.qualitative")[1] if a theme is set).
Number of by groups, i.e. one parameter per group. For example,
tinyplot(mpg ~ wt | factor(cyl), data = mtcars, type = type_hline(h = 21:23))
will give three horizontal lines, with colours matching the user's qualitative
palette.
Number of facet groups, i.e. one parameter per facet panel. For example:
tinyplot(mpg ~ wt, facet = ~am, data = mtcars, type = type_hline(h = c(20,30)))
would give separate horizontal lines per facet, but both using the same
default color.
Product of by and facet groups, i.e. one parameter for each unique
by-facet combination. Orders over facets first and then, within that, by
group. For example:
tinyplot(mpg ~ wt | factor(cyl), facet = ~am, data = mtcars, type = type_hline(h = 21:26))
will give six separate lines, with the first three (21:23) coloured by
group in the first facet, and second three (24:26) coloured by by group
in the second facet.
Alongside these general rules, we also try to accommodate special cases when
other aesthetic parameters like lwd or lty are invoked by the user. See
Examples.
# ## abline tinyplot(x = -10:10, y = rnorm(21) + -10:10, grid = TRUE) tinyplot_add(type = "abline") # same as... # tinyplot_add(type = type_abline(a = 0, b = 1)) # customize by passing bespoke intercept and slope values tinyplot_add(type = type_abline(a = -1, b = -0.5)) # note that calling as abline & co. as a base plot layer will still lead to # axes limits that respect the range of the data tinyplot(x = -10:10, y = -10:10, grid = TRUE, type = "abline") # ## hline and vline # Base plot layer tinyplot(mpg ~ hp | cyl, facet = "by", data = mtcars, ylim = c(0, 40)) # Add horizontal lines at the (default) 0 y-intercept tinyplot_add(type = "hline", col = "grey") # Note that group+facet aesthetics will be inherited. We can use this to # add customized lines (here: the mean `mpg` for each `cyl` group) tinyplot_add(type = type_hline(with(mtcars, tapply(mpg, cyl, mean))), lty = 2) # Similar idea for vline tinyplot_add(type = type_vline(with(mtcars, tapply(hp, cyl, mean))), lty = 2) # ## Flipped plots # Line parameters refer to the original x and y variables, so "hline" is # drawn vertically and "vline" horizontally when flip = TRUE tinyplot(mpg ~ wt, data = mtcars, flip = TRUE) tinyplot_add(type = type_hline(20), col = "hotpink") tinyplot_add(type = type_vline(3), col = "dodgerblue") tinyplot_add(type = type_abline(a = 37, b = -5), lty = 2) # ## Recycling logic # length(h) == no. of groups tinyplot(mpg ~ wt | factor(cyl), data = mtcars, type = type_hline(h = 21:23)) # length(h) == no. of facets tinyplot(mpg ~ wt, facet = ~am, data = mtcars, type = type_hline(h = c(20, 30))) # length(h) == no. of groups x no. of facets tinyplot(mpg ~ wt | factor(cyl), facet = ~am, data = mtcars, type = type_hline(h = 21:26)) # special adjustment case (here: lwd by group) tinyplot(mpg ~ wt | factor(cyl), facet = ~am, data = mtcars, type = type_hline(c(20, 30)), lwd = c(21, 14, 7))# ## abline tinyplot(x = -10:10, y = rnorm(21) + -10:10, grid = TRUE) tinyplot_add(type = "abline") # same as... # tinyplot_add(type = type_abline(a = 0, b = 1)) # customize by passing bespoke intercept and slope values tinyplot_add(type = type_abline(a = -1, b = -0.5)) # note that calling as abline & co. as a base plot layer will still lead to # axes limits that respect the range of the data tinyplot(x = -10:10, y = -10:10, grid = TRUE, type = "abline") # ## hline and vline # Base plot layer tinyplot(mpg ~ hp | cyl, facet = "by", data = mtcars, ylim = c(0, 40)) # Add horizontal lines at the (default) 0 y-intercept tinyplot_add(type = "hline", col = "grey") # Note that group+facet aesthetics will be inherited. We can use this to # add customized lines (here: the mean `mpg` for each `cyl` group) tinyplot_add(type = type_hline(with(mtcars, tapply(mpg, cyl, mean))), lty = 2) # Similar idea for vline tinyplot_add(type = type_vline(with(mtcars, tapply(hp, cyl, mean))), lty = 2) # ## Flipped plots # Line parameters refer to the original x and y variables, so "hline" is # drawn vertically and "vline" horizontally when flip = TRUE tinyplot(mpg ~ wt, data = mtcars, flip = TRUE) tinyplot_add(type = type_hline(20), col = "hotpink") tinyplot_add(type = type_vline(3), col = "dodgerblue") tinyplot_add(type = type_abline(a = 37, b = -5), lty = 2) # ## Recycling logic # length(h) == no. of groups tinyplot(mpg ~ wt | factor(cyl), data = mtcars, type = type_hline(h = 21:23)) # length(h) == no. of facets tinyplot(mpg ~ wt, facet = ~am, data = mtcars, type = type_hline(h = c(20, 30))) # length(h) == no. of groups x no. of facets tinyplot(mpg ~ wt | factor(cyl), facet = ~am, data = mtcars, type = type_hline(h = 21:26)) # special adjustment case (here: lwd by group) tinyplot(mpg ~ wt | factor(cyl), facet = ~am, data = mtcars, type = type_hline(c(20, 30)), lwd = c(21, 14, 7))
Type constructor functions for producing polygon ribbons, which
define a y interval (usually spanning from ymin to ymax) for each
x value. Area plots are a special case of ribbon plot where ymin is
set to 0 and ymax is set to y.
type_area(alpha = NULL, stack = FALSE, byord = NULL, fun = NULL) type_ribbon(alpha = NULL, dodge = 0, fixed.dodge = FALSE)type_area(alpha = NULL, stack = FALSE, byord = NULL, fun = NULL) type_ribbon(alpha = NULL, dodge = 0, fixed.dodge = FALSE)
alpha |
numeric value between 0 and 1 specifying the opacity of ribbon shading
If no |
stack |
logical. Should the |
byord |
keyword string or function. Permits on-the-fly (re)ordering of
the
Defaults to |
fun |
a function for collapsing repeated |
dodge |
Adjustment parameter for dodging overlapping points or ranges in grouped plots along the x-axis (or y-axis for flipped plots). Either:
Default value is 0 (no dodging). While we do not check, it is strongly recommended that dodging only be used in cases where the x-axis comprises a limited number of discrete breaks. |
fixed.dodge |
Logical. If |
We support dodging for grouped ribbon plots, enabling similar functionality to dodged errorbar and pointrange plots. However, it is strongly recommended that dodging is only implemented for cases where the x-axis comprises a limited number of discrete cases (e.g., coefficient or event-study plots). See Examples.
Passing type_area(stack = TRUE) stacks the by groups cumulatively,
rather than drawing each one from a zero baseline. Groups are accumulated in
the order of their (factor) levels, so the first level forms the bottom band
and the top of the final band traces the group total. Stacking is computed
separately within each facet.
The byord argument is a helpful companion to stacked area plots, since it
enables on-the-fly adjustment of the stacking order. For example,
the size keywords—"desc", "start", and "end"—rank the
stacked by groups according to their y values, either summed across the
x axis or taken at one end of it. Following convention, the ranking runs in
descending order, so that the biggest group is drawn on the bottom layer
(use "asc" for the reverse). However, size
is not the only route to a stable baseline. Because each band is
drawn on top of the ones below it, they all inherit whatever movement the
bottom layer has. A large but volatile group can therefore be a worse choice
of foundation than a small, steady one. In this latter case, the "minvar"
keyword would be a more appropriate choice since it places the lowest
variance group at the bottom. Your choice of stacking ordering should
therefore respond to the patterns in your data and which layers you want to
emphasize.
Stacking needs exactly one y value per group per x value. Repeated cells
—typically caused by a variable that is present in the data but absent from
the plot—are collapsed with fun (default mean) rather than being
stacked against each other. Conversely, groups that are missing an x
value (or have an NA there) count as contributing zero at that point, so
that a gap in one group does not shift the groups stacked above it. Note that
stacking negative values is not meaningful and will produce overlapping
bands.
Note that the legend key for stacked area plots is deliberately inverted
compared to other plot types (including non-stacked area plots) to ensure a
consistent ordering with the "bottoms-up" layering of the stacked regions.
Similarly, reordering of the by group levels will reassign the palette,
since group colours are allocated by level position. This matches what
releveling a factor does elsewhere, but it does mean that reordering the
bands repaints them.
Finally, note that unlike non-stacked area plots, the stacked bands are
drawn with opaque fill by default, since they do not overlap. Pass an
explicit alpha or fill value to override.
x = 1:100 / 10 y = sin(x) # ## Ribbon plots # "ribbon" convenience string tinyplot(x = x, ymin = y - 1, ymax = y + 1, type = "ribbon") # Same result with type_ribbon() tinyplot(x = x, ymin = y-1, ymax = y+1, type = type_ribbon()) # y will be added as a line if it is specified tinyplot(x = x, y = y, ymin = y-1, ymax = y+1, type = "ribbon") # ## Area plots # "area" type convenience string tinyplot(x, y, type = "area") # Same result with type_area() tinyplot(x, y, type = type_area()) # Area plots are often used for time series charts tinyplot(AirPassengers, type = "area") # ## Stacked area plots # Grouped area plots can be stacked cumulatively, rather than being drawn # from a common zero baseline. # Group B is small and steady; A and C are larger and wobblier. dat = expand.grid(year = 2000:2020, grp = factor(c("A", "B", "C"))) dat$val = as.integer(dat$grp) + c(1.2, 0.1, 1.8)[dat$grp] * sin(dat$year / 3) + c(0.06, 0.02, 0.10)[dat$grp] * (dat$year - 2000) tinyplot(val ~ year | grp, data = dat, type = type_area(stack = TRUE)) # Use `byord` to control which group stacks where. Here we stack by their # largest end value. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "end") ) # `"minvar"` instead puts the *least variable* group on the baseline. Every # band inherits the movement of the ones below it, so a steady bottom layer # keeps the whole chart legible. Here that picks group B, which the default # level order leaves in the middle and `"end"`/`"desc"` push to the top. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "minvar") ) # `"rev"` simply flips the existing level order, which is the one thing a # ranking function cannot do (it never sees which group it was handed). tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "rev") ) # Custom ranking functions are also accepted. Name an argument `x` and it # receives the group's x values too, which is what a slope needs. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = function(y, x) coef(lm(y ~ x))[2]) ) # Stacking expects a single `y` value per group per `x` value. Any repeats # are collapsed for us first, using `fun` (`mean` by default). Here, for # instance, ChickWeight records many chicks per diet at each timepoint. tinyplot( weight ~ Time | Diet, data = ChickWeight, type = type_area(stack = TRUE, fun = median) ) # (Illustrative purposes aside, we leave it to the reader to decide whether # stacking separate diets on top of one another makes any sense...) # ## Dodged ribbon/area plots # Dodged ribbon or area plots can be useful in cases where there is strong # overlap across groups (and a limited number of discrete x-axis values). dat = data.frame( x = rep(c("Before", "After"), each = 2), grp = rep(c("A", "B"), 2), y = c(10, 10.5, 15, 15.3), lwr = c(8, 8.5, 13, 13.3), upr = c(12, 12.5, 17, 17.3) ) tinyplot( y ~ x | grp, data = dat, ymin = lwr, ymax = upr, type = type_ribbon(), main = "Overlappling ribbons" ) tinyplot( y ~ x | grp, data = dat, ymin = lwr, ymax = upr, type = type_ribbon(dodge = 0.1), main = "Dodged ribbons" )x = 1:100 / 10 y = sin(x) # ## Ribbon plots # "ribbon" convenience string tinyplot(x = x, ymin = y - 1, ymax = y + 1, type = "ribbon") # Same result with type_ribbon() tinyplot(x = x, ymin = y-1, ymax = y+1, type = type_ribbon()) # y will be added as a line if it is specified tinyplot(x = x, y = y, ymin = y-1, ymax = y+1, type = "ribbon") # ## Area plots # "area" type convenience string tinyplot(x, y, type = "area") # Same result with type_area() tinyplot(x, y, type = type_area()) # Area plots are often used for time series charts tinyplot(AirPassengers, type = "area") # ## Stacked area plots # Grouped area plots can be stacked cumulatively, rather than being drawn # from a common zero baseline. # Group B is small and steady; A and C are larger and wobblier. dat = expand.grid(year = 2000:2020, grp = factor(c("A", "B", "C"))) dat$val = as.integer(dat$grp) + c(1.2, 0.1, 1.8)[dat$grp] * sin(dat$year / 3) + c(0.06, 0.02, 0.10)[dat$grp] * (dat$year - 2000) tinyplot(val ~ year | grp, data = dat, type = type_area(stack = TRUE)) # Use `byord` to control which group stacks where. Here we stack by their # largest end value. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "end") ) # `"minvar"` instead puts the *least variable* group on the baseline. Every # band inherits the movement of the ones below it, so a steady bottom layer # keeps the whole chart legible. Here that picks group B, which the default # level order leaves in the middle and `"end"`/`"desc"` push to the top. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "minvar") ) # `"rev"` simply flips the existing level order, which is the one thing a # ranking function cannot do (it never sees which group it was handed). tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = "rev") ) # Custom ranking functions are also accepted. Name an argument `x` and it # receives the group's x values too, which is what a slope needs. tinyplot( val ~ year | grp, data = dat, type = type_area(stack = TRUE, byord = function(y, x) coef(lm(y ~ x))[2]) ) # Stacking expects a single `y` value per group per `x` value. Any repeats # are collapsed for us first, using `fun` (`mean` by default). Here, for # instance, ChickWeight records many chicks per diet at each timepoint. tinyplot( weight ~ Time | Diet, data = ChickWeight, type = type_area(stack = TRUE, fun = median) ) # (Illustrative purposes aside, we leave it to the reader to decide whether # stacking separate diets on top of one another makes any sense...) # ## Dodged ribbon/area plots # Dodged ribbon or area plots can be useful in cases where there is strong # overlap across groups (and a limited number of discrete x-axis values). dat = data.frame( x = rep(c("Before", "After"), each = 2), grp = rep(c("A", "B"), 2), y = c(10, 10.5, 15, 15.3), lwr = c(8, 8.5, 13, 13.3), upr = c(12, 12.5, 17, 17.3) ) tinyplot( y ~ x | grp, data = dat, ymin = lwr, ymax = upr, type = type_ribbon(), main = "Overlappling ribbons" ) tinyplot( y ~ x | grp, data = dat, ymin = lwr, ymax = upr, type = type_ribbon(dodge = 0.1), main = "Dodged ribbons" )
Type function for producing barplots. For formulas of type
~ x (without left-hand side) the barplot visualizes the counts (absolute
frequencies) of the levels of x. For formulas of type y ~ x the value
of y within each level of x is visualized, if necessary aggregated
using some function (default: mean).
type_barplot( width = 5/6, beside = FALSE, center = FALSE, offset = NULL, fun = NULL, xlevels = NULL, xord = NULL, drop.zeros = FALSE, na.as.zero = NULL, lighten = TRUE, xaxlabels = NULL, FUN = NULL )type_barplot( width = 5/6, beside = FALSE, center = FALSE, offset = NULL, fun = NULL, xlevels = NULL, xord = NULL, drop.zeros = FALSE, na.as.zero = NULL, lighten = TRUE, xaxlabels = NULL, FUN = NULL )
width |
numeric, optional vector of bar widths. (The distance between the midpoints of the bars is always 1.) |
beside |
logical. In case of a |
center |
logical or numeric. In case of stacked barplots ( |
offset |
optional specification for shifting bar baselines, accepting one of two distinct forms. See the Examples for illustrations of both.
|
fun, FUN
|
a function to compute the summary statistic for |
xlevels, xord
|
arguments controlling the order of the
Note that a numeric |
drop.zeros |
logical. Should bars with zero height be dropped? If set
to |
na.as.zero |
logical. Should a category that no observation reaches be
treated as a zero? Defaults to |
lighten |
logical. Should the fills use a lighter, opaque tint of the
series colour(s)? Default is |
xaxlabels |
[Deprecated] a character vector with the axis labels for
the |
Grouping (by) or faceting a barplot asks for a bar per unique combination
(i.e., category + group + facet). However, some combinations may not be
supported by any observations in the data. In these cases, the bars are
still computed off the completed combination set; particularly since stacked
and centered barplots have to line up regardless. Yet this in turn invites
the question of whether an "empty" cell should be read as an implicit zero,
or treated as missing (NA).
In most cases, the question is answered by the fun aggregation. This is
because it computes the actual value that is being plotted. For example, a
count of no observations is 0, whereas a mean of no observations is
undefined and thus better treated as NA (similarly for other summary
statistics like the variance or median). Nonetheless, users can override
this behaviour either way with the na.as.zero argument.
Three related points are worth highlighting. First, a zero-height bar only
reads as zero when it is measured from zero. So offset layouts
(waterfall, diverging/Likert) never draw one unless na.as.zero = TRUE
asks for it explicitly. Second, a "zero" combination is still subject to
the drop.zeros argument like any other zero. So
na.as.zero = TRUE, drop.zeros = TRUE cancel out. Finally,
na.as.zero = TRUE marks only the categories that could have held data.
Where x, by or facet are mapped to the same variable, for example,
most combinations cannot occur at all—and are never drawn, regardless.
# ## Basic use (raw values) # (named) atomic vector tinyplot(c(A = 1, B = 2, C = 3), type = "barplot") # formula + data.frame method tinyplot(GNP ~ Year, data = longley, type = "barplot") tinyplot(demand ~ Time, data = BOD, type = "bar") # "bar" is a shorthand tinyplot_add(type = "text", pos = 3, xpd = NA) # add y values as text # reordering (just to demonstrate; these aren't sensible for a time variable) tinyplot(demand ~ Time, data = BOD, type = "bar", xord = "asc") jumble = c("7","1","5","2","4","3") # note: Time = 6 is also missing tinyplot(demand ~ Time, data = BOD, type = "bar", xlevels = jumble) # useful top-level args: # 1) xaxl to format the x labels, e.g. with a dictionary, keyword, or (here:) # function # 2) xaxr to rotate long category labels (best used with a dynamic theme) tinyplot( demand ~ Time, data = BOD, type = "bar", xaxl = function(x) paste("Time =", x), xaxr = 45, theme = "broadsheet" ) # ## Aggregated vs grouped values (multiple ys per x) # each person receives two drugs sleep2 = transform(sleep, drug = group) # less misleading name # default aggregation fun is mean tinyplot( extra ~ ID, data = sleep2, type = "barplot", main = "Mean extra sleep from 2 soporific drugs" ) # switch to diff (answers a more relevant q: who benefits most from drug 2?) tinyplot( extra ~ ID, data = sleep2, type = "barplot", fun = diff, main = "Sleep gain (drug 2 vs drug 1)" ) # we can sort in descending (or ascending) order too tinyplot( extra ~ ID, data = sleep2, type = "barplot", fun = diff, xord = "desc", main = "Sleep gain (drug 2 vs drug 1), ordered" ) # of course, we don't have to aggregate if we specify groups (stacked or non) tinyplot(extra ~ ID | drug, data = sleep2, type = "barplot", beside = TRUE) # Aside: We used automatic argument passing for 'xord', `fun`, etc. above. # But this wouldn't work for `width`, since it would conflict with the # top-level `tinyplot(..., width = <width>)` argument. It's safer to pass # these args through the `type_barplot()` functional equivalent... tinyplot( extra ~ ID | drug, data = sleep2, type = type_barplot(beside = TRUE, xord = "desc", width = 0.5) ) # ## matrix method (no formula required) tinyplot(VADeaths, type = "barplot") tinyplot(VADeaths, type = "barplot", beside = TRUE) # etc. see ?tinyplot.matrix # ## Frequency tables # No y variable (frequency calculated on the fly) tinyplot(~ cyl, data = mtcars, type = "barplot") tinyplot(~ cyl | vs, data = mtcars, type = "barplot") tinyplot(~ cyl | vs, data = mtcars, type = "barplot", beside = TRUE) # Fancy frequency table (y = frequency aleady computed) tinyplot( Freq ~ Sex | Survived, data = as.data.frame(Titanic), facet = ~ Class, facet.args = list(nrow = 1), type = "barplot", beside = TRUE, flip = TRUE, theme = "clean2" ) # ## Centering # Centered barplot for conditional proportions of "dark" (black/brown) vs. # "fair" (red/blond) hair color, conditional on eye color and sex. # Aside: use `lighten = FALSE` to avoid lightening the bar fill colors. hec = as.data.frame(proportions(HairEyeColor, 2:3)) hcols = c("black", "sienna", "indianred", "goldenrod") tinyplot( Freq ~ Eye | Hair, data = hec, facet = ~ Sex, facet.args = list(ncol = 1), type = type_barplot(center = TRUE, lighten = FALSE), flip = TRUE, yaxl = "percent", theme = list("clean2", palette.qualitative = hcols) ) tinyplot_add(type = "hline", col = "white") # "hline" b/c flip = TRUE # ## Offset examples # 1. Waterfall plot d = data.frame(item = c("Sales", "Services", "Costs", "Returns", "TOTAL"), value = c(100, 40, -80, -10, 50)) d$item = factor(d$item, levels = d$item) d$offset = c(0, cumsum(d$value[1:3]), 0) tinyplot( value ~ item | I(value < 0), data = d, type = type_barplot(offset = d$offset, lighten = FALSE), legend = FALSE ) tinyplot_add(type = type_vline(4.5), lty = 2, col = "grey50") # 2. Diverging/Likert layout: a character (or named numeric) offset "sets # aside" the named category, pulling it out of the centered stack and drawing # it as a standalone bar. Here a neutral "Unsure" response is shown apart from # the diverging agree/disagree scale. lik = expand.grid( question = c("Pay", "Workload", "Manager", "Culture"), response = c("Strong disagree", "Disagree", "Agree", "Strong agree", "Unsure") ) lik$share = c( # proportions summing to 1 within each question .10, .25, .05, .15, .20, .30, .15, .20, .35, .20, .40, .30, .25, .15, .35, .20, .10, .10, .05, .15 ) # diverging palette: reds (disagree) -> blues (agree), grey for "Unsure" pal = c("#b2182b", "#ef8a62", "#67a9cf", "#2166ac", "grey") tinyplot( share ~ question | response, data = lik, type = type_barplot(center = TRUE, offset = "Unsure", lighten = FALSE), flip = TRUE, xlab = NA, ylab = NA, yaxl = "percent", legend = list("top!", title = FALSE), theme = list("clean2", palette.qualitative = pal), main = "Hypothetical Likert example with category offset" ) tinyplot_add(type = "hline") # "hline" b/c flip = TRUE tinyplot_add(type = type_hline(1), lty = 2) # ditto # ## Implicit zeros and empty cells (see the section of the same name above) # No (mt)car has 8 cylinders and a straight engine, so that bar is a count # of zero and is marked as such (flat, along the baseline) tinyplot(~ cyl | vs, data = mtcars, type = "barplot", facet = "by") # But in this example, the aggregating statistic is a mean rather than a # count. The mean of unobserved combinations (e.g., carb==1 & vs==0) is # is undefined, so nothing is drawn for the empty cells tinyplot( mpg ~ factor(carb), data = mtcars, type = "barplot", facet = ~ vs, facet.args = list(ncol = 1) ) # ... use na.as.zero to override and mark as (implicit) zeros tinyplot( mpg ~ factor(carb), data = mtcars, type = type_barplot(na.as.zero = TRUE), facet = ~ vs, facet.args = list(ncol = 1) )# ## Basic use (raw values) # (named) atomic vector tinyplot(c(A = 1, B = 2, C = 3), type = "barplot") # formula + data.frame method tinyplot(GNP ~ Year, data = longley, type = "barplot") tinyplot(demand ~ Time, data = BOD, type = "bar") # "bar" is a shorthand tinyplot_add(type = "text", pos = 3, xpd = NA) # add y values as text # reordering (just to demonstrate; these aren't sensible for a time variable) tinyplot(demand ~ Time, data = BOD, type = "bar", xord = "asc") jumble = c("7","1","5","2","4","3") # note: Time = 6 is also missing tinyplot(demand ~ Time, data = BOD, type = "bar", xlevels = jumble) # useful top-level args: # 1) xaxl to format the x labels, e.g. with a dictionary, keyword, or (here:) # function # 2) xaxr to rotate long category labels (best used with a dynamic theme) tinyplot( demand ~ Time, data = BOD, type = "bar", xaxl = function(x) paste("Time =", x), xaxr = 45, theme = "broadsheet" ) # ## Aggregated vs grouped values (multiple ys per x) # each person receives two drugs sleep2 = transform(sleep, drug = group) # less misleading name # default aggregation fun is mean tinyplot( extra ~ ID, data = sleep2, type = "barplot", main = "Mean extra sleep from 2 soporific drugs" ) # switch to diff (answers a more relevant q: who benefits most from drug 2?) tinyplot( extra ~ ID, data = sleep2, type = "barplot", fun = diff, main = "Sleep gain (drug 2 vs drug 1)" ) # we can sort in descending (or ascending) order too tinyplot( extra ~ ID, data = sleep2, type = "barplot", fun = diff, xord = "desc", main = "Sleep gain (drug 2 vs drug 1), ordered" ) # of course, we don't have to aggregate if we specify groups (stacked or non) tinyplot(extra ~ ID | drug, data = sleep2, type = "barplot", beside = TRUE) # Aside: We used automatic argument passing for 'xord', `fun`, etc. above. # But this wouldn't work for `width`, since it would conflict with the # top-level `tinyplot(..., width = <width>)` argument. It's safer to pass # these args through the `type_barplot()` functional equivalent... tinyplot( extra ~ ID | drug, data = sleep2, type = type_barplot(beside = TRUE, xord = "desc", width = 0.5) ) # ## matrix method (no formula required) tinyplot(VADeaths, type = "barplot") tinyplot(VADeaths, type = "barplot", beside = TRUE) # etc. see ?tinyplot.matrix # ## Frequency tables # No y variable (frequency calculated on the fly) tinyplot(~ cyl, data = mtcars, type = "barplot") tinyplot(~ cyl | vs, data = mtcars, type = "barplot") tinyplot(~ cyl | vs, data = mtcars, type = "barplot", beside = TRUE) # Fancy frequency table (y = frequency aleady computed) tinyplot( Freq ~ Sex | Survived, data = as.data.frame(Titanic), facet = ~ Class, facet.args = list(nrow = 1), type = "barplot", beside = TRUE, flip = TRUE, theme = "clean2" ) # ## Centering # Centered barplot for conditional proportions of "dark" (black/brown) vs. # "fair" (red/blond) hair color, conditional on eye color and sex. # Aside: use `lighten = FALSE` to avoid lightening the bar fill colors. hec = as.data.frame(proportions(HairEyeColor, 2:3)) hcols = c("black", "sienna", "indianred", "goldenrod") tinyplot( Freq ~ Eye | Hair, data = hec, facet = ~ Sex, facet.args = list(ncol = 1), type = type_barplot(center = TRUE, lighten = FALSE), flip = TRUE, yaxl = "percent", theme = list("clean2", palette.qualitative = hcols) ) tinyplot_add(type = "hline", col = "white") # "hline" b/c flip = TRUE # ## Offset examples # 1. Waterfall plot d = data.frame(item = c("Sales", "Services", "Costs", "Returns", "TOTAL"), value = c(100, 40, -80, -10, 50)) d$item = factor(d$item, levels = d$item) d$offset = c(0, cumsum(d$value[1:3]), 0) tinyplot( value ~ item | I(value < 0), data = d, type = type_barplot(offset = d$offset, lighten = FALSE), legend = FALSE ) tinyplot_add(type = type_vline(4.5), lty = 2, col = "grey50") # 2. Diverging/Likert layout: a character (or named numeric) offset "sets # aside" the named category, pulling it out of the centered stack and drawing # it as a standalone bar. Here a neutral "Unsure" response is shown apart from # the diverging agree/disagree scale. lik = expand.grid( question = c("Pay", "Workload", "Manager", "Culture"), response = c("Strong disagree", "Disagree", "Agree", "Strong agree", "Unsure") ) lik$share = c( # proportions summing to 1 within each question .10, .25, .05, .15, .20, .30, .15, .20, .35, .20, .40, .30, .25, .15, .35, .20, .10, .10, .05, .15 ) # diverging palette: reds (disagree) -> blues (agree), grey for "Unsure" pal = c("#b2182b", "#ef8a62", "#67a9cf", "#2166ac", "grey") tinyplot( share ~ question | response, data = lik, type = type_barplot(center = TRUE, offset = "Unsure", lighten = FALSE), flip = TRUE, xlab = NA, ylab = NA, yaxl = "percent", legend = list("top!", title = FALSE), theme = list("clean2", palette.qualitative = pal), main = "Hypothetical Likert example with category offset" ) tinyplot_add(type = "hline") # "hline" b/c flip = TRUE tinyplot_add(type = type_hline(1), lty = 2) # ditto # ## Implicit zeros and empty cells (see the section of the same name above) # No (mt)car has 8 cylinders and a straight engine, so that bar is a count # of zero and is marked as such (flat, along the baseline) tinyplot(~ cyl | vs, data = mtcars, type = "barplot", facet = "by") # But in this example, the aggregating statistic is a mean rather than a # count. The mean of unobserved combinations (e.g., carb==1 & vs==0) is # is undefined, so nothing is drawn for the empty cells tinyplot( mpg ~ factor(carb), data = mtcars, type = "barplot", facet = ~ vs, facet.args = list(ncol = 1) ) # ... use na.as.zero to override and mark as (implicit) zeros tinyplot( mpg ~ factor(carb), data = mtcars, type = type_barplot(na.as.zero = TRUE), facet = ~ vs, facet.args = list(ncol = 1) )
Type function for producing box-and-whisker plots.
Arguments are passed to boxplot, although tinyplot
scaffolding allows added functionality such as grouping and faceting.
Box-and-whisker plots are the default plot type if x is a factor and y is
numeric.
type_boxplot( range = 1.5, width = NULL, varwidth = FALSE, notch = FALSE, outline = TRUE, boxwex = 0.8, staplewex = 0.5, outwex = 0.5, lighten = TRUE )type_boxplot( range = 1.5, width = NULL, varwidth = FALSE, notch = FALSE, outline = TRUE, boxwex = 0.8, staplewex = 0.5, outwex = 0.5, lighten = TRUE )
range |
this determines how far the plot whiskers extend out
from the box. If |
width |
a vector giving the relative widths of the boxes making up the plot. |
varwidth |
if |
notch |
if |
outline |
if |
boxwex |
a scale factor to be applied to all boxes. When there are only a few groups, the appearance of the plot can be improved by making the boxes narrower. |
staplewex |
staple line width expansion, proportional to box width. |
outwex |
outlier line width expansion, proportional to box width. |
lighten |
logical. Should the fills use a lighter, opaque tint of the
series colour(s)? Default is |
# "boxplot" type convenience string tinyplot(weight ~ feed, data = chickwts, type = "boxplot") # Note: Specifying the type here is redundant. Like base plot, tinyplot # automatically produces a boxplot if x is a factor and y is numeric tinyplot(weight ~ feed, data = chickwts) # For flipped boxplots, it's usually better to use a dynamic theme to # accommodate (horizontal) y-axis labels tinyplot(weight ~ feed, data = chickwts, flip = TRUE, theme = "dynamic") # Grouped boxplot example using a different dataset # (C.f., the final example in `?boxplot`) tinyplot( len ~ dose | supp, data = ToothGrowth, type = "boxplot", main = "Guinea Pigs' Tooth Growth", legend = list(title = "Supplement"), xlab = "Vitamin C dose mg", ylab = "tooth length" ) # Use `type_boxplot()` to pass extra arguments for customization tinyplot( len ~ dose | supp, data = ToothGrowth, type = type_boxplot(boxwex = 0.3, staplewex = 0, outline = FALSE), lty = 1, legend = list(title = "Supplement"), main = "Guinea Pigs' Tooth Growth", xlab = "Vitamin C dose mg", ylab = "tooth length" )# "boxplot" type convenience string tinyplot(weight ~ feed, data = chickwts, type = "boxplot") # Note: Specifying the type here is redundant. Like base plot, tinyplot # automatically produces a boxplot if x is a factor and y is numeric tinyplot(weight ~ feed, data = chickwts) # For flipped boxplots, it's usually better to use a dynamic theme to # accommodate (horizontal) y-axis labels tinyplot(weight ~ feed, data = chickwts, flip = TRUE, theme = "dynamic") # Grouped boxplot example using a different dataset # (C.f., the final example in `?boxplot`) tinyplot( len ~ dose | supp, data = ToothGrowth, type = "boxplot", main = "Guinea Pigs' Tooth Growth", legend = list(title = "Supplement"), xlab = "Vitamin C dose mg", ylab = "tooth length" ) # Use `type_boxplot()` to pass extra arguments for customization tinyplot( len ~ dose | supp, data = ToothGrowth, type = type_boxplot(boxwex = 0.3, staplewex = 0, outline = FALSE), lty = 1, legend = list(title = "Supplement"), main = "Guinea Pigs' Tooth Growth", xlab = "Vitamin C dose mg", ylab = "tooth length" )
Type function for drawing convex hulls around grouped points.
Uses chull to compute the convex hull of each
group and draws the result as a polygon.
type_chull(density = NULL, angle = 45)type_chull(density = NULL, angle = 45)
density |
the density of shading lines, in lines per inch. The
default value of |
angle |
the slope of shading lines, given as an angle in degrees (counter-clockwise). |
# "chull" type convenience character string tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = "chull") # layer filled convex hull(s) on top of points tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic") tinyplot_add(type = "chull", fill = 0.2)# "chull" type convenience character string tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = "chull") # layer filled convex hull(s) on top of points tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic") tinyplot_add(type = "chull", fill = 0.2)
Type function for density plots.
type_density( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, echo.bw = FALSE, alpha = NULL, singletons = c("warn", "drop", "none") )type_density( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, echo.bw = FALSE, alpha = NULL, singletons = c("warn", "drop", "none") )
bw |
the smoothing |
joint.bw |
character string indicating whether (and how) the smoothing
bandwidth should be computed from the joint data distribution when there
are multiple subgroups. The options are |
adjust |
the bandwidth used is actually |
kernel |
a character string giving the smoothing kernel to be used. This
must partially match one of
|
n |
the number of equally spaced points at which the density is
to be estimated. When |
echo.bw |
where to report the smoothing bandwidth (and the number of
observations behind it), since neither is visible from the curve itself.
The default |
alpha |
numeric value between 0 and 1 specifying the opacity of ribbon shading
If no |
singletons |
character string indicating what to do with singleton
groups, i.e. combinations of |
The algorithm used in density.default disperses the mass of the
empirical distribution function over a regular grid of at least 512
points and then uses the fast Fourier transform to convolve this
approximation with a discretized version of the kernel and then uses
linear approximation to evaluate the density at the specified points.
The statistical properties of a kernel are determined by
which is always for our kernels (and hence the bandwidth
bw is the standard deviation of the kernel) and
.
MSE-equivalent bandwidths (for different kernels) are proportional to
which is scale invariant and for our
kernels equal to . This value is returned when
give.Rkern = TRUE. See the examples for using exact equivalent
bandwidths.
Infinite values in x are assumed to correspond to a point mass at
+/-Inf and the density estimate is of the sub-density on
(-Inf, +Inf).
While the choice of smoothing bandwidth will
always stand to affect a density visualization, it gains an added
importance when multiple densities are drawn simultaneously (e.g., for
subgroups with respect to by or facet). Allowing each subgroup to
compute its own separate bandwidth independently offers greater flexibility
in capturing the unique characteristics of each subgroup, particularly when
distributions differ substantially in location and/or scale. However, this
approach may overemphasize small random variations and make it harder to
visually compare densities across subgroups. Hence, it is often useful to
employ the same ("joint") bandwidth across all subgroups. The following
strategies are available via the joint.bw argument:
The default joint.bw = "mean" first computes the individual bandwidths
for each group but then computes their mean, weighted by the number of
observations in each group. This will work well when all groups have
similar amounts of scatter (similar variances), even when they have
potentially rather different locations. The weighted averaging stabilizes
potential fluctuations in the individual bandwidths, especially when some
subgroups are rather small.
Alternatively, joint.bw = "full" can be used to compute the joint
bandwidth from the full joint distribution (merging all groups). This will
yield an even more robust bandwidth, especially when the groups overlap
substantially (i.e., have similar locations and scales). However, it may
lead to too large bandwidths and thus too much smoothing, especially when
the locations of the groups differ substantially.
Finally, joint.bw = "none" disables the joint bandwidth so that each
group just employs its individual bandwidth. This is often the best choice
if the amounts of scatter differ substantially between the groups, thus
necessitating different amounts of smoothing.
This tinyplot method for density plots differs from the base
plot.density function in its treatment of titles. The
x-axis title displays only the variable name, omitting details about the
number of observations and smoothing bandwidth. Additionally, the main
title is left blank by default for a cleaner appearance. Use echo.bw to
put those details back in the subtitle, a caption, or the console.
# "density" type convenience string tinyplot(~Sepal.Length, data = iris, type = "density") # grouped density example tinyplot(~Sepal.Length | Species, data = iris, type = "density") # use `bg = "by"` (or, equivalent `fill = "by"`) to get filled densities tinyplot(~Sepal.Length | Species, data = iris, type = "density", fill = "by") # use `type_density()` to pass extra arguments for customization tinyplot( ~Sepal.Length | Species, data = iris, type = type_density(bw = "SJ"), main = "Bandwidth computed using Sheather & Jones (1991)" ) # The default for grouped density plots is to use the mean of the # individual subgroup bandwidths (weighted by group size) as the # joint bandwidth. Alternatively, the bandwidth from the "full" # data or separate individual bandwidths ("none") can be used. tinyplot(~Sepal.Length | Species, data = iris, ylim = c(0, 1.25), type = "density") # mean (default) tinyplot_add(joint.bw = "full", lty = 2) # full data tinyplot_add(joint.bw = "none", lty = 3) # none (individual) legend("topright", c("Mean", "Full", "None"), lty = 1:3, bty = "n", title = "Joint BW") # neither the bandwidth nor the number of observations is visible from the # curve, so `echo.bw` can report them: in the subtitle, a caption, or the # console tinyplot(~Sepal.Length | Species, data = iris, type = type_density(echo.bw = "sub")) # individual bandwidths are listed per group tinyplot(~Sepal.Length | Species, data = iris, type = type_density(joint.bw = "none", echo.bw = "sub"))# "density" type convenience string tinyplot(~Sepal.Length, data = iris, type = "density") # grouped density example tinyplot(~Sepal.Length | Species, data = iris, type = "density") # use `bg = "by"` (or, equivalent `fill = "by"`) to get filled densities tinyplot(~Sepal.Length | Species, data = iris, type = "density", fill = "by") # use `type_density()` to pass extra arguments for customization tinyplot( ~Sepal.Length | Species, data = iris, type = type_density(bw = "SJ"), main = "Bandwidth computed using Sheather & Jones (1991)" ) # The default for grouped density plots is to use the mean of the # individual subgroup bandwidths (weighted by group size) as the # joint bandwidth. Alternatively, the bandwidth from the "full" # data or separate individual bandwidths ("none") can be used. tinyplot(~Sepal.Length | Species, data = iris, ylim = c(0, 1.25), type = "density") # mean (default) tinyplot_add(joint.bw = "full", lty = 2) # full data tinyplot_add(joint.bw = "none", lty = 3) # none (individual) legend("topright", c("Mean", "Full", "None"), lty = 1:3, bty = "n", title = "Joint BW") # neither the bandwidth nor the number of observations is visible from the # curve, so `echo.bw` can report them: in the subtitle, a caption, or the # console tinyplot(~Sepal.Length | Species, data = iris, type = type_density(echo.bw = "sub")) # individual bandwidths are listed per group tinyplot(~Sepal.Length | Species, data = iris, type = type_density(joint.bw = "none", echo.bw = "sub"))
Type function for drawing confidence ellipses around grouped points.
type_ellipse(level = 0.95, segments = 100, density = NULL, angle = 45)type_ellipse(level = 0.95, segments = 100, density = NULL, angle = 45)
level |
Numeric confidence level for the ellipse. Default is |
segments |
Integer number of line segments used to approximate the
ellipse. Default is |
density |
the density of shading lines, in lines per inch. The
default value of |
angle |
the slope of shading lines, given as an angle in degrees (counter-clockwise). |
A confidence ellipse summarizes the spread and correlation of two variables: its axes align with the principal directions of variation, their lengths reflect the standard deviations along those directions, and the overall size is scaled so that (assuming bivariate normality) the specified proportion of observations falls within the boundary.
Operationally, the ellipse is computed from the covariance matrix
(cov) of each group via eigendecomposition
(eigen), scaled by a chi-squared quantile
(qchisq) for the specified confidence level.
Groups with fewer than 3 points are silently dropped.
# "ellipse" type convenience character string tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = "ellipse") # layer filled ellipse(s) on top of points tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic") tinyplot_add(type = "ellipse", fill = 0.2) # to avoid clipping, it's better to reverse the layering (ellipse first) tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic", type = "ellipse", fill = 0.2) tinyplot_add(type = "p") # custom confidence level tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = type_ellipse(level = 0.5))# "ellipse" type convenience character string tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = "ellipse") # layer filled ellipse(s) on top of points tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic") tinyplot_add(type = "ellipse", fill = 0.2) # to avoid clipping, it's better to reverse the layering (ellipse first) tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, theme = "basic", type = "ellipse", fill = 0.2) tinyplot_add(type = "p") # custom confidence level tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, type = type_ellipse(level = 0.5))
Type function(s) for producing error bar and pointrange plots.
type_errorbar( length = 0.05, dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = "asis" ) type_pointrange(dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = "asis")type_errorbar( length = 0.05, dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = "asis" ) type_pointrange(dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = "asis")
length |
length of the edges of the arrow head (in inches). |
dodge |
Adjustment parameter for dodging overlapping points or ranges in grouped plots along the x-axis (or y-axis for flipped plots). Either:
Default value is 0 (no dodging). While we do not check, it is strongly recommended that dodging only be used in cases where the x-axis comprises a limited number of discrete breaks. |
fixed.dodge |
Logical. If |
xlevels, xord
|
arguments controlling the order of the
Note that Unlike most other plot types, |
tinytheme("basic") # filled points & background grid (but not dynamic yet) # ## Basic coefficient plot(s) mod = lm(mpg ~ wt * factor(am), mtcars) coefs = data.frame(names(coef(mod)), coef(mod), confint(mod)) colnames(coefs) = c("term", "est", "lwr", "upr") # "errorbar" and "pointrange" type convenience strings tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "errorbar") tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "pointrange") # Use `type_errorbar()` to pass extra arguments for customization tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = type_errorbar(length = 0.2)) # ## Flipped plots # For flipped errobar / pointrange plots, it is recommended to use a # *dynamic* theme for horizontal axis tick labels + appropriate spacing tinytheme("classic") # or "clean(2)", "bw", "socviz", "float", ... tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "errorbar", flip = TRUE) tinyplot_add(type = "hline", lty = 2) # "hline" b/c flip = TRUE (not vline!) tinytheme("basic") # back to basic theme for the remaining examples # ## Dodging groups models = list( "Model A" = lm(mpg ~ wt, data = mtcars), "Model B" = lm(mpg ~ wt + cyl, data = mtcars), "Model C" = lm(mpg ~ wt + cyl + hp, data = mtcars) ) models = do.call( rbind, lapply(names(models), function(m) { data.frame( model = m, term = names(coef(models[[m]])), estimate = coef(models[[m]]), setNames(data.frame(confint(models[[m]])), c("conf.low", "conf.high")) ) }) ) tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = type_pointrange(dodge = 0.1)) # Aside 1: relative vs fixed dodge # The default dodge position is based on the unique groups (here: models) # available to each x value (here: coefficient term). To "fix" the dodge # position across all x values, use `fixed.dodge = TRUE`. tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = type_pointrange(dodge = 0.1, fixed.dodge = TRUE)) # Aside 2: layering # For layering on top of dodged plots, rather pass the dodging arguments # through the top-level call if you'd like the dodging behaviour to be # inherited automatically by the added layers. tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = "pointrange", dodge = 0.1, fixed.dodge = TRUE) tinyplot_add(type = "l", lty = 2) # ## Handling (long/overlapping) tick labels # You may face the annoyance of long and/or overlapping tick labels, e.g. mod2 = lm(mpg ~ 0 + factor(cyl) * factor(am), mtcars) coefs2 = data.frame(names(coef(mod2)), coef(mod2), confint(mod2)) colnames(coefs2) = c("term", "est", "lwr", "upr") # (re-usable plot function) demo_plot = function(...) { tinyplot( est ~ term, ymin = lwr, ymax = upr, data = coefs2, type = "errorbar", xlab = NA, ylab = "MPG (miles per gallon)", main = "Impact on fuel efficiency", ... ) } demo_plot() # Here are some useful arguments (strategies) to avoid this annoyance... # 1) dynamic theme + rotated x-labels demo_plot(theme = "clean", xaxr = 45) # 2) dynamic theme + labeller function (here: dictionary w/ newline spacing) dict = c( "factor(cyl)4" = "Manual\n4 Cyclinders", "factor(cyl)6" = "Manual\n6 Cyclinders", "factor(cyl)8" = "Manual\n8 Cyclinders", "factor(am)1" = "Automatic\n4 Cylinders", "factor(cyl)6:factor(am)1" = "Automatic\n6 Cylinders", "factor(cyl)8:factor(am)1" = "Automatic\n8 Cylinders" ) demo_plot(theme = "clean", xaxl = dict) # 3) dynamic theme + flipped axes demo_plot(theme = "clean", flip = TRUE) # 4) any combination of the above, e.g., labeller dictionary + flipped axes demo_plot(theme = "clean", flip = TRUE, xaxl = dict) tinytheme() # reset themetinytheme("basic") # filled points & background grid (but not dynamic yet) # ## Basic coefficient plot(s) mod = lm(mpg ~ wt * factor(am), mtcars) coefs = data.frame(names(coef(mod)), coef(mod), confint(mod)) colnames(coefs) = c("term", "est", "lwr", "upr") # "errorbar" and "pointrange" type convenience strings tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "errorbar") tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "pointrange") # Use `type_errorbar()` to pass extra arguments for customization tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = type_errorbar(length = 0.2)) # ## Flipped plots # For flipped errobar / pointrange plots, it is recommended to use a # *dynamic* theme for horizontal axis tick labels + appropriate spacing tinytheme("classic") # or "clean(2)", "bw", "socviz", "float", ... tinyplot(est ~ term, ymin = lwr, ymax = upr, data = coefs, type = "errorbar", flip = TRUE) tinyplot_add(type = "hline", lty = 2) # "hline" b/c flip = TRUE (not vline!) tinytheme("basic") # back to basic theme for the remaining examples # ## Dodging groups models = list( "Model A" = lm(mpg ~ wt, data = mtcars), "Model B" = lm(mpg ~ wt + cyl, data = mtcars), "Model C" = lm(mpg ~ wt + cyl + hp, data = mtcars) ) models = do.call( rbind, lapply(names(models), function(m) { data.frame( model = m, term = names(coef(models[[m]])), estimate = coef(models[[m]]), setNames(data.frame(confint(models[[m]])), c("conf.low", "conf.high")) ) }) ) tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = type_pointrange(dodge = 0.1)) # Aside 1: relative vs fixed dodge # The default dodge position is based on the unique groups (here: models) # available to each x value (here: coefficient term). To "fix" the dodge # position across all x values, use `fixed.dodge = TRUE`. tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = type_pointrange(dodge = 0.1, fixed.dodge = TRUE)) # Aside 2: layering # For layering on top of dodged plots, rather pass the dodging arguments # through the top-level call if you'd like the dodging behaviour to be # inherited automatically by the added layers. tinyplot(estimate ~ term | model, ymin = conf.low, ymax = conf.high, data = models, type = "pointrange", dodge = 0.1, fixed.dodge = TRUE) tinyplot_add(type = "l", lty = 2) # ## Handling (long/overlapping) tick labels # You may face the annoyance of long and/or overlapping tick labels, e.g. mod2 = lm(mpg ~ 0 + factor(cyl) * factor(am), mtcars) coefs2 = data.frame(names(coef(mod2)), coef(mod2), confint(mod2)) colnames(coefs2) = c("term", "est", "lwr", "upr") # (re-usable plot function) demo_plot = function(...) { tinyplot( est ~ term, ymin = lwr, ymax = upr, data = coefs2, type = "errorbar", xlab = NA, ylab = "MPG (miles per gallon)", main = "Impact on fuel efficiency", ... ) } demo_plot() # Here are some useful arguments (strategies) to avoid this annoyance... # 1) dynamic theme + rotated x-labels demo_plot(theme = "clean", xaxr = 45) # 2) dynamic theme + labeller function (here: dictionary w/ newline spacing) dict = c( "factor(cyl)4" = "Manual\n4 Cyclinders", "factor(cyl)6" = "Manual\n6 Cyclinders", "factor(cyl)8" = "Manual\n8 Cyclinders", "factor(am)1" = "Automatic\n4 Cylinders", "factor(cyl)6:factor(am)1" = "Automatic\n6 Cylinders", "factor(cyl)8:factor(am)1" = "Automatic\n8 Cylinders" ) demo_plot(theme = "clean", xaxl = dict) # 3) dynamic theme + flipped axes demo_plot(theme = "clean", flip = TRUE) # 4) any combination of the above, e.g., labeller dictionary + flipped axes demo_plot(theme = "clean", flip = TRUE, xaxl = dict) tinytheme() # reset theme
Plot a function
type_function(fun = dnorm, args = list(), n = 101, ...)type_function(fun = dnorm, args = list(), n = 101, ...)
fun |
Function of |
args |
List of additional arguments to be passed to |
n |
Number of points to interpolate on the x axis. |
... |
Additional arguments are passed to the |
When using type_function() in a tinyplot() call, the x value indicates
the range of values to plot on the x-axis.
# Plot the normal density (default function) tinyplot(x = -4:4, type = "function") # tinyplot(x = -4:4, type = type_function()) # same # Customize by passing explicit arguments to your function tinyplot(x = -1:10, type = type_function( fun = dnorm, args = list(mean = 3) )) # Additional arguments are passed to the `lines()` function. tinyplot(x = -4:4, type = type_function( fun = dnorm, col = "pink", type = "p", pch = 3 )) # Custom function example ## (Here using `function(x)`, but you could also use the shorter `\(x)` ## anonymous function syntax introduced in R 4.1.0) tinyplot(x = -4:4, type = type_function(fun = function(x) 0.5 * exp(-abs(x))))# Plot the normal density (default function) tinyplot(x = -4:4, type = "function") # tinyplot(x = -4:4, type = type_function()) # same # Customize by passing explicit arguments to your function tinyplot(x = -1:10, type = type_function( fun = dnorm, args = list(mean = 3) )) # Additional arguments are passed to the `lines()` function. tinyplot(x = -4:4, type = type_function( fun = dnorm, col = "pink", type = "p", pch = 3 )) # Custom function example ## (Here using `function(x)`, but you could also use the shorter `\(x)` ## anonymous function syntax introduced in R 4.1.0) tinyplot(x = -4:4, type = type_function(fun = function(x) 0.5 * exp(-abs(x))))
Type function for plotting a generalized model fit.
Arguments are passed to glm.
type_glm( family = "gaussian", se = TRUE, level = 0.95, type = "response", weights = NULL )type_glm( family = "gaussian", se = TRUE, level = 0.95, type = "response", weights = NULL )
family |
a description of the error distribution and link
function to be used in the model. For |
se |
logical. If TRUE, confidence intervals are drawn. |
level |
the confidence level required. |
type |
character, partial matching allowed. Type of weights to extract from the fitted model object. Can be abbreviated. |
weights |
an optional numeric vector of observation weights for the model
fit, of the same length as the number of data points. Weights can also be
supplied via the top-level |
# "glm" type convenience string tinyplot(am ~ mpg, data = mtcars, type = "glm") # Use `type_glm()` to pass extra arguments for customization tinyplot(am ~ mpg, data = mtcars, type = type_glm(family = "binomial"))# "glm" type convenience string tinyplot(am ~ mpg, data = mtcars, type = "glm") # Use `type_glm()` to pass extra arguments for customization tinyplot(am ~ mpg, data = mtcars, type = type_glm(family = "binomial"))
Type function for hexagonal bin plots (a 2D analogue of a histogram). Point density is aggregated into a regular hexagonal lattice and each occupied cell is drawn as a hexagon whose fill colour encodes the number of points it contains. This is a lightweight (vectorized), pure R implementation of the canonical hexagonal binning algorithm of Carr et al. (1987).
type_hexbin( xbins = 30, shape = 1, mincnt = 1, maxcnt = Inf, border = NA, fun = NULL )type_hexbin( xbins = 30, shape = 1, mincnt = 1, maxcnt = Inf, border = NA, fun = NULL )
xbins |
Integer. The number of bins partitioning the range of the
x-axis. Default is |
shape |
Numeric. The aspect ratio (height/width) of the plotting region
used to compute the hexagon geometry. Default is |
mincnt, maxcnt
|
Integer. Cells with counts outside the
|
border |
Colour for the hexagon borders, passed to
|
fun |
Function used to summarise a numeric |
Hexagonal binning partitions the plotting region into a regular
lattice of hexagons. Following the original Carr et al. (1987) algorithm,
rows are spaced apart in scaled space, with odd rows
offset by half a cell in the x-direction, while each point is assigned to
its nearest lattice node.
What the fill colour encodes depends on whether a by variable is supplied
(e.g. y ~ x | z):
No by (default). The fill encodes the cell count, mapped to a
continuous colour gradient with an automatic colourbar legend.
Discrete by. The fill encodes the modal (most frequent) level of
the by variable within each cell, drawn with a discrete qualitative
palette and legend. Useful for mapping the dominant category across a
dense scatter.
Numeric by. The fill encodes a per-cell summary of the by
variable—by default the mean, or any other function passed via fun
(e.g. fun = sum). Like the original no-by case, the legend is drawn
as a continuous gradient. This is the hexagonal analogue of a binned
heatmap.
In all three modes, the mincnt/maxcnt filters still apply to the raw
cell count, so sparsely populated cells can be excluded regardless of
what the colour encodes.
Because the hexagon size is derived from the data ranges, hexagons will
only appear perfectly regular when the plot region's aspect ratio matches
shape. Adjust shape (or the device dimensions) if you need visually
regular hexagons.
The tinyplot implementation presented here is a compact (vectorised) translation of the original Carr et al. algorithm into base R. Users requiring the fuller feature set of a dedicated hexbinning package should consult hexbin as a canonical reference, which is built on top of compiled Fortran code. Note that we have validated our cell counts against this package to confirm they match exactly.
Carr, D. B., Littlefield, R. J., Nicholson, W. L., and Littlefield, J. S. (1987). Scatterplot Matrix Techniques for Large N. Journal of the American Statistical Association, 82(398), 424-436. Available: https://doi.org/10.2307/2289444
Carr, D., Lewin-Koh, N., Maechler, M., and Sarkar, D. (2024). hexbin: Hexagonal Binning Routines. R package version 1.28.5. Available: https://doi.org/10.32614/CRAN.package.hexbin. The hexbin package provides the canonical implementation of this algorithm, and was a valuable reference for validating our cell counts.
set.seed(1234) dat = data.frame(x = rnorm(20000), y = rnorm(20000)) # "hexbin"/"hex" type convenience string tinyplot(y ~ x, data = dat, type = "hexbin") # Use type_hexbin() to pass extra arguments tinyplot(y ~ x, data = dat, type = type_hexbin(xbins = 40)) # tinyplot's default palette logic maps darker colours (the end of the # spectrum) to higher densities. For hexbin plots it can sometimes be more # visually pleasing to reverse this, which users can do manually by passing a # reversed palette. tinyplot( y ~ x, data = dat, type = "hexbin", palette = hcl.colors(100, palette = "viridis", rev = TRUE) ) # Passing a `by` grouping variable will colour cells according to a summary # of this variable (in each hex cell) instead of density count. The default # summary function depends on whether `by` is discrete or continuous: # 1) Discrete grouping variable: each cell is coloured by its mode. dat$g = cut(dat$x, breaks = c(-Inf, -1, 1, Inf), labels = c("lo", "mid", "hi")) tinyplot(y ~ x | g, data = dat, type = "hexbin") # 2) Continuous grouping variable: each cell is coloured by its mean. # Example: Create a long version of the `volcano` dataset, and plot its # elevations onto a gridded terrain map. volc = data.frame( x = as.vector(row(volcano)), y = as.vector(col(volcano)), elevation = as.vector(volcano) ) tinyplot( y ~ x | elevation, data = volc, type = "hexbin", xbins = 50, palette = terrain.colors(100, rev = TRUE) )set.seed(1234) dat = data.frame(x = rnorm(20000), y = rnorm(20000)) # "hexbin"/"hex" type convenience string tinyplot(y ~ x, data = dat, type = "hexbin") # Use type_hexbin() to pass extra arguments tinyplot(y ~ x, data = dat, type = type_hexbin(xbins = 40)) # tinyplot's default palette logic maps darker colours (the end of the # spectrum) to higher densities. For hexbin plots it can sometimes be more # visually pleasing to reverse this, which users can do manually by passing a # reversed palette. tinyplot( y ~ x, data = dat, type = "hexbin", palette = hcl.colors(100, palette = "viridis", rev = TRUE) ) # Passing a `by` grouping variable will colour cells according to a summary # of this variable (in each hex cell) instead of density count. The default # summary function depends on whether `by` is discrete or continuous: # 1) Discrete grouping variable: each cell is coloured by its mode. dat$g = cut(dat$x, breaks = c(-Inf, -1, 1, Inf), labels = c("lo", "mid", "hi")) tinyplot(y ~ x | g, data = dat, type = "hexbin") # 2) Continuous grouping variable: each cell is coloured by its mean. # Example: Create a long version of the `volcano` dataset, and plot its # elevations onto a gridded terrain map. volc = data.frame( x = as.vector(row(volcano)), y = as.vector(col(volcano)), elevation = as.vector(volcano) ) tinyplot( y ~ x | elevation, data = volc, type = "hexbin", xbins = 50, palette = terrain.colors(100, rev = TRUE) )
Type function for histogram plots. type_hist is an alias for
type_histogram.
type_histogram( breaks = "Sturges", freq = NULL, right = TRUE, free.breaks = FALSE, drop.zeros = TRUE ) type_hist( breaks = "Sturges", freq = NULL, right = TRUE, free.breaks = FALSE, drop.zeros = TRUE )type_histogram( breaks = "Sturges", freq = NULL, right = TRUE, free.breaks = FALSE, drop.zeros = TRUE ) type_hist( breaks = "Sturges", freq = NULL, right = TRUE, free.breaks = FALSE, drop.zeros = TRUE )
breaks |
Passed to
|
freq |
logical; if |
right |
logical; if |
free.breaks |
Logical indicating whether the breakpoints should be
computed separately for each group or facet? Default is |
drop.zeros |
Logical indicating whether bins with zero counts should be
dropped before plotting. Default is |
# "histogram"/"hist" type convenience string(s) tinyplot(Nile, type = "histogram") # Use `type_histogram()` to pass extra arguments for customization tinyplot(Nile, type = type_histogram(breaks = 30)) tinyplot(Nile, type = type_histogram(breaks = 30, freq = FALSE)) # etc. # Grouped histogram example tinyplot( ~ Petal.Width | Species, type = "histogram", data = iris ) # Special case: `by`==`x`. # Here we colour each bar (bin) according to its position along the x-axis tinyplot( ~ Petal.Width | Petal.Width, type = "histogram", data = iris ) # Faceted version tinyplot( ~Petal.Width, facet = ~Species, type = "histogram", data = iris ) # For visualizing faceted histograms across varying scales, you may also wish # to impose free histogram breaks too (i.e., calculate breaks separately for # each group). Compare: # free facet scales + shared histogram breaks, versus... tinyplot( ~Petal.Width, facet = ~Species, facet.args = list(free = TRUE), type = type_histogram(), data = iris ) # ... free facet scales + free histogram breaks tinyplot( ~Petal.Width, facet = ~Species, facet.args = list(free = TRUE), type = type_histogram(free = TRUE), data = iris )# "histogram"/"hist" type convenience string(s) tinyplot(Nile, type = "histogram") # Use `type_histogram()` to pass extra arguments for customization tinyplot(Nile, type = type_histogram(breaks = 30)) tinyplot(Nile, type = type_histogram(breaks = 30, freq = FALSE)) # etc. # Grouped histogram example tinyplot( ~ Petal.Width | Species, type = "histogram", data = iris ) # Special case: `by`==`x`. # Here we colour each bar (bin) according to its position along the x-axis tinyplot( ~ Petal.Width | Petal.Width, type = "histogram", data = iris ) # Faceted version tinyplot( ~Petal.Width, facet = ~Species, type = "histogram", data = iris ) # For visualizing faceted histograms across varying scales, you may also wish # to impose free histogram breaks too (i.e., calculate breaks separately for # each group). Compare: # free facet scales + shared histogram breaks, versus... tinyplot( ~Petal.Width, facet = ~Species, facet.args = list(free = TRUE), type = type_histogram(), data = iris ) # ... free facet scales + free histogram breaks tinyplot( ~Petal.Width, facet = ~Species, facet.args = list(free = TRUE), type = type_histogram(free = TRUE), data = iris )
Type function for plotting jittered points.
Arguments are passed to jitter.
type_jitter(factor = 1, amount = NULL)type_jitter(factor = 1, amount = NULL)
factor |
numeric; used in calculation of |
amount |
number or |
The result of r <- x + amount * runif(n, -1, 1)
where n <- length(x).
When amount is NULL (the default)
amount <- factor * d/5 where d is about the smallest
difference between adjacent unique (up to fuzz) x values.
If amount == 0, amount <- factor * (max(x) - min(x))/50,
(using only finite x values), which is the same as in S and the
references.
In the above cases, the final amount is always ensured to be positive.
The short jitter() function is itself a succinct definition.
# "jitter" type convenience string tinyplot(Sepal.Length ~ Species, data = iris, type = "jitter") # Use `type_jitter()` to pass extra arguments for customization tinyplot(Sepal.Length ~ Species, data = iris, type = type_jitter(factor = 0.5))# "jitter" type convenience string tinyplot(Sepal.Length ~ Species, data = iris, type = "jitter") # Use `type_jitter()` to pass extra arguments for customization tinyplot(Sepal.Length ~ Species, data = iris, type = type_jitter(factor = 0.5))
Type function for plotting lines.
type_lines( type = "l", dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = NULL )type_lines( type = "l", dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = NULL )
type |
1-character string giving the type of plot desired. The
following values are possible, for details, see |
dodge |
Adjustment parameter for dodging overlapping points or ranges in grouped plots along the x-axis (or y-axis for flipped plots). Either:
Default value is 0 (no dodging). While we do not check, it is strongly recommended that dodging only be used in cases where the x-axis comprises a limited number of discrete breaks. |
fixed.dodge |
Logical. If |
xlevels, xord
|
arguments controlling the order of the (categorical)
Note that |
Like the other plot types, type_lines() places categorical (factor or
character) data according to the factor levels. Character variables are
coerced with factor() and so end up in alphabetical order. To order the
categories by their appearance in the data instead, use
xord = "asis", or set the levels explicitly, e.g.
factor(x, levels = unique(x)).
Note that the lines themselves are always drawn in the order that the rows
arrive in, exactly as base lines() does. Categories whose level order
differs from their row order will therefore produce a zig-zag, just as an
unsorted numeric x-variable would.
# "l" type convenience character string tinyplot(circumference ~ age | Tree, data = Orange, type = "l") # Use `type_lines()` to pass extra arguments for customization tinyplot(circumference ~ age | Tree, data = Orange, type = type_lines(type = "s")) # Direct legend labels are a good option for grouped lined plots (assuming # there aren't too many groups and the data are sorted along the x-axis) tinyplot( circumference ~ age | Tree, data = Orange, type = "l", legend = "direct" ) # Fancier version(s) that use a theme and repel overlapping labels Orange2 = transform(Orange, Tree = paste("Tree", Tree)) tinyplot( circumference ~ age | Tree, data = Orange2, type = "l", legend = list("direct", repel = TRUE), # auto repel theme = "socviz" ) tinyplot( circumference ~ age | Tree, data = Orange2, type = "l", legend = list("direct", nudge_y = c("Tree 1" = 3, "Tree 3" = -5)), # manual theme = "socviz" ) # A continuous `by` variable is also supported (as of tinyplot v0.8.0). # This is particularly useful for trajectories, where a third variable (often # time) orders the path. time = seq(0, 8*pi, length.out = 600) spiral = data.frame(time = time, x = time * cos(time), y = time * sin(time)) tinyplot( y ~ x | time, data = spiral, type = "l", lwd = 2, asp = 1, # optional args theme = "clean" ) # The canonical time-path example: the x-z projection of a Lorenz attractor. step = function(p, i) { p + 0.005 * c( 10 * (p[2] - p[1]), p[1] * (28 - p[3]) - p[2], p[1] * p[2] - 8/3 * p[3] ) } lz = do.call(rbind, Reduce(step, 1:6000, c(1, 1, 1), accumulate = TRUE)) lorenz = data.frame(time = seq_len(nrow(lz)) * 0.005, x = lz[, 1], z = lz[, 3]) tinyplot(z ~ x | time, data = lorenz, type = "l", theme = "clean")# "l" type convenience character string tinyplot(circumference ~ age | Tree, data = Orange, type = "l") # Use `type_lines()` to pass extra arguments for customization tinyplot(circumference ~ age | Tree, data = Orange, type = type_lines(type = "s")) # Direct legend labels are a good option for grouped lined plots (assuming # there aren't too many groups and the data are sorted along the x-axis) tinyplot( circumference ~ age | Tree, data = Orange, type = "l", legend = "direct" ) # Fancier version(s) that use a theme and repel overlapping labels Orange2 = transform(Orange, Tree = paste("Tree", Tree)) tinyplot( circumference ~ age | Tree, data = Orange2, type = "l", legend = list("direct", repel = TRUE), # auto repel theme = "socviz" ) tinyplot( circumference ~ age | Tree, data = Orange2, type = "l", legend = list("direct", nudge_y = c("Tree 1" = 3, "Tree 3" = -5)), # manual theme = "socviz" ) # A continuous `by` variable is also supported (as of tinyplot v0.8.0). # This is particularly useful for trajectories, where a third variable (often # time) orders the path. time = seq(0, 8*pi, length.out = 600) spiral = data.frame(time = time, x = time * cos(time), y = time * sin(time)) tinyplot( y ~ x | time, data = spiral, type = "l", lwd = 2, asp = 1, # optional args theme = "clean" ) # The canonical time-path example: the x-z projection of a Lorenz attractor. step = function(p, i) { p + 0.005 * c( 10 * (p[2] - p[1]), p[1] * (28 - p[3]) - p[2], p[1] * p[2] - 8/3 * p[3] ) } lz = do.call(rbind, Reduce(step, 1:6000, c(1, 1, 1), accumulate = TRUE)) lorenz = data.frame(time = seq_len(nrow(lz)) * 0.005, x = lz[, 1], z = lz[, 3]) tinyplot(z ~ x | time, data = lorenz, type = "l", theme = "clean")
Type function for plotting a linear model fit.
Arguments are passed to lm.
type_lm(se = TRUE, level = 0.95, weights = NULL)type_lm(se = TRUE, level = 0.95, weights = NULL)
se |
logical. If TRUE, confidence intervals are drawn. |
level |
the confidence level required. |
weights |
an optional numeric vector of observation weights for the model
fit, of the same length as the number of data points. Weights can also be
supplied via the top-level |
# "lm" type convenience string tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = "lm") # Grouped model fits (here: illustrating an example of Simpson's paradox) tinyplot(Sepal.Width ~ Petal.Width | Species, data = iris, type = "lm") tinyplot_add(type = "p") # Use `type_lm()` to pass extra arguments for customization tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = type_lm(level = 0.8)) # Weighted fit example, either as a top-level argument (which supports # non-standard evaluation in the formula method)... s77 = as.data.frame(state.x77) tinyplot(`Life Exp` ~ Income, data = s77, type = "lm", weights = Population) # ...or directly via the type constructor (requires an evaluated vector) tinyplot(`Life Exp` ~ Income, data = s77, type = type_lm( weights = s77$Population))# "lm" type convenience string tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = "lm") # Grouped model fits (here: illustrating an example of Simpson's paradox) tinyplot(Sepal.Width ~ Petal.Width | Species, data = iris, type = "lm") tinyplot_add(type = "p") # Use `type_lm()` to pass extra arguments for customization tinyplot(Sepal.Width ~ Petal.Width, data = iris, type = type_lm(level = 0.8)) # Weighted fit example, either as a top-level argument (which supports # non-standard evaluation in the formula method)... s77 = as.data.frame(state.x77) tinyplot(`Life Exp` ~ Income, data = s77, type = "lm", weights = Population) # ...or directly via the type constructor (requires an evaluated vector) tinyplot(`Life Exp` ~ Income, data = s77, type = type_lm( weights = s77$Population))
Type function for plotting a LOESS (LOcal regrESSion) fit.
Arguments are passed to loess.
type_loess( span = 0.75, degree = 2, family = "gaussian", control = loess.control(), se = TRUE, level = 0.95, n = 100, weights = NULL )type_loess( span = 0.75, degree = 2, family = "gaussian", control = loess.control(), se = TRUE, level = 0.95, n = 100, weights = NULL )
span |
the parameter |
degree |
the degree of the polynomials to be used, normally 1 or 2. (Degree 0 is also allowed, but see the ‘Note’.) |
family |
a description of the error distribution and link
function to be used in the model. For |
control |
control parameters: see |
se |
logical. If |
level |
the confidence level required if |
n |
integer. Number of equally-spaced points at which the fitted model
is evaluated for drawing, per group. Default is 100. Note that this affects
only where the fitted curve is sampled, not the fit itself, which always
uses every observation. Larger values trace a wiggly fit more faithfully, at
proportionally greater cost; consider raising it if you combine a small
|
weights |
an optional numeric vector of observation weights for the model
fit, of the same length as the number of data points. Weights can also be
supplied via the top-level |
loess can be a time-consuming algorithm. From a
plotting perspective, though, the expensive half is usually not the model fit
but the prediction step (y values corresponding to each x).
type_loess() mitigates this in two ways.
First, the fitted model is evaluated on an equally-spaced grid of n points
spanning the data range of each group, rather than at every observation. On
large data this skips a great deal of redundant work—dozens of observations
can crowd into a single pixel, so evaluating the curve at each of them costs
time without revealing anything—while n points remain ample to trace a
smooth curve. The model is still fitted on the full dataset, so the estimates
are unchanged. It's only the points along x at which they are read off that
differ. (If the x-axis is logarithmic, the grid is spaced evenly in log(x),
so that the curve is traced evenly across the plot.)
Second, once prediction is cheap the fit itself becomes the bottleneck, and
here lowess is substituted for loess() wherever the
two are equivalent: unweighted local linear fits, without standard errors, on
a non-logarithmic x-axis. That path smooths millions of observations in
seconds. Standard errors, quadratic fits and weighted fits all fall back to
loess(), as does a logarithmic x-axis, where lowess() interpolates too
coarsely through the compressed decades.
Note that se = TRUE carries a hard ceiling of its own:
predict.loess's workspace grows quadratically in the
number of observations—regardless of how many points you predict at—and
fails outright at around 38,000. Confidence intervals are thus unavailable at
the sizes where the lowess() path matters most, and se = FALSE is
required to draw a smooth over very large data.
# "loess" type convenience string tinyplot(dist ~ speed, data = cars, type = "loess") # Use `type_loess()` to pass extra arguments for customization tinyplot(dist ~ speed, data = cars, type = type_loess(span = 0.5, degree = 1)) # The fast `lowess` path is used automatically where it is equivalent, which # makes short work of larger datasets tinyplot(sunspots, type = "l", col = "grey") tinyplot_add(type = type_loess(span = 0.05, degree = 1, se = FALSE), lwd = 2) # Raise `n` if a small `span` needs more than 100 points to trace faithfully tinyplot(sunspots, type = "l", col = "grey") tinyplot_add(type = type_loess(span = 0.05, degree = 1, se = FALSE, n = 500), lwd = 2)# "loess" type convenience string tinyplot(dist ~ speed, data = cars, type = "loess") # Use `type_loess()` to pass extra arguments for customization tinyplot(dist ~ speed, data = cars, type = type_loess(span = 0.5, degree = 1)) # The fast `lowess` path is used automatically where it is equivalent, which # makes short work of larger datasets tinyplot(sunspots, type = "l", col = "grey") tinyplot_add(type = type_loess(span = 0.05, degree = 1, se = FALSE), lwd = 2) # Raise `n` if a small `span` needs more than 100 points to trace faithfully tinyplot(sunspots, type = "l", col = "grey") tinyplot_add(type = type_loess(span = 0.05, degree = 1, se = FALSE, n = 500), lwd = 2)
Type function for plotting points, i.e. a scatter plot.
type_points( clim = c(0.5, 2.5), dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = NULL )type_points( clim = c(0.5, 2.5), dodge = 0, fixed.dodge = FALSE, xlevels = NULL, xord = NULL )
clim |
Numeric giving the lower and upper limits of the character
expansion ( |
dodge |
Adjustment parameter for dodging overlapping points or ranges in grouped plots along the x-axis (or y-axis for flipped plots). Either:
Default value is 0 (no dodging). While we do not check, it is strongly recommended that dodging only be used in cases where the x-axis comprises a limited number of discrete breaks. |
fixed.dodge |
Logical. If |
xlevels, xord
|
arguments controlling the order of the (categorical)
Note that |
# "p" type convenience character string tinyplot(Sepal.Length ~ Petal.Length, data = iris, type = "p") # Same result with type_points() tinyplot(Sepal.Length ~ Petal.Length, data = iris, type = type_points()) # Note: Specifying the type here is redundant. Like base plot, tinyplot # automatically produces a scatter plot if x and y are numeric tinyplot(Sepal.Length ~ Petal.Length, data = iris) # Grouped scatter plot example tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris) # Continuous grouping (with gradient legend) tinyplot(Sepal.Length ~ Petal.Length | Sepal.Width, data = iris, pch = 19) # Bubble chart version tinyplot(Sepal.Length ~ Petal.Length, data = iris, cex = iris$Sepal.Width) # Fancier version with dual legends and extra customization tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, cex = iris$Sepal.Width, clim = c(1, 5), pch = 21, fill = 0.3)# "p" type convenience character string tinyplot(Sepal.Length ~ Petal.Length, data = iris, type = "p") # Same result with type_points() tinyplot(Sepal.Length ~ Petal.Length, data = iris, type = type_points()) # Note: Specifying the type here is redundant. Like base plot, tinyplot # automatically produces a scatter plot if x and y are numeric tinyplot(Sepal.Length ~ Petal.Length, data = iris) # Grouped scatter plot example tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris) # Continuous grouping (with gradient legend) tinyplot(Sepal.Length ~ Petal.Length | Sepal.Width, data = iris, pch = 19) # Bubble chart version tinyplot(Sepal.Length ~ Petal.Length, data = iris, cex = iris$Sepal.Width) # Fancier version with dual legends and extra customization tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris, cex = iris$Sepal.Width, clim = c(1, 5), pch = 21, fill = 0.3)
Type function for plotting polygons.
Arguments are passed to polygon.
type_polygon(density = NULL, angle = 45)type_polygon(density = NULL, angle = 45)
density |
the density of shading lines, in lines per inch. The
default value of |
angle |
the slope of shading lines, given as an angle in degrees (counter-clockwise). |
# "polygon" type convenience character string tinyplot(1:9, c(2,1,2,1,NA,2,1,2,1), type = "polygon") # Use `type_polygon()` to pass extra arguments for customization tinyplot(1:9, c(2,1,2,1,NA,2,1,2,1), type = type_polygon(density = c(10, 20)))# "polygon" type convenience character string tinyplot(1:9, c(2,1,2,1,NA,2,1,2,1), type = "polygon") # Use `type_polygon()` to pass extra arguments for customization tinyplot(1:9, c(2,1,2,1,NA,2,1,2,1), type = type_polygon(density = c(10, 20)))
Type function for plotting polygons.
Arguments are passed to polypath.
type_polypath(rule = "winding")type_polypath(rule = "winding")
rule |
character value specifying the path fill mode: either
|
# "polypath" type convenience character string tinyplot( c(.1, .1, .6, .6, NA, .4, .4, .9, .9), c(.1, .6, .6, .1, NA, .4, .9, .9, .4), type = "polypath", fill = "grey" ) # Use `type_polypath()` to pass extra arguments for customization tinyplot( c(.1, .1, .6, .6, NA, .4, .4, .9, .9), c(.1, .6, .6, .1, NA, .4, .9, .9, .4), type = type_polypath(rule = "evenodd"), fill = "grey" )# "polypath" type convenience character string tinyplot( c(.1, .1, .6, .6, NA, .4, .4, .9, .9), c(.1, .6, .6, .1, NA, .4, .9, .9, .4), type = "polypath", fill = "grey" ) # Use `type_polypath()` to pass extra arguments for customization tinyplot( c(.1, .1, .6, .6, NA, .4, .4, .9, .9), c(.1, .6, .6, .1, NA, .4, .9, .9, .4), type = type_polypath(rule = "evenodd"), fill = "grey" )
Plots the theoretical quantiles of x on the horizontal axis
against observed values of x on the vertical axis.
type_qq(distribution = qnorm)type_qq(distribution = qnorm)
distribution |
Distribution function to use. |
tinyplot(~mpg, data = mtcars, type = type_qq()) # suppress the line tinyplot(~mpg, data = mtcars, lty = 0, type = type_qq())tinyplot(~mpg, data = mtcars, type = type_qq()) # suppress the line tinyplot(~mpg, data = mtcars, lty = 0, type = type_qq())
Type function for plotting rectangles.
type_rect()type_rect()
Contrary to base rect, rectangles in
tinyplot must be specified using the xmin, ymin,xmax, and ymax
arguments.
i = 4*(0:10) # "rect" type convenience character string tinyplot( xmin = 100+i, ymin = 300+i, xmax = 150+i, ymax = 380+i, by = i, fill = 0.2, type = "rect" ) # Same result with type_rect() tinyplot( xmin = 100+i, ymin = 300+i, xmax = 150+i, ymax = 380+i, by = i, fill = 0.2, type = type_rect() )i = 4*(0:10) # "rect" type convenience character string tinyplot( xmin = 100+i, ymin = 300+i, xmax = 150+i, ymax = 380+i, by = i, fill = 0.2, type = "rect" ) # Same result with type_rect() tinyplot( xmin = 100+i, ymin = 300+i, xmax = 150+i, ymax = 380+i, by = i, fill = 0.2, type = type_rect() )
Type function for producing ridge plots (also known as joy plots),
which display density distributions for multiple groups with vertical offsets.
This function uses tinyplot scaffolding, which enables added functionality
such as grouping and faceting.
The line color is controlled by the col argument in the tinyplot() call.
The fill color is controlled by the bg argument in the tinyplot() call.
type_ridge( scale = 1.5, joint.max = c("all", "facet", "by"), breaks = NULL, probs = NULL, ylevels = NULL, yord = NULL, bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, gradient = FALSE, raster = FALSE, col = NULL, alpha = NULL, singletons = c("warn", "drop", "none") )type_ridge( scale = 1.5, joint.max = c("all", "facet", "by"), breaks = NULL, probs = NULL, ylevels = NULL, yord = NULL, bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, gradient = FALSE, raster = FALSE, col = NULL, alpha = NULL, singletons = c("warn", "drop", "none") )
scale |
Numeric. Controls the scaling factor of each plot. Values greater than 1 means that plots overlap. |
joint.max |
character indicating how to scale the maximum of the densities:
The default |
breaks |
Numeric. If a color gradient is used for shading, the
breaks between the colors can be modified. The default is to use
equidistant breaks spanning the range of the |
probs |
Numeric. Instead of specifying the same |
ylevels, yord
|
arguments controlling the order of the
Note that a numeric |
bw |
the smoothing |
joint.bw |
character string indicating whether (and how) the smoothing
bandwidth should be computed from the joint data distribution. The default
of |
adjust |
the bandwidth used is actually |
kernel |
a character string giving the smoothing kernel to be used. This
must partially match one of
|
n |
the number of equally spaced points at which the density is
to be estimated. When |
gradient |
Logical or character. Should a gradient fill be used to
shade the area under the density? If a character specification is used,
then it can either be of length 1 and specify the palette to be used with
|
raster |
Logical. Should the |
col |
Character string denoting the outline (border) color for all
of the ridge densities. Note that a singular value is expected; if multiple
colors are provided then only the first will be used. This argument is mostly
useful for the aesthetic effect of drawing a common outline color in
combination with gradient fills. See Examples. If left unset here, the
outline color can also be supplied via the top-level |
alpha |
Numeric in the range |
singletons |
character string indicating what to do with singleton
groups, i.e. combinations of |
tinyplot uses two basic approaches for drawing gradient fills in ridge line
plots, e.g., if type_ridge(gradient = TRUE).
The first (and default) polygon-based approach involves dividing up the main density region into many smaller polygons along the x-axis. Each of these smaller polygons inherits a different color "segment" from the underlying palette swatch, which in turn creates the effect of a continuous gradient when they are all plotted together. Internally, this polygon-based approach is vectorized (i.e., all of the sub-polygons are plotted simultaneously). It is thus efficient from a plotting perspective and generally also performs well from an aesthetic perspective. However, it can occasionally produce undesirable plotting artifacts on some graphics devices—e.g., thin but visible vertical lines—if alpha transparency is being used at the same time.
For this reason, we also offer an alternative raster-based approach for
gradient fills that users can invoke via
type_ridge(gradient = TRUE, raster = TRUE). The essential idea is that we
coerce the density polygon into a raster representation (using
rasterImage) and achieve the gradient effect via
color interpolation. The trade-off this time is potential smoothness
artifacts around the top of the ridge densities at high resolutions, since we
have converted a vector object into a raster object.
Again, we expect that the choice between these two approaches will only matter for ridge plots that combine gradient fills with alpha transparency (and on certain graphics devices). We recommend that users experiment to determine which approach is optimal for their device.
aq = transform( airquality, Month = factor(month.abb[Month], levels = month.abb[5:9]), Month2 = factor(month.name[Month], levels = month.name[5:9]), Late = ifelse(Day > 15, "Late", "Early") ) # default ridge plot (using the "ridge" convenience string) tinyplot(Month ~ Temp, data = aq, type = "ridge") # for ridge plots, we recommend pairing with the dedicated theme(s), which # facilitate nicer y-axis labels, grid lines, etc. tinytheme("ridge") tinyplot(Month ~ Temp, data = aq, type = "ridge") tinytheme("ridge2") # removes the plot frame (but keeps x-axis line) tinyplot(Month ~ Temp, data = aq, type = "ridge") # the "ridge(2)" themes are especially helpful for long y labels, due to # dynamic plot adjustment tinyplot(Month2 ~ Temp, data = aq, type = "ridge") # pass customization arguments through type_ridge()... for example, use # the scale argument to change/avoid overlap of densities (more on scaling # further below) tinyplot(Month ~ Temp, data = aq, type = type_ridge(scale = 1)) ## by grouping is also supported. two special cases of interest: # 1) by == y (color by y groups) tinyplot(Month ~ Temp | Month, data = aq, type = "ridge") # 2) by == x (gradient coloring along x) tinyplot(Month ~ Temp | Temp, data = aq, type = "ridge") # aside: pass explicit `type_ridge(col = <col>)` arg to set a different # border color tinyplot(Month ~ Temp | Temp, data = aq, type = type_ridge(col = "white")) # gradient coloring along the x-axis can also be invoked manually without # a legend (the next two tinyplot calls are equivalent) # tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = "agsunset")) tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE)) # aside: when combining gradient fill with alpha transparency, it may be # better to use the raster-based approach (test on your graphics device) tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE, alpha = 0.5), main = "polygon fill (default)") tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE, alpha = 0.5, raster = TRUE), main = "raster fill") # highlighting only the center 50% of the density (i.e., 25%-75% quantiles) tinyplot(Month ~ Temp, data = aq, type = type_ridge( gradient = hcl.colors(3, "Dark Mint")[c(2, 1, 2)], probs = c(0.25, 0.75), col = "white")) # highlighting the probability distribution by color gradient # (darkest point = median) tinyplot(Month ~ Temp, data = aq, type = type_ridge( gradient = hcl.colors(250, "Dark Mint")[c(250:1, 1:250)], probs = 0:500/500)) ## faceting works too. for example: tinyplot(Month ~ Ozone, facet = ~ Late, data = aq, type = type_ridge(gradient = TRUE)) # use the joint.max argument to vary the maximum density used for # determining relative scaling... # jointly across all densities (default) vs. per facet tinyplot(Month ~ Temp, facet = ~ Late, data = aq, type = type_ridge(scale = 1)) tinyplot(Month ~ Temp, facet = ~ Late, data = aq, type = type_ridge(scale = 1, joint.max = "facet")) # jointly across all densities (default) vs. per by row tinyplot(Month ~ Temp | Late, data = aq, type = type_ridge(scale = 1)) tinyplot(Month ~ Temp | Late, data = aq, type = type_ridge(scale = 1, joint.max = "by")) ## restore the default theme tinytheme()aq = transform( airquality, Month = factor(month.abb[Month], levels = month.abb[5:9]), Month2 = factor(month.name[Month], levels = month.name[5:9]), Late = ifelse(Day > 15, "Late", "Early") ) # default ridge plot (using the "ridge" convenience string) tinyplot(Month ~ Temp, data = aq, type = "ridge") # for ridge plots, we recommend pairing with the dedicated theme(s), which # facilitate nicer y-axis labels, grid lines, etc. tinytheme("ridge") tinyplot(Month ~ Temp, data = aq, type = "ridge") tinytheme("ridge2") # removes the plot frame (but keeps x-axis line) tinyplot(Month ~ Temp, data = aq, type = "ridge") # the "ridge(2)" themes are especially helpful for long y labels, due to # dynamic plot adjustment tinyplot(Month2 ~ Temp, data = aq, type = "ridge") # pass customization arguments through type_ridge()... for example, use # the scale argument to change/avoid overlap of densities (more on scaling # further below) tinyplot(Month ~ Temp, data = aq, type = type_ridge(scale = 1)) ## by grouping is also supported. two special cases of interest: # 1) by == y (color by y groups) tinyplot(Month ~ Temp | Month, data = aq, type = "ridge") # 2) by == x (gradient coloring along x) tinyplot(Month ~ Temp | Temp, data = aq, type = "ridge") # aside: pass explicit `type_ridge(col = <col>)` arg to set a different # border color tinyplot(Month ~ Temp | Temp, data = aq, type = type_ridge(col = "white")) # gradient coloring along the x-axis can also be invoked manually without # a legend (the next two tinyplot calls are equivalent) # tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = "agsunset")) tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE)) # aside: when combining gradient fill with alpha transparency, it may be # better to use the raster-based approach (test on your graphics device) tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE, alpha = 0.5), main = "polygon fill (default)") tinyplot(Month ~ Temp, data = aq, type = type_ridge(gradient = TRUE, alpha = 0.5, raster = TRUE), main = "raster fill") # highlighting only the center 50% of the density (i.e., 25%-75% quantiles) tinyplot(Month ~ Temp, data = aq, type = type_ridge( gradient = hcl.colors(3, "Dark Mint")[c(2, 1, 2)], probs = c(0.25, 0.75), col = "white")) # highlighting the probability distribution by color gradient # (darkest point = median) tinyplot(Month ~ Temp, data = aq, type = type_ridge( gradient = hcl.colors(250, "Dark Mint")[c(250:1, 1:250)], probs = 0:500/500)) ## faceting works too. for example: tinyplot(Month ~ Ozone, facet = ~ Late, data = aq, type = type_ridge(gradient = TRUE)) # use the joint.max argument to vary the maximum density used for # determining relative scaling... # jointly across all densities (default) vs. per facet tinyplot(Month ~ Temp, facet = ~ Late, data = aq, type = type_ridge(scale = 1)) tinyplot(Month ~ Temp, facet = ~ Late, data = aq, type = type_ridge(scale = 1, joint.max = "facet")) # jointly across all densities (default) vs. per by row tinyplot(Month ~ Temp | Late, data = aq, type = type_ridge(scale = 1)) tinyplot(Month ~ Temp | Late, data = aq, type = type_ridge(scale = 1, joint.max = "by")) ## restore the default theme tinytheme()
Adds a rug representation (1-d plot) of the data to the plot.
type_rug( ticksize = 0.03, side = 1, quiet = getOption("warn") < 0, jitter = FALSE, amount = NULL )type_rug( ticksize = 0.03, side = 1, quiet = getOption("warn") < 0, jitter = FALSE, amount = NULL )
ticksize |
The length of the ticks making up the ‘rug’. Positive lengths give inwards ticks. |
side |
On which side of the plot box the rug will be plotted. Normally 1 (bottom) or 3 (top). |
quiet |
logical indicating if there should be a warning about clipped values. |
jitter |
Logical. Add jittering to separate ties? Default is |
amount |
Numeric. Amount of jittering (see |
This function should only be used as part of tinyplot_add(), i.e. adding
to an existing plot.
In most cases, determining which variable receives the rug representation
will be based on the side argument (i.e., x-variable if side is 1 or 3, and
y-variable if side is 2 or 4). An exception is if the preceding plot type was
either "density" or "histogram"; for these latter cases, the x-variable
will always be used. See Examples.
tinyplot(~wt | am, data = mtcars, type = "density", facet = "by", fill = "by") tinyplot_add(type = "rug") # use type_rug() to pass extra options tinyplot_add(type = type_rug(side = 3, ticksize = 0.05)) # For ties, use jittering tinyplot(eruptions ~ waiting, data = faithful, type = "lm") tinyplot_add(type = type_rug(jitter = TRUE, amount = 0.3)) tinyplot_add(type = type_rug(jitter = TRUE, amount = 0.1, side = 2)) # Add original points just for reference tinyplot_add(type = "p")tinyplot(~wt | am, data = mtcars, type = "density", facet = "by", fill = "by") tinyplot_add(type = "rug") # use type_rug() to pass extra options tinyplot_add(type = type_rug(side = 3, ticksize = 0.05)) # For ties, use jittering tinyplot(eruptions ~ waiting, data = faithful, type = "lm") tinyplot_add(type = type_rug(jitter = TRUE, amount = 0.3)) tinyplot_add(type = type_rug(jitter = TRUE, amount = 0.1, side = 2)) # Add original points just for reference tinyplot_add(type = "p")
Type function for plotting line segments.
type_segments()type_segments()
Contrary to base segments, line segments in
tinyplot must be specified using the xmin, ymin,xmax, and ymax
arguments.
# "segments" type convenience character string tinyplot( xmin = c(0,.1), ymin = c(.2,1), xmax = c(1,.9), ymax = c(.75,0), type = "segments" ) # Same result with type_segments() tinyplot( xmin = c(0,.1), ymin = c(.2,1), xmax = c(1,.9), ymax = c(.75,0), type = type_segments() )# "segments" type convenience character string tinyplot( xmin = c(0,.1), ymin = c(.2,1), xmax = c(1,.9), ymax = c(.75,0), type = "segments" ) # Same result with type_segments() tinyplot( xmin = c(0,.1), ymin = c(.2,1), xmax = c(1,.9), ymax = c(.75,0), type = type_segments() )
Type function(s) for producing spineplots and spinograms, which
are modified versions of histograms or mosaic plots, and particularly
useful for visualizing factor variables. Note that tinyplot defaults
to type_spineplot() if y is a factor variable.
type_spineplot( breaks = NULL, tol.ylab = 0.05, off = NULL, xlevels = NULL, xord = NULL, ylevels = NULL, yord = NULL, col = NULL, weights = NULL, lighten = FALSE, xaxlabels = NULL, yaxlabels = NULL )type_spineplot( breaks = NULL, tol.ylab = 0.05, off = NULL, xlevels = NULL, xord = NULL, ylevels = NULL, yord = NULL, col = NULL, weights = NULL, lighten = FALSE, xaxlabels = NULL, yaxlabels = NULL )
breaks |
if the explanatory variable is numeric, this controls how
it is discretized. |
tol.ylab |
convenience tolerance parameter for y-axis annotation. If the distance between two labels drops under this threshold, they are plotted equidistantly. |
off |
vertical offset between the bars (in per cent). It is fixed to
|
xlevels, xord
|
arguments controlling the order of the
Note that |
ylevels, yord
|
as for |
col |
a vector of fill colors of the same length as |
weights |
numeric. A vector of frequency weights for each
observation in the data. If |
lighten |
logical. For grouped spineplots where the |
xaxlabels, yaxlabels
|
[Deprecated] character vectors for annotation of
the x and y axis. Use the top-level |
# "spineplot" type convenience string tinyplot(Species ~ Sepal.Width, data = iris, type = "spineplot") # Aside: specifying the type is redundant for this example, since tinyplot() # defaults to "spineplot" if y is a factor (just like base plot). tinyplot(Species ~ Sepal.Width, data = iris) # Use `type_spineplot()` to pass extra arguments for customization tinyplot( Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4) ) # Passing custom colors to the y-axis categories tinyplot( Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4, col = palette.colors(3, "Pastel 1")) ) # More idiomatic tinyplot way of drawing the previous plot: use y == by tinyplot( Species ~ Sepal.Width | Species, data = iris, type = type_spineplot(breaks = 4), palette = "Pastel 1", legend = FALSE ) ## Grouped and faceted spineplots ttnc = as.data.frame(Titanic) # Note: The Titanic (ttnc) dataset is pre-tabulated, so we pass its frequency # counts via the top-level `weights` argument (accepted via non-standard # evaluation in the formula method). tinyplot( Survived ~ Sex, facet = ~ Class, data = ttnc, # type_spineplot(weights = ttnc$Freq), ## same thing but not NSE type = "spineplot", weights = Freq ) # Reorder x and y variable categories either by their character levels or # numeric indexes. (Here we combine a top-level `weights` with constructor- # level arguments passed through `type_spineplot()`.) tinyplot( Survived ~ Sex, facet = ~ Class, data = ttnc, type = type_spineplot(xlevels = c("Female", "Male"), ylevels = 2:1), weights = Freq ) # For (colour) grouped "by" spineplots, it's visually better to facet too tinyplot( Survived ~ Sex | Class, data = ttnc, facet = "by", type = "spineplot", weights = Freq ) # Fancier version. Note the smart inheritance of spacing etc. tinyplot( Survived ~ Sex | Class, data = ttnc, facet = "by", facet.args = list(nrow = 1), type = "spineplot", weights = Freq, theme = "void", axes = "t", lty = 0, legend = FALSE, main = "Who survived the Titanic disaster?", sub = "Frequencies by boarding class and sex" ) # Aside: It's possible to use "by" on its own (without faceting), but the # overlaid result isn't great. We will likely overhaul this behaviour in a # future version of tinyplot... tinyplot(Survived ~ Sex | Class, data = ttnc, type = "spineplot", weights = Freq, alpha = 0.3 )# "spineplot" type convenience string tinyplot(Species ~ Sepal.Width, data = iris, type = "spineplot") # Aside: specifying the type is redundant for this example, since tinyplot() # defaults to "spineplot" if y is a factor (just like base plot). tinyplot(Species ~ Sepal.Width, data = iris) # Use `type_spineplot()` to pass extra arguments for customization tinyplot( Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4) ) # Passing custom colors to the y-axis categories tinyplot( Species ~ Sepal.Width, data = iris, type = type_spineplot(breaks = 4, col = palette.colors(3, "Pastel 1")) ) # More idiomatic tinyplot way of drawing the previous plot: use y == by tinyplot( Species ~ Sepal.Width | Species, data = iris, type = type_spineplot(breaks = 4), palette = "Pastel 1", legend = FALSE ) ## Grouped and faceted spineplots ttnc = as.data.frame(Titanic) # Note: The Titanic (ttnc) dataset is pre-tabulated, so we pass its frequency # counts via the top-level `weights` argument (accepted via non-standard # evaluation in the formula method). tinyplot( Survived ~ Sex, facet = ~ Class, data = ttnc, # type_spineplot(weights = ttnc$Freq), ## same thing but not NSE type = "spineplot", weights = Freq ) # Reorder x and y variable categories either by their character levels or # numeric indexes. (Here we combine a top-level `weights` with constructor- # level arguments passed through `type_spineplot()`.) tinyplot( Survived ~ Sex, facet = ~ Class, data = ttnc, type = type_spineplot(xlevels = c("Female", "Male"), ylevels = 2:1), weights = Freq ) # For (colour) grouped "by" spineplots, it's visually better to facet too tinyplot( Survived ~ Sex | Class, data = ttnc, facet = "by", type = "spineplot", weights = Freq ) # Fancier version. Note the smart inheritance of spacing etc. tinyplot( Survived ~ Sex | Class, data = ttnc, facet = "by", facet.args = list(nrow = 1), type = "spineplot", weights = Freq, theme = "void", axes = "t", lty = 0, legend = FALSE, main = "Who survived the Titanic disaster?", sub = "Frequencies by boarding class and sex" ) # Aside: It's possible to use "by" on its own (without faceting), but the # overlaid result isn't great. We will likely overhaul this behaviour in a # future version of tinyplot... tinyplot(Survived ~ Sex | Class, data = ttnc, type = "spineplot", weights = Freq, alpha = 0.3 )
Type function for plotting a cubic (or Hermite) spline interpolation.
Arguments are passed to spline; see this latter function
for default argument values.
type_spline( n = NULL, method = "fmm", xmin = NULL, xmax = NULL, xout = NULL, ties = mean )type_spline( n = NULL, method = "fmm", xmin = NULL, xmax = NULL, xout = NULL, ties = mean )
n |
if |
method |
specifies the type of spline to be used. Possible
values are |
xmin, xmax
|
left-hand and right-hand endpoint of the
interpolation interval (when |
xout |
an optional set of values specifying where interpolation is to take place. |
ties |
handling of tied |
See spline for further details on the available
interpolation methods.
# "spline" type convenience string tinyplot(dist ~ speed, data = cars, type = "spline") # Use `type_spline()` to pass extra arguments for customization tinyplot(dist ~ speed, data = cars, type = type_spline(method = "natural", n = 25), add = TRUE, lty = 2)# "spline" type convenience string tinyplot(dist ~ speed, data = cars, type = "spline") # Use `type_spline()` to pass extra arguments for customization tinyplot(dist ~ speed, data = cars, type = type_spline(method = "natural", n = 25), add = TRUE, lty = 2)
y at unique values of x
Applies a summary function to y along unique values of x. For example,
plot the mean y value for each x value. Internally,
type_summary() applies a thin wrapper around aggregate
and then passes the result to type_lines for drawing.
type_summary(fun = mean, dodge = 0, fixed.dodge = FALSE, ...)type_summary(fun = mean, dodge = 0, fixed.dodge = FALSE, ...)
fun |
summarizing function. Should be compatible with
|
dodge |
Adjustment parameter for dodging overlapping points or ranges in grouped plots along the x-axis (or y-axis for flipped plots). Either:
Default value is 0 (no dodging). While we do not check, it is strongly recommended that dodging only be used in cases where the x-axis comprises a limited number of discrete breaks. |
fixed.dodge |
Logical. If |
... |
Additional arguments are passed to the |
aggregate which performs the summarizing (aggregating) behind
the scenes.
# Plot the mean chick weight over time tinyplot(weight ~ Time, data = ChickWeight, type = "summary") # Note: "mean" is the default function, so these are also equivalent: # tinyplot(weight ~ Time, data = ChickWeight, type = type_summary()) # tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(mean)) # Plot the median instead tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(median)) # Works with groups and/or facets too tinyplot(weight ~ Time | Diet, facet = "by", data = ChickWeight, type = "summary") # Custom/complex function example tinyplot( weight ~ Time | Diet, facet = "by", data = ChickWeight, type = type_summary(function(y) quantile(y, probs = 0.9) / max(y)) )# Plot the mean chick weight over time tinyplot(weight ~ Time, data = ChickWeight, type = "summary") # Note: "mean" is the default function, so these are also equivalent: # tinyplot(weight ~ Time, data = ChickWeight, type = type_summary()) # tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(mean)) # Plot the median instead tinyplot(weight ~ Time, data = ChickWeight, type = type_summary(median)) # Works with groups and/or facets too tinyplot(weight ~ Time | Diet, facet = "by", data = ChickWeight, type = "summary") # Custom/complex function example tinyplot( weight ~ Time | Diet, facet = "by", data = ChickWeight, type = type_summary(function(y) quantile(y, probs = 0.9) / max(y)) )
Type function for adding text annotations to a plot at the
specified (x,y) coordinates.
type_text( labels = NULL, labeller = NULL, adj = NULL, pos = NULL, offset = 0.5, family = NULL, font = NULL, vfont = NULL, xpd = NULL, srt = 0, repel = FALSE, clim = c(0.5, 2.5) )type_text( labels = NULL, labeller = NULL, adj = NULL, pos = NULL, offset = 0.5, family = NULL, font = NULL, vfont = NULL, xpd = NULL, srt = 0, repel = FALSE, clim = c(0.5, 2.5) )
labels |
Character vector of length |
labeller |
A formatting function, convenience string, or dictionary
(named vector or list) passed to |
adj |
one or two values in |
pos |
a position specifier for the text. If specified this
overrides any |
offset |
when |
family |
The name of a font family. Default of |
font |
Integer giving the font face to be used,
following |
vfont |
|
xpd |
Logical value or |
srt |
Numeric giving the desired string rotation in degrees. |
repel |
Logical or numeric controlling automatic repulsion of
overlapping text labels. The default |
clim |
Numeric giving the lower and upper limits of the character
expansion ( |
# simplest case (no labels), will auto revert to y labels tinyplot(1:12, type = "text") # pass explicit `labels` arg if you want specific text tinyplot(1:12, type = "text", labels = month.abb) # you can also use a labeller function (passed to `tinylabel`) to # customize tinyplot(1:12, type = "text", labels = month.abb, labeller = toupper) # tip: use `xpd = NA` to avoid clipping text at the plot region tinyplot(1:12, type = "text", labels = month.name, xpd = NA) # for advanced customization, it's safer to pass args through `type_text()` tinyplot( 1:12, type = type_text( labels = month.abb, family = "HersheyScript", srt = -20) ) # some formula + data.frame examples... mt = transform(mtcars[1:20,], cyl = factor(cyl), model = rownames(mtcars[1:20,])) # as a top-level argument, `labels` supports non-standard evaluation, so a # bare column name is resolved against `data` (just like the plot variables) # tinyplot(mpg ~ wt, data = mt, type = type_text(labels = mt$model)) tinyplot(mpg ~ wt, data = mt, type = "text", labels = model) # same # tip: use `repel = TRUE` to automatically nudge overlapping labels apart tinyplot( mpg ~ wt, data = mt, type = "text", labels = model, repel = TRUE, xpd = NA ) # limitation: `repel` logic currently works per group, so grouped text data # may still overlap tinyplot( mpg ~ wt | cyl, data = mt, type = "text", labels = model, repel = TRUE, xpd = NA ) # an advantage of the top-level `labels` approach is that data subsetting and # sanitizing ops pass through automatically tinyplot(hp ~ wt, data = mt) tinyplot_add(subset = carb==2, col = "red", pch = 16) tinyplot_add(subset = carb==2, col = "red", type = "text", labels = model, pos = 4) # fancier plot that combines a theme and some other customizations tinyplot( mpg ~ hp | cyl, data = mt, legend = list(title = "Cylinders"), theme = "web" ) tinyplot_add( labels = model, type = type_text( family = "HersheySans", font = 2, pos = 4, repel = TRUE, xpd = NA ) )# simplest case (no labels), will auto revert to y labels tinyplot(1:12, type = "text") # pass explicit `labels` arg if you want specific text tinyplot(1:12, type = "text", labels = month.abb) # you can also use a labeller function (passed to `tinylabel`) to # customize tinyplot(1:12, type = "text", labels = month.abb, labeller = toupper) # tip: use `xpd = NA` to avoid clipping text at the plot region tinyplot(1:12, type = "text", labels = month.name, xpd = NA) # for advanced customization, it's safer to pass args through `type_text()` tinyplot( 1:12, type = type_text( labels = month.abb, family = "HersheyScript", srt = -20) ) # some formula + data.frame examples... mt = transform(mtcars[1:20,], cyl = factor(cyl), model = rownames(mtcars[1:20,])) # as a top-level argument, `labels` supports non-standard evaluation, so a # bare column name is resolved against `data` (just like the plot variables) # tinyplot(mpg ~ wt, data = mt, type = type_text(labels = mt$model)) tinyplot(mpg ~ wt, data = mt, type = "text", labels = model) # same # tip: use `repel = TRUE` to automatically nudge overlapping labels apart tinyplot( mpg ~ wt, data = mt, type = "text", labels = model, repel = TRUE, xpd = NA ) # limitation: `repel` logic currently works per group, so grouped text data # may still overlap tinyplot( mpg ~ wt | cyl, data = mt, type = "text", labels = model, repel = TRUE, xpd = NA ) # an advantage of the top-level `labels` approach is that data subsetting and # sanitizing ops pass through automatically tinyplot(hp ~ wt, data = mt) tinyplot_add(subset = carb==2, col = "red", pch = 16) tinyplot_add(subset = carb==2, col = "red", type = "text", labels = model, pos = 4) # fancier plot that combines a theme and some other customizations tinyplot( mpg ~ hp | cyl, data = mt, legend = list(title = "Cylinders"), theme = "web" ) tinyplot_add( labels = model, type = type_text( family = "HersheySans", font = 2, pos = 4, repel = TRUE, xpd = NA ) )
Type functions for tile plots, i.e. a grid of rectangles whose
fill colour encodes a third variable. type_tile() is the default building
block for these gridded shapes, drawing the values exactly as supplied. It
underpins heatmaps, correlation matrices, calendar plots, confusion
matrices, and similar displays.
type_heatmap() is a specialised case that first rescales the fill values
within each category of one axis. Reach for it when those values are not
already on a common scale.
type_tile(width = 1, height = 1) type_heatmap( width = 1, height = 1, scale = c("none", "x", "y"), method = c("zscore", "rescale") )type_tile(width = 1, height = 1) type_heatmap( width = 1, height = 1, scale = c("none", "x", "y"), method = c("zscore", "rescale") )
width, height
|
Numeric tile dimensions in data units. Both default to
|
scale |
Character. Should the Note that Rescaling is computed independently per facet; pooling across facets would
pin a panel on a different scale to one end of the ramp and lose its
internal structure. Since rescaled values are no longer in the units of the
|
method |
Character. How should the values be rescaled, if
Groups with no spread—a constant column, or a single tile—would divide
by zero, so they are set to the midpoint of the target range ( |
Tile plots are specified as z ~ x with the fill variable passed as
the by grouping, i.e. tinyplot(y ~ x | z, type = "tile"). The x and
y variables may be factors, characters, or numerics; the by variable
supplies the fill and will typically be numeric, yielding a continuous
colour gradient and colourbar legend. Omitting by leaves the tiles
unfilled, since there is nothing for the fill to encode; pass an explicit
fill (or bg) if you want a uniform colour in that case.
Unlike the closely-related type_rect, which requires explicit
xmin/xmax/ymin/ymax bounds, type_tile() derives the tile bounds
for you: each tile is centred on its x/y position and extends
width/2 and height/2 in each direction. Categorical axes are converted
to consecutive integer positions and the axis tick labels are taken from
the factor levels automatically.
Explicit bounds still take precedence. Passing any of xmin, xmax,
ymin, or ymax leaves that dimension untouched, which is useful for
irregular or unequal-width tiles (e.g. binned continuous data). Bounds may
be given for one axis while the other is derived.
Note that tiles are opaque and drawn edge-to-edge, so the default axis
padding and grid lines of most themes are redundant (and the grid is hidden
behind the tiles in any case). We therefore ship a dedicated "heatmap"
theme that removes the padding and grid, rotates the tick labels, and
switches to a sequential palette. See tinytheme() and the Examples.
type_heatmap()'s scale argument is the analogue of the scale argument
in base R's heatmap, and like the latter it z-scores
along the chosen margin by default. Pass method = "rescale" to map each
group onto the unit [0, 1] interval instead.
type_heatmap() also reverses the y-axis by default, so that the first
row sits at the top, matching how one reads a matrix (and again cf. base
R's heatmap() and image). Pass an explicit ylim
to override. type_tile() makes no such adjustment, since it draws the
values exactly as supplied.
Either way, note that scaling along a margin necessarily discards the
relative spread of each group: a narrow-range column will occupy as much
of the colour ramp as a wide-range one, since both are divided by their own
measure of spread. That is the price of making a matrix of incomparable
units legible; use scale = "none" (or type_tile()) when preserving
cross-group magnitudes matters more.
type_rect for the lower-level rectangle type that
type_tile() builds on, and tinytheme() for the companion "heatmap"
theme.
# It is recommended to use the dedicated "heatmap" theme for tile plots tinytheme("heatmap") # ## type_tile ---- # Correlation matrix of the base `attitude` dataset in "long" form. catt = as.data.frame(as.table(cor(attitude)), responseName = "Correlation") tinyplot(Var1 ~ Var2 | Correlation, data = catt, type = "tile") # fancier version where we reverse the y-axis (to mimic the usual correlation # matrix layout), add white borders around each tile, and suppress the legend # but layer on the values as text tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = "tile", col = "white", legend = FALSE, main = "Correlation matrix of base attitude dataset", xlab = NA, ylab = NA, ylim = "rev" ) tinyplot_add(type = "text", labels = round(catt$Correlation, 2)) # Pass scaled tile widths and heights through type_tile() for a gridded look tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = type_tile(width = 0.9, height = 0.9) ) # It doesn't really work for this example, but you can easily switch to a # diverging palettes if it makes sense for your data tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = type_tile(width = 0.9, height = 0.9), palette = "tropic" ) # Numeric axes work too, e.g. a (reshaped long) data.frame of volcano heights volc = data.frame( x = as.vector(row(volcano)), y = as.vector(col(volcano)), elevation = as.vector(volcano) ) tinyplot( y ~ x | elevation, data = volc, type = "tile", theme = "void", # void theme looks better with this numeric example xlab = NA, ylab = NA, main = "Maunga Whau volcano" ) # ## type_heatmap ---- # Raw data matrices are usually dominated by their largest-magnitude column. # `type_heatmap()` can rescale within each column to make the rest legible. mt = as.data.frame(as.table(as.matrix(mtcars))) # first, the unscaled version: only `disp` and `hp` are visible tinyplot( Var1 ~ Var2 | Freq, data = mt, type = "heatmap", xlab = NA, ylab = NA ) # and now scaled within each x variable (i.e., column). The default is to # z-score, matching base R's `heatmap(scale = "column")`. tinyplot( Var1 ~ Var2 | Freq, data = mt, type = type_heatmap(scale = "x"), xlab = NA, ylab = NA ) # `method = "rescale"` maps each column onto [0, 1] instead. This uses the # colour ramp more fully, at the cost of pinning every column's min and max to # the same two colours. tinyplot( Var1 ~ Var2 | Freq, data = mt, type = type_heatmap(scale = "x", method = "rescale"), xlab = NA, ylab = NA ) # ## tips ---- # tip 1: use tinyplot.matrix() directly to avoid reshaping tinyplot(as.matrix(mtcars), type = type_heatmap(scale = "x"), col = "white") # tip 2: use per-axis tick label scaling (cex) for dense heatmaps tinyplot(as.matrix(mtcars), type = type_heatmap(scale = "x"), col = "white", theme = list("heatmap", cex.yaxs = 0.75, cex.xaxs = 1.25)) ## restore the default theme tinytheme()# It is recommended to use the dedicated "heatmap" theme for tile plots tinytheme("heatmap") # ## type_tile ---- # Correlation matrix of the base `attitude` dataset in "long" form. catt = as.data.frame(as.table(cor(attitude)), responseName = "Correlation") tinyplot(Var1 ~ Var2 | Correlation, data = catt, type = "tile") # fancier version where we reverse the y-axis (to mimic the usual correlation # matrix layout), add white borders around each tile, and suppress the legend # but layer on the values as text tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = "tile", col = "white", legend = FALSE, main = "Correlation matrix of base attitude dataset", xlab = NA, ylab = NA, ylim = "rev" ) tinyplot_add(type = "text", labels = round(catt$Correlation, 2)) # Pass scaled tile widths and heights through type_tile() for a gridded look tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = type_tile(width = 0.9, height = 0.9) ) # It doesn't really work for this example, but you can easily switch to a # diverging palettes if it makes sense for your data tinyplot( Var1 ~ Var2 | Correlation, data = catt, type = type_tile(width = 0.9, height = 0.9), palette = "tropic" ) # Numeric axes work too, e.g. a (reshaped long) data.frame of volcano heights volc = data.frame( x = as.vector(row(volcano)), y = as.vector(col(volcano)), elevation = as.vector(volcano) ) tinyplot( y ~ x | elevation, data = volc, type = "tile", theme = "void", # void theme looks better with this numeric example xlab = NA, ylab = NA, main = "Maunga Whau volcano" ) # ## type_heatmap ---- # Raw data matrices are usually dominated by their largest-magnitude column. # `type_heatmap()` can rescale within each column to make the rest legible. mt = as.data.frame(as.table(as.matrix(mtcars))) # first, the unscaled version: only `disp` and `hp` are visible tinyplot( Var1 ~ Var2 | Freq, data = mt, type = "heatmap", xlab = NA, ylab = NA ) # and now scaled within each x variable (i.e., column). The default is to # z-score, matching base R's `heatmap(scale = "column")`. tinyplot( Var1 ~ Var2 | Freq, data = mt, type = type_heatmap(scale = "x"), xlab = NA, ylab = NA ) # `method = "rescale"` maps each column onto [0, 1] instead. This uses the # colour ramp more fully, at the cost of pinning every column's min and max to # the same two colours. tinyplot( Var1 ~ Var2 | Freq, data = mt, type = type_heatmap(scale = "x", method = "rescale"), xlab = NA, ylab = NA ) # ## tips ---- # tip 1: use tinyplot.matrix() directly to avoid reshaping tinyplot(as.matrix(mtcars), type = type_heatmap(scale = "x"), col = "white") # tip 2: use per-axis tick label scaling (cex) for dense heatmaps tinyplot(as.matrix(mtcars), type = type_heatmap(scale = "x"), col = "white", theme = list("heatmap", cex.yaxs = 0.75, cex.xaxs = 1.25)) ## restore the default theme tinytheme()
Type functions for violin plots, which are an alternative to box
plots for visualizing continuous distributions (by group) in the form of
mirrored densities. type_violin() draws the smooth outline of each
density, while type_sina() scatters the underlying observations as points
within the same outline (similar to a beeswarm plot).
type_violin( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, trim = FALSE, width = 0.9, lighten = TRUE, singletons = c("warn", "drop", "none") ) type_sina( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, trim = FALSE, width = 0.9, method = c("quasirandom", "random"), singletons = c("keep", "warn", "drop") )type_violin( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, trim = FALSE, width = 0.9, lighten = TRUE, singletons = c("warn", "drop", "none") ) type_sina( bw = "nrd0", joint.bw = c("mean", "full", "none"), adjust = 1, kernel = c("gaussian", "epanechnikov", "rectangular", "triangular", "biweight", "cosine", "optcosine"), n = 512, trim = FALSE, width = 0.9, method = c("quasirandom", "random"), singletons = c("keep", "warn", "drop") )
bw |
the smoothing |
joint.bw |
character string indicating whether (and how) the smoothing
bandwidth should be computed from the joint data distribution when there
are multiple subgroups. The options are |
adjust |
the bandwidth used is actually |
kernel |
a character string giving the smoothing kernel to be used. This
must partially match one of
|
n |
the number of equally spaced points at which the density is
to be estimated. When |
trim |
logical indicating whether the densities should be trimmed to
the range of the data. Default is |
width |
numeric (ideally in the range |
lighten |
logical. Should the fills use a lighter, opaque tint of the
series colour(s)? Default is |
singletons |
character string indicating what to do with singleton
groups, i.e. combinations of The remaining option differs by type, as does the default.
|
method |
character string giving how |
See type_density for more details and considerations related to
bandwidth selection and kernel types.
A sina plot (Sidiropoulos et al., 2018) is closely related to a beeswarm
plot, but is arguably the more principled of the two. Both spread a
group's observations sideways to expose its shape. A beeswarm does so by
packing points until they no longer collide, which makes its width an
artefact of the rendering: change the symbol size or the device and the
swarm changes shape. A sina instead displaces each point by the kernel
density at its own y value, so its width is a property of the data,
stable across devices and comparable between groups. The trade-off is
occlusion: a beeswarm guarantees that no point hides another, whereas a
sina accepts the occasional overlap. If you need collision-free packing,
use a dedicated package such as beeswarm.
Sidiropoulos, N., Sohi, S. H., Pedersen, T. L., Porse, B. T., Winther, O., Rapin, N., and Bagger, F. O. (2018). SinaPlot: An Enhanced Chart for Simple and Truthful Representation of Single Observations Over Multiple Classes. Journal of Computational and Graphical Statistics, 27(3), 673-676. Available: https://doi.org/10.1080/10618600.2017.1366914
type_boxplot, type_density and type_ridge for the other ways of displaying a distribution by group, and type_jitter for displacing points without reference to a density.
# "violin" type convenience string tinyplot(weight ~ feed, data = chickwts, type = "violin") # to match the defaults of `ggplot2::geom_violin()`, use `trim = TRUE` and # `joint.bw = FALSE` tinyplot( weight ~ feed, data = chickwts, # type = type_violin(trim = TRUE, joint.bw = FALSE) # same but see final ex. type = "violin", trim = TRUE, joint.bw = FALSE ) # For flipped violin plots, it's usually better to use a dynamic theme to # accommodate (horizontal) y-axis labels tinyplot( weight ~ feed, data = chickwts, type = "violin", flip = TRUE, theme = "dynamic" # or "clean(2)", "classic", "minimal", etc. ) # you can group by the x var to add colour (here with the original orientation) tinyplot(weight ~ feed | feed, data = chickwts, type = "violin", legend = FALSE) # dodged grouped violin plot example (different dataset) tinyplot(len ~ dose | supp, data = ToothGrowth, type = "violin") # the "sina" type shows the observations themselves, rather than a smooth # outline drawn around them tinyplot(weight ~ feed, data = chickwts, type = "sina") # layering a sina on top of a violin lines up exactly, since the points are # displaced by the violin's own half-width tinyplot(weight ~ feed, data = chickwts, type = "violin") tinyplot_add(type = "sina", pch = 16, col = "black") # unlike `type_violin()`, `type_sina()` supports a continuous `by` variable; # it colours the points rather than splitting them into groups tinyplot( Sepal.Length ~ Species | Petal.Width, data = iris, type = "sina", pch = 16 ) # note: above we relied on `...` argument passing alongside the type # convenience strings. But this won't work for `width`, since it will # clash with the top-level `tinyplot(..., width = <width>)` arg. To ensure # correct arg passing, it's safer to use the functional type. tinyplot( len ~ dose | supp, data = ToothGrowth, type = type_violin(width = 0.75) )# "violin" type convenience string tinyplot(weight ~ feed, data = chickwts, type = "violin") # to match the defaults of `ggplot2::geom_violin()`, use `trim = TRUE` and # `joint.bw = FALSE` tinyplot( weight ~ feed, data = chickwts, # type = type_violin(trim = TRUE, joint.bw = FALSE) # same but see final ex. type = "violin", trim = TRUE, joint.bw = FALSE ) # For flipped violin plots, it's usually better to use a dynamic theme to # accommodate (horizontal) y-axis labels tinyplot( weight ~ feed, data = chickwts, type = "violin", flip = TRUE, theme = "dynamic" # or "clean(2)", "classic", "minimal", etc. ) # you can group by the x var to add colour (here with the original orientation) tinyplot(weight ~ feed | feed, data = chickwts, type = "violin", legend = FALSE) # dodged grouped violin plot example (different dataset) tinyplot(len ~ dose | supp, data = ToothGrowth, type = "violin") # the "sina" type shows the observations themselves, rather than a smooth # outline drawn around them tinyplot(weight ~ feed, data = chickwts, type = "sina") # layering a sina on top of a violin lines up exactly, since the points are # displaced by the violin's own half-width tinyplot(weight ~ feed, data = chickwts, type = "violin") tinyplot_add(type = "sina", pch = 16, col = "black") # unlike `type_violin()`, `type_sina()` supports a continuous `by` variable; # it colours the points rather than splitting them into groups tinyplot( Sepal.Length ~ Species | Petal.Width, data = iris, type = "sina", pch = 16 ) # note: above we relied on `...` argument passing alongside the type # convenience strings. But this won't work for `width`, since it will # clash with the top-level `tinyplot(..., width = <width>)` arg. To ensure # correct arg passing, it's safer to use the functional type. tinyplot( len ~ dose | supp, data = ToothGrowth, type = type_violin(width = 0.75) )