grantmcdermott · GitHub

Closes #557.

This ended up being a trickier bug to fix than I first thought and, very specifically, only affects the ephemeral "default" theme (persistent default was fine) in combination with by and tinyplot_add().

The root cause: when tinyplot() exits, the ephemeral theme cleanup calls do.call(tinytheme, otheme) to restore the pre-theme state. For non-default themes this is fine, since they use hook = TRUE and their par changes are deferred via before.plot.new hooks. But tinytheme("default") uses hook = FALSE, which means it calls par(mar = c(5.1, 4.1, 4.1, 2.1)) directly. This overwrites the legend's mar[4] = 0 adjustment and, with no hook left to restore it, plt_add() inherits the wrong margins, and so the plot region of this added layer is squeezed (clipped).

The fix here is surgical. For ephemeral theme = "default" only, we:

  1. immediately restore par(mar) to its pre-theme value after tinytheme("default") is called, so the legend can manage margins from a clean state, and
  2. replace the standard on.exit cleanup with init_tpar(rm_hook = TRUE) instead of do.call(tinytheme, otheme). This resets the internal .tpar state and removes any theme hooks, without touching par(mar), leaving the legend's margin adjustment intact for plt_add() to inherit.

All other (non-"default") ephemeral themes are unaffected, as are the persistent themes, and continue to use the existing cleanup path.

I've included a new test which shows the fix in action.

Read the original on github.com ↗