CRAN version R-universe status badge R-CMD-check Docs


A lightweight extension of the base R graphics system, with support for automatic grouping, legends, facets, and various other enhancements.

tinyplot is not yet on CRAN, but can be installed from R-universe.

install.packages("tinyplot", repos = "https://grantmcdermott.r-universe.dev")

Our goal is to submit to CRAN within the first few months of 2024, once we have settled on some remaining design choices and features support. You can take a look at the open issues to see what’s currently under consideration. Please feel free to weigh on these if you have opinions. We want end users to have a say in determining the final product.


R users are spoiled for choice when it comes to visualization frameworks. The options include ggplot2 (arguably the most important graphics system of the last decade) and lattice, not to mention a bewildering array of extensions built on top of, around, and in between these amazing packages.

As a result, it is not surprising that the base R graphics system can sometimes get short shrift. This is unfortunate, because base R offers very powerful and flexible plotting facilities. Just type demo(graphics) or demo(persp) into your R console to get an idea. Or, take a look at these two excellent tutorials. The downside of this power and flexibility is that base R plotting can require a fair bit of manual tinkering. A case in point is plotting grouped data with an appropriate legend. Doing so with the generic plot() function can require several function calls or a loop, fiddling with your plot regions, and then generating the legend manually.

The tinyplot package aims to remove this overhead. It provides a lightweight extension of the base R graphics system that comes with various convenience features, yet relies on no additional dependencies beyond base R itself. For example, the core tinyplot() function—or its shorthand alias plt()—makes it easy to plot different groups of a dataset and generate an automatic legend in a single function call. While tinyplot offers various other enhancements like facets, additional plot types, etc. it tries as far as possible to be a drop-in replacement for the equivalent base plotting function. Users should generally be able to swap a valid plot() call for tinyplot() without any changes to the expected output.


The tinyplot website includes a detailed introductory tutorial, with numerous examples. But here are some quickstart examples of the package in action.


Grouped scatterplot with automatic legend:

# with(iris, tinyplot(x = Petal.Length, y = Sepal.Length, by = Species)) # atomic
tinyplot(Sepal.Length ~ Petal.Length | Species, data = iris)             # formula

If you would prefer to save on a few keystrokes, you can use the shorthand plt() alias instead instead of typing out tinyplot() in full. Here’s the same plot with this shorthand alias, plus a few aesthetic tweaks:

  Sepal.Length ~ Petal.Length | Species, 
  data = iris,
  palette = "dark", pch  = 16,
  grid = TRUE, frame = FALSE

Grouped grouped density plot with automatic legend:

  ~ Petal.Length | Species,
  data = iris,
  type = "density",
  palette = "dark", fill = "by",
  grid = TRUE,
  main = "Distribution of petal lengths by species"

Grouped scatterplot with (continuous) gradient legend, combined with facet layout:

  Sepal.Length ~ Petal.Length | Sepal.Length, data = iris,
  facet = ~Species, facet.args = list(bg = "grey90"),
  pch = 19,
  main = "Faceted Species!",
  grid = TRUE, frame = FALSE

Hopefully, these have been enough to pique your interest. Head over to the intro tutorial for many more examples, including range plots and customization.