tinyplot icon indicating copy to clipboard operation
tinyplot copied to clipboard

Smarter palette choice / recycling with many groups

Open eddelbuettel opened this issue 8 months ago • 4 comments

Updating lecture slides and a year ago I made (screenshotting from the pdf here)

Image

whereas right now with 0.3.0 (under R 4.4.3, everything else CRAN current) I get

Image

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?

eddelbuettel avatar Mar 29 '25 22:03 eddelbuettel

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)

tinyplot-datasaurus

zeileis avatar Mar 29 '25 22:03 zeileis

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 ...

eddelbuettel avatar Mar 29 '25 22:03 eddelbuettel

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.

grantmcdermott avatar Mar 30 '25 16:03 grantmcdermott

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.qualitative or palette.sequential.
  • The warning is only triggered when going through the palette argument of tinyplot() 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.qualitative and no palette.sequential are set, use recycling rather than empty colors, possibly with a warning.
  • Set palette.qualitative and palette.sequential also for default theme.
  • If a palette.colors() palette is specified, determine its number of colors via length(palette.colors(palette = palette)). (For a hcl.colors() palette, any number of colors can be obtained.)
  • Avoid hard-coded 8 in some computations. This comes from length(palette()) with the default R4 palette. But the user could change this, of course.
  • If palette.sequential is a color vector, generally use interpolation via color ramp, no matter whether there are enough or too few colors in the color vector.

zeileis avatar Mar 31 '25 01:03 zeileis

@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.)

grantmcdermott avatar May 23 '25 01:05 grantmcdermott