diff --git a/NEWS.md b/NEWS.md index 64382904..1425e1ea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,11 @@ where the formatting is also better._ - `type_hexbin()` (equivalently, `type = "hexbin"`) for hexagonal bin plots, a 2D analogue of a histogram. (#667 @grantmcdermott) +### Bug fixes + +- Fixed bug where single-valued discrete axes would trigger invalid `par(usr)` + values when combined with free facets. (#668 @grantmcdermott) + ## v0.7.0 **tinyplot** v0.7.0 is a big release with many new features, including major diff --git a/R/facet.R b/R/facet.R index e9b31e74..1f360489 100644 --- a/R/facet.R +++ b/R/facet.R @@ -368,6 +368,11 @@ draw_facet_window = function( # extendrange() returns an ascending pair, so reverse afterwards xext = extendrange(sort(xlim), f = 0.04) yext = extendrange(sort(ylim), f = 0.04) + # A facet with a single distinct x (or y) value yields a zero-width + # extent, which par(usr=) rejects. Mirror base plot.window() and pad + # a degenerate range symmetrically so the facet still draws. (#668) + if (diff(xext) == 0) xext = xext + c(-1, 1) * (if (xext[1L] == 0) 1 else 0.04 * abs(xext[1L])) + if (diff(yext) == 0) yext = yext + c(-1, 1) * (if (yext[1L] == 0) 1 else 0.04 * abs(yext[1L])) # base axTicks() misbehaves on a reversed usr (it collapses to a single # tick), so precompute ticks from the ascending extent and pass them as # an explicit `at` below; placement against the reversed usr is fine. diff --git a/inst/tinytest/_tinysnapshot/facet_free_single_value.svg b/inst/tinytest/_tinysnapshot/facet_free_single_value.svg new file mode 100644 index 00000000..64fc4406 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/facet_free_single_value.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + +Free facets: single-value facet +x +y + + + + + + + + + + + +a + + + + + + +0.96 +0.98 +1.00 +1.02 +1.04 + +A + + + + + + + + + + + + +b + + + + + + + +2.0 +2.2 +2.4 +2.6 +2.8 +3.0 + +B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-facet.R b/inst/tinytest/test-facet.R index 5742d3ac..0c139a7c 100644 --- a/inst/tinytest/test-facet.R +++ b/inst/tinytest/test-facet.R @@ -556,6 +556,22 @@ f = function() { } expect_snapshot_plot(f, label = "facet_free_yscale") +# Free facets where a facet has a single distinct (discrete) axis value, which +# collapses the free-scale range to zero width (issue #668) +f = function() { + dat = data.frame( + x = c("a", "b", "b"), + y = c(1, 2, 3), + g = c("A", "B", "B") + ) + tinyplot( + y ~ x, data = dat, + facet = ~g, facet.args = list(free = TRUE), + main = "Free facets: single-value facet" + ) +} +expect_snapshot_plot(f, label = "facet_free_single_value") + # # restore original par settings #