From 078e1a52fd7463f21bdf0abbf922326da2fe510e Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 2 Apr 2026 15:08:02 +0200 Subject: [PATCH 1/2] add (failing) test for #555 --- .../_tinysnapshot/facet_free_asp_1.svg | 110 ++++++++++++++++++ inst/tinytest/test-facet.R | 16 +++ 2 files changed, 126 insertions(+) create mode 100644 inst/tinytest/_tinysnapshot/facet_free_asp_1.svg diff --git a/inst/tinytest/_tinysnapshot/facet_free_asp_1.svg b/inst/tinytest/_tinysnapshot/facet_free_asp_1.svg new file mode 100644 index 00000000..f1b19b0c --- /dev/null +++ b/inst/tinytest/_tinysnapshot/facet_free_asp_1.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + +x +y + + + + + + + + + + + + + + + +2 +4 +6 +8 +10 + + + + + +-5 +0 +5 +10 + +A + + + + + + + + + + + + + + + + +2 +4 +6 +8 +10 + + + + + +-5 +0 +5 +10 + +B + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-facet.R b/inst/tinytest/test-facet.R index 8b991e6c..09d9b16f 100644 --- a/inst/tinytest/test-facet.R +++ b/inst/tinytest/test-facet.R @@ -513,6 +513,22 @@ f = function() { } expect_snapshot_plot(f, label = "facet_free_grid") +f = function() { + tinyplot( + y ~ x, + facet = ~group, + facet.args = list(free = TRUE), + data = data.frame( + y = rep(c(1, 1, 2, 2, 1, 1.5, 1.5), 2), + x = rep(c(2, 1, 1, 2, 2, 2, 11), 2), + group = c(rep("A", 7), rep("B", 7)) + ), + type = "l", + asp = 1 + ) +} +expect_snapshot_plot(f, label = "facet_free_asp_1") + # # restore original par settings # From e27660089d2a76172157582e6f0b388401f5ccf4 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 2 Apr 2026 18:19:54 +0200 Subject: [PATCH 2/2] Attempt at #555 --- R/facet.R | 5 +++-- R/lim.R | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/R/facet.R b/R/facet.R index fde5f529..469ac789 100644 --- a/R/facet.R +++ b/R/facet.R @@ -311,8 +311,9 @@ draw_facet_window = function( # individual facet. xfree = if (!is.null(facet)) split(c(x, xmin, xmax), facet)[[ii]] else c(x, xmin, xmax) yfree = if (!is.null(facet)) split(c(y, ymin, ymax), facet)[[ii]] else c(y, ymin, ymax) - if (null_xlim) xlim = range(xfree, na.rm = TRUE) - if (null_ylim) ylim = range(yfree, na.rm = TRUE) + lim = calc_lim(range(xfree, na.rm = TRUE), range(yfree, na.rm = TRUE), asp) + if (null_xlim) xlim = lim$xlim + if (null_ylim) ylim = lim$ylim xext = extendrange(xlim, f = 0.04) yext = extendrange(ylim, f = 0.04) # We'll save this in a special .fusr env var (list) that we'll re-use diff --git a/R/lim.R b/R/lim.R index 7eb13aad..621ba033 100644 --- a/R/lim.R +++ b/R/lim.R @@ -47,3 +47,32 @@ lim_args = function(settings) { c("xlim", "ylim", "xlabs", "ylabs", "xaxb", "yaxb") ) } + +# translated from C_plot_window function in r-source/src/library/graphics/src/plot.c +calc_lim <- function( + xlim, + ylim, + asp, + xin = grconvertX(1, "npc", "inches"), + yin = grconvertY(1, "npc", "inches") +) { + if (!is.null(asp) && !is.na(asp) && asp > 0) { + xmin = xlim[1]; xmax = xlim[2]; ymin = ylim[1]; ymax = ylim[2]; + xdelta = abs(xmax - xmin) / asp + ydelta = abs(ymax - ymin) + if(xdelta == 0.0 && ydelta == 0.0) { + # Not from R source: actual zero used here + return(list(xlim = xlim, ylim = ylim)) + } + scale = min(c(xin / xdelta, yin / ydelta)) + xadd = .5 * (xin / scale - xdelta) * asp + yadd = .5 * (yin / scale - ydelta) + if (xmax < xmin) xadd = xadd * -1 + if (ymax < ymin) yadd = yadd * -1 + return(list( + xlim = c(xmin - xadd, xmax + xadd), + ylim = c(ymin - yadd, ymax + yadd) + )) + } + list(xlim = xlim, ylim = ylim) +}