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..bb3fbe00d 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -5,6 +5,25 @@ #' @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`. 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. 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)) @@ -43,25 +62,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( @@ -71,6 +103,12 @@ 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, + size_point = NULL, + size_line = NULL, ... ) { insight::check_if_installed("tinyplot") @@ -146,14 +184,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) { @@ -164,6 +194,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(size_line)) { + dots$lwd <- size_line + } + # dodging ------------------------------- # Set dodge value for grouped point or pointrange plots. @@ -188,11 +238,27 @@ 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 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) && + !is.null(aes$color) && + length(all.vars(dots$facet)) > 0 && + 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( @@ -253,6 +319,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) && length(text_sizes)) { + old_pars <- graphics::par(text_sizes) + on.exit(graphics::par(old_pars), add = TRUE) + } + # plot it! suppressWarnings(do.call(tinyplot::tinyplot, plot_args)) } 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 e5d536f8c..4b5351816 100644 --- a/man/visualisation_recipe.estimate_predicted.Rd +++ b/man/visualisation_recipe.estimate_predicted.Rd @@ -20,6 +20,12 @@ show_data = FALSE, collapse_group = NULL, numeric_as_discrete = NULL, + colors = NULL, + size_title = NULL, + size_axis_title = NULL, + size_axis_text = NULL, + size_point = NULL, + size_line = NULL, ... ) @@ -96,6 +102,30 @@ 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 +are restored afterwards. The default size 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. 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 predictors in the data grid, using \code{\link[=residualize_over_grid]{residualize_over_grid()}}. For mixed @@ -114,7 +144,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()} @@ -203,25 +235,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}