From 1359b385314d06b773d0038cd891390b7dd9ed7b Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 09:15:51 +0200 Subject: [PATCH 1/7] Add more features to `tinyplot()` --- DESCRIPTION | 2 +- R/tinyplot.R | 28 +++++++++++++++---- ...visualisation_recipe.estimate_predicted.Rd | 21 +++++++++++--- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6898ecf90..083fc3e17 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: modelbased Title: Estimation of Model-Based Predictions, Contrasts and Means -Version: 0.16.0.6 +Version: 0.16.0.7 Authors@R: c(person(given = "Dominique", family = "Makowski", diff --git a/R/tinyplot.R b/R/tinyplot.R index 1b9f2e678..e06161a43 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -43,25 +43,38 @@ #' # Reset to default theme #' tinytheme() #' -#' # facets, grids, legends +#' # facets +#' # ---------------------- +#' # when using facets, the `tinyplot()` method checks if the legend is +#' # redundant (because it already appears in the facets), and if so, it +#' # removes the legend. Set `legend = TRUE` to add it back. +#' #' data(efc, package = "modelbased") +#' # convert to factors, assign labels. we use datawizard::to_factor() in +#' # the second row to automatically assign value labels as factor levels. +#' # because labels are too long for `c172code`, we assign new labels using +#' # `as.factor()` #' efc$c172code <- factor(efc$c172code, labels = c("low", "mid", "high")) +#' efc$e42dep <- datawizard::to_factor(efc$e42dep) +#' # fit model #' m <- lm(neg_c_7 ~ c172code * e42dep, data = efc) #' em <- estimate_means(m, c("c172code", "e42dep")) #' #' # for facets, it can be useful to remove dodging #' plt(em, facet = ~e42dep, dodge = 0, theme = "float") #' -#' # remove x-axis limits adjustments with `xlim`, remove legend +#' # remove x-axis limits adjustments with `xlim` #' plt( #' em, #' facet = ~e42dep, #' dodge = 0, #' theme = "float", #' xlim = c(1, 3), -#' grid = TRUE, -#' legend = FALSE +#' grid = TRUE #' ) +#' +#' # add back legend +#' plt(em, facet = ~e42dep, legend = TRUE) #' } #' @exportS3Method tinyplot::tinyplot tinyplot.estimate_means <- function( @@ -192,7 +205,12 @@ tinyplot.estimate_means <- function( # we also need to account for custom legend options passed through dots if (is.null(dots$legend)) { - dots$legend <- list(title = aes$labs$colour) + # check if legend is already in facets - if so, we don't need a legend + if (!is.null(dots$facet) && all(all.vars(dots$facet) %in% aes$color)) { + dots$legend <- FALSE + } else { + dots$legend <- list(title = aes$labs$colour) + } } else if (inherits(dots$legend, "list")) { if (!("title" %in% names(dots$legend))) { dots$legend <- utils::modifyList( diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index e5d536f8c..94984240b 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -203,25 +203,38 @@ plt_add(type = "l", lty = 2) # Reset to default theme tinytheme() -# facets, grids, legends +# facets +# ---------------------- +# when using facets, the `tinyplot()` method checks if the legend is +# redundant (because it already appears in the facets), and if so, it +# removes the legend. Set `legend = TRUE` to add it back. + data(efc, package = "modelbased") +# convert to factors, assign labels. we use datawizard::to_factor() in +# the second row to automatically assign value labels as factor levels. +# because labels are too long for `c172code`, we assign new labels using +# `as.factor()` efc$c172code <- factor(efc$c172code, labels = c("low", "mid", "high")) +efc$e42dep <- datawizard::to_factor(efc$e42dep) +# fit model m <- lm(neg_c_7 ~ c172code * e42dep, data = efc) em <- estimate_means(m, c("c172code", "e42dep")) # for facets, it can be useful to remove dodging plt(em, facet = ~e42dep, dodge = 0, theme = "float") -# remove x-axis limits adjustments with `xlim`, remove legend +# remove x-axis limits adjustments with `xlim` plt( em, facet = ~e42dep, dodge = 0, theme = "float", xlim = c(1, 3), - grid = TRUE, - legend = FALSE + grid = TRUE ) + +# add back legend +plt(em, facet = ~e42dep, legend = TRUE) } \dontshow{\}) # examplesIf} \dontshow{if (all(insight::check_if_installed(c("marginaleffects", "see", "ggplot2", "lme4"), quietly = TRUE)) && getRversion() >= "4.1.0") withAutoprint(\{ # examplesIf} From aae277966e3a48826be6ff87b3afe328323a4361 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 09:28:01 +0200 Subject: [PATCH 2/7] add size args --- R/tinyplot.R | 30 ++++++++++++++----- ...visualisation_recipe.estimate_predicted.Rd | 2 ++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index e06161a43..5e9aaab76 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -84,6 +84,8 @@ tinyplot.estimate_means <- function( show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + size_point = NULL, + linewidth = NULL, ... ) { insight::check_if_installed("tinyplot") @@ -159,14 +161,6 @@ tinyplot.estimate_means <- function( dots$frame <- FALSE } - # move geoms on x-axis closer together - if (is.null(dots$xlim) && !is.numeric(data[[aes$x]])) { - n_categories <- insight::n_unique(data[[aes$x]]) - if (!is.null(n_categories)) { - dots$xlim <- c(0.5, n_categories + 0.5) - } - } - # add remaining aesthetics to the plot description as symbols elements <- c("xmin", "xmax", "ymin", "ymax") plot_args <- lapply(elements, function(el) { @@ -177,6 +171,26 @@ tinyplot.estimate_means <- function( }) names(plot_args) <- elements + # margins ------------------------------- + + # move geoms on x-axis closer together + if (is.null(dots$xlim) && !is.numeric(data[[aes$x]])) { + n_categories <- insight::n_unique(data[[aes$x]]) + if (!is.null(n_categories)) { + dots$xlim <- c(0.5, n_categories + 0.5) + } + } + + # geom sizes ------------------------------- + + if (is.null(dots$cex) && !is.null(size_point)) { + dots$cex <- size_point + } + + if (is.null(dots$lwd) && !is.null(linewidth)) { + dots$lwd <- linewidth + } + # dodging ------------------------------- # Set dodge value for grouped point or pointrange plots. diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index 94984240b..7b6903e3f 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -20,6 +20,8 @@ show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + size_point = NULL, + linewidth = NULL, ... ) From 5668a85cbcdbcb899961512a5770ec7023cd2d8c Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 09:30:26 +0200 Subject: [PATCH 3/7] resolve comment --- R/tinyplot.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index 5e9aaab76..88eb10035 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -220,7 +220,11 @@ tinyplot.estimate_means <- function( # we also need to account for custom legend options passed through dots if (is.null(dots$legend)) { # check if legend is already in facets - if so, we don't need a legend - if (!is.null(dots$facet) && all(all.vars(dots$facet) %in% aes$color)) { + if ( + !is.null(dots$facet) && + !is.null(aes$color) && + all(all.vars(dots$facet) %in% aes$color) + ) { dots$legend <- FALSE } else { dots$legend <- list(title = aes$labs$colour) From 633b49abf5c0814b624845b259349241324380e1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 09:46:56 +0200 Subject: [PATCH 4/7] add more convenience arguments --- R/tinyplot.R | 22 +++++++++++++++++++ ...visualisation_recipe.estimate_predicted.Rd | 12 ++++++++++ 2 files changed, 34 insertions(+) diff --git a/R/tinyplot.R b/R/tinyplot.R index 88eb10035..03f4a1041 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -5,6 +5,13 @@ #' @param dodge Dodge value for grouped plots. If `NULL` (the default), then #' the dodging behavior is determined by the number of groups and #' `getOption("modelbased_tinyplot_dodge")`. +#' @param size_title,size_axis_title,size_axis_text Numeric, set the size of +#' plot title, axis title or axis labels. If not `NULL`, `par()` is called +#' temporarily to set `cex.main`, `cex.axis` and `cex.lab`. These values are set +#' back to their default before the plot-method was called. The default size is +#' `1`. Larger values increase text sizes and vice versa. +#' @param size_point,linewidth Size of points and lines in the plot. Default is +#' `1`. Larger values increase text sizes and vice versa. #' @param ... Other arguments passed to \code{\link[tinyplot]{tinyplot}}. #' #' @examplesIf all(insight::check_if_installed(c("tinyplot", "marginaleffects"), quietly = TRUE)) @@ -84,6 +91,9 @@ tinyplot.estimate_means <- function( show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + size_title = NULL, + size_axis_title = NULL, + size_axis_text = NULL, size_point = NULL, linewidth = NULL, ... @@ -289,6 +299,18 @@ tinyplot.estimate_means <- function( } } + # set text sizes -------------------------------- + text_sizes <- insight::compact_list(list( + cex.axis = size_axis_text, + cex.main = size_title, + cex.lab = size_axis_title + )) + + if (!is.null(text_sizes)) { + old_pars <- graphics::par(text_sizes) + on.exit(graphics::par(old_pars)) + } + # plot it! suppressWarnings(do.call(tinyplot::tinyplot, plot_args)) } diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index 7b6903e3f..b73f1682a 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -20,6 +20,9 @@ show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + size_title = NULL, + size_axis_title = NULL, + size_axis_text = NULL, size_point = NULL, linewidth = NULL, ... @@ -98,6 +101,15 @@ predictor. Use \code{FALSE} to always use continuous color scales for numeric predictors. It is possible to set a global default value using \code{options()}, e.g. \code{options(modelbased_numeric_as_discrete = 10)}.} +\item{size_title, size_axis_title, size_axis_text}{Numeric, set the size of +plot title, axis title or axis labels. If not \code{NULL}, \code{par()} is called +temporarily to set \code{cex.main}, \code{cex.axis} and \code{cex.lab}. These values are set +back to their default before the plot-method was called. The default size is +\code{1}. Larger values increase text sizes and vice versa.} + +\item{size_point, linewidth}{Size of points and lines in the plot. Default is +\code{1}. Larger values increase text sizes and vice versa.} + \item{show_residuals}{Logical, if \code{TRUE}, display residuals of the model as a background to the model-based estimation. Residuals will be computed for the predictors in the data grid, using \code{\link[=residualize_over_grid]{residualize_over_grid()}}. For mixed From 83fa27b6ed759fc7d71024c6f46389d1cdb276d1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 09:49:04 +0200 Subject: [PATCH 5/7] docs --- R/visualisation_recipe.R | 4 +++- man/visualisation_recipe.estimate_predicted.Rd | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/R/visualisation_recipe.R b/R/visualisation_recipe.R index d90f54383..e712c8008 100644 --- a/R/visualisation_recipe.R +++ b/R/visualisation_recipe.R @@ -70,7 +70,9 @@ #' #' @return An object of class `visualisation_recipe` that describes the layers #' used to create a plot based on `{ggplot2}`. The related `plot()` method is in -#' the `{see}` package. +#' the `{see}` package. For `tinyplot()` (or its alias `plt()`), a base graphics +#' R plot is created, which can be modified further using classic R graphics +#' code. #' #' @section Global Options to Customize Plots: #' Some arguments for `plot()` can get global defaults using `options()`: diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index b73f1682a..095aa7cca 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -128,7 +128,9 @@ and error bars are shown. It is possible to set a global default value using \value{ An object of class \code{visualisation_recipe} that describes the layers used to create a plot based on \code{{ggplot2}}. The related \code{plot()} method is in -the \code{{see}} package. +the \code{{see}} package. For \code{tinyplot()} (or its alias \code{plt()}), a base graphics +R plot is created, which can be modified further using classic R graphics +code. } \description{ Most \strong{modelbased} objects can be visualized using either the \code{plot()} From 9929ba1d7afd3127ef28cb047efaccacdd07b2a7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 11:22:39 +0200 Subject: [PATCH 6/7] resolve comments --- R/tinyplot.R | 21 ++++++++++--------- ...visualisation_recipe.estimate_predicted.Rd | 12 +++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index 03f4a1041..1766fd877 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -7,11 +7,11 @@ #' `getOption("modelbased_tinyplot_dodge")`. #' @param size_title,size_axis_title,size_axis_text Numeric, set the size of #' plot title, axis title or axis labels. If not `NULL`, `par()` is called -#' temporarily to set `cex.main`, `cex.axis` and `cex.lab`. These values are set -#' back to their default before the plot-method was called. The default size is -#' `1`. Larger values increase text sizes and vice versa. -#' @param size_point,linewidth Size of points and lines in the plot. Default is -#' `1`. Larger values increase text sizes and vice versa. +#' temporarily to set `cex.main`, `cex.axis` and `cex.lab`. The original values +#' are restored afterwards. The default size is `1`. Larger values increase text +#' sizes and vice versa. +#' @param size_point,size_line Size of points and lines in the plot. Default is +#' `1`. Larger values increase point/line sizes and vice versa. #' @param ... Other arguments passed to \code{\link[tinyplot]{tinyplot}}. #' #' @examplesIf all(insight::check_if_installed(c("tinyplot", "marginaleffects"), quietly = TRUE)) @@ -95,7 +95,7 @@ tinyplot.estimate_means <- function( size_axis_title = NULL, size_axis_text = NULL, size_point = NULL, - linewidth = NULL, + size_line = NULL, ... ) { insight::check_if_installed("tinyplot") @@ -197,8 +197,8 @@ tinyplot.estimate_means <- function( dots$cex <- size_point } - if (is.null(dots$lwd) && !is.null(linewidth)) { - dots$lwd <- linewidth + if (is.null(dots$lwd) && !is.null(size_line)) { + dots$lwd <- size_line } # dodging ------------------------------- @@ -233,6 +233,7 @@ tinyplot.estimate_means <- function( if ( !is.null(dots$facet) && !is.null(aes$color) && + length(all.vars(dots$facet)) > 0 && all(all.vars(dots$facet) %in% aes$color) ) { dots$legend <- FALSE @@ -306,9 +307,9 @@ tinyplot.estimate_means <- function( cex.lab = size_axis_title )) - if (!is.null(text_sizes)) { + if (!is.null(text_sizes) && length(text_sizes)) { old_pars <- graphics::par(text_sizes) - on.exit(graphics::par(old_pars)) + on.exit(graphics::par(old_pars), add = TRUE) } # plot it! diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index 095aa7cca..a9d1b0fe2 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -24,7 +24,7 @@ size_axis_title = NULL, size_axis_text = NULL, size_point = NULL, - linewidth = NULL, + size_line = NULL, ... ) @@ -103,12 +103,12 @@ e.g. \code{options(modelbased_numeric_as_discrete = 10)}.} \item{size_title, size_axis_title, size_axis_text}{Numeric, set the size of plot title, axis title or axis labels. If not \code{NULL}, \code{par()} is called -temporarily to set \code{cex.main}, \code{cex.axis} and \code{cex.lab}. These values are set -back to their default before the plot-method was called. The default size is -\code{1}. Larger values increase text sizes and vice versa.} +temporarily to set \code{cex.main}, \code{cex.axis} and \code{cex.lab}. The original values +are restored afterwards. The default size is \code{1}. Larger values increase text +sizes and vice versa.} -\item{size_point, linewidth}{Size of points and lines in the plot. Default is -\code{1}. Larger values increase text sizes and vice versa.} +\item{size_point, size_line}{Size of points and lines in the plot. Default is +\code{1}. Larger values increase point/line sizes and vice versa.} \item{show_residuals}{Logical, if \code{TRUE}, display residuals of the model as a background to the model-based estimation. Residuals will be computed for the From 9d3b70304f3c0905fbbeac6f14464e17f3f23496 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 7 Jul 2026 11:46:18 +0200 Subject: [PATCH 7/7] add colors argument --- R/tinyplot.R | 21 ++++++++++++++++++- ...visualisation_recipe.estimate_predicted.Rd | 18 +++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index 1766fd877..bb3fbe00d 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -11,7 +11,19 @@ #' are restored afterwards. The default size is `1`. Larger values increase text #' sizes and vice versa. #' @param size_point,size_line Size of points and lines in the plot. Default is -#' `1`. Larger values increase point/line sizes and vice versa. +#' `1`. Larger values increase point/line sizes and vice versa. If argument +#' `cex` is used, `size_point` will be ignored. Same for argument `lwd`, which +#' overrides `size_line`. +#' @param colors Colors or color palette used for plotting. Following options +#' are allowed: +#' - A string corresponding to one of the many palettes listed by either +#' `palette.pals()` or `hcl.pals()`. +#' - The `palette.colors()` function, e.g. +#' `palette.colors(palette = "Okabe-Ito", alpha = 0.5)`. +#' - A vector or list of colours, e.g. `c("darkorange", "purple", "cyan4")`. If +#' too few colours are provided, they will be recycled (for discrete palettes) +#' or a gradient palette will be interpolated for continuous palettes. +#' If the `palette` argument is used, `colors` will be ignored. #' @param ... Other arguments passed to \code{\link[tinyplot]{tinyplot}}. #' #' @examplesIf all(insight::check_if_installed(c("tinyplot", "marginaleffects"), quietly = TRUE)) @@ -91,6 +103,7 @@ tinyplot.estimate_means <- function( show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + colors = NULL, size_title = NULL, size_axis_title = NULL, size_axis_text = NULL, @@ -225,6 +238,12 @@ tinyplot.estimate_means <- function( dots$xlab <- aes$labs$x dots$ylab <- aes$labs$y + # color palette -------------------------------- + + if (is.null(dots$palette) && !is.null(colors)) { + dots$palette <- colors + } + # legend labels -------------------------------- # we also need to account for custom legend options passed through dots diff --git a/man/visualisation_recipe.estimate_predicted.Rd b/man/visualisation_recipe.estimate_predicted.Rd index a9d1b0fe2..4b5351816 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -20,6 +20,7 @@ show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + colors = NULL, size_title = NULL, size_axis_title = NULL, size_axis_text = NULL, @@ -101,6 +102,19 @@ predictor. Use \code{FALSE} to always use continuous color scales for numeric predictors. It is possible to set a global default value using \code{options()}, e.g. \code{options(modelbased_numeric_as_discrete = 10)}.} +\item{colors}{Colors or color palette used for plotting. Following options +are allowed: +\itemize{ +\item A string corresponding to one of the many palettes listed by either +\code{palette.pals()} or \code{hcl.pals()}. +\item The \code{palette.colors()} function, e.g. +\code{palette.colors(palette = "Okabe-Ito", alpha = 0.5)}. +\item A vector or list of colours, e.g. \code{c("darkorange", "purple", "cyan4")}. If +too few colours are provided, they will be recycled (for discrete palettes) +or a gradient palette will be interpolated for continuous palettes. +If the \code{palette} argument is used, \code{colors} will be ignored. +}} + \item{size_title, size_axis_title, size_axis_text}{Numeric, set the size of plot title, axis title or axis labels. If not \code{NULL}, \code{par()} is called temporarily to set \code{cex.main}, \code{cex.axis} and \code{cex.lab}. The original values @@ -108,7 +122,9 @@ are restored afterwards. The default size is \code{1}. Larger values increase te sizes and vice versa.} \item{size_point, size_line}{Size of points and lines in the plot. Default is -\code{1}. Larger values increase point/line sizes and vice versa.} +\code{1}. Larger values increase point/line sizes and vice versa. If argument +\code{cex} is used, \code{size_point} will be ignored. Same for argument \code{lwd}, which +overrides \code{size_line}.} \item{show_residuals}{Logical, if \code{TRUE}, display residuals of the model as a background to the model-based estimation. Residuals will be computed for the