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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ S3method(tinyplot,data.frame)
S3method(tinyplot,default)
S3method(tinyplot,density)
S3method(tinyplot,formula)
S3method(tinyplot,matrix)
S3method(tinyplot,ts)
export(draw_legend)
export(get_saved_par)
Expand Down
22 changes: 17 additions & 5 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,9 @@ Theme fixes:

#### New `tinyplot.*` methods

- A top-level `tinypairs()` function, together with a dedicated
`tinyplot.data.frame()` method, now supports direct plotting of data frames,
with or without a formula. Combining with a formula is mostly useful insofar
as it facilitates piping, e.g.
- `tinyplot.data.frame()`: Supports direct plotting of data frames, alongside
the new top-level function `tinypairs()`. Can be called with or without a
formula. One benefit of the former is that it facilitates piping, e.g.

```r
iris |> plt(Sepal.Length ~ Petal.Width | Species)
Expand All @@ -176,7 +175,16 @@ Theme fixes:
variables will yield a `pairs()`-style grid of all variable combinations.
Thanks to @mthulin for the suggestion and original implementation idea.
(#613, #640 @zeileis @grantmcdermott)
- New dedicated `tinyplot.ts()` method for `ts` time series, e.g.
- `tinyplot.matrix()`: for `matrix` objects, e.g.

```r
plt(VADeaths, type = "b")
```

The output largely mimics the base `matplot`/`matlines` equivalents, but with
additional **tinyplot** functionality related to automatic legends, options
for faceting, etc. (#649 @grantmcdermott)
- `tinyplot.ts()`: for `ts` time series, e.g.

```r
plt(EuStockMarkets)
Expand Down Expand Up @@ -299,6 +307,10 @@ Theme fixes:
`sub`, `cap`, `xlab`, and `ylab` being evaluated instead of coerced to
plotmath expressions, e.g. `plt(0, 0, main = bquote(foo == .(pi)))`. Thanks
(again) to @bastistician for the report. (#642 @grantmcdermott)
- Line plots (`type = "l"`, and relatives like `"b"`/`"o"`) with a factor or
character `x` variable now draw the category labels on the x-axis, matching
the behaviour of point plots. Previously these tick labels were only shown
when dodging was active. (#648 @grantmcdermott)

## v0.6.1

Expand Down
6 changes: 4 additions & 2 deletions R/facet.R
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,9 @@ draw_facet_window = function(
)
if (!is.null(xaxb)) args_x$at = xaxb
if (!is.null(yaxb)) args_y$at = yaxb
type_range_x = type %in% c("barplot", "pointrange", "errorbar", "ribbon", "boxplot", "p", "violin") && !is.null(xlabs)
# `xlabs` is only non-NULL when a type has placed categorical data on the
# x-axis, so its presence is the signal to draw labelled ticks.
type_range_x = !is.null(xlabs)
type_range_y = !is.null(ylabs) && (type == "p" || (isTRUE(flip) && type %in% c("barplot", "pointrange", "errorbar", "ribbon", "boxplot", "violin")))
if (type_range_x) {
args_x = modifyList(args_x, list(at = xlabs, labels = names(xlabs)))
Expand Down Expand Up @@ -369,7 +371,7 @@ draw_facet_window = function(
# Explicitly set (override) the current facet extent
par(usr = fusr[[ii]])
# if plot frame is true then print axes per normal...
if (type %in% c("barplot", "pointrange", "errorbar", "ribbon", "boxplot", "p", "violin") && !is.null(xlabs)) {
if (!is.null(xlabs)) {
tinyAxis(xfree, side = xside, at = xlabs, labels = names(xlabs), type = xaxt, labeller = xaxl)
} else {
tinyAxis(xfree, side = xside, type = xaxt, labeller = xaxl)
Expand Down
13 changes: 9 additions & 4 deletions R/sanitize_type.R
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ sanitize_type = function(settings) {
"hline" = type_hline,
"j" = type_jitter,
"jitter" = type_jitter,
"l" = type_lines,
"lines" = type_lines,
"lm" = type_lm,
"loess" = type_loess,
"p" = type_points,
Expand All @@ -110,15 +108,22 @@ sanitize_type = function(settings) {
"text" = type_text,
"violin" = type_violin,
"vline" = type_vline,
type # default case
type # default case (incl. line-family chars, handled below)
)
}
# browser()

if (is.function(type)) {
args = intersect(names(formals(type)), names(dots))
args = if (length(args) >= 1L) dots[args] else list()
type = do.call(type, args)
type$dots = dots[setdiff(names(dots), names(args))]
} else if (is.character(type) && type %in% c("l", "lines", "o", "b", "c", "h", "s", "S")) {
# Line-family convenience characters route through type_lines(), preserving
# the requested plot character (so e.g. "b" stays points + lines, rather than
# defaulting to "l").
args = dots[intersect(names(formals(type_lines)), names(dots))]
args[["type"]] = if (type == "lines") "l" else type
type = do.call(type_lines, args)
}

if (inherits(type, "tinyplot_type")) {
Expand Down
92 changes: 92 additions & 0 deletions R/tinyplot.matrix.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#' tinyplot Method for Plotting Matrices
#'
#' @description Convenience interface for visualizing
#' \code{\link[base]{matrix}} objects with tinyplot.
#'
#' @details 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
#' \code{\link[graphics]{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.
#'
#' @param x an object of class `"matrix"`.
#' @param type plot type passed on to `tinyplot`. Defaults to `"p"` (points).
#' @param legend specification passed on to `tinyplot`. The default is to draw a
#' legend when the matrix has named columns, and to suppress it otherwise.
#' @param facet specification of `facet` passed on to `tinyplot`. The only
#' accepted non-`NULL` value is the `"by"` convenience string, which facets
#' the plot by matrix column.
#' @param xlab,ylab axis labels passed on to `tinyplot`. `ylab` defaults to the
#' deparsed matrix name. `xlab` defaults to `"Index"` when the matrix has no
#' row names; when it does, the row names already label the ticks so the
#' x-axis title is suppressed.
#' @param ... further arguments passed to `tinyplot`.
#'
#' @returns No return value, called for the side effect of producing a plot.
#'
#' @seealso \code{\link[graphics]{matplot}}
#'
#' @examples
#' # 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")
#'
#' # equivalent 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)))
#'
#' @export
tinyplot.matrix = function(x, type = NULL, legend = NULL, facet = NULL, xlab = NULL, ylab = NULL, ...) {
assert_choice(facet, "by", null.ok = TRUE)
## Default to points. We set this explicitly (rather than relying on
## tinyplot's auto-inference) because the x-axis row labels are passed as a
## factor, which would otherwise be inferred as a boxplot.
if (is.null(type)) type = "p"
dep_x = deparse1(substitute(x))
dims = dim(x)
if (dims[2] == 1L) {
bby = NULL
legend = FALSE
} else {
nms = colnames(x)
if (!is.null(nms)) {
bby = factor(rep(nms, each = dims[1]), levels = nms)
if (is.null(legend)) legend = list(title = NULL)
} else {
bby = factor(rep(seq_len(dims[2]), each = dims[1]))
legend = FALSE
}
}
## If the matrix has row names, use them for the x-axis tick labels via an
## ordered factor (preserving row order). Otherwise fall back to a plain
## numeric index.
rnms = rownames(x)
dim(x) = dims[1] * dims[2]
y = x
if (is.null(rnms)) {
x = rep(seq_len(dims[1]), times = dims[2])
## no row names: x is a plain numeric index, so label it as such
if (is.null(xlab)) xlab = "Index"
} else {
x = factor(rep(rnms, times = dims[2]), levels = rnms, ordered = TRUE)
## row names already label the ticks, so an "Index" title is redundant
if (is.null(xlab)) xlab = NA
}
if (is.null(ylab)) ylab = dep_x
tinyplot.default(
x = x, y = y,
type = type,
by = bby,
facet = facet,
legend = legend,
xlab = xlab,
ylab = ylab,
...
)
}
4 changes: 2 additions & 2 deletions R/type_lines.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ type_lines = function(type = "l", dodge = 0, fixed.dodge = FALSE) {


data_lines = function(dodge = 0, fixed.dodge = FALSE) {
if (is.null(dodge) || dodge == 0) return(NULL)
fun = function(settings, ...) {
env2env(settings, environment(), c("datapoints", "xlabs"))

if (is.character(datapoints$x)) {
datapoints$x = as.factor(datapoints$x)
}
if (is.factor(datapoints$x)) {
xlvls = unique(datapoints$x)
# honour pre-ordered factors; otherwise fall back to first-appearance order
xlvls = if (is.ordered(datapoints$x)) levels(datapoints$x) else unique(datapoints$x)
datapoints$x = factor(datapoints$x, levels = xlvls)
xlabs = seq_along(xlvls)
names(xlabs) = xlvls
Expand Down
2 changes: 1 addition & 1 deletion altdoc/pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ altdoc: 0.7.2
pandoc: '3.10'
pkgdown: 2.1.3
pkgdown_sha: ~
last_built: 2026-06-23T18:52:00+0000
last_built: 2026-06-26T05:13:18+0000
urls:
reference: https://grantmcdermott.com/tinyplot/man
article: https://grantmcdermott.com/tinyplot/vignettes
2 changes: 2 additions & 0 deletions altdoc/quarto_website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ website:
contents:
- text: tinyplot.data.frame
file: man/tinyplot.data.frame.qmd
- text: tinyplot.matrix
file: man/tinyplot.matrix.qmd
- text: tinyplot.ts
file: man/tinyplot.ts.qmd

Expand Down
103 changes: 103 additions & 0 deletions inst/tinytest/_tinysnapshot/matrix_basic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading