From 8584512dd41c626834990de915543b86eab04634 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Jul 2026 15:33:12 -0700 Subject: [PATCH 1/4] fix single value discrete free facet --- R/facet.R | 5 +++++ 1 file changed, 5 insertions(+) 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. From 3668eb9b24d6102a93e648e868c6b2b303ecc148 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Jul 2026 15:33:16 -0700 Subject: [PATCH 2/4] test --- .../_tinysnapshot/facet_free_single_value.svg | 113 ++++++++++++++++++ inst/tinytest/test-facet.R | 16 +++ 2 files changed, 129 insertions(+) create mode 100644 inst/tinytest/_tinysnapshot/facet_free_single_value.svg 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 # From ad0a1d98f371fc47b3b2946ae9bf45f1402c5d42 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Jul 2026 15:34:51 -0700 Subject: [PATCH 3/4] news --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 64382904..0ad1ffaa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,10 @@ 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 + +- Fix bug for single-valued discrete axes with free facets (#668 @grantmcdermott) + ## v0.7.0 **tinyplot** v0.7.0 is a big release with many new features, including major From 67ae7c9f88127ff11667aa7ef8f1be7c3df48a92 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Jul 2026 15:36:44 -0700 Subject: [PATCH 4/4] news --- NEWS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 0ad1ffaa..1425e1ea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,7 +15,8 @@ where the formatting is also better._ ### Bug fixes -- Fix bug for single-valued discrete axes with free facets (#668 @grantmcdermott) +- Fixed bug where single-valued discrete axes would trigger invalid `par(usr)` + values when combined with free facets. (#668 @grantmcdermott) ## v0.7.0