From c404e43b0012ce8d8b42b619049fa1181439ea65 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 13:33:58 +0200 Subject: [PATCH 1/6] plot.parameters_simulate formatting VS parameters_model formatting Fixes #278 --- R/plot.parameters_simulate.R | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/R/plot.parameters_simulate.R b/R/plot.parameters_simulate.R index 7e5512874..38e221827 100644 --- a/R/plot.parameters_simulate.R +++ b/R/plot.parameters_simulate.R @@ -50,6 +50,9 @@ data_plot.parameters_simulate <- function(x, out$Component[grepl(paste0(i, "$"), out$Parameter)] <- i out$Parameter <- gsub(paste0(i, "$"), "", out$Parameter) } + } else if ("Response" %in% colnames(x)) { + out$Component <- rep(x$Response, each = nrow(out) / nrow(x)) + out$Parameter <- rep(x$Parameter, each = nrow(out) / nrow(x)) } out @@ -93,7 +96,9 @@ plot.see_parameters_simulate <- function(x, ci = 0.95, ...) { is_mlm <- !is.null(attributes(x)$object_class) && "mlm" %in% attributes(x)$object_class - if (is.null(n_columns) && isTRUE(is_mlm)) n_columns <- 1 + if (is.null(n_columns) && (isTRUE(is_mlm) || "Response" %in% colnames(x))) { + n_columns <- 1 + } # check for defaults if (missing(centrality) && !is.null(attributes(x)$centrality)) { From e0784a5cee378adf40581e687d14e7f0fc640291 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 13:43:56 +0200 Subject: [PATCH 2/6] add test --- DESCRIPTION | 3 +- .../testthat/test-plot.simulate_parameters.R | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/testthat/test-plot.simulate_parameters.R diff --git a/DESCRIPTION b/DESCRIPTION index d836e1090..f3484bc45 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: see Title: Model Visualisation Toolbox for 'easystats' and 'ggplot2' -Version: 0.9.0.3 +Version: 0.9.0.4 Authors@R: c(person(given = "Daniel", family = "Lüdecke", @@ -93,6 +93,7 @@ Suggests: lme4, logspline, MASS, + mclogit, mclust, merDeriv, mgcv, diff --git a/tests/testthat/test-plot.simulate_parameters.R b/tests/testthat/test-plot.simulate_parameters.R new file mode 100644 index 000000000..3581b34aa --- /dev/null +++ b/tests/testthat/test-plot.simulate_parameters.R @@ -0,0 +1,46 @@ +skip_if(TRUE) + +## FIXME: currently does not retrieve the data + +skip_on_cran() +skip_if_offline() +skip_if_not_installed("withr") +skip_if_not_installed("mclogit") +skip_if_not_installed("parameters") +skip_if_not_installed("vdiffr") + +withr::with_environment( + new.env(), + test_that("`plot()` for simulate_parameters", { + pict <- base::readRDS(url("https://slcladal.github.io/data/pict.rda", "rb")) + suppressWarnings({ + m1.mn <- mclogit::mblogit( + formula = Response ~ Gender + Group, + random = ~ 1 | Item, + data = pict + ) + }) + set.seed(1234) + ms <- parameters::simulate_parameters(m1.mn) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works", + fig = plot(ms) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-2", + fig = plot(ms, stack = FALSE) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-3", + fig = plot(ms, stack = FALSE, show_intercept = TRUE, normalize_height = TRUE) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-4", + fig = plot(ms, stack = TRUE, show_intercept = TRUE, normalize_height = TRUE) + ) + }) +) From 6008adc96df32f910cc85c0a627751f3307546bd Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 13:44:44 +0200 Subject: [PATCH 3/6] news --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 0246faa94..63f12eda8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,9 @@ - `plot()` for `model_parameters()` now also plots group-levels of random effects (i.e. for mixed models, when `model_parameters(x, ..., group_level = TRUE)`). +- `plot()` for `simulate_parameters()` now better copes with models that have + multiple response levels (e.g. multinomial models). + # see 0.9.0 ## Changes From 3d4383a614f8aa23379196e147280885bbe66f2c Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 14:30:25 +0200 Subject: [PATCH 4/6] fix test --- .../testthat/test-plot.simulate_parameters.R | 64 +++++++++---------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/tests/testthat/test-plot.simulate_parameters.R b/tests/testthat/test-plot.simulate_parameters.R index 3581b34aa..f292ffa54 100644 --- a/tests/testthat/test-plot.simulate_parameters.R +++ b/tests/testthat/test-plot.simulate_parameters.R @@ -4,43 +4,39 @@ skip_if(TRUE) skip_on_cran() skip_if_offline() -skip_if_not_installed("withr") skip_if_not_installed("mclogit") skip_if_not_installed("parameters") skip_if_not_installed("vdiffr") -withr::with_environment( - new.env(), - test_that("`plot()` for simulate_parameters", { - pict <- base::readRDS(url("https://slcladal.github.io/data/pict.rda", "rb")) - suppressWarnings({ - m1.mn <- mclogit::mblogit( - formula = Response ~ Gender + Group, - random = ~ 1 | Item, - data = pict - ) - }) - set.seed(1234) - ms <- parameters::simulate_parameters(m1.mn) - set.seed(1234) - vdiffr::expect_doppelganger( - title = "plot.simulate_parameters works", - fig = plot(ms) - ) - set.seed(1234) - vdiffr::expect_doppelganger( - title = "plot.simulate_parameters works-2", - fig = plot(ms, stack = FALSE) - ) - set.seed(1234) - vdiffr::expect_doppelganger( - title = "plot.simulate_parameters works-3", - fig = plot(ms, stack = FALSE, show_intercept = TRUE, normalize_height = TRUE) - ) - set.seed(1234) - vdiffr::expect_doppelganger( - title = "plot.simulate_parameters works-4", - fig = plot(ms, stack = TRUE, show_intercept = TRUE, normalize_height = TRUE) +test_that("`plot()` for simulate_parameters", { + pict <- base::readRDS(url("https://slcladal.github.io/data/pict.rda", "rb")) + suppressWarnings({ + m1.mn <- mclogit::mblogit( + formula = Response ~ Gender + Group, + random = ~ 1 | Item, + data = pict ) }) -) + set.seed(1234) + ms <- parameters::simulate_parameters(m1.mn) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works", + fig = plot(ms) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-2", + fig = plot(ms, stack = FALSE) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-3", + fig = plot(ms, stack = FALSE, show_intercept = TRUE, normalize_height = TRUE) + ) + set.seed(1234) + vdiffr::expect_doppelganger( + title = "plot.simulate_parameters works-4", + fig = plot(ms, stack = TRUE, show_intercept = TRUE, normalize_height = TRUE) + ) +}) From 89174b6165b96ff461a0ff7aafcdeb0e6f15a4f5 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 14:50:28 +0200 Subject: [PATCH 5/6] fix GAM issues --- NEWS.md | 4 ++ R/plot.parameters_model.R | 13 ++++- .../plot-model-parameters-gam.svg | 57 +++++++++++++++++++ tests/testthat/test-plot.parameters_model.R | 17 +++++- 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-gam.svg diff --git a/NEWS.md b/NEWS.md index 63f12eda8..b67471409 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,10 @@ - `plot()` for `simulate_parameters()` now better copes with models that have multiple response levels (e.g. multinomial models). +## Bug fixes + +- Fixed issue in `plot()` for `parameters::model_parameters()` for GAM models. + # see 0.9.0 ## Changes diff --git a/R/plot.parameters_model.R b/R/plot.parameters_model.R index 3b4cf2b6a..4a9f0b0e6 100644 --- a/R/plot.parameters_model.R +++ b/R/plot.parameters_model.R @@ -53,6 +53,15 @@ plot.see_parameters_model <- function(x, # retrieve settings ---------------- model_attributes <- attributes(x)[!names(attributes(x)) %in% c("names", "row.names", "class")] + # for GAMs, remove smooth terms + if (!is.null(x$Component) && any(x$Component == "smooth_terms")) { + x <- x[x$Component != "smooth_terms", ] + # if we only have one component left, remove Component column + if (insight::n_unique(x$Component) == 1) { + x$Component <- NULL + } + } + # user wants to plot random effects (group levels)? if (isFALSE(model_attributes$ignore_group) && isTRUE(model_attributes$mixed_model) && @@ -366,7 +375,7 @@ plot.see_parameters_model <- function(x, x$CI <- as.character(x$CI) x$group <- factor(x$Coefficient < y_intercept, levels = c(FALSE, TRUE)) - if (all(x$group == "TRUE")) { + if (all(x$group == "TRUE", na.rm = TRUE)) { color_scale <- scale_color_material(reverse = TRUE) } else { color_scale <- scale_color_material() @@ -401,7 +410,7 @@ plot.see_parameters_model <- function(x, } else { # plot setup for regular model parameters x$group <- factor(x$Coefficient < y_intercept, levels = c(FALSE, TRUE)) - if (all(x$group == "TRUE")) { + if (all(x$group == "TRUE", na.rm = TRUE)) { color_scale <- scale_color_material(reverse = TRUE) } else { color_scale <- scale_color_material() diff --git a/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-gam.svg b/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-gam.svg new file mode 100644 index 000000000..9465c96d0 --- /dev/null +++ b/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-gam.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +disp +gear +cyl + +-2 +-1 +0 +1 +Coefficient +plot.model_parameters_gam + + diff --git a/tests/testthat/test-plot.parameters_model.R b/tests/testthat/test-plot.parameters_model.R index a8c2a8cdd..e3799f37e 100644 --- a/tests/testthat/test-plot.parameters_model.R +++ b/tests/testthat/test-plot.parameters_model.R @@ -69,7 +69,7 @@ test_that("`plot.see_parameters_model()` random parameters works", { data(sleepstudy, package = "lme4") set.seed(12345) - sleepstudy$grp <- sample(1:5, size = 180, replace = TRUE) + sleepstudy$grp <- sample.int(5, size = 180, replace = TRUE) model <- lme4::lmer( Reaction ~ Days + (1 | grp) + (1 | Subject), data = sleepstudy @@ -80,3 +80,18 @@ test_that("`plot.see_parameters_model()` random parameters works", { fig = plot(out) ) }) + + +test_that("`plot.see_parameters_model()` random parameters works", { + skip_if_not_installed("vdiffr") + skip_if_not_installed("mgcv") + skip_if_not_installed("parameters") + + data(mtcars) + m <- mgcv::gam(mpg ~ s(wt) + cyl + gear + disp, data = mtcars) + result <- parameters::model_parameters(m) + vdiffr::expect_doppelganger( + title = "plot.model_parameters_gam", + fig = plot(result) + ) +}) From 661faaeaefb4f5d0428a5ee4885326ab94818bd4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 29 Sep 2024 15:04:21 +0200 Subject: [PATCH 6/6] add show_direction arg --- NEWS.md | 3 + R/plot.parameters_model.R | 37 +++++++++-- man/plot.see_parameters_model.Rd | 14 +++++ .../plot-model-parameters-no-dir.svg | 62 +++++++++++++++++++ tests/testthat/test-plot.parameters_model.R | 4 ++ 5 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-no-dir.svg diff --git a/NEWS.md b/NEWS.md index b67471409..d18966bfa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,9 @@ - `plot()` for `model_parameters()` now also plots group-levels of random effects (i.e. for mixed models, when `model_parameters(x, ..., group_level = TRUE)`). +- `plot()` for `model_parameters()` gets a `show_direction` argument, to turn + off the direction of the effect in the plot. + - `plot()` for `simulate_parameters()` now better copes with models that have multiple response levels (e.g. multinomial models). diff --git a/R/plot.parameters_model.R b/R/plot.parameters_model.R index 4a9f0b0e6..5fe51539c 100644 --- a/R/plot.parameters_model.R +++ b/R/plot.parameters_model.R @@ -21,6 +21,9 @@ #' @param show_density Should the compatibility density (i.e., posterior, #' bootstrap, or confidence density) of each parameter be shown? #' (default: `FALSE`) +#' @param show_direction Should the "direction" of coefficients (e.g., positive +#' or negative coefficients) be highlighted using different colors? +#' (default: `TRUE`) #' @param log_scale Should exponentiated coefficients (e.g., odds-ratios) be #' plotted on a log scale? (default: `FALSE`) #' @param n_columns For models with multiple components (like fixed and random, @@ -29,6 +32,14 @@ #' #' @return A ggplot2-object. #' +#' @note By default, coefficients and their confidence intervals are colored +#' depending on whether they show a "positive" or "negative" association with +#' the outcome. E.g., in case of linear models, colors simply distinguish positive +#' or negative coefficients. For logistic regression models that are shown on the +#' odds ratio scale, colors distinguish odds ratios above or below 1. Use +#' `show_direction = FALSE` to disable this feature and only show a one-colored +#' forest plot. +#' #' @examples #' library(parameters) #' m <- lm(mpg ~ wt + cyl + gear + disp, data = mtcars) @@ -48,6 +59,7 @@ plot.see_parameters_model <- function(x, show_estimate = TRUE, show_interval = TRUE, show_density = FALSE, + show_direction = TRUE, log_scale = FALSE, ...) { # retrieve settings ---------------- @@ -381,10 +393,20 @@ plot.see_parameters_model <- function(x, color_scale <- scale_color_material() } - p <- ggplot2::ggplot(x, ggplot2::aes( - y = .data$Parameter, x = .data$Coefficient, - size = rev(.data$CI), color = .data$group - )) + + # should positive/negative coefficients be highlighted? + if (show_direction) { + p <- ggplot2::ggplot(x, ggplot2::aes( + y = .data$Parameter, x = .data$Coefficient, + size = rev(.data$CI), color = .data$group + )) + } else { + p <- ggplot2::ggplot(x, ggplot2::aes( + y = .data$Parameter, x = .data$Coefficient, + size = rev(.data$CI) + )) + } + + p <- p + ggplot2::geom_vline(ggplot2::aes(xintercept = y_intercept), linetype = "dotted") + theme_modern(legend.position = "none") + color_scale @@ -416,10 +438,17 @@ plot.see_parameters_model <- function(x, color_scale <- scale_color_material() } + if (show_direction) { p <- ggplot2::ggplot(x, ggplot2::aes(y = .data$Parameter, x = .data$Coefficient, color = .data$group)) + ggplot2::geom_vline(ggplot2::aes(xintercept = y_intercept), linetype = "dotted") + theme_modern(legend.position = "none") + color_scale + } else { + p <- ggplot2::ggplot(x, ggplot2::aes(y = .data$Parameter, x = .data$Coefficient)) + + ggplot2::geom_vline(ggplot2::aes(xintercept = y_intercept), linetype = "dotted") + + theme_modern(legend.position = "none") + + color_scale + } if (show_density) { p <- p + density_layer diff --git a/man/plot.see_parameters_model.Rd b/man/plot.see_parameters_model.Rd index f78e4e7c8..b7d55d216 100644 --- a/man/plot.see_parameters_model.Rd +++ b/man/plot.see_parameters_model.Rd @@ -19,6 +19,7 @@ show_estimate = TRUE, show_interval = TRUE, show_density = FALSE, + show_direction = TRUE, log_scale = FALSE, ... ) @@ -81,6 +82,10 @@ be shown? (default: \code{TRUE})} bootstrap, or confidence density) of each parameter be shown? (default: \code{FALSE})} +\item{show_direction}{Should the "direction" of coefficients (e.g., positive +or negative coefficients) be highlighted using different colors? +(default: \code{TRUE})} + \item{log_scale}{Should exponentiated coefficients (e.g., odds-ratios) be plotted on a log scale? (default: \code{FALSE})} @@ -104,6 +109,15 @@ A ggplot2-object. \description{ The \code{plot()} method for the \code{parameters::model_parameters()} function. } +\note{ +By default, coefficients and their confidence intervals are colored +depending on whether they show a "positive" or "negative" association with +the outcome. E.g., in case of linear models, colors simply distinguish positive +or negative coefficients. For logistic regression models that are shown on the +odds ratio scale, colors distinguish odds ratios above or below 1. Use +\code{show_direction = FALSE} to disable this feature and only show a one-colored +forest plot. +} \examples{ library(parameters) m <- lm(mpg ~ wt + cyl + gear + disp, data = mtcars) diff --git a/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-no-dir.svg b/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-no-dir.svg new file mode 100644 index 000000000..f54908933 --- /dev/null +++ b/tests/testthat/_snaps/plot.parameters_model/plot-model-parameters-no-dir.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +disp +gear +cyl +wt + +-6 +-4 +-2 +0 +Coefficient +plot.model_parameters_no_dir + + diff --git a/tests/testthat/test-plot.parameters_model.R b/tests/testthat/test-plot.parameters_model.R index e3799f37e..e7e368065 100644 --- a/tests/testthat/test-plot.parameters_model.R +++ b/tests/testthat/test-plot.parameters_model.R @@ -8,6 +8,10 @@ test_that("`plot.see_parameters_model()` works", { title = "plot.model_parameters_1", fig = plot(result) ) + vdiffr::expect_doppelganger( + title = "plot.model_parameters_no_dir", + fig = plot(result, show_direction = FALSE) + ) }) test_that("`plot.see_parameters_model()` random parameters works", {