Smarter palette choice / recycling with many groups
Updating lecture slides and a year ago I made (screenshotting from the pdf here)
whereas right now with 0.3.0 (under R 4.4.3, everything else CRAN current) I get
which isn't fair. Moments ago I used the branch @grantmcdermott worked on for violins, and that filled seven or so of the categories. Code is a pretty plain and possibly even from your documentation:
dd <- datasauRus::datasaurus_dozen
tinyplot::plt(y ~ x | as.factor(dataset), data = dd,
facet = ~ dataset, pch = 18, legend = FALSE, main = "Datasaurus Dozen")
As so often writing this out made the solution suggest itself: dd$dataset <- as.factor(dd$dataset) and all is well.
So should tinyplot bark a little when ask to facet on a variable that is not a factor?
I seem to recall that Grant recently did some improvements regarding this - but maybe I'm wrong. In any case, with the current R-universe version, you can use the character variable dataset directly. It's just that the default qualitative palette does not provide enough colors but changing to "Viridis" or "Dark 3" are alternatives that work.
dd <- datasauRus::datasaurus_dozen
install.packages("tinyplot", repos = "https://grantmcdermott.R-universe.dev")
library("tinyplot")
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, palette = "Dark 3", legend = FALSE)
That's likely what I saw re-rendering the slide: by not adding an appropriate palette, I 'ran out of colours', got some empty boxes and it all went downhill from there.
Do as you please: close as non-issue, keep open as reminder to nag user when not a factor, or more factor levels that colors, or ...
I think the problem here is actually that something got overwritten or missed when we added our tinytheme logic. E.g., the following works because the palette.qualitiative correctly upgrades to palette.sequential when a high number of groups are detected.
dd = datasauRus::datasaurus_dozen
library("tinyplot")
tinytheme('clean')
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)

tinytheme()
Created on 2025-03-30 with reprex v2.1.1
Hopefully an easy fix. I'll take a look after I get to some other issues.
Thanks, Grant, I was wondering about the same when playing around with the example today:
## data and package
dd = datasauRus::datasaurus_dozen
library("tinyplot")
## default: partially empty, no warning
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)
## insufficient palette: partially empty, with warning
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE, palette = "Okabe-Ito")
## sufficient palette: ok
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE, palette = "Dark 3")
## theme with palette.qualitative (insufficient) & palette.sequential: ok (failover to sequential)
tinytheme("minimal")
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)
## theme with palette.qualitative (sufficient by name) & palette.sequential: still failover to sequential
tinytheme("minimal", palette.qualitative = "Dark 3")
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)
## theme with palette.qualitative (sufficient by vector) & palette.sequential: ok
tinytheme("minimal", palette.qualitative = hcl.colors(13, "Dark 3"))
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)
## theme with palette.qualitative (insufficient) & palette.sequential (too short): recycling, with warning
tinytheme("minimal", palette.sequential = hcl.colors(9))
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)
So the situation seems to be:
- The default is partially empty because the default theme does not set any
palette.qualitativeorpalette.sequential. - The warning is only triggered when going through the
paletteargument oftinyplot()but not when the theme sets something insufficient. - The heuristics with which the number of colors is determined, as provided by
palette.qualitative, only work when this is a color vector but not a color name. - Too short sequential palettes are recycled rather than interpolated via color ramp.
Potential improvements:
- If no
palette.qualitativeand nopalette.sequentialare set, use recycling rather than empty colors, possibly with a warning. - Set
palette.qualitativeandpalette.sequentialalso for default theme. - If a
palette.colors()palette is specified, determine its number of colors vialength(palette.colors(palette = palette)). (For ahcl.colors()palette, any number of colors can be obtained.) - Avoid hard-coded
8in some computations. This comes fromlength(palette())with the defaultR4palette. But the user could change this, of course. - If
palette.sequentialis a color vector, generally use interpolation via color ramp, no matter whether there are enough or too few colors in the color vector.
@eddelbuettel Thanks again for flagging. This is fixed in tinyplot v0.4.0, which just landed on CRAN.
dd = datasauRus::datasaurus_dozen
library("tinyplot")
plt(y ~ x | dataset, facet = "by", data = dd, pch = 18, legend = FALSE)

Created on 2025-05-22 with reprex v2.1.1
(Note slightly different call to your original, leveraging the facet = "by" syntax, which also automatically converts the grouping variable to a factor.)