From b088f5cb5135e3436defb499eba0a4ec970515d7 Mon Sep 17 00:00:00 2001 From: Vincent Arel-Bundock Date: Fri, 13 Feb 2026 18:40:31 -0500 Subject: [PATCH 01/30] issue #303 margin adjustment for multi-line labels and titles --- R/facet.R | 32 + R/legend.R | 2 +- R/tinyplot.R | 9 +- R/tinytheme.R | 2 - R/title.R | 41 +- R/utils.R | 12 + .../_tinysnapshot/margins_facet_multiline.svg | 124 + .../_tinysnapshot/margins_missing_labels.svg | 81 + .../_tinysnapshot/margins_multiline_2x2.svg | 330 ++ .../margins_multiline_labels.svg | 87 + .../margins_sub_na_bottom_legend.svg | 118 + .../pointrange_with_layers_flipped.svg | 48 +- .../_tinysnapshot/ridge_basic_theme_ridge.svg | 40 +- .../ridge_basic_theme_ridge2.svg | 30 +- .../_tinysnapshot/ridge_by_x_theme_ridge.svg | 3106 ++++++------ .../_tinysnapshot/ridge_by_x_theme_ridge2.svg | 3096 ++++++------ .../_tinysnapshot/ridge_by_y_theme_ridge.svg | 48 +- .../_tinysnapshot/ridge_by_y_theme_ridge2.svg | 34 +- .../ridge_gradient_facet_theme_ridge.svg | 4166 ++++++++--------- .../ridge_gradient_facet_theme_ridge2.svg | 4150 ++++++++-------- .../ridge_gradient_theme_ridge.svg | 3106 ++++++------ .../ridge_gradient_theme_ridge2.svg | 3096 ++++++------ .../_tinysnapshot/tinytheme_dynamic_yaxl.svg | 178 +- inst/tinytest/test-margins.R | 83 + 24 files changed, 11465 insertions(+), 10554 deletions(-) create mode 100644 inst/tinytest/_tinysnapshot/margins_facet_multiline.svg create mode 100644 inst/tinytest/_tinysnapshot/margins_missing_labels.svg create mode 100644 inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg create mode 100644 inst/tinytest/_tinysnapshot/margins_multiline_labels.svg create mode 100644 inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg create mode 100644 inst/tinytest/test-margins.R diff --git a/R/facet.R b/R/facet.R index 9183a680..76897864 100644 --- a/R/facet.R +++ b/R/facet.R @@ -31,8 +31,12 @@ draw_facet_window = function( draw, grid, has_legend, + main, + sub, type, + xlab, x, xmax, xmin, + ylab, y, ymax, ymin, tpars = NULL ) { @@ -155,6 +159,20 @@ draw_facet_window = function( fmar[1] = fmar[1] - (whtsbp * cex_fct_adj) } } + + # Adjust margins for missing and multi-line annotation strings. + xlab_lines = text_line_count(xlab) + ylab_lines = text_line_count(ylab) + main_lines = text_line_count(main) + + if (xlab_lines == 0) omar[1] = omar[1] - 1 + if (ylab_lines == 0) omar[2] = omar[2] - 1 + if (main_lines == 0) omar[3] = omar[3] - 1 + + if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * par("cex.lab") + if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * par("cex.lab") + if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * par("cex.main") + # FIXME: Is this causing issues for lhs legends with facet_grid? # catch for missing rhs legend if (isTRUE(attr(facet, "facet_grid")) && !has_legend) { @@ -218,6 +236,20 @@ draw_facet_window = function( omar[1] = omar[1] + whtsbp } } + + # Adjust margins for missing and multi-line annotation strings. + xlab_lines = text_line_count(xlab) + ylab_lines = text_line_count(ylab) + main_lines = text_line_count(main) + + if (xlab_lines == 0) omar[1] = omar[1] - 1 + if (ylab_lines == 0) omar[2] = omar[2] - 1 + if (main_lines == 0) omar[3] = omar[3] - 1 + + if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * par("cex.lab") + if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * par("cex.lab") + if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * par("cex.main") + par(mar = omar) } diff --git a/R/legend.R b/R/legend.R index c41ecb71..9ed04d82 100644 --- a/R/legend.R +++ b/R/legend.R @@ -407,7 +407,7 @@ prepare_legend = function(settings) { } legend_draw_flag = (is.null(legend) || !is.character(legend) || legend != "none" || bubble) && !isTRUE(add) - has_sub = !is.null(sub) + has_sub = text_line_count(sub) > 0L # Generate labels for discrete legends if (legend_draw_flag && isFALSE(by_continuous) && (!bubble || multi_legend)) { diff --git a/R/tinyplot.R b/R/tinyplot.R index a1304b2c..bd2e3bc7 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -1051,8 +1051,12 @@ tinyplot.default = function( draw = draw, grid = grid, has_legend = has_legend, + main = main, + sub = sub, type = type, + xlab = xlab, x = x, xmax = xmax, xmin = xmin, + ylab = ylab, y = y, ymax = ymax, ymin = ymin, tpars = tpars ), @@ -1075,8 +1079,12 @@ tinyplot.default = function( draw = draw, grid = grid, has_legend = has_legend, + main = main, + sub = sub, type = type, + xlab = xlab, x = datapoints$x, xmax = datapoints$xmax, xmin = datapoints$xmin, + ylab = ylab, y = datapoints$y, ymax = datapoints$ymax, ymin = datapoints$ymin, tpars = tpar() # https://github.com/grantmcdermott/tinyplot/issues/474 ), @@ -1084,7 +1092,6 @@ tinyplot.default = function( ) list2env(facet_window_args, environment()) - # ## split and draw datapoints ----- # diff --git a/R/tinytheme.R b/R/tinytheme.R index 5fc29348..e82c3009 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -49,8 +49,6 @@ #' Known current limitations include: #' #' - Themes do not work well when `legend = "top!"`. -#' - Dynamic margin spacing does not account for multi-line strings (e.g., axes -#' or main titles that contain "\\n"). #' #' @return The function returns nothing. It is called for its side effects. #' diff --git a/R/title.R b/R/title.R index 74311d05..9db45e6c 100644 --- a/R/title.R +++ b/R/title.R @@ -29,6 +29,9 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (is.null(line_main)) line_main = par("mgp")[3] + 1.7 - .1 line_main = line_main + 1.2 } + } + + if (!is.null(sub)) { if (isTRUE(get_tpar("side.sub", 1) == 3)) { line_sub = get_tpar("line.sub", 1.7) } else { @@ -49,13 +52,33 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { } if (!is.null(main)) { + main_lines = text_line_count(main) + if (main_lines > 1L) { + # Keep line 1 aligned with single-line titles by shifting the centered + # multi-line block downward by half its extra line height. + if (is.null(line_main)) line_main = par("mgp")[3] + 1.1 + line_main = line_main - (main_lines - 1) / 2 + } + adj_main = get_tpar(c("adj.main", "adj"), 3) + ylab_lines = text_line_count(ylab) + # dynmar can expand left margin for multi-line ylab after title draw; apply + # a compensating right shift so main stays aligned with the plot box. + if (ylab_lines > 1L && isTRUE(get_tpar("dynmar", FALSE))) { + delta_in = (ylab_lines - 1) * par("csi") * par("cex.lab") + if (is.finite(par("pin")[1]) && par("pin")[1] > 0) { + multi_panel = prod(par("mfrow")) > 1 || prod(par("mfcol")) > 1 + panel_boost = if (isTRUE(multi_panel)) 2 else 1 + adj_main = adj_main + panel_boost * (delta_in / par("pin")[1]) + } + adj_main = min(1, max(0, adj_main)) + } args = list( main = main, line = line_main, cex.main = get_tpar("cex.main", 1.4), col.main = get_tpar("col.main", "black"), font.main = get_tpar("font.main", 2), - adj = get_tpar(c("adj.main", "adj"), 3)) + adj = adj_main) args = Filter(function(x) !is.null(x), args) do.call(title, args) } @@ -65,7 +88,23 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { args = list(xlab = xlab) args[["adj"]] = get_tpar(c("adj.xlab", "adj")) do.call(title, args) + args = list(ylab = ylab) + ylab_lines = text_line_count(ylab) + if (ylab_lines > 1L) { + # Keep multi-line ylab centered around the default label line so outer + # lines do not get pushed off-device in tighter layouts (e.g., mfrow 2x2). + line_ylab = par("mgp")[1] - (ylab_lines - 1) + cex_ylab = get_tpar(c("cex.ylab", "cex.lab"), 1) + csi = par("csi") + left_margin_in = par("mai")[2] + # Keep roughly one glyph-width of room from the left device edge to avoid + # clipping of the outermost ylab line on compact multi-panel layouts. + edge_pad_in = 0.75 * csi * cex_ylab + max_line = (left_margin_in - edge_pad_in) / csi + line_ylab = min(line_ylab, max_line) + args[["line"]] = max(0, line_ylab) + } args[["adj"]] = get_tpar(c("adj.ylab", "adj")) do.call(title, args) } diff --git a/R/utils.R b/R/utils.R index c680235d..51b8eb23 100644 --- a/R/utils.R +++ b/R/utils.R @@ -3,6 +3,18 @@ if (getRversion() <= "4.4.0") { `%||%` = function(x, y) if (is.null(x)) y else x } +# Count text lines. Returns 0 for absent text and 1 for expression objects. +text_line_count = function(x) { + if (is.null(x)) return(0L) + if (identical(x, NA) || identical(x, NA_character_)) return(0L) + if (!is.character(x)) return(1L) + if (!length(x)) return(0L) + keep = !is.na(x) & nzchar(x) + if (!any(keep)) return(0L) + x = x[which(keep)[1L]] + as.integer(1L + nchar(gsub("[^\n]", "", x))) +} + ## Function that computes an appropriate bandwidth kernel based on a string ## input diff --git a/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg b/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg new file mode 100644 index 00000000..d59f221a --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + 4 + 5 + 6 + 7 + 8 +- - +- - +- - +- - +- - +cyl + + + + + + + +Weight +(1000 lbs) +mpg + + + + + + + +2 +3 +4 +5 + + + + + + +10 +15 +20 +25 +30 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_missing_labels.svg b/inst/tinytest/_tinysnapshot/margins_missing_labels.svg new file mode 100644 index 00000000..08f181f1 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_missing_labels.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + +2 +4 +6 +8 +10 + + + + + + +2 +4 +6 +8 +10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg b/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg new file mode 100644 index 00000000..9488042d --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + +xlab = NA +Y + + + + + + + +5 +10 +15 +20 + + + + + + +0 +5 +10 +15 +20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +xlab present +X +Y + + + + + + + +5 +10 +15 +20 + + + + + + +0 +5 +10 +15 +20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Multi-line labels +X line 1 +X line 2 +Y line 1 +Y line 2 + + + + + + + +5 +10 +15 +20 + + + + + + +0 +5 +10 +15 +20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Multi-line +main title +X +Y + + + + + + + +5 +10 +15 +20 + + + + + + +0 +5 +10 +15 +20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg new file mode 100644 index 00000000..239b2c93 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + +E +F +A +B +C +D + + + + + + +2 +4 +6 +8 +10 + + + + + + +2 +4 +6 +8 +10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg b/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg new file mode 100644 index 00000000..a2550cb4 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + +factor(cyl) +4 +6 +8 + + + + + + + +wt +mpg + + + + + + + +2 +3 +4 +5 + + + + + + +10 +15 +20 +25 +30 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg index f2ca5b15..52c4575d 100644 --- a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg +++ b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg @@ -39,34 +39,34 @@ 10 20 30 - - - - - -(Intercept) -hp -factor(cyl)6 -factor(cyl)8 - + + + + + +(Intercept) +hp +factor(cyl)6 +factor(cyl)8 + - - + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg index 207520e8..161f46c0 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg @@ -43,32 +43,32 @@ 3.5 4.0 4.5 - + - - + + - - - - - - - - - - + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg index e0194521..a6ce4ad3 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg @@ -37,25 +37,25 @@ 4.5 - - + + - - - - - - - - - - + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg index 75ba956f..41947aa7 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg @@ -64,1565 +64,1565 @@ 3.5 4.0 4.5 - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg index 6ffce087..33bd8668 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg @@ -58,1558 +58,1558 @@ 4.5 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg index 1a99a67a..01c57153 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg @@ -59,42 +59,42 @@ 3.5 4.0 4.5 - + - - + + - - - - + + + + - - -virginica + + +virginica - - - - + + + + - - -versicolor + + +versicolor - - - - + + + + - - -setosa + + +setosa diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg index 2155309d..68ae32c5 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg @@ -53,17 +53,17 @@ 4.5 - - + + - - - - + + + + -virginica +virginica @@ -73,13 +73,13 @@ - - - - + + + + -versicolor +versicolor @@ -89,13 +89,13 @@ - - - - + + + + -setosa +setosa diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg index 80ffa81f..29c006c7 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg @@ -30,11 +30,11 @@ am - - + + - + @@ -54,16 +54,16 @@ 30 35 40 - -0 - + +0 + - - + + - + @@ -83,2090 +83,2090 @@ 30 35 40 - -1 - + +1 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - -0 -1 + + + +0 +1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - -0 -1 + + + +0 +1 - - + + - + diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg index 0e355975..d430f71b 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg @@ -30,11 +30,11 @@ am - - + + - + 5 @@ -45,15 +45,15 @@ 30 35 40 - -0 + +0 - - + + - + 5 @@ -64,1042 +64,1042 @@ 30 35 40 - -1 + +1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0 -1 +0 +1 @@ -1110,1039 +1110,1039 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0 -1 +0 +1 @@ -2154,11 +2154,11 @@ - - + + - + diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg index 3cceee10..0933e40b 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg @@ -43,1565 +43,1565 @@ 3.5 4.0 4.5 - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg index 5a866458..cc208520 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg @@ -37,1558 +37,1558 @@ 4.5 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg index 67e97d5a..ca1165d8 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg @@ -45,99 +45,99 @@ F G H - - - - - - - - -0% -20% -40% -60% -80% -100% -120% - + + + + + + + + +0% +20% +40% +60% +80% +100% +120% + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-margins.R b/inst/tinytest/test-margins.R new file mode 100644 index 00000000..d65dada6 --- /dev/null +++ b/inst/tinytest/test-margins.R @@ -0,0 +1,83 @@ +source("helpers.R") +using("tinysnapshot") + +# Missing labels should reclaim margin space under dynmar themes. +f = function() { + tinytheme("clean") + tinyplot(1:10, 1:10, xlab = NA, ylab = NA, main = NA) + tinytheme() +} +expect_snapshot_plot(f, label = "margins_missing_labels") + +# Multi-line annotation strings should increase margins as needed. +f = function() { + tinytheme("clean") + tinyplot(1:10, 1:10, xlab = "A\nB", ylab = "C\nD", main = "E\nF") + tinytheme() +} +expect_snapshot_plot(f, label = "margins_multiline_labels") + +# Faceted path should also handle multi-line annotation strings. +f = function() { + tinytheme("clean") + tinyplot(mpg ~ wt | cyl, data = mtcars, xlab = "Weight\n(1000 lbs)") + tinytheme() +} +expect_snapshot_plot(f, label = "margins_facet_multiline") + +# sub = NA should not reserve extra bottom legend space. +f = function() { + tinytheme("clean", side.sub = 1) + tinyplot(mpg ~ wt | factor(cyl), data = mtcars, legend = "bottom!", sub = NA) + tinytheme() +} +expect_snapshot_plot(f, label = "margins_sub_na_bottom_legend") + +# 2x2 layout from reprex should handle mixed single/multiline labels. +f = function() { + tinytheme("clean") + on.exit(tinytheme(), add = TRUE) + + set.seed(1) + x = 1:20 + y = x + stats::rnorm(length(x), sd = 2) + + op = par(mfrow = c(2, 2)) + on.exit(par(op), add = TRUE) + + tinyplot(x, y, main = "xlab = NA", xlab = NA, ylab = "Y") + tinyplot(x, y, main = "xlab present", xlab = "X", ylab = "Y") + tinyplot(x, y, main = "Multi-line labels", + xlab = "X line 1\nX line 2", ylab = "Y line 1\nY line 2") + tinyplot(x, y, main = "Multi-line\nmain title", xlab = "X", ylab = "Y") +} +expect_snapshot_plot(f, label = "margins_multiline_2x2") + +get_plot_mar = function(...) { + op = par(no.readonly = TRUE) + on.exit(par(op), add = TRUE) + tinyplot(...) + par("mar") +} + +expect_true( + { + tinytheme("clean") + on.exit(tinytheme(), add = TRUE) + mar_with_xlab = get_plot_mar(1:10, 1:10, xlab = "X") + mar_without_xlab = get_plot_mar(1:10, 1:10, xlab = NA) + mar_without_xlab[1] < mar_with_xlab[1] + }, + info = "bottom_margin_shrinks_when_xlab_missing" +) + +expect_true( + { + tinytheme("clean") + on.exit(tinytheme(), add = TRUE) + mar_single_xlab = get_plot_mar(1:10, 1:10, xlab = "X") + mar_multiline_xlab = get_plot_mar(1:10, 1:10, xlab = "X\nY") + mar_multiline_xlab[1] > mar_single_xlab[1] + }, + info = "bottom_margin_grows_for_multiline_xlab" +) From 53cbb82057631ee79ea98ff9a4d8c021abed7ba6 Mon Sep 17 00:00:00 2001 From: Vincent Arel-Bundock Date: Sun, 15 Feb 2026 08:24:44 -0500 Subject: [PATCH 02/30] update snapshot --- inst/tinytest/_tinysnapshot/tinylabel.svg | 160 +++++++++++----------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/inst/tinytest/_tinysnapshot/tinylabel.svg b/inst/tinytest/_tinysnapshot/tinylabel.svg index 07a3a30f..bef132d3 100644 --- a/inst/tinytest/_tinysnapshot/tinylabel.svg +++ b/inst/tinytest/_tinysnapshot/tinylabel.svg @@ -64,90 +64,90 @@ $5,000 $5,500 $6,000 - - - - - - - -68 -69 -70 -71 -72 -73 - + + + + + + + +68 +69 +70 +71 +72 +73 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d1d2cba0acc00f25979f63ffc9eac5937ed775f8 Mon Sep 17 00:00:00 2001 From: Vincent Arel-Bundock Date: Sun, 15 Feb 2026 08:30:08 -0500 Subject: [PATCH 03/30] docs --- man/facet.Rd | 4 ++++ man/tinytheme.Rd | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/man/facet.Rd b/man/facet.Rd index 0c226cb7..666b14eb 100644 --- a/man/facet.Rd +++ b/man/facet.Rd @@ -47,10 +47,14 @@ draw_facet_window( draw, grid, has_legend, + main, + sub, type, + xlab, x, xmax, xmin, + ylab, y, ymax, ymin, diff --git a/man/tinytheme.Rd b/man/tinytheme.Rd index a8906549..c614c676 100644 --- a/man/tinytheme.Rd +++ b/man/tinytheme.Rd @@ -64,8 +64,6 @@ behaviour to our GitHub repo: Known current limitations include: \itemize{ \item Themes do not work well when \code{legend = "top!"}. -\item Dynamic margin spacing does not account for multi-line strings (e.g., axes -or main titles that contain "\\n"). } } \examples{ From fbd19f87991613113bd8ab70ebc1046efd409c78 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 15 Feb 2026 18:47:20 -0800 Subject: [PATCH 04/30] theme_dynamic --- R/legend.R | 2 +- R/tinytheme.R | 60 ++++++++++++++++++++++++++++-------------------- man/tinytheme.Rd | 9 ++++---- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/R/legend.R b/R/legend.R index 9ed04d82..0da75be7 100644 --- a/R/legend.R +++ b/R/legend.R @@ -124,7 +124,7 @@ legend_outer_margins = function(legend_env, apply = TRUE) { if (legend_env$dynmar) { omar = par("mar") if (legend_env$outer_bottom) { - omar[1] = theme_clean$mgp[1] + 1 * par("cex.lab") + omar[1] = theme_dynamic$mgp[1] + 1 * par("cex.lab") if (legend_env$has_sub && (is.null(.tpar[["side.sub"]]) || .tpar[["side.sub"]] == 1)) { omar[1] = omar[1] + 1 * par("cex.sub") } diff --git a/R/tinytheme.R b/R/tinytheme.R index e82c3009..354602e9 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -16,12 +16,13 @@ #' #' - `"default"`: inherits the user's default base graphics settings. #' - `"basic"`: light modification of `"default"`, only adding filled points, a panel background grid, and light gray background to facet titles. -#' - `"clean"` (*): builds on `"basic"` by moving the subtitle above the plotting area, adding horizontal axis labels, employing tighter default plot margins and title gaps to reduce whitespace, and setting different default palettes ("Tableau 10" for discrete colors and "agSunset" for gradient colors). The first of our dynamic themes and the foundation for several derivative themes that follow below. +#' - `"dynamic"` (*): builds on `"basic"` by enabling dynamic margin adjustment with tighter default margins, horizontal axis labels, and the subtitle moved above the plotting area. Turns off the panel grid. Provides the foundation for all other dynamic themes and is a good starting point for users who wish to build custom dynamic themes. +#' - `"clean"` (*): builds on `"dynamic"` by re-enabling the panel background grid and setting different default palettes ("Tableau 10" for discrete colors and "agSunset" for gradient colors). #' - `"clean2"` (*): removes the plot frame (box) from `"clean"`. -#' - `"classic"` (*): connects the axes in a L-shape, but removes the other top and right-hand edges of the plot frame (box). Also sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the **ggplot2** theme of the same name. -#' - `"bw"` (*): similar to `"clean"`, except uses thinner lines for the plot frame (box), solid grid lines, and sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the **ggplot2** theme of the same name. -#' - `"minimal"` (*): removes the plot frame (box) from `"bw"`, as well as the background for facet titles. Inspired by the **ggplot2** theme of the same name. -#' - `"ipsum"` (*): similar to `"minimal"`, except subtitle is italicised and axes titles are aligned to the far edges. Inspired by the **hrbrthemes** theme of the same name for **ggplot2**. +#' - `"classic"` (*): builds on `"dynamic"` with L-shaped axes (removing the top and right-hand edges of the plot frame). Also sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the **ggplot2** theme of the same name. +#' - `"bw"` (*): similar to `"clean"`, except uses thinner lines for the plot frame (box), solid grid lines, and sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the **ggplot2** theme of the same name. +#' - `"minimal"` (*): removes the plot frame (box) from `"bw"`, as well as the background for facet titles. Inspired by the **ggplot2** theme of the same name. +#' - `"ipsum"` (*): similar to `"minimal"`, except subtitle is italicised and axes titles are aligned to the far edges. Inspired by the **hrbrthemes** theme of the same name for **ggplot2**. #' - `"dark"` (*): similar to `"minimal"`, but set against a dark background with foreground and a palette colours lightened for appropriate contrast. #' - `"ridge"` (*): a specialized theme for ridge plots (see [`type_ridge()`]). Builds off of `"clean"`, but adds ridge-specific tweaks (e.g. default "Zissou 1" palette for discrete colors, solid horizontal grid lines, and minor adjustments to y-axis labels). Not recommended for non-ridge plots. #' - `"ridge2"` (*): removes the plot frame (box) from `"ridge"`, but retains the x-axis line. Again, not recommended for non-ridge plots. @@ -117,7 +118,7 @@ #' @export tinytheme = function( theme = c( - "default", "basic", + "default", "basic", "dynamic", "clean", "clean2", "bw", "classic", "minimal", "ipsum", "dark", "ridge", "ridge2", @@ -136,8 +137,8 @@ tinytheme = function( theme, c( "default", - sort(c("basic", "bw", "classic", "clean", "clean2", "dark", "ipsum", - "minimal", "ridge", "ridge2", "tufte", "void")) + sort(c("basic", "bw", "classic", "clean", "clean2", "dark", "dynamic", + "ipsum", "minimal", "ridge", "ridge2", "tufte", "void")) ) ) @@ -149,6 +150,7 @@ tinytheme = function( "clean" = theme_clean, "clean2" = theme_clean2, "dark" = theme_dark, + "dynamic" = theme_dynamic, "ipsum" = theme_ipsum, "minimal" = theme_minimal, "ridge" = theme_ridge, @@ -271,10 +273,10 @@ theme_void = modifyList(theme_default, list( yaxt = "none" )) -# derivatives of "basic" -# - clean +# derivatives of "basic" +# - dynamic -theme_clean = modifyList(theme_basic, list( +theme_dynamic = modifyList(theme_basic, list( ## Notes: ## - 1. Reduce axis title gap by 0.5 lines and also reduce tcl to 0.3 lines. ## - 2. Sub moves to top. @@ -287,40 +289,48 @@ theme_clean = modifyList(theme_basic, list( ## -- mar[3] should remain unchanged (main + sub will adjust automatically) ## -- mar[4] should be adjusted by 1.5 (relative to 2.1) ## - tinytheme = "clean", + tinytheme = "dynamic", adj.main = 0, adj.sub = 0, dynmar = TRUE, + grid = FALSE, las = 1, mar = c(5.1, 4.1, 4.1, 2.1) - c(1+0.5+0.3, 0.5+0.3, 0, 1.5), ## test mgp = c(3, 1, 0) - c(0.5+0.3, 0.3, 0), # i.e., subtract 0.5 lines + the (abs) value of the tcl adjustment - palette.qualitative = "Tableau 10", - palette.sequential = "ag_Sunset", side.sub = 3, tcl = -0.3 )) -# derivatives of "clean" -# - clean2 +# derivatives of "dynamic" +# - clean # - classic -# - bw -theme_clean2 = modifyList(theme_clean, list( - tinytheme = "clean2", - facet.border = "gray90", - xaxt = "labels", - yaxt = "labels" +theme_clean = modifyList(theme_dynamic, list( + tinytheme = "clean", + grid = TRUE, + palette.qualitative = "Tableau 10", + palette.sequential = "ag_Sunset" )) -theme_classic = modifyList(theme_clean, list( +theme_classic = modifyList(theme_dynamic, list( tinytheme = "classic", bty = "l", facet.bg = NULL, font.main = 1, - grid = FALSE, palette.qualitative = "Okabe-Ito" )) +# derivatives of "clean" +# - clean2 +# - bw + +theme_clean2 = modifyList(theme_clean, list( + tinytheme = "clean2", + facet.border = "gray90", + xaxt = "labels", + yaxt = "labels" +)) + theme_bw = modifyList(theme_clean, list( tinytheme = "bw", font.main = 1, @@ -370,7 +380,7 @@ theme_dark = modifyList(theme_minimal, list( palette.sequential = "Sunset" )) -# derivative of clean/clean2 +# derivatives of clean/clean2 theme_ridge = modifyList(theme_clean, list( tinytheme = "ridge", diff --git a/man/tinytheme.Rd b/man/tinytheme.Rd index c614c676..85a93a1f 100644 --- a/man/tinytheme.Rd +++ b/man/tinytheme.Rd @@ -5,8 +5,8 @@ \title{Set or Reset Plot Themes for \code{tinyplot}} \usage{ tinytheme( - theme = c("default", "basic", "clean", "clean2", "bw", "classic", "minimal", "ipsum", - "dark", "ridge", "ridge2", "tufte", "void"), + theme = c("default", "basic", "dynamic", "clean", "clean2", "bw", "classic", "minimal", + "ipsum", "dark", "ridge", "ridge2", "tufte", "void"), ... ) } @@ -20,9 +20,10 @@ dynamic plots are marked with an asterisk (*) below. \itemize{ \item \code{"default"}: inherits the user's default base graphics settings. \item \code{"basic"}: light modification of \code{"default"}, only adding filled points, a panel background grid, and light gray background to facet titles. -\item \code{"clean"} (*): builds on \code{"basic"} by moving the subtitle above the plotting area, adding horizontal axis labels, employing tighter default plot margins and title gaps to reduce whitespace, and setting different default palettes ("Tableau 10" for discrete colors and "agSunset" for gradient colors). The first of our dynamic themes and the foundation for several derivative themes that follow below. +\item \code{"dynamic"} (*): builds on \code{"basic"} by enabling dynamic margin adjustment with tighter default margins, horizontal axis labels, and the subtitle moved above the plotting area. Turns off the panel grid. Provides the foundation for all other dynamic themes and is a good starting point for users who wish to build custom dynamic themes. +\item \code{"clean"} (*): builds on \code{"dynamic"} by re-enabling the panel background grid and setting different default palettes ("Tableau 10" for discrete colors and "agSunset" for gradient colors). \item \code{"clean2"} (*): removes the plot frame (box) from \code{"clean"}. -\item \code{"classic"} (*): connects the axes in a L-shape, but removes the other top and right-hand edges of the plot frame (box). Also sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the \strong{ggplot2} theme of the same name. +\item \code{"classic"} (*): builds on \code{"dynamic"} with L-shaped axes (removing the top and right-hand edges of the plot frame). Also sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the \strong{ggplot2} theme of the same name. \item \code{"bw"} (*): similar to \code{"clean"}, except uses thinner lines for the plot frame (box), solid grid lines, and sets the "Okabe-Ito" palette as a default for discrete colors. Inspired by the \strong{ggplot2} theme of the same name. \item \code{"minimal"} (*): removes the plot frame (box) from \code{"bw"}, as well as the background for facet titles. Inspired by the \strong{ggplot2} theme of the same name. \item \code{"ipsum"} (*): similar to \code{"minimal"}, except subtitle is italicised and axes titles are aligned to the far edges. Inspired by the \strong{hrbrthemes} theme of the same name for \strong{ggplot2}. From 109640b5316ca7cbd30e63f4dd3e3f741a5207be Mon Sep 17 00:00:00 2001 From: Vincent Arel-Bundock Date: Sat, 21 Feb 2026 10:31:24 -0500 Subject: [PATCH 05/30] get_tpar instead of par() --- R/facet.R | 12 ++++++------ R/title.R | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/R/facet.R b/R/facet.R index 76897864..7817d45e 100644 --- a/R/facet.R +++ b/R/facet.R @@ -169,9 +169,9 @@ draw_facet_window = function( if (ylab_lines == 0) omar[2] = omar[2] - 1 if (main_lines == 0) omar[3] = omar[3] - 1 - if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * par("cex.lab") - if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * par("cex.lab") - if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * par("cex.main") + if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * get_tpar(c("cex.xlab", "cex.lab"), tpar_list = tpars) + if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * get_tpar(c("cex.ylab", "cex.lab"), tpar_list = tpars) + if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * get_tpar("cex.main", tpar_list = tpars) # FIXME: Is this causing issues for lhs legends with facet_grid? # catch for missing rhs legend @@ -246,9 +246,9 @@ draw_facet_window = function( if (ylab_lines == 0) omar[2] = omar[2] - 1 if (main_lines == 0) omar[3] = omar[3] - 1 - if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * par("cex.lab") - if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * par("cex.lab") - if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * par("cex.main") + if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * get_tpar(c("cex.xlab", "cex.lab"), tpar_list = tpars) + if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * get_tpar(c("cex.ylab", "cex.lab"), tpar_list = tpars) + if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * get_tpar("cex.main", tpar_list = tpars) par(mar = omar) } diff --git a/R/title.R b/R/title.R index 9db45e6c..bc95d300 100644 --- a/R/title.R +++ b/R/title.R @@ -26,7 +26,7 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (!is.null(sub)) { if (isTRUE(get_tpar("side.sub", 1) == 3)) { - if (is.null(line_main)) line_main = par("mgp")[3] + 1.7 - .1 + if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 1.7 - .1 line_main = line_main + 1.2 } } @@ -56,7 +56,7 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (main_lines > 1L) { # Keep line 1 aligned with single-line titles by shifting the centered # multi-line block downward by half its extra line height. - if (is.null(line_main)) line_main = par("mgp")[3] + 1.1 + if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 1.1 line_main = line_main - (main_lines - 1) / 2 } adj_main = get_tpar(c("adj.main", "adj"), 3) @@ -94,7 +94,7 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (ylab_lines > 1L) { # Keep multi-line ylab centered around the default label line so outer # lines do not get pushed off-device in tighter layouts (e.g., mfrow 2x2). - line_ylab = par("mgp")[1] - (ylab_lines - 1) + line_ylab = get_tpar("mgp")[1] - (ylab_lines - 1) cex_ylab = get_tpar(c("cex.ylab", "cex.lab"), 1) csi = par("csi") left_margin_in = par("mai")[2] From ebf44dba23a8757fdf9b7ad969378bbec9661919 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 22 Feb 2026 11:01:05 -0800 Subject: [PATCH 06/30] tests --- .../_tinysnapshot/tinytheme_dynamic.svg | 113 ++++++++ .../tinytheme_dynamic_dynamic.svg | 241 ++++++++++++++++++ inst/tinytest/test-tinytheme.R | 4 + 3 files changed, 358 insertions(+) create mode 100644 inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg create mode 100644 inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg new file mode 100644 index 00000000..794af50c --- /dev/null +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + +factor(am) +0 +1 +tinytheme("dynamic") + + + + + + + +Title of the plot +hp +mpg + + + + + + + + + +50 +100 +150 +200 +250 +300 + + + + + + +10 +15 +20 +25 +30 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg new file mode 100644 index 00000000..c742ef8b --- /dev/null +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + +Species +setosa +versicolor +virginica +For themes with las = 1, etc. + + + + + + + +Dynamic plot adjustment and whitespace reduction +Petal.Length +I(Sepal.Length * 1e+09) + + + + + + + + + + +1 +2 +3 +4 +5 +6 +7 + + + + + + + + + +4.5e+09 +5.0e+09 +5.5e+09 +6.0e+09 +6.5e+09 +7.0e+09 +7.5e+09 +8.0e+09 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-tinytheme.R b/inst/tinytest/test-tinytheme.R index 01bb9d0b..b3f9f313 100644 --- a/inst/tinytest/test-tinytheme.R +++ b/inst/tinytest/test-tinytheme.R @@ -53,6 +53,10 @@ f = function() { ) } +tinytheme("dynamic") +f() +expect_snapshot_plot(f, label = "tinytheme_dynamic_dynamic") + tinytheme("clean") f() expect_snapshot_plot(f, label = "tinytheme_dynamic_clean") From 03c07ff33758768af03ab5d1b6eb6c23f31dba78 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 20 Apr 2026 21:47:44 -0700 Subject: [PATCH 07/30] Refactor dynamic margin logic to additive build Instead of starting with a pre-inflated mar and subtracting when titles are absent, dynamic themes now start at c(0.1, 0.1, 0.1, 0.1) and build up per-side margins additively for the elements that are actually present (tick row, axis labels, main, sub). Key changes: - New helper dynmar_side() in R/utils.R is the single source of truth for 'how much margin does this side need'. Both the pre-title path in tinyplot.default() and draw_facet_window() call into it. - theme_dynamic$mar reduced to the minimal pad baseline. All dynamic derivatives (clean, clean2, bw, classic, minimal, ipsum, dark, ridge, ridge2) inherit via modifyList. - draw_facet_window() simplified: no more 'if missing, subtract 1' per side; the new formula takes max(tick_extent, label_extent) because tick labels and axis titles share vertical space. - Pre-sizing margins and calling plot.window() before draw_title() ensures title/mtext alignment measures against the plot region (not the default [0,1,0,1] figure region). - draw_title() refactored: removed post-hoc ylab/main compensators that were workarounds for the old undersized-margin regime. Added explicit line = mgp[1] + (N-1)*cex for multi-line xlab so line 1 lands where a single-line xlab would sit (rather than being pushed up into the tick-label zone by base R's default multi-line layout). - line_sub default tightened from 1.7 to 0.7 (side.sub=3) to reduce the gap between sub and the plot box top. - xaxt / yaxt = 'n' is now honored: no tick row reserved when axes are off under a dynamic theme. Non-dynmar themes (default, basic, tufte, void) are unchanged. Snapshots will need regeneration on Linux (devcontainer) since the pixel output has shifted for every dynamic theme. --- R/facet.R | 57 ++++++++++++++++++++++++++------------------------- R/tinyplot.R | 23 +++++++++++++++++++++ R/tinytheme.R | 18 +++++++--------- R/title.R | 54 ++++++++++++++++-------------------------------- R/utils.R | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 75 deletions(-) diff --git a/R/facet.R b/R/facet.R index 01f82239..310efb69 100644 --- a/R/facet.R +++ b/R/facet.R @@ -118,6 +118,20 @@ draw_facet_window = function( ## Dynamic plot margin adjustments if (dynmar) { + # Build each side's margin additively from a zero-ish baseline: pad + + # tick row (when axis on) + axis label (when present) + main/sub. + side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) + omar[1] = dynmar_side(1, xlab, main = main, sub = sub, + side.sub = side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = tpars) + omar[2] = dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = tpars) + omar[3] = dynmar_side(3, NULL, main = main, sub = sub, + side.sub = side.sub, tpars = tpars) + omar[4] = dynmar_side(4, NULL, tpars = tpars) + if (par("las") %in% 1:2) { # extra whitespace bump on the y axis ## overrides for ridge and some types that use integer spacing with (named) axis labels ## FXIME @@ -160,18 +174,7 @@ draw_facet_window = function( } } - # Adjust margins for missing and multi-line annotation strings. - xlab_lines = text_line_count(xlab) - ylab_lines = text_line_count(ylab) - main_lines = text_line_count(main) - - if (xlab_lines == 0) omar[1] = omar[1] - 1 - if (ylab_lines == 0) omar[2] = omar[2] - 1 - if (main_lines == 0) omar[3] = omar[3] - 1 - - if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * get_tpar(c("cex.xlab", "cex.lab"), tpar_list = tpars) - if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * get_tpar(c("cex.ylab", "cex.lab"), tpar_list = tpars) - if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * get_tpar("cex.main", tpar_list = tpars) + if (type == "spineplot") omar[4] = 2.1 # FIXME catch for spineplot RHS axis labs # FIXME: Is this causing issues for lhs legends with facet_grid? # catch for missing rhs legend @@ -201,9 +204,20 @@ draw_facet_window = function( # on our earlier calculations. par(mfrow = c(nfacet_rows, nfacet_cols)) } else if (dynmar) { - # Dynamic plot margin adjustments - omar = par("mar") - omar = omar - c(0, 0, 1, 0) # reduce top whitespace since no facet (title) + # Dynamic plot margin adjustments (no facets): build each side additively + # from a tiny pad. Tick-label *width/height* (whtsbp) is added below. + side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) + omar = c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = tpars), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = tpars), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, + tpars = tpars), + dynmar_side(4, NULL, tpars = tpars) + ) if (type == "spineplot") omar[4] = 2.1 # FIXME catch for spineplot RHS axis labs if (par("las") %in% 1:2) { # extra whitespace bump on the y axis @@ -237,19 +251,6 @@ draw_facet_window = function( } } - # Adjust margins for missing and multi-line annotation strings. - xlab_lines = text_line_count(xlab) - ylab_lines = text_line_count(ylab) - main_lines = text_line_count(main) - - if (xlab_lines == 0) omar[1] = omar[1] - 1 - if (ylab_lines == 0) omar[2] = omar[2] - 1 - if (main_lines == 0) omar[3] = omar[3] - 1 - - if (xlab_lines > 1) omar[1] = omar[1] + (xlab_lines - 1) * get_tpar(c("cex.xlab", "cex.lab"), tpar_list = tpars) - if (ylab_lines > 1) omar[2] = omar[2] + (ylab_lines - 1) * get_tpar(c("cex.ylab", "cex.lab"), tpar_list = tpars) - if (main_lines > 1) omar[3] = omar[3] + (main_lines - 1) * get_tpar("cex.main", tpar_list = tpars) - par(mar = omar) } diff --git a/R/tinyplot.R b/R/tinyplot.R index e017bd89..57270bc7 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -988,6 +988,29 @@ tinyplot.default = function( # if (!add) { + # Under dynmar, pre-size the margins for main/sub/xlab/ylab so that + # draw_title() writes into adequate space. draw_facet_window() will + # later add tick-label width/height (whtsbp) and any facet-specific + # bumps on top of this baseline. + # We also need plot.window() to have been called so mtext/title align + # relative to the plot region (not the default [0,1,0,1] figure region). + if (isTRUE(get_tpar("dynmar"))) { + .side.sub = get_tpar("side.sub", default = 3) + par(mar = c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = .side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n")), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n")), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = .side.sub), + dynmar_side(4, NULL) + )) + # Establish user coordinates so title/mtext adj is measured against the + # plot region. draw_facet_window() will call plot.window() again with + # final asp/log etc., but that's idempotent for alignment purposes. + if (!is.null(xlim) && !is.null(ylim)) { + plot.window(xlim = xlim, ylim = ylim) + } + } draw_title(main, sub, xlab, ylab, legend, legend_args, opar) } diff --git a/R/tinytheme.R b/R/tinytheme.R index 354602e9..cd22b4b5 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -278,16 +278,12 @@ theme_void = modifyList(theme_default, list( theme_dynamic = modifyList(theme_basic, list( ## Notes: - ## - 1. Reduce axis title gap by 0.5 lines and also reduce tcl to 0.3 lines. - ## - 2. Sub moves to top. - ## - 3. Also want to remove excess white on rhs of plot margin (when no legend). - ## - Together, 1, 2, and 3 imply that... - ## -- mgp[1] should be adjusted by 0.8 (= 0.5 + 0.3) - ## -- mgp[2] should be adjusted by 0.3 - ## -- mar[1] should be adjusted by 1.8 (= 1 (no sub) + 0.5 + 0.3 (tighter axis labs)) - ## -- mar[2] should be adjusted by 0.8 (= 0.5 + 0.3) - ## -- mar[3] should remain unchanged (main + sub will adjust automatically) - ## -- mar[4] should be adjusted by 1.5 (relative to 2.1) + ## - Dynamic themes start from an (almost) zero `mar` baseline. The + ## `draw_facet_window()` helper builds each side's margin up from this + ## pad, adding only what the plot actually needs (tick row, axis label, + ## main, sub). See `dynmar_side()` in utils.R. + ## - `side.sub = 3` moves the sub-caption above the plot (below main). + ## - `tcl = -0.3` tightens axis tick marks relative to the base default. ## tinytheme = "dynamic", adj.main = 0, @@ -295,7 +291,7 @@ theme_dynamic = modifyList(theme_basic, list( dynmar = TRUE, grid = FALSE, las = 1, - mar = c(5.1, 4.1, 4.1, 2.1) - c(1+0.5+0.3, 0.5+0.3, 0, 1.5), ## test + mar = c(0.1, 0.1, 0.1, 0.1), mgp = c(3, 1, 0) - c(0.5+0.3, 0.3, 0), # i.e., subtract 0.5 lines + the (abs) value of the tcl adjustment side.sub = 3, tcl = -0.3 diff --git a/R/title.R b/R/title.R index bc95d300..3c53d394 100644 --- a/R/title.R +++ b/R/title.R @@ -24,16 +24,16 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { line_main = NULL } - if (!is.null(sub)) { - if (isTRUE(get_tpar("side.sub", 1) == 3)) { - if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 1.7 - .1 - line_main = line_main + 1.2 - } + # When sub sits on top (side.sub == 3), push main up by the sub row height + # so main is above sub rather than overlapping it. + if (!is.null(sub) && isTRUE(get_tpar("side.sub", 1) == 3)) { + if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - .1 + line_main = line_main + 1.2 } if (!is.null(sub)) { if (isTRUE(get_tpar("side.sub", 1) == 3)) { - line_sub = get_tpar("line.sub", 1.7) + line_sub = get_tpar("line.sub", 0.7) } else { line_sub = get_tpar("line.sub", 4) } @@ -59,52 +59,34 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 1.1 line_main = line_main - (main_lines - 1) / 2 } - adj_main = get_tpar(c("adj.main", "adj"), 3) - ylab_lines = text_line_count(ylab) - # dynmar can expand left margin for multi-line ylab after title draw; apply - # a compensating right shift so main stays aligned with the plot box. - if (ylab_lines > 1L && isTRUE(get_tpar("dynmar", FALSE))) { - delta_in = (ylab_lines - 1) * par("csi") * par("cex.lab") - if (is.finite(par("pin")[1]) && par("pin")[1] > 0) { - multi_panel = prod(par("mfrow")) > 1 || prod(par("mfcol")) > 1 - panel_boost = if (isTRUE(multi_panel)) 2 else 1 - adj_main = adj_main + panel_boost * (delta_in / par("pin")[1]) - } - adj_main = min(1, max(0, adj_main)) - } args = list( main = main, line = line_main, cex.main = get_tpar("cex.main", 1.4), col.main = get_tpar("col.main", "black"), font.main = get_tpar("font.main", 2), - adj = adj_main) + adj = get_tpar(c("adj.main", "adj"), 3)) args = Filter(function(x) !is.null(x), args) do.call(title, args) } - # Axis titles + # Axis titles. For multi-line labels, base R places line 1 at + # `line = mgp[1] - (N-1)*cex`, which pushes line 1 up into the tick-label + # zone. Shift `line` down so line 1 aligns with where a single-line xlab + # would be (and the extra lines extend below). args = list(xlab = xlab) + xlab_lines = text_line_count(xlab) + if (xlab_lines > 1L) { + cex_xlab = get_tpar(c("cex.xlab", "cex.lab"), 1) + args[["line"]] = get_tpar("mgp")[1] + (xlab_lines - 1) * cex_xlab + } args[["adj"]] = get_tpar(c("adj.xlab", "adj")) do.call(title, args) + # ylab: base R already places multi-line text correctly (outermost line at + # mgp[1], subsequent lines closer to the plot), so no line shift needed. args = list(ylab = ylab) - ylab_lines = text_line_count(ylab) - if (ylab_lines > 1L) { - # Keep multi-line ylab centered around the default label line so outer - # lines do not get pushed off-device in tighter layouts (e.g., mfrow 2x2). - line_ylab = get_tpar("mgp")[1] - (ylab_lines - 1) - cex_ylab = get_tpar(c("cex.ylab", "cex.lab"), 1) - csi = par("csi") - left_margin_in = par("mai")[2] - # Keep roughly one glyph-width of room from the left device edge to avoid - # clipping of the outermost ylab line on compact multi-panel layouts. - edge_pad_in = 0.75 * csi * cex_ylab - max_line = (left_margin_in - edge_pad_in) / csi - line_ylab = min(line_ylab, max_line) - args[["line"]] = max(0, line_ylab) - } args[["adj"]] = get_tpar(c("adj.ylab", "adj")) do.call(title, args) } diff --git a/R/utils.R b/R/utils.R index 51b8eb23..dafc8d45 100644 --- a/R/utils.R +++ b/R/utils.R @@ -15,6 +15,59 @@ text_line_count = function(x) { as.integer(1L + nchar(gsub("[^\n]", "", x))) } +# Compute additive margin "build" for a given side under dynmar. +# Starts from a tiny pad and adds only what the plot actually needs. The tick +# row and the axis-label row occupy overlapping vertical space (tick row +# ends at ~|tcl| + mgp[2] + 1, axis label baseline sits at mgp[1]), so the +# margin is the max of: +# - tick-row height (|tcl| + mgp[2] + 1), when the axis is drawn +# - axis-label extent (mgp[1] + (N - 1) * cex + 1 line for asc/desc), when present +# Main/sub sit above/below the plot box on the top/bottom side and add to the +# margin additively. +# Tick-label *width* for sides 2/4 (and *height* for 1/3 under las 2:3) is +# handled separately by the existing whtsbp logic in draw_facet_window(). +# `pad` is the baseline breathing room added to every side (in line units); +# 0.3 is a good visual default for dynamic themes. 0.4 is also reasonable if +# a little more whitespace is desired. +dynmar_side = function(side, label, main = NULL, sub = NULL, + side.sub = 3, axis_on = TRUE, tpars = NULL, + pad = 0.3) { + mgp = get_tpar("mgp", tpar_list = tpars) + tcl = get_tpar("tcl", tpar_list = tpars, default = par("tcl")) + tick_extent = if (side %in% 1:2 && isTRUE(axis_on)) { + max(0, -tcl) + mgp[2] + 1 + } else 0 + label_extent = 0 + lines = text_line_count(label) + if (side %in% 1:2 && lines >= 1L) { + cex_lab = get_tpar( + if (side == 1L) c("cex.xlab", "cex.lab") else c("cex.ylab", "cex.lab"), + tpar_list = tpars, default = 1 + ) + # Last-line baseline sits at mgp[1] + (N-1)*cex (after line-shift in + # draw_title); add a full line to cover ascender+descender so the text + # doesn't clip against the device edge. + label_extent = mgp[1] + (lines - 1) * cex_lab + 1 + } + mar = pad + max(tick_extent, label_extent) + if (side == 3L) { + mlines = text_line_count(main) + if (mlines >= 1L) { + cex_main = get_tpar("cex.main", tpar_list = tpars, default = 1.2) + # Main baseline sits at `mgp[3] + 0.7` (+1.2 further up if sub is also + # on top, applied via the sub branch below). Add half a line for + # ascender so the top of the text stays within the device. + mar = mar + 0.7 + (mlines - 1) * cex_main + 0.5 + } + } + slines = text_line_count(sub) + if (slines >= 1L && side == side.sub && side %in% c(1L, 3L)) { + cex_sub = get_tpar("cex.sub", tpar_list = tpars, default = 1) + mar = mar + 1.2 + (slines - 1) * cex_sub + } + mar +} + ## Function that computes an appropriate bandwidth kernel based on a string ## input From 7cf3082996e86513a16d81c790a09a62b2860e60 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 12:04:10 -0700 Subject: [PATCH 08/30] Anchor main title at consistent line under dynmar Previously, main was drawn at base R's default line when sub was absent, and at a tinyplot-specified line when sub was present. The two differed slightly, causing main to shift when sub was toggled on/off. Now we explicitly set line_main = mgp[3] + 0.6 for dynmar themes regardless of sub presence. The sub branch still bumps main up by 1.2 lines when needed. Non-dynmar themes retain base R's default. --- R/title.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/R/title.R b/R/title.R index 3c53d394..2aae6919 100644 --- a/R/title.R +++ b/R/title.R @@ -20,6 +20,11 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { if (isTRUE(adj_title)) { line_main = par("mar")[3] - opar[["mar"]][3] + 1.7 + 0.1 + } else if (isTRUE(get_tpar("dynmar", FALSE))) { + # Anchor main at a fixed line above the plot box so it stays in the same + # position regardless of whether sub is also present (the sub branch + # below adds a +1.2 shift on top of this baseline when needed). + line_main = get_tpar("mgp")[3] + 0.7 - 0.1 } else { line_main = NULL } @@ -27,7 +32,7 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { # When sub sits on top (side.sub == 3), push main up by the sub row height # so main is above sub rather than overlapping it. if (!is.null(sub) && isTRUE(get_tpar("side.sub", 1) == 3)) { - if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - .1 + if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - 0.1 line_main = line_main + 1.2 } From 096097bf0e0971955a06420efa513e6db1f42f7f Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 15:12:06 -0700 Subject: [PATCH 09/30] Gotcha: treat sub=NA as absent when positioning main !is.null(NA) is TRUE, so the 'push main up to make room for sub' branch was firing for sub = NA even though no sub space was reserved. Use text_line_count(sub) > 0 so NA/empty sub is treated the same as NULL. --- R/title.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/title.R b/R/title.R index 2aae6919..fb589e1b 100644 --- a/R/title.R +++ b/R/title.R @@ -30,8 +30,9 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { } # When sub sits on top (side.sub == 3), push main up by the sub row height - # so main is above sub rather than overlapping it. - if (!is.null(sub) && isTRUE(get_tpar("side.sub", 1) == 3)) { + # so main is above sub rather than overlapping it. Treat NA/empty sub as + # absent so main stays at its normal position. + if (text_line_count(sub) > 0L && isTRUE(get_tpar("side.sub", 1) == 3)) { if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - 0.1 line_main = line_main + 1.2 } From 7ff977d60edd66311d09a7571fb2bda396188459 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 15:25:16 -0700 Subject: [PATCH 10/30] Anchor multi-line main at line N, not center title() stacks multi-line main above the passed line (line N sits at line, earlier lines extend upward). Dropping the old -(N-1)/2 adjustment, which was centering the block and causing line 1 to drift with N. The top margin reservation already accounts for (N-1)*cex_main extra lines. --- R/title.R | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/R/title.R b/R/title.R index fb589e1b..fb8a551c 100644 --- a/R/title.R +++ b/R/title.R @@ -58,13 +58,10 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { } if (!is.null(main)) { - main_lines = text_line_count(main) - if (main_lines > 1L) { - # Keep line 1 aligned with single-line titles by shifting the centered - # multi-line block downward by half its extra line height. - if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 1.1 - line_main = line_main - (main_lines - 1) / 2 - } + # title() stacks multi-line main *above* `line_main` (line N at + # `line_main`, extra lines extend upward). The reserved top margin + # already accounts for (N-1)*cex_main extra lines, so no line-shift + # adjustment is needed here. args = list( main = main, line = line_main, From d472f534d4a84f0d2ba35f15365e9ad48f79334a Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 15:32:51 -0700 Subject: [PATCH 11/30] Scale main title bump with multi-line sub The sub-row offset applied to line_main was a hardcoded +1.2 regardless of sub line count, so main overlapped multi-line sub. Now scales as 1.2 + (N-1)*cex.sub, mirroring the margin reservation in dynmar_side(). --- R/title.R | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/R/title.R b/R/title.R index fb8a551c..53aa698b 100644 --- a/R/title.R +++ b/R/title.R @@ -31,10 +31,13 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { # When sub sits on top (side.sub == 3), push main up by the sub row height # so main is above sub rather than overlapping it. Treat NA/empty sub as - # absent so main stays at its normal position. - if (text_line_count(sub) > 0L && isTRUE(get_tpar("side.sub", 1) == 3)) { + # absent so main stays at its normal position. Scale the bump with the + # number of sub lines. + sub_lines = text_line_count(sub) + if (sub_lines > 0L && isTRUE(get_tpar("side.sub", 1) == 3)) { if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - 0.1 - line_main = line_main + 1.2 + cex_sub = get_tpar("cex.sub", 1.2) + line_main = line_main + 1.2 + (sub_lines - 1) * cex_sub } if (!is.null(sub)) { From daae773d421a58eff9a45b2c98e57b1988e346d8 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 15:46:14 -0700 Subject: [PATCH 12/30] Replace hardcoded 1.2 sub-row bump with cex_sub + 0.2 The main-push-up and margin-reservation formulas for sub both used a hardcoded +1.2 for the first sub row, which happens to equal the default cex.sub but doesn't scale if the user customises it. Express the first-row bump as cex_sub + 0.2 (0.2-line breathing room) so it tracks user-supplied cex.sub. Also fix the get_tpar default for cex.sub in dynmar_side() to match the 1.2 used in draw_title(). No visual change for default cex.sub = 1. --- R/title.R | 10 +++++----- R/utils.R | 11 ++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/R/title.R b/R/title.R index 53aa698b..51e5b8a5 100644 --- a/R/title.R +++ b/R/title.R @@ -29,15 +29,15 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { line_main = NULL } - # When sub sits on top (side.sub == 3), push main up by the sub row height - # so main is above sub rather than overlapping it. Treat NA/empty sub as - # absent so main stays at its normal position. Scale the bump with the - # number of sub lines. + # When sub sits on top (side.sub == 3), push main up by the sub block + # height so main is above sub rather than overlapping it. Treat NA/empty + # sub as absent so main stays at its normal position. First sub row gets + # a small (0.2-line) extra bump for visual breathing room. sub_lines = text_line_count(sub) if (sub_lines > 0L && isTRUE(get_tpar("side.sub", 1) == 3)) { if (is.null(line_main)) line_main = get_tpar("mgp")[3] + 0.7 - 0.1 cex_sub = get_tpar("cex.sub", 1.2) - line_main = line_main + 1.2 + (sub_lines - 1) * cex_sub + line_main = line_main + (cex_sub + 0.2) + (sub_lines - 1) * cex_sub } if (!is.null(sub)) { diff --git a/R/utils.R b/R/utils.R index dafc8d45..9bfd643d 100644 --- a/R/utils.R +++ b/R/utils.R @@ -54,16 +54,17 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, mlines = text_line_count(main) if (mlines >= 1L) { cex_main = get_tpar("cex.main", tpar_list = tpars, default = 1.2) - # Main baseline sits at `mgp[3] + 0.7` (+1.2 further up if sub is also - # on top, applied via the sub branch below). Add half a line for - # ascender so the top of the text stays within the device. + # Main baseline sits at `mgp[3] + 0.7`; each extra line adds cex_main + # of vertical space; plus ~half a line for the ascender so the top + # of the text stays within the device. mar = mar + 0.7 + (mlines - 1) * cex_main + 0.5 } } slines = text_line_count(sub) if (slines >= 1L && side == side.sub && side %in% c(1L, 3L)) { - cex_sub = get_tpar("cex.sub", tpar_list = tpars, default = 1) - mar = mar + 1.2 + (slines - 1) * cex_sub + cex_sub = get_tpar("cex.sub", tpar_list = tpars, default = 1.2) + # First sub row gets a 0.2-line extra bump; extra lines add cex_sub. + mar = mar + (cex_sub + 0.2) + (slines - 1) * cex_sub } mar } From f0919ae00de2c1e1e4f346db12748e0220190508 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 16:51:29 -0700 Subject: [PATCH 13/30] Remove internal pad from dynmar_side(); use theme mar as baseline Previously dynmar_side() smuggled in a pad = 0.3 constant as baseline breathing room, which conflicted with the theme's own mar values. Now the theme's mar acts as the baseline (via pmax), and dynmar_side() returns exactly what's needed for the elements actually present. Also: - Main contribution now scales the top-line ascender with cex_main (0.6 * cex_main) so custom cex.main values (e.g. 2) don't clip. - Sub contribution adds its own ascender when drawn alone (no main), derived from 0.6 * cex_sub. When main is present, main's ascender already covers the top so sub just contributes its row heights. - Comments updated; call sites in tinyplot.R and facet.R use pmax(theme_mar, computed) as documented. --- R/facet.R | 36 ++++++++++++++++++++---------------- R/tinyplot.R | 5 +++-- R/utils.R | 29 +++++++++++++++++------------ 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/R/facet.R b/R/facet.R index 310efb69..83e0bc15 100644 --- a/R/facet.R +++ b/R/facet.R @@ -118,19 +118,21 @@ draw_facet_window = function( ## Dynamic plot margin adjustments if (dynmar) { - # Build each side's margin additively from a zero-ish baseline: pad + - # tick row (when axis on) + axis label (when present) + main/sub. + # Build each side's margin additively. The theme's `mar` acts as a + # baseline padding (via pmax) and dynmar_side() adds enough space for + # tick rows, axis labels, main, and sub when present. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - omar[1] = dynmar_side(1, xlab, main = main, sub = sub, - side.sub = side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), - tpars = tpars) - omar[2] = dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), - tpars = tpars) - omar[3] = dynmar_side(3, NULL, main = main, sub = sub, - side.sub = side.sub, tpars = tpars) - omar[4] = dynmar_side(4, NULL, tpars = tpars) + omar = pmax(omar, c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = tpars), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = tpars), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, + tpars = tpars), + dynmar_side(4, NULL, tpars = tpars) + )) if (par("las") %in% 1:2) { # extra whitespace bump on the y axis @@ -204,10 +206,12 @@ draw_facet_window = function( # on our earlier calculations. par(mfrow = c(nfacet_rows, nfacet_cols)) } else if (dynmar) { - # Dynamic plot margin adjustments (no facets): build each side additively - # from a tiny pad. Tick-label *width/height* (whtsbp) is added below. + # Dynamic plot margin adjustments (no facets). The theme's `mar` acts + # as a baseline padding (via pmax); dynmar_side() adds enough space + # for tick rows, axis labels, main, and sub when present. Tick-label + # *width/height* (whtsbp) is added further below. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - omar = c( + omar = pmax(par("mar"), c( dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), tpars = tpars), @@ -217,7 +221,7 @@ draw_facet_window = function( dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, tpars = tpars), dynmar_side(4, NULL, tpars = tpars) - ) + )) if (type == "spineplot") omar[4] = 2.1 # FIXME catch for spineplot RHS axis labs if (par("las") %in% 1:2) { # extra whitespace bump on the y axis diff --git a/R/tinyplot.R b/R/tinyplot.R index 57270bc7..3fda59e3 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -996,14 +996,15 @@ tinyplot.default = function( # relative to the plot region (not the default [0,1,0,1] figure region). if (isTRUE(get_tpar("dynmar"))) { .side.sub = get_tpar("side.sub", default = 3) - par(mar = c( + .theme_mar = par("mar") + par(mar = pmax(.theme_mar, c( dynmar_side(1, xlab, main = main, sub = sub, side.sub = .side.sub, axis_on = !identical(xaxt, "none") && !identical(xaxt, "n")), dynmar_side(2, ylab, axis_on = !identical(yaxt, "none") && !identical(yaxt, "n")), dynmar_side(3, NULL, main = main, sub = sub, side.sub = .side.sub), dynmar_side(4, NULL) - )) + ))) # Establish user coordinates so title/mtext adj is measured against the # plot region. draw_facet_window() will call plot.window() again with # final asp/log etc., but that's idempotent for alignment purposes. diff --git a/R/utils.R b/R/utils.R index 9bfd643d..a2992064 100644 --- a/R/utils.R +++ b/R/utils.R @@ -16,7 +16,7 @@ text_line_count = function(x) { } # Compute additive margin "build" for a given side under dynmar. -# Starts from a tiny pad and adds only what the plot actually needs. The tick +# Starts from zero and adds only what the plot actually needs. The tick # row and the axis-label row occupy overlapping vertical space (tick row # ends at ~|tcl| + mgp[2] + 1, axis label baseline sits at mgp[1]), so the # margin is the max of: @@ -26,12 +26,10 @@ text_line_count = function(x) { # margin additively. # Tick-label *width* for sides 2/4 (and *height* for 1/3 under las 2:3) is # handled separately by the existing whtsbp logic in draw_facet_window(). -# `pad` is the baseline breathing room added to every side (in line units); -# 0.3 is a good visual default for dynamic themes. 0.4 is also reasonable if -# a little more whitespace is desired. +# The caller is expected to take max(theme_mar[side], dynmar_side(...)) so +# that the theme's starting `mar` acts as a baseline padding. dynmar_side = function(side, label, main = NULL, sub = NULL, - side.sub = 3, axis_on = TRUE, tpars = NULL, - pad = 0.3) { + side.sub = 3, axis_on = TRUE, tpars = NULL) { mgp = get_tpar("mgp", tpar_list = tpars) tcl = get_tpar("tcl", tpar_list = tpars, default = par("tcl")) tick_extent = if (side %in% 1:2 && isTRUE(axis_on)) { @@ -49,22 +47,29 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, # doesn't clip against the device edge. label_extent = mgp[1] + (lines - 1) * cex_lab + 1 } - mar = pad + max(tick_extent, label_extent) + mar = max(tick_extent, label_extent) if (side == 3L) { mlines = text_line_count(main) if (mlines >= 1L) { cex_main = get_tpar("cex.main", tpar_list = tpars, default = 1.2) - # Main baseline sits at `mgp[3] + 0.7`; each extra line adds cex_main - # of vertical space; plus ~half a line for the ascender so the top - # of the text stays within the device. - mar = mar + 0.7 + (mlines - 1) * cex_main + 0.5 + # Main last-line baseline sits 0.7 lines above the box. Additional + # lines stack upward at cex_main per row. The top line's visible + # extent reaches ~0.6 * cex_main above its baseline (empirical from + # strheight("X") / csi). + mar = mar + 0.7 + (mlines - 1 + 0.6) * cex_main } } slines = text_line_count(sub) if (slines >= 1L && side == side.sub && side %in% c(1L, 3L)) { cex_sub = get_tpar("cex.sub", tpar_list = tpars, default = 1.2) # First sub row gets a 0.2-line extra bump; extra lines add cex_sub. - mar = mar + (cex_sub + 0.2) + (slines - 1) * cex_sub + # The top line's visible extent reaches ~0.6 * cex_sub above baseline. + # If main is ALSO present on the same side, its ascender already covers + # the top — the sub contribution is just the stacked sub row height. + # Otherwise, add the sub's own ascender. + has_main_here = side == 3L && text_line_count(main) >= 1L + asc = if (has_main_here) 0 else 0.6 * cex_sub + mar = mar + (cex_sub + 0.2) + (slines - 1) * cex_sub + asc } mar } From 4e9a9b0c2267c963d240469a988a77e66fecd444 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 18:05:37 -0700 Subject: [PATCH 14/30] Bump top outer margin by facet-strip height under dynmar Without this, main/sub titles drawn above the top facet strip would overlap the strip contents. fmar[3] already encodes facet_newlines and the facet_grid special-case; we add back the 0.5 line that's stripped when frame.plot is FALSE (that reduction is for inter-panel gaps, not the top strip itself). --- R/facet.R | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/R/facet.R b/R/facet.R index 83e0bc15..c20190e7 100644 --- a/R/facet.R +++ b/R/facet.R @@ -133,6 +133,17 @@ draw_facet_window = function( tpars = tpars), dynmar_side(4, NULL, tpars = tpars) )) + # Under facets, main/sub sit ABOVE the top facet strip. Bump the + # outer top margin by the strip height so sub doesn't collide with + # the strip. fmar[3] already captures facet_newlines and the + # facet_grid adjustment; add back the 0.5 line that was stripped + # when frame.plot is FALSE (that reduction is meant to tighten + # inter-panel gaps, not the top strip). + strip_bump = fmar[3] + if (isFALSE(frame.plot) && !isTRUE(facet.args[["free"]])) { + strip_bump = strip_bump + 0.5 + } + omar[3] = omar[3] + strip_bump if (par("las") %in% 1:2) { # extra whitespace bump on the y axis From eb506125ad773783f2ebbea0cc5342fe6b5c318b Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 21 Apr 2026 18:06:16 -0700 Subject: [PATCH 15/30] Add 0.6-line baseline padding to dynamic theme mar[4] The right side never gets tick/label content (except spineplot), so theme mar is the sole source of padding there. Bumping from 0.1 to 0.6 restores the breathing room the pre-refactor layout had. Other sides stay at 0.1 (they get ample space from tick rows and labels when present). --- R/tinytheme.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/tinytheme.R b/R/tinytheme.R index cd22b4b5..302607f8 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -291,7 +291,7 @@ theme_dynamic = modifyList(theme_basic, list( dynmar = TRUE, grid = FALSE, las = 1, - mar = c(0.1, 0.1, 0.1, 0.1), + mar = c(0.1, 0.1, 0.1, 0.6), mgp = c(3, 1, 0) - c(0.5+0.3, 0.3, 0), # i.e., subtract 0.5 lines + the (abs) value of the tcl adjustment side.sub = 3, tcl = -0.3 From ac711ab49492e81e67afc1d2a60c08f90094238d Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Wed, 22 Apr 2026 14:37:19 -0700 Subject: [PATCH 16/30] Compute dynmar margins up front; drop theme baseline on outer-legend sides - Move full dynmar margin computation (theme_mar + dynmar_side + whtsbp) into tinyplot.default before legend drawing, pass dynmar_computed through to draw_facet_window instead of recomputing in two places. - On outer-legend sides, zero only the theme baseline padding (.theme_mar) so the plot meets the legend's oma flush, while preserving axis-driven bumps (.dyn) for left!/bottom! legends. - Detect legend position via tryCatch(eval(legend)) since sanitize_legend runs later inside draw_legend; default NULL legend treated as 'right!'. - Hoist .whtsbp default so post-block references are always defined. - draw_title gains ylab_line_offset for whtsbp-aware ylab placement. - theme_dynamic baseline mar changed to c(0.1, 0.1, 0.6, 0.6). --- R/facet.R | 65 +++++++++++++++---------- R/tinyplot.R | 128 +++++++++++++++++++++++++++++++++++++++++--------- R/tinytheme.R | 2 +- R/title.R | 6 ++- 4 files changed, 150 insertions(+), 51 deletions(-) diff --git a/R/facet.R b/R/facet.R index c20190e7..adea9066 100644 --- a/R/facet.R +++ b/R/facet.R @@ -38,7 +38,8 @@ draw_facet_window = function( x, xmax, xmin, ylab, y, ymax, ymin, - tpars = NULL + tpars = NULL, + dynmar_computed = NULL ) { if (is.null(tpars)) tpars = tpar() @@ -118,21 +119,28 @@ draw_facet_window = function( ## Dynamic plot margin adjustments if (dynmar) { - # Build each side's margin additively. The theme's `mar` acts as a - # baseline padding (via pmax) and dynmar_side() adds enough space for - # tick rows, axis labels, main, and sub when present. + # Margins were pre-computed in tinyplot.default (dynmar_computed). + # Use that as the base instead of par("mar") which may have been + # reset by the before.plot.new hook. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - omar = pmax(omar, c( - dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), - tpars = tpars), - dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), - tpars = tpars), - dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, - tpars = tpars), - dynmar_side(4, NULL, tpars = tpars) - )) + if (!is.null(dynmar_computed)) { + omar = dynmar_computed + } else { + # Fallback: recompute if dynmar_computed wasn't passed (e.g. add = TRUE + # or future code paths). Build each side's margin additively; the + # theme's mar acts as baseline padding (via pmax). + omar = pmax(omar, c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = tpars), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = tpars), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, + tpars = tpars), + dynmar_side(4, NULL, tpars = tpars) + )) + } # Under facets, main/sub sit ABOVE the top facet strip. Bump the # outer top margin by the strip height so sub doesn't collide with # the strip. fmar[3] already captures facet_newlines and the @@ -222,17 +230,22 @@ draw_facet_window = function( # for tick rows, axis labels, main, and sub when present. Tick-label # *width/height* (whtsbp) is added further below. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - omar = pmax(par("mar"), c( - dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), - tpars = tpars), - dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), - tpars = tpars), - dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, - tpars = tpars), - dynmar_side(4, NULL, tpars = tpars) - )) + if (!is.null(dynmar_computed)) { + omar = dynmar_computed + } else { + # Fallback: recompute if dynmar_computed wasn't passed. + omar = pmax(par("mar"), c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = tpars), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = tpars), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, + tpars = tpars), + dynmar_side(4, NULL, tpars = tpars) + )) + } if (type == "spineplot") omar[4] = 2.1 # FIXME catch for spineplot RHS axis labs if (par("las") %in% 1:2) { # extra whitespace bump on the y axis diff --git a/R/tinyplot.R b/R/tinyplot.R index 3fda59e3..e413f62d 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -938,6 +938,101 @@ tinyplot.default = function( env2env(settings, environment()) + # + ## dynmar: compute margins up front ----- + # + # Under dynmar themes, compute the full margin once before any drawing. + # theme_mar (from the theme) is the baseline padding; dynmar_side() adds + # space for ticks, axis labels, main, and sub. whtsbp adds tick-label + # width/height for horizontal y-labels or vertical x-labels. + # For outer legends ("bottom!", "left!", etc.), skip dynmar_side on the + # legend's side — the legend code owns that side's mar via oma. + # + dynmar_computed = NULL + .whtsbp = c(0, 0, 0, 0) + if (!add && isTRUE(get_tpar("dynmar"))) { + .side.sub = get_tpar("side.sub", default = 3) + # Read the theme's intended mar. Also build a tpars list from the theme + # definition so dynmar_side uses theme mgp/tcl/las (which aren't in + # par() yet since the before.plot.new hook hasn't fired). + .tinytheme = get_tpar("tinytheme", default = "default") + .theme_def = if (!is.null(.tinytheme) && .tinytheme != "default") { + get(paste0("theme_", .tinytheme), envir = asNamespace("tinyplot")) + } else NULL + .theme_mar = if (!is.null(.theme_def[["mar"]])) .theme_def[["mar"]] else par("mar") + .tpars = if (!is.null(.theme_def)) .theme_def else tpar() + + # Detect outer-legend sides (order: bottom, left, top, right). + # legend_args[["x"]] isn't normalized yet (sanitize_legend runs later + # inside draw_legend), so evaluate the raw `legend` argument here. + # When legend is NULL (user didn't specify), the default is "right!". + .lgnd_eval = tryCatch(eval(legend), error = function(e) legend) + if (is.null(.lgnd_eval)) .lgnd_eval = "right!" + .lgnd_pos = if (is.character(.lgnd_eval)) .lgnd_eval + else if (is.list(.lgnd_eval)) as.character(.lgnd_eval[[1]]) + else NULL + .outer_sides = c( + grepl("bottom!$", .lgnd_pos), + grepl("left!$", .lgnd_pos), + grepl("top!$", .lgnd_pos), + grepl("right!$", .lgnd_pos) + ) + + .dyn = c( + dynmar_side(1, xlab, main = main, sub = sub, side.sub = .side.sub, + axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), + tpars = .tpars), + dynmar_side(2, ylab, + axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), + tpars = .tpars), + dynmar_side(3, NULL, main = main, sub = sub, side.sub = .side.sub, + tpars = .tpars), + dynmar_side(4, NULL, tpars = .tpars) + ) + # Drop the theme's baseline padding on outer-legend sides so the plot + # region meets the legend's oma flush. Only .theme_mar is zeroed — the + # axis-driven bumps in .dyn (tick rows, axis labels, main/sub) are kept + # so that "left!" and "bottom!" legends don't collide with axis content. + .theme_mar[.outer_sides] = 0 + + # Establish user coordinates for strwidth (needed by whtsbp) and for + # title/mtext alignment later. draw_facet_window() will call + # plot.window() again with final asp/log etc., but that's idempotent + # for alignment purposes. + plot.new() + if (!is.null(xlim) && !is.null(ylim)) { + plot.window(xlim = xlim, ylim = ylim) + } + + # Compute whtsbp (tick-label width/height bump) + .whtsbp = c(0, 0, 0, 0) + if (par("las") %in% 1:2) { + if (type == "ridge") { + yaxlabs = levels(y) + } else if (!is.null(ylabs)) { + yaxlabs = if (!is.null(names(ylabs))) names(ylabs) else ylabs + } else if (type == "boxplot" && isTRUE(flip) && !is.null(xlabs)) { + yaxlabs = if (!is.null(names(xlabs))) names(xlabs) else xlabs + } else { + yaxlabs = axisTicks(usr = extendrange(ylim, f = 0.04), log = par("ylog")) + } + if (!is.null(yaxl)) yaxlabs = tinylabel(yaxlabs, yaxl) + whtsbp_y = grconvertX(max(strwidth(yaxlabs, "figure")), from = "nfc", to = "lines") - + grconvertX(0, from = "nfc", to = "lines") - 1 + if (is.finite(whtsbp_y) && whtsbp_y > 0) .whtsbp[2] = whtsbp_y + } + if (par("las") %in% 2:3) { + xaxlabs = if (is.null(xlabs)) axisTicks(usr = extendrange(xlim, f = 0.04), log = par("xlog")) else + if (!is.null(names(xlabs))) names(xlabs) else xlabs + if (!is.null(xaxl)) xaxlabs = tinylabel(xaxlabs, xaxl) + whtsbp_x = grconvertX(max(strwidth(xaxlabs, "figure")), from = "nfc", to = "lines") - 1 + if (is.finite(whtsbp_x) && whtsbp_x > 0) .whtsbp[1] = whtsbp_x + } + + dynmar_computed = .theme_mar + .dyn + par(mar = dynmar_computed + .whtsbp) + } + if (legend_draw_flag) { if (!multi_legend) { ## simple case: single legend only @@ -988,31 +1083,16 @@ tinyplot.default = function( # if (!add) { - # Under dynmar, pre-size the margins for main/sub/xlab/ylab so that - # draw_title() writes into adequate space. draw_facet_window() will - # later add tick-label width/height (whtsbp) and any facet-specific - # bumps on top of this baseline. - # We also need plot.window() to have been called so mtext/title align - # relative to the plot region (not the default [0,1,0,1] figure region). - if (isTRUE(get_tpar("dynmar"))) { - .side.sub = get_tpar("side.sub", default = 3) - .theme_mar = par("mar") - par(mar = pmax(.theme_mar, c( - dynmar_side(1, xlab, main = main, sub = sub, side.sub = .side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n")), - dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n")), - dynmar_side(3, NULL, main = main, sub = sub, side.sub = .side.sub), - dynmar_side(4, NULL) - ))) - # Establish user coordinates so title/mtext adj is measured against the - # plot region. draw_facet_window() will call plot.window() again with - # final asp/log etc., but that's idempotent for alignment purposes. + # Reinstate dynmar margins and user coordinates after draw_legend + # (which may have called plot.new and reset par via hooks). + if (!is.null(dynmar_computed)) { + par(mar = dynmar_computed + .whtsbp) if (!is.null(xlim) && !is.null(ylim)) { plot.window(xlim = xlim, ylim = ylim) } } - draw_title(main, sub, xlab, ylab, legend, legend_args, opar) + draw_title(main, sub, xlab, ylab, legend, legend_args, opar, + ylab_line_offset = if (!is.null(dynmar_computed)) .whtsbp[2] else 0) } @@ -1093,7 +1173,8 @@ tinyplot.default = function( x = x, xmax = xmax, xmin = xmin, ylab = ylab, y = y, ymax = ymax, ymin = ymin, - tpars = tpars + tpars = tpars, + dynmar_computed = dynmar_computed ), list = list( add = add, @@ -1121,7 +1202,8 @@ tinyplot.default = function( x = datapoints$x, xmax = datapoints$xmax, xmin = datapoints$xmin, ylab = ylab, y = datapoints$y, ymax = datapoints$ymax, ymin = datapoints$ymin, - tpars = tpar() # https://github.com/grantmcdermott/tinyplot/issues/474 + tpars = tpar(), # https://github.com/grantmcdermott/tinyplot/issues/474 + dynmar_computed = dynmar_computed ), getNamespace("tinyplot") ) diff --git a/R/tinytheme.R b/R/tinytheme.R index 302607f8..102a7e4c 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -291,7 +291,7 @@ theme_dynamic = modifyList(theme_basic, list( dynmar = TRUE, grid = FALSE, las = 1, - mar = c(0.1, 0.1, 0.1, 0.6), + mar = c(0.1, 0.1, 0.6, 0.6), mgp = c(3, 1, 0) - c(0.5+0.3, 0.3, 0), # i.e., subtract 0.5 lines + the (abs) value of the tcl adjustment side.sub = 3, tcl = -0.3 diff --git a/R/title.R b/R/title.R index 51e5b8a5..62e435d4 100644 --- a/R/title.R +++ b/R/title.R @@ -1,4 +1,5 @@ -draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { +draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar, + ylab_line_offset = 0) { # main title # Note that we include a special catch for the main title if legend is # "top!" (and main is specified in the first place). @@ -93,6 +94,9 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar) { # ylab: base R already places multi-line text correctly (outermost line at # mgp[1], subsequent lines closer to the plot), so no line shift needed. args = list(ylab = ylab) + if (ylab_line_offset != 0) { + args[["line"]] = get_tpar("mgp")[1] + ylab_line_offset + } args[["adj"]] = get_tpar(c("adj.ylab", "adj")) do.call(title, args) } From e55b771b5b42e00cba965fbecea346b5f14b13ad Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 11:16:30 -0700 Subject: [PATCH 17/30] known false positives for test suite on macos --- .CLAUDE.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.CLAUDE.md b/.CLAUDE.md index 8d9da08d..bc7f0b67 100644 --- a/.CLAUDE.md +++ b/.CLAUDE.md @@ -135,7 +135,12 @@ Tests use `tinytest` + `tinysnapshot`. Snapshot tests produce SVG output with Li 2. Command Palette → "Dev Containers: Reopen in Container" 3. Dependencies install automatically -Non-snapshot tests (logical assertions, error checks, etc.) run fine on any platform. Even with the devcontainer, a small number of snapshot tests (~2-3) may produce false positive failures on macOS hosts due to imperceptible rendering differences. These show up in `inst/tinytest/_tinysnapshot_review/` but the visual differences are too small to detect by eye. This is a known quirk — don't worry about these specific persistent failures. However, if you see more than ~3 snapshot failures, something real is likely broken and needs investigation. +Non-snapshot tests (logical assertions, error checks, etc.) run fine on any platform. Even with the devcontainer, a small number of snapshot tests (~2-3) may produce false positive failures on macOS hosts due to imperceptible rendering differences. These show up in `inst/tinytest/_tinysnapshot_review/` but the visual differences are too small to detect by eye. Known false positives: + +- `xaxl_yaxl` +- `palette_manual_continuous` + +This is a known quirk — don't worry about these specific persistent failures. However, if you see more than ~3 snapshot failures, something real is likely broken and needs investigation. ### Running Tests ```bash From cadbc4c152abda1f17d0451793f835201357e1c4 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 11:19:12 -0700 Subject: [PATCH 18/30] fix mfrow + plot.new clash --- R/tinyplot.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index e413f62d..a6e0ddce 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -995,14 +995,14 @@ tinyplot.default = function( # so that "left!" and "bottom!" legends don't collide with axis content. .theme_mar[.outer_sides] = 0 - # Establish user coordinates for strwidth (needed by whtsbp) and for - # title/mtext alignment later. draw_facet_window() will call - # plot.window() again with final asp/log etc., but that's idempotent - # for alignment purposes. - plot.new() - if (!is.null(xlim) && !is.null(ylim)) { - plot.window(xlim = xlim, ylim = ylim) - } + # whtsbp uses strwidth(units="figure") + grconvertX("nfc" → "lines"), + # both of which give device-default font metrics without requiring + # plot.new()/plot.window() first. A preparatory plot.new() here would + # advance par("mfg") (breaking mfrow layouts) and create a blank page + # in IDE plot panes (Positron). Left/bottom/top margin sizing for + # title alignment is handled later by draw_legend or the no-legend + # path's own plot.new(), after which the margins are reinstated + # via dynmar_computed + .whtsbp before draw_title runs. # Compute whtsbp (tick-label width/height bump) .whtsbp = c(0, 0, 0, 0) From 11e240658ae45a9369310d45b2d6027dc22a08a8 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 11:19:25 -0700 Subject: [PATCH 19/30] update test snapshots --- .../_tinysnapshot/margins_facet_multiline.svg | 162 +- .../_tinysnapshot/margins_missing_labels.svg | 92 +- .../_tinysnapshot/margins_multiline_2x2.svg | 412 +- .../margins_multiline_labels.svg | 82 +- .../margins_sub_na_bottom_legend.svg | 154 +- .../pointrange_with_layers_flipped.svg | 50 +- .../_tinysnapshot/ridge_basic_theme_ridge.svg | 42 +- .../ridge_basic_theme_ridge2.svg | 32 +- .../_tinysnapshot/ridge_by_x_theme_ridge.svg | 3148 ++++++------- .../_tinysnapshot/ridge_by_x_theme_ridge2.svg | 3138 ++++++------- .../_tinysnapshot/ridge_by_y_theme_ridge.svg | 94 +- .../_tinysnapshot/ridge_by_y_theme_ridge2.svg | 104 +- .../ridge_gradient_facet_theme_ridge.svg | 4168 ++++++++--------- .../ridge_gradient_facet_theme_ridge2.svg | 4152 ++++++++-------- .../ridge_gradient_theme_ridge.svg | 3108 ++++++------ .../ridge_gradient_theme_ridge2.svg | 3098 ++++++------ .../_tinysnapshot/ridge_theme_bg_numeric.svg | 32 +- .../_tinysnapshot/ridge_theme_palette.svg | 56 +- inst/tinytest/_tinysnapshot/tinylabel.svg | 224 +- inst/tinytest/_tinysnapshot/tinytheme_bw.svg | 154 +- .../_tinysnapshot/tinytheme_classic.svg | 132 +- .../_tinysnapshot/tinytheme_clean.svg | 154 +- .../_tinysnapshot/tinytheme_clean2.svg | 132 +- .../tinytest/_tinysnapshot/tinytheme_dark.svg | 132 +- .../_tinysnapshot/tinytheme_dynamic.svg | 132 +- .../tinytheme_dynamic_boxplot_flip.svg | 156 +- .../_tinysnapshot/tinytheme_dynamic_clean.svg | 426 +- .../tinytheme_dynamic_clean_facet.svg | 612 +-- .../tinytheme_dynamic_clean_spineplot.svg | 122 +- .../_tinysnapshot/tinytheme_dynamic_dark.svg | 392 +- .../tinytheme_dynamic_dark_facet.svg | 368 +- .../tinytheme_dynamic_dynamic.svg | 396 +- .../tinytheme_dynamic_jitter_flip.svg | 208 +- .../_tinysnapshot/tinytheme_dynamic_ridge.svg | 46 +- .../tinytheme_dynamic_x_boxplot.svg | 160 +- .../_tinysnapshot/tinytheme_dynamic_yaxl.svg | 180 +- .../_tinysnapshot/tinytheme_ephemeral.svg | 388 +- .../_tinysnapshot/tinytheme_ipsum.svg | 132 +- .../_tinysnapshot/tinytheme_legend_bottom.svg | 166 +- .../_tinysnapshot/tinytheme_legend_left.svg | 166 +- .../_tinysnapshot/tinytheme_minimal.svg | 132 +- .../_tinysnapshot/tinytheme_ridge.svg | 132 +- .../_tinysnapshot/tinytheme_ridge2.svg | 110 +- .../_tinysnapshot/tinytheme_tufte.svg | 4 +- .../tinytest/_tinysnapshot/tinytheme_void.svg | 4 +- 45 files changed, 13742 insertions(+), 13742 deletions(-) diff --git a/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg b/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg index d59f221a..07c0270c 100644 --- a/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg +++ b/inst/tinytest/_tinysnapshot/margins_facet_multiline.svg @@ -26,99 +26,99 @@ - - 4 - 5 - 6 - 7 - 8 -- - -- - -- - -- - -- - -cyl + + 4 + 5 + 6 + 7 + 8 +- - +- - +- - +- - +- - +cyl - - + + - -Weight -(1000 lbs) -mpg + +Weight +(1000 lbs) +mpg - + - - - + + + 2 -3 -4 -5 - - - - - - -10 -15 -20 -25 -30 - +3 +4 +5 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_missing_labels.svg b/inst/tinytest/_tinysnapshot/margins_missing_labels.svg index 08f181f1..5f73f727 100644 --- a/inst/tinytest/_tinysnapshot/margins_missing_labels.svg +++ b/inst/tinytest/_tinysnapshot/margins_missing_labels.svg @@ -26,56 +26,56 @@ - - - - - - -2 -4 -6 -8 -10 - - - - - - -2 -4 -6 -8 -10 - + + + + + + +2 +4 +6 +8 +10 + + + + + + +2 +4 +6 +8 +10 + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg b/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg index 9488042d..2908f662 100644 --- a/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg +++ b/inst/tinytest/_tinysnapshot/margins_multiline_2x2.svg @@ -33,74 +33,74 @@ -xlab = NA -Y +xlab = NA +Y - - - - - -5 -10 -15 -20 - - - - - - -0 -5 -10 -15 -20 - + + + + + +5 +10 +15 +20 + + + + + + +0 +5 +10 +15 +20 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + @@ -108,9 +108,9 @@ -xlab present +xlab present X -Y +Y @@ -122,61 +122,61 @@ 10 15 20 - - - - - - -0 -5 -10 -15 -20 - + + + + + + +0 +5 +10 +15 +20 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + @@ -184,11 +184,11 @@ -Multi-line labels -X line 1 -X line 2 -Y line 1 -Y line 2 +Multi-line labels +X line 1 +X line 2 +Y line 1 +Y line 2 @@ -200,61 +200,61 @@ 10 15 20 - - - - - - -0 -5 -10 -15 -20 - + + + + + + +0 +5 +10 +15 +20 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + @@ -262,10 +262,10 @@ -Multi-line -main title +Multi-line +main title X -Y +Y @@ -277,54 +277,54 @@ 10 15 20 - - - - - - -0 -5 -10 -15 -20 - + + + + + + +0 +5 +10 +15 +20 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg index 239b2c93..903e9001 100644 --- a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg +++ b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg @@ -26,12 +26,12 @@ -E -F -A -B -C -D +E +F +A +B +C +D @@ -43,45 +43,45 @@ 6 8 10 - - - - - - -2 -4 -6 -8 -10 - + + + + + + +2 +4 +6 +8 +10 + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg b/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg index a2550cb4..70168c2f 100644 --- a/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg +++ b/inst/tinytest/_tinysnapshot/margins_sub_na_bottom_legend.svg @@ -26,93 +26,93 @@ - - - -factor(cyl) -4 -6 -8 + + + +factor(cyl) +4 +6 +8 - - + + - -wt -mpg + +wt +mpg - - - - - -2 -3 -4 -5 - - - - - - -10 -15 -20 -25 -30 - + + + + + +2 +3 +4 +5 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg index 52c4575d..cb006f36 100644 --- a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg +++ b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg @@ -27,7 +27,7 @@ y -x +x @@ -39,34 +39,34 @@ 10 20 30 - - - - - -(Intercept) -hp -factor(cyl)6 -factor(cyl)8 - + + + + + +(Intercept) +hp +factor(cyl)6 +factor(cyl)8 + - - + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg index 161f46c0..0bedaeac 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species @@ -43,32 +43,32 @@ 3.5 4.0 4.5 - + - - + + - - - - - - - - - - + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg index a6ce4ad3..41750039 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species 1.5 2.0 2.5 @@ -37,25 +37,25 @@ 4.5 - - + + - - - - - - - - - - + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg index 41947aa7..8aae131b 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg @@ -26,18 +26,18 @@ - - 2.0 - 2.5 - 3.0 - 3.5 - 4.0 -- - -- - -- - -- - -- - -Sepal.Width + + 2.0 + 2.5 + 3.0 + 3.5 + 4.0 +- - +- - +- - +- - +- - +Sepal.Width @@ -45,1584 +45,1584 @@ -Sepal.Width -Species +Sepal.Width +Species - + - + - - + + 1.5 2.0 2.5 -3.0 +3.0 3.5 -4.0 -4.5 - +4.0 +4.5 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg index 33bd8668..480b4382 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg @@ -26,18 +26,18 @@ - - 2.0 - 2.5 - 3.0 - 3.5 - 4.0 -- - -- - -- - -- - -- - -Sepal.Width + + 2.0 + 2.5 + 3.0 + 3.5 + 4.0 +- - +- - +- - +- - +- - +Sepal.Width @@ -45,1579 +45,1579 @@ -Sepal.Width -Species +Sepal.Width +Species 1.5 2.0 2.5 -3.0 +3.0 3.5 -4.0 -4.5 +4.0 +4.5 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -setosa -versicolor -virginica - +setosa +versicolor +virginica + - + - - + + diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg index 01c57153..7b862111 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg @@ -26,75 +26,75 @@ - - - -Species -virginica -versicolor -setosa + + + +Species +virginica +versicolor +setosa - - + + - -Sepal.Width -Species + +Sepal.Width +Species - + - - - - - + + + + + 1.5 2.0 -2.5 -3.0 -3.5 -4.0 -4.5 - +2.5 +3.0 +3.5 +4.0 +4.5 + - - + + - - - - + + + + - - -virginica + + +virginica - - - - + + + + - - -versicolor + + +versicolor - - - - + + + + - - -setosa + + +setosa diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg index 68ae32c5..01d57e8b 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg @@ -26,84 +26,84 @@ - - - -Species -virginica -versicolor -setosa + + + +Species +virginica +versicolor +setosa - - + + - -Sepal.Width -Species + +Sepal.Width +Species 1.5 2.0 -2.5 -3.0 -3.5 -4.0 -4.5 +2.5 +3.0 +3.5 +4.0 +4.5 - - + + - - - - + + + + -virginica - +virginica + - - - - - + + + + + - - - - + + + + -versicolor - +versicolor + - - - - - + + + + + - - - - + + + + -setosa - +setosa + - - - - - + + + + + diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg index 29c006c7..1b1ebf32 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge.svg @@ -27,14 +27,14 @@ mpg -am +am - - + + - + @@ -54,16 +54,16 @@ 30 35 40 - -0 - + +0 + - - + + - + @@ -83,2090 +83,2090 @@ 30 35 40 - -1 - + +1 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - -0 -1 + + + +0 +1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - -0 -1 + + + +0 +1 - - + + - + diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg index d430f71b..f3ebe371 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_facet_theme_ridge2.svg @@ -27,14 +27,14 @@ mpg -am +am - - + + - + 5 @@ -45,15 +45,15 @@ 30 35 40 - -0 + +0 - - + + - + 5 @@ -64,1042 +64,1042 @@ 30 35 40 - -1 + +1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0 -1 +0 +1 @@ -1110,1039 +1110,1039 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0 -1 +0 +1 @@ -2154,11 +2154,11 @@ - - + + - + diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg index 0933e40b..438fea0e 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species @@ -43,1565 +43,1565 @@ 3.5 4.0 4.5 - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg index cc208520..e15acfcb 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species 1.5 2.0 2.5 @@ -37,1558 +37,1558 @@ 4.5 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg b/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg index 7acdb280..ebf2fcf4 100644 --- a/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg +++ b/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species 1.5 2.0 2.5 @@ -37,25 +37,25 @@ 4.5 - - + + - - - - - - - - - - + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg b/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg index 7138677a..e4d818ac 100644 --- a/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg +++ b/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg @@ -27,7 +27,7 @@ Sepal.Width -Species +Species 1.5 2.0 2.5 @@ -37,37 +37,37 @@ 4.5 - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + -setosa -versicolor -virginica +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/tinylabel.svg b/inst/tinytest/_tinysnapshot/tinylabel.svg index bef132d3..6c9c4c4c 100644 --- a/inst/tinytest/_tinysnapshot/tinylabel.svg +++ b/inst/tinytest/_tinysnapshot/tinylabel.svg @@ -26,128 +26,128 @@ - - 0.5% - 1.0% - 1.5% - 2.0% - 2.5% -- - -- - -- - -- - -- - -Illiteracy + + 0.5% + 1.0% + 1.5% + 2.0% + 2.5% +- - +- - +- - +- - +- - +Illiteracy - - + + - -Income -Life.Exp + +Income +Life.Exp - - - - - - - - -$3,000 -$3,500 -$4,000 -$4,500 -$5,000 -$5,500 -$6,000 - - - - - - - -68 -69 -70 -71 -72 -73 - + + + + + + + + +$3,000 +$3,500 +$4,000 +$4,500 +$5,000 +$5,500 +$6,000 + + + + + + + +68 +69 +70 +71 +72 +73 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_bw.svg b/inst/tinytest/_tinysnapshot/tinytheme_bw.svg index b8170063..45ad1965 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_bw.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_bw.svg @@ -26,99 +26,99 @@ - - -factor(am) -0 -1 -tinytheme("bw") + + +factor(am) +0 +1 +tinytheme("bw") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - + - + - - + + 50 100 -150 +150 200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_classic.svg b/inst/tinytest/_tinysnapshot/tinytheme_classic.svg index d19f4f19..866cbc38 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_classic.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_classic.svg @@ -26,88 +26,88 @@ - - -factor(am) -0 -1 -tinytheme("classic") + + +factor(am) +0 +1 +tinytheme("classic") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - + - + - - + + 50 100 -150 +150 200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_clean.svg b/inst/tinytest/_tinysnapshot/tinytheme_clean.svg index 7a0275d6..41582919 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_clean.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_clean.svg @@ -26,99 +26,99 @@ - - -factor(am) -0 -1 -tinytheme("clean") + + +factor(am) +0 +1 +tinytheme("clean") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - + - + - - + + 50 100 -150 +150 200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_clean2.svg b/inst/tinytest/_tinysnapshot/tinytheme_clean2.svg index 63c78a6f..f45fd079 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_clean2.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_clean2.svg @@ -26,85 +26,85 @@ - - -factor(am) -0 -1 -tinytheme("clean2") + + +factor(am) +0 +1 +tinytheme("clean2") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg 50 100 -150 +150 200 -250 -300 -10 -15 -20 -25 -30 +250 +300 +10 +15 +20 +25 +30 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dark.svg b/inst/tinytest/_tinysnapshot/tinytheme_dark.svg index 15c45365..e529c236 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dark.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dark.svg @@ -26,85 +26,85 @@ - - -factor(am) -0 -1 -tinytheme("dark") + + +factor(am) +0 +1 +tinytheme("dark") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg 50 100 -150 +150 200 -250 -300 -10 -15 -20 -25 -30 +250 +300 +10 +15 +20 +25 +30 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg index 794af50c..6451150f 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic.svg @@ -26,88 +26,88 @@ - - -factor(am) -0 -1 -tinytheme("dynamic") + + +factor(am) +0 +1 +tinytheme("dynamic") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - + - + - - + + 50 100 -150 +150 200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg index 5c9c39f4..266a4c23 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg @@ -26,23 +26,23 @@ -Flipped boxplot version -Dynamic plot adjustment and whitespace reduction +Flipped boxplot version +Dynamic plot adjustment and whitespace reduction weight -feed - - - - - - - -casein -horsebean -linseed -meatmeal -soybean -sunflower +feed + + + + + + + +casein +horsebean +linseed +meatmeal +soybean +sunflower @@ -58,72 +58,72 @@ 300 350 400 - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg index 4784c827..6642225e 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg @@ -26,231 +26,231 @@ - - - -Species -setosa -versicolor -virginica -For themes with las = 1, etc. + + + +Species +setosa +versicolor +virginica +For themes with las = 1, etc. - - + + - -Dynamic plot adjustment and whitespace reduction -Petal.Length -I(Sepal.Length * 1e+09) + +Dynamic plot adjustment and whitespace reduction +Petal.Length +I(Sepal.Length * 1e+09) - + - - - - - - + + + + + + 1 -2 -3 -4 -5 -6 -7 - - - - - - - - - -4.5e+09 -5.0e+09 -5.5e+09 -6.0e+09 -6.5e+09 -7.0e+09 -7.5e+09 -8.0e+09 - +2 +3 +4 +5 +6 +7 + + + + + + + + + +4.5e+09 +5.0e+09 +5.5e+09 +6.0e+09 +6.5e+09 +7.0e+09 +7.5e+09 +8.0e+09 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg index d8545ef9..7017dbfe 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg @@ -26,370 +26,370 @@ - - 100 - 200 - 300 - 400 -- - -- - -- - -- - -disp -Works with facets too + + 100 + 200 + 300 + 400 +- - +- - +- - +- - +disp +Works with facets too - - + + - -Dynamic plot adjustment and whitespace reduction -I(hp * 100) -I(mpg * 1000) + +Dynamic plot adjustment and whitespace reduction +I(hp * 100) +I(mpg * 1000) - - + + - + - - - - - - - -5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - -0 - + + + + + + + +5000 +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + +0 + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - - - - - - -5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - -1 - -4 - + + + + + + + +5000 +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + +1 + +4 + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - - - - - - -5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - + + + + + + + +5000 +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - - - - - - -5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - -6 - + + + + + + + +5000 +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + +6 + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - + - - - - - + + + + + 5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - - - - - - - -5000 -10000 -15000 -20000 -25000 -30000 - - - - - - -10000 -15000 -20000 -25000 -30000 - -8 - + + + + + + + +5000 +10000 +15000 +20000 +25000 +30000 + + + + + + +10000 +15000 +20000 +25000 +30000 + +8 + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + + - - + + - + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg index cde4452b..3b6b7f5c 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg @@ -26,65 +26,65 @@ -Spineplot version -Dynamic plot adjustment and whitespace reduction +Spineplot version +Dynamic plot adjustment and whitespace reduction Petal.Length -Species +Species - - + + - - - - - - - + + + + + + + - - - - - + + + + + - + - - - - + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -110,23 +110,23 @@ 5.5 6 7 -virginica -versicolor -setosa - +virginica +versicolor +setosa + - - - - - + + + + + 0.0 -0.2 -0.4 -0.6 -0.8 -1.0 - +0.2 +0.4 +0.6 +0.8 +1.0 + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg index 698e59e9..805a94d1 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg @@ -26,213 +26,213 @@ - - - -Species -setosa -versicolor -virginica -For themes with las = 1, etc. + + + +Species +setosa +versicolor +virginica +For themes with las = 1, etc. - - + + - -Dynamic plot adjustment and whitespace reduction -Petal.Length -I(Sepal.Length * 1e+09) + +Dynamic plot adjustment and whitespace reduction +Petal.Length +I(Sepal.Length * 1e+09) 1 -2 -3 -4 -5 -6 -7 -4.5e+09 -5.0e+09 -5.5e+09 -6.0e+09 -6.5e+09 -7.0e+09 -7.5e+09 -8.0e+09 +2 +3 +4 +5 +6 +7 +4.5e+09 +5.0e+09 +5.5e+09 +6.0e+09 +6.5e+09 +7.0e+09 +7.5e+09 +8.0e+09 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg index f2b84c43..6f3527fe 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg @@ -26,247 +26,247 @@ - - 100 - 200 - 300 - 400 -- - -- - -- - -- - -disp -Works with facets too + + 100 + 200 + 300 + 400 +- - +- - +- - +- - +disp +Works with facets too - - + + - -Dynamic plot adjustment and whitespace reduction -I(hp * 100) -I(mpg * 1000) + +Dynamic plot adjustment and whitespace reduction +I(hp * 100) +I(mpg * 1000) - - + + - + -10000 -15000 -20000 -25000 -30000 - -0 +10000 +15000 +20000 +25000 +30000 + +0 - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - -1 - -4 + +1 + +4 - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + -10000 -15000 -20000 -25000 -30000 +10000 +15000 +20000 +25000 +30000 - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + - -6 + +6 - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + 5000 -10000 -15000 -20000 -25000 -30000 -10000 -15000 -20000 -25000 -30000 +10000 +15000 +20000 +25000 +30000 +10000 +15000 +20000 +25000 +30000 - - - - - - - - - - - - + + + + + + + + + + + + - - + + - + -5000 -10000 -15000 -20000 -25000 -30000 - -8 +5000 +10000 +15000 +20000 +25000 +30000 + +8 - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + + - - + + - + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg index c742ef8b..14e33db3 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg @@ -26,216 +26,216 @@ - - - -Species -setosa -versicolor -virginica -For themes with las = 1, etc. + + + +Species +setosa +versicolor +virginica +For themes with las = 1, etc. - - + + - -Dynamic plot adjustment and whitespace reduction -Petal.Length -I(Sepal.Length * 1e+09) + +Dynamic plot adjustment and whitespace reduction +Petal.Length +I(Sepal.Length * 1e+09) - + - - - - - - + + + + + + 1 -2 -3 -4 -5 -6 -7 - - - - - - - - - -4.5e+09 -5.0e+09 -5.5e+09 -6.0e+09 -6.5e+09 -7.0e+09 -7.5e+09 -8.0e+09 - +2 +3 +4 +5 +6 +7 + + + + + + + + + +4.5e+09 +5.0e+09 +5.5e+09 +6.0e+09 +6.5e+09 +7.0e+09 +7.5e+09 +8.0e+09 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg index 28b52e18..d0e6b9ea 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg @@ -26,10 +26,10 @@ -Flipped jitter plot version -Dynamic plot adjustment and whitespace reduction +Flipped jitter plot version +Dynamic plot adjustment and whitespace reduction weight -feed +feed @@ -45,111 +45,111 @@ 300 350 400 - - - - - - - -casein -horsebean -linseed -meatmeal -soybean -sunflower - + + + + + + + +casein +horsebean +linseed +meatmeal +soybean +sunflower + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg index 907a0c4f..31030343 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg @@ -26,10 +26,10 @@ -Ridge plot version -Dynamic plot adjustment and whitespace reduction +Ridge plot version +Dynamic plot adjustment and whitespace reduction Petal.Length -Species +Species @@ -45,32 +45,32 @@ 5 6 7 - + - - + + - - - - - - - - - - + + + + + + + + + + - - - - -setosa -versicolor -virginica + + + + +setosa +versicolor +virginica diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg index 4e5fac5e..560e73fb 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg @@ -26,10 +26,10 @@ -Works for perpendicular x-axis labels too -Dynamic plot adjustment and whitespace reduction +Works for perpendicular x-axis labels too +Dynamic plot adjustment and whitespace reduction feed -weight +weight @@ -43,87 +43,87 @@ meatmeal soybean sunflower - - - - - - - - -100 -150 -200 -250 -300 -350 -400 - + + + + + + + + +100 +150 +200 +250 +300 +350 +400 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg index ca1165d8..d6e41836 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg @@ -27,7 +27,7 @@ treatment -I(decrease/100) +I(decrease/100) @@ -45,99 +45,99 @@ F G H - - - - - - - - -0% -20% -40% -60% -80% -100% -120% - + + + + + + + + +0% +20% +40% +60% +80% +100% +120% + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg b/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg index 11d81648..db189f77 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg @@ -33,9 +33,9 @@ -Ephemeral theme +Ephemeral theme Petal.Length -Sepal.Length +Sepal.Length @@ -53,202 +53,202 @@ 5 6 7 - - - - - - - - - -4.5 -5.0 -5.5 -6.0 -6.5 -7.0 -7.5 -8.0 - + + + + + + + + + +4.5 +5.0 +5.5 +6.0 +6.5 +7.0 +7.5 +8.0 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_ipsum.svg b/inst/tinytest/_tinysnapshot/tinytheme_ipsum.svg index 099ac8be..9b74daa3 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_ipsum.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_ipsum.svg @@ -26,85 +26,85 @@ - - -factor(am) -0 -1 -tinytheme("ipsum") + + +factor(am) +0 +1 +tinytheme("ipsum") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg 50 100 -150 +150 200 -250 -300 -10 -15 -20 -25 -30 +250 +300 +10 +15 +20 +25 +30 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_legend_bottom.svg b/inst/tinytest/_tinysnapshot/tinytheme_legend_bottom.svg index 3e2ce5de..c0794510 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_legend_bottom.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_legend_bottom.svg @@ -26,99 +26,99 @@ - - -factor(am) -0 -1 -tinytheme("clean") + legend = "bottom!" + + +factor(am) +0 +1 +tinytheme("clean") + legend = "bottom!" - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - - - - - - - -50 -100 -150 -200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - + + + + + + + +50 +100 +150 +200 +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_legend_left.svg b/inst/tinytest/_tinysnapshot/tinytheme_legend_left.svg index 570e1273..be9bad4c 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_legend_left.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_legend_left.svg @@ -26,99 +26,99 @@ - - -factor(am) -0 -1 -tinytheme("clean") + legend = "left!" + + +factor(am) +0 +1 +tinytheme("clean") + legend = "left!" - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - - - - - - - -50 -100 -150 -200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - + + + + + + + +50 +100 +150 +200 +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_minimal.svg b/inst/tinytest/_tinysnapshot/tinytheme_minimal.svg index ce968468..0e81523f 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_minimal.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_minimal.svg @@ -26,85 +26,85 @@ - - -factor(am) -0 -1 -tinytheme("minimal") + + +factor(am) +0 +1 +tinytheme("minimal") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg 50 100 -150 +150 200 -250 -300 -10 -15 -20 -25 -30 +250 +300 +10 +15 +20 +25 +30 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_ridge.svg b/inst/tinytest/_tinysnapshot/tinytheme_ridge.svg index 8134008a..15805627 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_ridge.svg @@ -26,88 +26,88 @@ - - -factor(am) -0 -1 -tinytheme("ridge") + + +factor(am) +0 +1 +tinytheme("ridge") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg - + - + - - + + 50 100 -150 +150 200 -250 -300 - - - - - - -10 -15 -20 -25 -30 - +250 +300 + + + + + + +10 +15 +20 +25 +30 + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_ridge2.svg b/inst/tinytest/_tinysnapshot/tinytheme_ridge2.svg index 5856a7a9..9d3c4f7c 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_ridge2.svg @@ -26,74 +26,74 @@ - - -factor(am) -0 -1 -tinytheme("ridge2") + + +factor(am) +0 +1 +tinytheme("ridge2") - - + + - -Title of the plot -hp -mpg + +Title of the plot +hp +mpg 50 100 -150 +150 200 -250 -300 -10 -15 -20 -25 -30 +250 +300 +10 +15 +20 +25 +30 - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/tinytheme_tufte.svg b/inst/tinytest/_tinysnapshot/tinytheme_tufte.svg index 9800d7d5..faa6f3d7 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_tufte.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_tufte.svg @@ -31,7 +31,7 @@ factor(am) 0 1 -tinytheme("tufte") +tinytheme("tufte") @@ -39,7 +39,7 @@ -Title of the plot +Title of the plot hp mpg diff --git a/inst/tinytest/_tinysnapshot/tinytheme_void.svg b/inst/tinytest/_tinysnapshot/tinytheme_void.svg index 14683c3d..bf1366fd 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_void.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_void.svg @@ -31,7 +31,7 @@ factor(am) 0 1 -tinytheme("void") +tinytheme("void") @@ -39,7 +39,7 @@ -Title of the plot +Title of the plot hp mpg From fd84857816c763247b1745058a78fbef303f66f1 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 12:24:34 -0700 Subject: [PATCH 20/30] avoid duplicate sanitize_legend calls --- R/legend.R | 2 - R/legend_multi.R | 9 +- R/tinyplot.R | 20 +-- inst/tinytest/_tinysnapshot/tinylabel.svg | 166 +++++++++++----------- 4 files changed, 101 insertions(+), 96 deletions(-) diff --git a/R/legend.R b/R/legend.R index 0da75be7..e02d7af1 100644 --- a/R/legend.R +++ b/R/legend.R @@ -487,8 +487,6 @@ build_legend_args = function( # Configuration gradient ) { - legend_args = sanitize_legend(legend, legend_args) - # Set defaults if (!exists("title", where = legend_args)) legend_args[["title"]] = by_dep legend_args[["pch"]] = legend_args[["pch"]] %||% pch diff --git a/R/legend_multi.R b/R/legend_multi.R index 8bc4b082..4b26cf82 100644 --- a/R/legend_multi.R +++ b/R/legend_multi.R @@ -35,8 +35,6 @@ prepare_legend_multi = function(settings) { ) ) - legend_args = sanitize_legend(legend, legend_args) - # Legend for grouping variable (by) lgby = list( legend_args = modifyList( @@ -162,10 +160,15 @@ draw_multi_legend = function( sub_positions = c("bottomleft!", "topleft!") } - # Assign positions of individual legends + # Assign positions of individual legends. Re-sanitize so the new per-legend + # position string ("bottomright!" etc.) populates legend_args[["x"]], which + # downstream code (e.g. build_legend_args) reads without further normalization. for (ll in seq_along(legend_list)) { legend_list[[ll]][["legend"]] = sub_positions[ll] legend_list[[ll]][["legend_args"]][["x"]] = NULL + legend_list[[ll]][["legend_args"]] = sanitize_legend( + sub_positions[ll], legend_list[[ll]][["legend_args"]] + ) } # diff --git a/R/tinyplot.R b/R/tinyplot.R index a6e0ddce..b0498f43 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -833,6 +833,17 @@ tinyplot.default = function( } else { settings$legend_args = list(x = NULL) } + # normalize legend position up front so downstream code can read + # legend_args[["x"]] directly (idempotent: guarded inside sanitize_legend). + # Use settings$legend (captured via substitute()) rather than the raw + # `legend` promise, since the latter may be an unevaluated call like + # `legend("bottom!", ...)` that would error if forced by is.null() etc. + # Skip when add=TRUE: no new legend is drawn in add-mode, and + # settings$legend is coerced to FALSE which sanitize_legend would + # spuriously normalize to the "right!" default. + if (!isTRUE(add)) { + settings$legend_args = sanitize_legend(settings$legend, settings$legend_args) + } # alias: bg = fill if (is.null(bg) && !is.null(fill)) settings$bg = fill @@ -963,14 +974,7 @@ tinyplot.default = function( .tpars = if (!is.null(.theme_def)) .theme_def else tpar() # Detect outer-legend sides (order: bottom, left, top, right). - # legend_args[["x"]] isn't normalized yet (sanitize_legend runs later - # inside draw_legend), so evaluate the raw `legend` argument here. - # When legend is NULL (user didn't specify), the default is "right!". - .lgnd_eval = tryCatch(eval(legend), error = function(e) legend) - if (is.null(.lgnd_eval)) .lgnd_eval = "right!" - .lgnd_pos = if (is.character(.lgnd_eval)) .lgnd_eval - else if (is.list(.lgnd_eval)) as.character(.lgnd_eval[[1]]) - else NULL + .lgnd_pos = settings$legend_args[["x"]] .outer_sides = c( grepl("bottom!$", .lgnd_pos), grepl("left!$", .lgnd_pos), diff --git a/inst/tinytest/_tinysnapshot/tinylabel.svg b/inst/tinytest/_tinysnapshot/tinylabel.svg index 6c9c4c4c..f89ccaa8 100644 --- a/inst/tinytest/_tinysnapshot/tinylabel.svg +++ b/inst/tinytest/_tinysnapshot/tinylabel.svg @@ -45,25 +45,25 @@ -Income +Income Life.Exp - - - - - - - - -$3,000 -$3,500 -$4,000 -$4,500 -$5,000 -$5,500 -$6,000 + + + + + + + + +$3,000 +$3,500 +$4,000 +$4,500 +$5,000 +$5,500 +$6,000 @@ -77,77 +77,77 @@ 71 72 73 - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 853135ff84babc37c8d2ce700475735725b39226 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 14:11:44 -0700 Subject: [PATCH 21/30] remove unreachable dynmar_side fallbacks --- R/facet.R | 43 +++++-------------------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/R/facet.R b/R/facet.R index adea9066..3d1b1b95 100644 --- a/R/facet.R +++ b/R/facet.R @@ -123,24 +123,7 @@ draw_facet_window = function( # Use that as the base instead of par("mar") which may have been # reset by the before.plot.new hook. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - if (!is.null(dynmar_computed)) { - omar = dynmar_computed - } else { - # Fallback: recompute if dynmar_computed wasn't passed (e.g. add = TRUE - # or future code paths). Build each side's margin additively; the - # theme's mar acts as baseline padding (via pmax). - omar = pmax(omar, c( - dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), - tpars = tpars), - dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), - tpars = tpars), - dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, - tpars = tpars), - dynmar_side(4, NULL, tpars = tpars) - )) - } + omar = dynmar_computed # Under facets, main/sub sit ABOVE the top facet strip. Bump the # outer top margin by the strip height so sub doesn't collide with # the strip. fmar[3] already captures facet_newlines and the @@ -225,27 +208,11 @@ draw_facet_window = function( # on our earlier calculations. par(mfrow = c(nfacet_rows, nfacet_cols)) } else if (dynmar) { - # Dynamic plot margin adjustments (no facets). The theme's `mar` acts - # as a baseline padding (via pmax); dynmar_side() adds enough space - # for tick rows, axis labels, main, and sub when present. Tick-label - # *width/height* (whtsbp) is added further below. + # Dynamic plot margin adjustments (no facets). Margins were pre-computed + # in tinyplot.default and passed via dynmar_computed; use them directly. + # Tick-label *width/height* (whtsbp) is added further below. side.sub = get_tpar("side.sub", tpar_list = tpars, default = 3) - if (!is.null(dynmar_computed)) { - omar = dynmar_computed - } else { - # Fallback: recompute if dynmar_computed wasn't passed. - omar = pmax(par("mar"), c( - dynmar_side(1, xlab, main = main, sub = sub, side.sub = side.sub, - axis_on = !identical(xaxt, "none") && !identical(xaxt, "n"), - tpars = tpars), - dynmar_side(2, ylab, - axis_on = !identical(yaxt, "none") && !identical(yaxt, "n"), - tpars = tpars), - dynmar_side(3, NULL, main = main, sub = sub, side.sub = side.sub, - tpars = tpars), - dynmar_side(4, NULL, tpars = tpars) - )) - } + omar = dynmar_computed if (type == "spineplot") omar[4] = 2.1 # FIXME catch for spineplot RHS axis labs if (par("las") %in% 1:2) { # extra whitespace bump on the y axis From c8fe8ad206d98848493166ef4d916bc75ad76931 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 14:35:39 -0700 Subject: [PATCH 22/30] fix r cmd check errors --- R/legend.R | 6 ++++++ man/facet.Rd | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/R/legend.R b/R/legend.R index e02d7af1..f341a3a8 100644 --- a/R/legend.R +++ b/R/legend.R @@ -487,6 +487,12 @@ build_legend_args = function( # Configuration gradient ) { + # Ensure legend_args[["x"]] is populated. When called from the main + # tinyplot pipeline, this is a no-op (sanitize_legend short-circuits on + # the is.null guard); when called standalone via the public draw_legend + # entry point, this normalizes the input. + legend_args = sanitize_legend(legend, legend_args) + # Set defaults if (!exists("title", where = legend_args)) legend_args[["title"]] = by_dep legend_args[["pch"]] = legend_args[["pch"]] %||% pch diff --git a/man/facet.Rd b/man/facet.Rd index 666b14eb..bd5f864a 100644 --- a/man/facet.Rd +++ b/man/facet.Rd @@ -58,7 +58,8 @@ draw_facet_window( y, ymax, ymin, - tpars = NULL + tpars = NULL, + dynmar_computed = NULL ) facet_layout(settings) From 9e3abfb0ba83e6778a944e5554fd41d504278ad8 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 15:57:18 -0700 Subject: [PATCH 23/30] test tweaks --- .../margins_multiline_labels.svg | 110 +++++++++--------- inst/tinytest/test-margins.R | 21 ++-- 2 files changed, 70 insertions(+), 61 deletions(-) diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg index 903e9001..6a6506eb 100644 --- a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg +++ b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg @@ -26,62 +26,68 @@ -E -F -A -B -C -D - - - - - - -2 -4 -6 -8 -10 - - - - - - -2 -4 -6 -8 -10 - +sub 1 +sub 2 +main 1 +main 2 +x lab1 +xlab 2 +ylab 1 +ylab 2 + + + + + + +2 +4 +6 +8 +10 + + + + + + + +1000 +1002 +1004 +1006 +1008 +1010 + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-margins.R b/inst/tinytest/test-margins.R index d65dada6..896e82bd 100644 --- a/inst/tinytest/test-margins.R +++ b/inst/tinytest/test-margins.R @@ -3,25 +3,28 @@ using("tinysnapshot") # Missing labels should reclaim margin space under dynmar themes. f = function() { - tinytheme("clean") - tinyplot(1:10, 1:10, xlab = NA, ylab = NA, main = NA) - tinytheme() + tinyplot(1:10, 1:10, xlab = NA, ylab = NA, main = NA, theme = "clean") } expect_snapshot_plot(f, label = "margins_missing_labels") # Multi-line annotation strings should increase margins as needed. f = function() { - tinytheme("clean") - tinyplot(1:10, 1:10, xlab = "A\nB", ylab = "C\nD", main = "E\nF") - tinytheme() + tinyplot( + 1000:1010, + xlab = "x lab1\nxlab 2", ylab = "ylab 1\nylab 2", + main = "main 1\nmain 2", sub = "sub 1\nsub 2", + theme = "clean" + ) } expect_snapshot_plot(f, label = "margins_multiline_labels") # Faceted path should also handle multi-line annotation strings. f = function() { - tinytheme("clean") - tinyplot(mpg ~ wt | cyl, data = mtcars, xlab = "Weight\n(1000 lbs)") - tinytheme() + tinyplot( + mpg ~ wt | cyl, data = mtcars, + xlab = "Weight\n(1000 lbs)", + theme = "clean" + ) } expect_snapshot_plot(f, label = "margins_facet_multiline") From 8c385e8a72cf1bf3955e554029f856a790404a97 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 17:36:45 -0700 Subject: [PATCH 24/30] issue #479 --- R/tinyplot.R | 28 +++++++++++++++++++++++++--- R/title.R | 11 ++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index b0498f43..ef289e86 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -972,6 +972,16 @@ tinyplot.default = function( } else NULL .theme_mar = if (!is.null(.theme_def[["mar"]])) .theme_def[["mar"]] else par("mar") .tpars = if (!is.null(.theme_def)) .theme_def else tpar() + # Merge pending before.plot.new hook values into .tpars so user + # overrides passed via tinytheme(..., las = 2) (or tpar(...)) are + # visible to dynmar_side()/whtsbp before plot.new fires. Without this, + # user overrides for par-level values (las, cex.lab, mgp, tcl, etc.) + # are queued in hook closures and unreachable from par() at this point. + .pending_hooks = get_environment_variable(".tpar_hooks") + for (.h in .pending_hooks) { + .bp = environment(.h)[["base_par"]] + if (is.list(.bp)) .tpars = modifyList(.tpars, .bp) + } # Detect outer-legend sides (order: bottom, left, top, right). .lgnd_pos = settings$legend_args[["x"]] @@ -1008,9 +1018,13 @@ tinyplot.default = function( # path's own plot.new(), after which the margins are reinstated # via dynmar_computed + .whtsbp before draw_title runs. - # Compute whtsbp (tick-label width/height bump) + # Compute whtsbp (tick-label width/height bump). Read `las` from .tpars + # (the theme definition) rather than par() — par("las") isn't set to the + # theme's intended value until the before.plot.new hook fires, but this + # block runs before that. .whtsbp = c(0, 0, 0, 0) - if (par("las") %in% 1:2) { + .las = get_tpar("las", tpar_list = .tpars, default = par("las")) + if (.las %in% 1:2) { if (type == "ridge") { yaxlabs = levels(y) } else if (!is.null(ylabs)) { @@ -1025,7 +1039,7 @@ tinyplot.default = function( grconvertX(0, from = "nfc", to = "lines") - 1 if (is.finite(whtsbp_y) && whtsbp_y > 0) .whtsbp[2] = whtsbp_y } - if (par("las") %in% 2:3) { + if (.las %in% 2:3) { xaxlabs = if (is.null(xlabs)) axisTicks(usr = extendrange(xlim, f = 0.04), log = par("xlog")) else if (!is.null(names(xlabs))) names(xlabs) else xlabs if (!is.null(xaxl)) xaxlabs = tinylabel(xaxlabs, xaxl) @@ -1033,6 +1047,13 @@ tinyplot.default = function( if (is.finite(whtsbp_x) && whtsbp_x > 0) .whtsbp[1] = whtsbp_x } + # Under facets, per-facet tick labels render smaller (scaled by + # cex_fct_adj), so whtsbp — which is computed from device font metrics + # — needs the same scaling to match the actual rendered margin used by + # draw_facet_window. Without this, draw_title's mar reserves too much + # space on the LHS and anchors the title too far right. + if (cex_fct_adj != 1) .whtsbp = .whtsbp * cex_fct_adj + dynmar_computed = .theme_mar + .dyn par(mar = dynmar_computed + .whtsbp) } @@ -1096,6 +1117,7 @@ tinyplot.default = function( } } draw_title(main, sub, xlab, ylab, legend, legend_args, opar, + xlab_line_offset = if (!is.null(dynmar_computed)) .whtsbp[1] else 0, ylab_line_offset = if (!is.null(dynmar_computed)) .whtsbp[2] else 0) } diff --git a/R/title.R b/R/title.R index 62e435d4..7781dc0a 100644 --- a/R/title.R +++ b/R/title.R @@ -1,4 +1,5 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar, + xlab_line_offset = 0, ylab_line_offset = 0) { # main title # Note that we include a special catch for the main title if legend is @@ -82,11 +83,15 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar, # `line = mgp[1] - (N-1)*cex`, which pushes line 1 up into the tick-label # zone. Shift `line` down so line 1 aligns with where a single-line xlab # would be (and the extra lines extend below). + # Also push down by xlab_line_offset (= .whtsbp[1]) when dynmar has + # reserved extra space for rotated (las=2/3) x-tick labels. args = list(xlab = xlab) xlab_lines = text_line_count(xlab) - if (xlab_lines > 1L) { - cex_xlab = get_tpar(c("cex.xlab", "cex.lab"), 1) - args[["line"]] = get_tpar("mgp")[1] + (xlab_lines - 1) * cex_xlab + cex_xlab = get_tpar(c("cex.xlab", "cex.lab"), 1) + if (xlab_lines > 1L || xlab_line_offset != 0) { + args[["line"]] = get_tpar("mgp")[1] + + (xlab_lines - 1) * cex_xlab + + xlab_line_offset } args[["adj"]] = get_tpar(c("adj.xlab", "adj")) do.call(title, args) From 55f9afbd540f3406c0a6e95d4a2331bc1fe28017 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 17:36:56 -0700 Subject: [PATCH 25/30] update test snapshots --- .../_tinysnapshot/margins_multiline_labels.svg | 12 ++++++------ .../_tinysnapshot/pointrange_with_layers_flipped.svg | 2 +- .../_tinysnapshot/ridge_basic_theme_ridge.svg | 2 +- .../_tinysnapshot/ridge_basic_theme_ridge2.svg | 2 +- .../_tinysnapshot/ridge_by_x_theme_ridge.svg | 2 +- .../_tinysnapshot/ridge_by_x_theme_ridge2.svg | 2 +- .../_tinysnapshot/ridge_by_y_theme_ridge.svg | 2 +- .../_tinysnapshot/ridge_by_y_theme_ridge2.svg | 2 +- .../_tinysnapshot/ridge_gradient_theme_ridge.svg | 2 +- .../_tinysnapshot/ridge_gradient_theme_ridge2.svg | 2 +- .../_tinysnapshot/ridge_theme_bg_numeric.svg | 2 +- inst/tinytest/_tinysnapshot/ridge_theme_palette.svg | 2 +- .../_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_clean.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_clean_facet.svg | 8 ++++---- .../tinytheme_dynamic_clean_spineplot.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_dark.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_dark_facet.svg | 8 ++++---- .../_tinysnapshot/tinytheme_dynamic_dynamic.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_jitter_flip.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_ridge.svg | 6 +++--- .../_tinysnapshot/tinytheme_dynamic_x_boxplot.svg | 8 ++++---- .../_tinysnapshot/tinytheme_dynamic_yaxl.svg | 2 +- inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg | 4 ++-- inst/tinytest/test-margins.R | 2 +- 25 files changed, 54 insertions(+), 54 deletions(-) diff --git a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg index 6a6506eb..e07d83e3 100644 --- a/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg +++ b/inst/tinytest/_tinysnapshot/margins_multiline_labels.svg @@ -26,12 +26,12 @@ -sub 1 -sub 2 -main 1 -main 2 -x lab1 -xlab 2 +sub 1 +sub 2 +main 1 +main 2 +xlab 1 +xlab 2 ylab 1 ylab 2 diff --git a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg index cb006f36..1b33106b 100644 --- a/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg +++ b/inst/tinytest/_tinysnapshot/pointrange_with_layers_flipped.svg @@ -26,7 +26,7 @@ -y +y x diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg index 0bedaeac..5168817a 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg index 41750039..f200d154 100644 --- a/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_basic_theme_ridge2.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species 1.5 2.0 diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg index 8aae131b..1cf08158 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge.svg @@ -45,7 +45,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg index 480b4382..0c024823 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_x_theme_ridge2.svg @@ -45,7 +45,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg index 7b862111..c49809a7 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge.svg @@ -40,7 +40,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg index 01d57e8b..ab221ec4 100644 --- a/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_by_y_theme_ridge2.svg @@ -40,7 +40,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg index 438fea0e..10cfe16b 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species diff --git a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg index e15acfcb..f18d999d 100644 --- a/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg +++ b/inst/tinytest/_tinysnapshot/ridge_gradient_theme_ridge2.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species 1.5 2.0 diff --git a/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg b/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg index ebf2fcf4..3c840d53 100644 --- a/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg +++ b/inst/tinytest/_tinysnapshot/ridge_theme_bg_numeric.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species 1.5 2.0 diff --git a/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg b/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg index e4d818ac..69fa6e1d 100644 --- a/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg +++ b/inst/tinytest/_tinysnapshot/ridge_theme_palette.svg @@ -26,7 +26,7 @@ -Sepal.Width +Sepal.Width Species 1.5 2.0 diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg index 266a4c23..79bdee34 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_boxplot_flip.svg @@ -26,9 +26,9 @@ -Flipped boxplot version -Dynamic plot adjustment and whitespace reduction -weight +Flipped boxplot version +Dynamic plot adjustment and whitespace reduction +weight feed diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg index 6642225e..9071cf55 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean.svg @@ -33,7 +33,7 @@ setosa versicolor virginica -For themes with las = 1, etc. +For themes with las = 1, etc. @@ -41,8 +41,8 @@ -Dynamic plot adjustment and whitespace reduction -Petal.Length +Dynamic plot adjustment and whitespace reduction +Petal.Length I(Sepal.Length * 1e+09) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg index 7017dbfe..597fadf2 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_facet.svg @@ -36,7 +36,7 @@ - - - - disp -Works with facets too +Works with facets too @@ -44,9 +44,9 @@ -Dynamic plot adjustment and whitespace reduction -I(hp * 100) -I(mpg * 1000) +Dynamic plot adjustment and whitespace reduction +I(hp * 100) +I(mpg * 1000) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg index 3b6b7f5c..c2d285c7 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_clean_spineplot.svg @@ -26,9 +26,9 @@ -Spineplot version -Dynamic plot adjustment and whitespace reduction -Petal.Length +Spineplot version +Dynamic plot adjustment and whitespace reduction +Petal.Length Species diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg index 805a94d1..afecad7e 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark.svg @@ -33,7 +33,7 @@ setosa versicolor virginica -For themes with las = 1, etc. +For themes with las = 1, etc. @@ -41,8 +41,8 @@ -Dynamic plot adjustment and whitespace reduction -Petal.Length +Dynamic plot adjustment and whitespace reduction +Petal.Length I(Sepal.Length * 1e+09) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg index 6f3527fe..7f78a655 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dark_facet.svg @@ -36,7 +36,7 @@ - - - - disp -Works with facets too +Works with facets too @@ -44,9 +44,9 @@ -Dynamic plot adjustment and whitespace reduction -I(hp * 100) -I(mpg * 1000) +Dynamic plot adjustment and whitespace reduction +I(hp * 100) +I(mpg * 1000) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg index 14e33db3..1850ee5e 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_dynamic.svg @@ -33,7 +33,7 @@ setosa versicolor virginica -For themes with las = 1, etc. +For themes with las = 1, etc. @@ -41,8 +41,8 @@ -Dynamic plot adjustment and whitespace reduction -Petal.Length +Dynamic plot adjustment and whitespace reduction +Petal.Length I(Sepal.Length * 1e+09) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg index d0e6b9ea..e64cbd3c 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_jitter_flip.svg @@ -26,9 +26,9 @@ -Flipped jitter plot version -Dynamic plot adjustment and whitespace reduction -weight +Flipped jitter plot version +Dynamic plot adjustment and whitespace reduction +weight feed diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg index 31030343..4ea57844 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_ridge.svg @@ -26,9 +26,9 @@ -Ridge plot version -Dynamic plot adjustment and whitespace reduction -Petal.Length +Ridge plot version +Dynamic plot adjustment and whitespace reduction +Petal.Length Species diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg index 560e73fb..bcf23ce9 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_x_boxplot.svg @@ -26,10 +26,10 @@ -Works for perpendicular x-axis labels too -Dynamic plot adjustment and whitespace reduction -feed -weight +Works for perpendicular x-axis labels too +Dynamic plot adjustment and whitespace reduction +feed +weight diff --git a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg index d6e41836..a99ea0d4 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_dynamic_yaxl.svg @@ -26,7 +26,7 @@ -treatment +treatment I(decrease/100) diff --git a/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg b/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg index db189f77..9b3a4897 100644 --- a/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg +++ b/inst/tinytest/_tinysnapshot/tinytheme_ephemeral.svg @@ -33,8 +33,8 @@ -Ephemeral theme -Petal.Length +Ephemeral theme +Petal.Length Sepal.Length diff --git a/inst/tinytest/test-margins.R b/inst/tinytest/test-margins.R index 896e82bd..8f56e59d 100644 --- a/inst/tinytest/test-margins.R +++ b/inst/tinytest/test-margins.R @@ -11,7 +11,7 @@ expect_snapshot_plot(f, label = "margins_missing_labels") f = function() { tinyplot( 1000:1010, - xlab = "x lab1\nxlab 2", ylab = "ylab 1\nylab 2", + xlab = "xlab 1\nxlab 2", ylab = "ylab 1\nylab 2", main = "main 1\nmain 2", sub = "sub 1\nsub 2", theme = "clean" ) From d0c4652f5d8b6f3aa5507a70b990817d7d68807c Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 27 Apr 2026 21:51:24 -0700 Subject: [PATCH 26/30] news and dev version bump --- DESCRIPTION | 2 +- NEWS.md | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4dc431ed..4f4886b2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: tinyplot Type: Package Title: Lightweight Extension of the Base R Graphics System -Version: 0.6.1 +Version: 0.6.1.99 Date: 2026-03-28 Authors@R: c( diff --git a/NEWS.md b/NEWS.md index 27402614..82617f03 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,33 @@ _If you are viewing this file on CRAN, please check the [latest NEWS](https://grantmcdermott.com/tinyplot/NEWS.html) on our website where the formatting is also better._ +## Development + +### Aesthetic changes + +- **Dynamic themes**. We have significantly refactored how our _dynamic_ themes + work. Recall, these are themes like `"dynamic"`, `"clean"`, `"bw"`, etc. that + automatically adjust margin spacing and other elements to reduce whitespace. + Our refactoring and internal changes have some user-facing implications, + insofar as they can affect the appearance of your plots. Technically, these + are "breaking" aesthetic changes---since your plot might look slightly + different from before---but we hope that you will agree that these are clear + improvements. (#549 @grantmcdermott, @vincentarelbundock) + + - Plot margins now correctly respond to missing and/or multi-line `main`, + `sub`, and `x`/`y` axis titles. For example, a plot with a `main` (or `sub`) + title will expand to the top of the device region to reduce excess + whitespace. (#303) + - Left-justified `main` and `sub` titles now correctly anchor to the y-axis + line, even when long horizontal tick labels widen the left margin. (#479) + - Similarly, center-justified axis titles are now anchored on the relevant + axis alone, rather than the full plot region. (#573) + +### New features + +- New `"dynamic"` theme that now serves as the foundation for all other dynamic + (tiny)themes. (#549 @grantmcdermott) + ## v0.6.1 ### Aesthetic changes From cd06059ec2b2f2d4b21a1f8c39e4587c18f13b2d Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Apr 2026 12:55:23 -0700 Subject: [PATCH 27/30] issue #574 --- NEWS.md | 2 ++ R/tinytheme.R | 4 ++-- R/title.R | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 82617f03..2bd2a57c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -25,6 +25,8 @@ where the formatting is also better._ line, even when long horizontal tick labels widen the left margin. (#479) - Similarly, center-justified axis titles are now anchored on the relevant axis alone, rather than the full plot region. (#573) + - `cex.xlab` and `cex.ylab` now correctly control axis title size. The + more general `cex.lab` is still respected as a fallback. (#574) ### New features diff --git a/R/tinytheme.R b/R/tinytheme.R index 102a7e4c..166518f0 100644 --- a/R/tinytheme.R +++ b/R/tinytheme.R @@ -196,8 +196,8 @@ theme_default = list( cex = par("cex"), #1, cex.axis = par("cex.axis"), #1, cex.main = par("cex.main"), #1.2, - cex.xlab = par("cex.axis"), #1, - cex.ylab = par("cex.axis"), #1, + cex.xlab = NULL, # defer to par("cex.lab") unless set explicitly + cex.ylab = NULL, # defer to par("cex.lab") unless set explicitly col.axis = par("col.axis"), #1, col.xaxs = par("col.axis"), #1, col.yaxs = par("col.axis"), #1, diff --git a/R/title.R b/R/title.R index 7781dc0a..64e4a69f 100644 --- a/R/title.R +++ b/R/title.R @@ -94,14 +94,17 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar, xlab_line_offset } args[["adj"]] = get_tpar(c("adj.xlab", "adj")) + args[["cex.lab"]] = cex_xlab do.call(title, args) # ylab: base R already places multi-line text correctly (outermost line at # mgp[1], subsequent lines closer to the plot), so no line shift needed. args = list(ylab = ylab) + cex_ylab = get_tpar(c("cex.ylab", "cex.lab"), 1) if (ylab_line_offset != 0) { args[["line"]] = get_tpar("mgp")[1] + ylab_line_offset } args[["adj"]] = get_tpar(c("adj.ylab", "adj")) + args[["cex.lab"]] = cex_ylab do.call(title, args) } From fc63283f580e190d87ce282cf8bd0da79d72d5bd Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Tue, 28 Apr 2026 12:59:30 -0700 Subject: [PATCH 28/30] scalar comments for provenance --- R/utils.R | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/R/utils.R b/R/utils.R index a2992064..c8658875 100644 --- a/R/utils.R +++ b/R/utils.R @@ -33,6 +33,9 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, mgp = get_tpar("mgp", tpar_list = tpars) tcl = get_tpar("tcl", tpar_list = tpars, default = par("tcl")) tick_extent = if (side %in% 1:2 && isTRUE(axis_on)) { + # |tcl| = tick mark length (outward); mgp[2] = tick-label distance from + # axis; +1 = one line for the tick-label text itself. These mirror base + # R's default layout: par(tcl = -0.5, mgp = c(3,1,0)) gives 0.5+1+1=2.5. max(0, -tcl) + mgp[2] + 1 } else 0 label_extent = 0 @@ -45,6 +48,10 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, # Last-line baseline sits at mgp[1] + (N-1)*cex (after line-shift in # draw_title); add a full line to cover ascender+descender so the text # doesn't clip against the device edge. + # TODO: the +1 constant doesn't scale with cex_lab, so large values + # (e.g. cex.xlab = 3) under-reserve margin and the title overlaps + # tick labels. Fixing this requires also pushing the draw-position + # (line arg in draw_title) further out. See "P.S." in #574. label_extent = mgp[1] + (lines - 1) * cex_lab + 1 } mar = max(tick_extent, label_extent) @@ -52,21 +59,24 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, mlines = text_line_count(main) if (mlines >= 1L) { cex_main = get_tpar("cex.main", tpar_list = tpars, default = 1.2) - # Main last-line baseline sits 0.7 lines above the box. Additional - # lines stack upward at cex_main per row. The top line's visible - # extent reaches ~0.6 * cex_main above its baseline (empirical from - # strheight("X") / csi). + # 0.7 = distance (in lines) from plot box to main baseline. Matches + # line_main = mgp[3] + 0.7 - 0.1 in draw_title (mgp[3] default 0). + # Chosen to visually match base R's default title gap at cex.main=1.2 + # with par(mar=c(5.1,4.1,4.1,2.1), mgp=c(3,1,0)). + # 0.6 = empirical ascender fraction: the top line's visible extent + # reaches ~0.6 * cex_main above its baseline. Derived from + # strheight("X") / par("csi") ≈ 0.6 on standard devices. mar = mar + 0.7 + (mlines - 1 + 0.6) * cex_main } } slines = text_line_count(sub) if (slines >= 1L && side == side.sub && side %in% c(1L, 3L)) { cex_sub = get_tpar("cex.sub", tpar_list = tpars, default = 1.2) - # First sub row gets a 0.2-line extra bump; extra lines add cex_sub. - # The top line's visible extent reaches ~0.6 * cex_sub above baseline. - # If main is ALSO present on the same side, its ascender already covers - # the top — the sub contribution is just the stacked sub row height. - # Otherwise, add the sub's own ascender. + # Sub sits between the plot box and main (when side.sub = 3). + # 0.2 = breathing room between sub baseline and the element above it + # (plot box or main). Tuned visually to avoid crowding at default cex. + # 0.6 = same ascender fraction as main (see above). Applied only when + # main is absent, since main's ascender already covers the top. has_main_here = side == 3L && text_line_count(main) >= 1L asc = if (has_main_here) 0 else 0.6 * cex_sub mar = mar + (cex_sub + 0.2) + (slines - 1) * cex_sub + asc From 311a4830fb6f3c9b9cfc401b2ad353d2c620e22a Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 4 May 2026 10:18:26 -0700 Subject: [PATCH 29/30] custom height adjustment for math expressions --- R/title.R | 12 +- R/utils.R | 9 ++ .../_tinysnapshot/margins_math_expression.svg | 109 ++++++++++++++++++ inst/tinytest/test-margins.R | 9 ++ 4 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 inst/tinytest/_tinysnapshot/margins_math_expression.svg diff --git a/R/title.R b/R/title.R index 64e4a69f..5dffd555 100644 --- a/R/title.R +++ b/R/title.R @@ -88,10 +88,18 @@ draw_title = function(main, sub, xlab, ylab, legend, legend_args, opar, args = list(xlab = xlab) xlab_lines = text_line_count(xlab) cex_xlab = get_tpar(c("cex.xlab", "cex.lab"), 1) - if (xlab_lines > 1L || xlab_line_offset != 0) { + # Compute expression height excess (same logic as dynmar_side) + xlab_expr_excess = 0 + if (is.language(xlab)) { + expr_lines = strheight(xlab, units = "inches", cex = cex_xlab) / par("csi") + text_lines = strheight("X", units = "inches", cex = cex_xlab) / par("csi") + xlab_expr_excess = max(0, expr_lines - text_lines) + } + if (xlab_lines > 1L || xlab_line_offset != 0 || xlab_expr_excess > 0) { args[["line"]] = get_tpar("mgp")[1] + (xlab_lines - 1) * cex_xlab + - xlab_line_offset + xlab_line_offset + + xlab_expr_excess } args[["adj"]] = get_tpar(c("adj.xlab", "adj")) args[["cex.lab"]] = cex_xlab diff --git a/R/utils.R b/R/utils.R index c8658875..3e647a11 100644 --- a/R/utils.R +++ b/R/utils.R @@ -53,6 +53,15 @@ dynmar_side = function(side, label, main = NULL, sub = NULL, # tick labels. Fixing this requires also pushing the draw-position # (line arg in draw_title) further out. See "P.S." in #574. label_extent = mgp[1] + (lines - 1) * cex_lab + 1 + # Expressions (e.g., ylab = expression(mm^{1/2})) can be taller than a + # plain text line due to superscripts, subscripts, fractions, etc. Measure + # the actual rendered height and add the excess over a normal text line. + if (is.language(label)) { + expr_lines = strheight(label, units = "inches", cex = cex_lab) / par("csi") + text_lines = strheight("X", units = "inches", cex = cex_lab) / par("csi") + excess = expr_lines - text_lines + if (excess > 0) label_extent = label_extent + excess + } } mar = max(tick_extent, label_extent) if (side == 3L) { diff --git a/inst/tinytest/_tinysnapshot/margins_math_expression.svg b/inst/tinytest/_tinysnapshot/margins_math_expression.svg new file mode 100644 index 00000000..293d6365 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/margins_math_expression.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + +Δ +y +Δ +x + +P +r +e +c +i +p +i +t +a +t +i +o +n + +[ + +m +m +1 + +2 + +] + + + + + + +2 +4 +6 +8 +10 + + + + + + +2 +4 +6 +8 +10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-margins.R b/inst/tinytest/test-margins.R index 8f56e59d..703983f3 100644 --- a/inst/tinytest/test-margins.R +++ b/inst/tinytest/test-margins.R @@ -84,3 +84,12 @@ expect_true( }, info = "bottom_margin_grows_for_multiline_xlab" ) + +# Expression labels should expand margins beyond plain text (#549) +f = function() { + tinyplot(1:10, + xlab = expression(frac(Delta*y, Delta*x)), + ylab = expression(Precipitation~"["~mm^{1/2}~"]"), + theme = "clean") +} +expect_snapshot_plot(f, label = "margins_math_expression") \ No newline at end of file From 16f526831ad9914f893f863a65514b1b4ba17199 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Mon, 4 May 2026 10:38:39 -0700 Subject: [PATCH 30/30] simplify test - drop "Delta" part since that triggers a font rendering issue on the CI's Linux box --- .../_tinysnapshot/margins_math_expression.svg | 146 +++++++++--------- inst/tinytest/test-margins.R | 2 +- 2 files changed, 73 insertions(+), 75 deletions(-) diff --git a/inst/tinytest/_tinysnapshot/margins_math_expression.svg b/inst/tinytest/_tinysnapshot/margins_math_expression.svg index 293d6365..5df90ca8 100644 --- a/inst/tinytest/_tinysnapshot/margins_math_expression.svg +++ b/inst/tinytest/_tinysnapshot/margins_math_expression.svg @@ -26,84 +26,82 @@ -Δ -y -Δ -x - -P -r -e -c -i -p -i -t -a -t -i -o -n - -[ - -m -m -1 - -2 - -] - - - - - - -2 -4 -6 -8 -10 - - - - - - -2 -4 -6 -8 -10 - +y +x + +P +r +e +c +i +p +i +t +a +t +i +o +n + +[ + +m +m +1 + +2 + +] + + + + + + +2 +4 +6 +8 +10 + + + + + + +2 +4 +6 +8 +10 + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-margins.R b/inst/tinytest/test-margins.R index 703983f3..32f353bd 100644 --- a/inst/tinytest/test-margins.R +++ b/inst/tinytest/test-margins.R @@ -88,7 +88,7 @@ expect_true( # Expression labels should expand margins beyond plain text (#549) f = function() { tinyplot(1:10, - xlab = expression(frac(Delta*y, Delta*x)), + xlab = expression(frac(y, x)), ylab = expression(Precipitation~"["~mm^{1/2}~"]"), theme = "clean") }