Skip to content

added tinyplot.data.frame method#613

Merged
grantmcdermott merged 17 commits into
mainfrom
data-frame-method
Jun 20, 2026
Merged

added tinyplot.data.frame method#613
grantmcdermott merged 17 commits into
mainfrom
data-frame-method

Conversation

@zeileis

@zeileis zeileis commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

Replaces #347

The new data.frame method for tinyplot() draws some inspiration from the corresponding method for base plot(). It mainly facilitates using tinyplot() with data frames and pipes.

tinytheme("clean2")
cars |> tinyplot()
tinyplot-dataframe1
iris |> tinyplot(Sepal.Length ~ Petal.Width | Species)
tinyplot-dataframe2

Currently, this only works for data frames with 1 or 2 variables. In the future we might add a pairs-style display as follows but this would require better handling of axes and their labels.

par(mfrow = c(5, 5))
for (i in names(iris)) for(j in names(iris)) tinyplot(iris[, unique(c(j, i)), drop = FALSE])
tinyplot-dataframe3

So far the PR only contains code and documentation. NEWS and tests can be added when we agree on the code.

@grantmcdermott

Copy link
Copy Markdown
Owner

This is great, thanks @zeileis.

As you would have seen, your updates here have inspired me to tack a crack at fixing the default colour case in #614. I think we should agree on that PR first and, if we decide to adopt it, merge those changes into this branch so we can review the combined effect.

@grantmcdermott grantmcdermott left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some specific (and high-level) thoughts in my review below. Happy to discuss!

Comment thread R/tinyplot.data.frame.R Outdated
Comment thread R/tinyplot.data.frame.R Outdated
## 2d: y ~ x
## 3d: pairs? (not supported, yet)
if (is.null(formula)) {
if (ncol(x) > 2L) stop("'formula' is missing with no default for more than 2 columns")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think we could do better than erroring out here. My own preference is that we either:

  1. Subset to the first 2 columns and display the resulting simple two-way plot (maybe with a message), or

  2. Subset to the first N (<=5?) columns and then internally implement the "manual" pairs-esque plot that you demonstrate in the Examples above (maybe with a message if any columns are dropped), or

  3. Don't subset at all and just try to implement the "manual" pairs-esque plot you demonstrate above (but risk poor viewability/zooming.)

P.S. I don't think we should try to mimic base plot(df)/pairs(df) exactly. Apart from the top + right axes variation being a pain, I think your example shows several improvements, especially w.r.t. to the histogram and way that factor/character variables are handled consistently (barplots + spineplots).

P.P.S. If we go with option 2 or 3, one other thing to consider is whether we support an (atomic) by argument without a formula. E.g., tinyplot(iris, by = "species").

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. I think we should just go for 3 and explain the limitations in the manual page.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have attempted to implement 3 now including some very simple setting of xlab, ylab, and main. It's not great but probably better than nothing. Further improvements would be welcome.

Comment thread R/tinyplot.data.frame.R Outdated
Comment thread R/tinyplot.data.frame.R Outdated
Comment thread R/tinyplot.data.frame.R Outdated
#' 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 data frames,
#' either only one variable or a pair of variables. In the future, the

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment about the n>2 case below.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated it a little bit now. But depending on where we go with the pairs-esque display, further updates will probably be necessary.

@grantmcdermott

Copy link
Copy Markdown
Owner

@mthulin please take a look too, since this would replace your previous PR in #347.

@grantmcdermott

Copy link
Copy Markdown
Owner

Hi @zeileis,

I made a few tweaks for the n > 3 case, which are more suggestions that than definitive choices. But want to push so you could test on your side. Let me know what you think (and feel free to push back if you feel strongly about anything):

  • I dropped the axis labs for all of the sub plots. This is consistent with how pairs does it and also means that the plot regions are all equally size.
  • I scaled the cex for the individual plots, so that the points etc. are a bit smaller. This is similar to how we reduce the cex size in faceted plots (and base R plots are also scaled for mfrow adjustments).
  • I added a box around each sub-plot. I just found that this helped me a bit visually; especially for certain themes. But maybe we can add an argument so that users can control this.

MWE:

plt(iris, theme = 'clean2')
df-iris

@zeileis

zeileis commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator Author

An important (and deliberate) difference between our plot and pairs is that we have a univariate display on the diagonal while pairs only has a large label. That's why pairs doesn't need additional axis labels. In our plot I felt that the axis labels in the margins were a useful addition because the main labels on the diagonal are a bit smaller. Maybe we should control this by an extra argument?

The cex looks good to me. Good idea.

Personally, I'm not fond of the frames. But maybe an argument would also be useful here.

Finally, you might want to have a stab at the additional by argument? This would also be very useful.

@grantmcdermott

Copy link
Copy Markdown
Owner

Done. I added labs and frames args to control the axis titles and subplot boxes, respectively. I also added support for a by argument.

I need to get to bed but please kick the tyres and let me know if this looks good to you now.

P.S. On the axis labels/titles. I initially tried to support an "outer" subplot labeling only; what you were referring to "margin" labels above. The trouble is that there's no way to do this consistently, In the iris dataset, for example the top left plot y-axis ends up saying "Frequency", while the rest of the top row y-axis are really representing "Sepal.Width". So I went for a simple all-or-nothing approach.

@zeileis

zeileis commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator Author

Just had a very quick look, very nice!! Two short comments:

  • In themes that have axis lines (such as the default theme), I think that frames = TRUE is definitely too much. For other themes, frames are ok, even if I typically prefer no frames. Hence the simplest solution would be to set the default to frames = FALSE.

  • In addition to by being a character string indicating an existing column, we could also allow a full variable so that you can do: tinyplot(iris[, 1:4], by = iris$Species).

@grantmcdermott

Copy link
Copy Markdown
Owner

Two short comments:

Done! I think that this is ready to be merged now.

@grantmcdermott grantmcdermott merged commit 7404dc7 into main Jun 20, 2026
3 checks passed
@grantmcdermott grantmcdermott deleted the data-frame-method branch June 20, 2026 17:55
@zeileis

zeileis commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks, this is fantastic.

One more thought/question: Should we separate the functionality into a tinypairs() function as well? This would facilitate the creation of 2 x 2 pairs displays.

@grantmcdermott

Copy link
Copy Markdown
Owner

One more thought/question: Should we separate the functionality into a tinypairs() function as well? This would facilitate the creation of 2 x 2 pairs displays.

Sure, that sounds reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants