Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions R/plot.gg_variable.R
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,11 @@ plot.gg_variable <- function(x, # nolint: cyclocomp_linter
)
}
} else {
# Factor predictor: jitter + boxplot coloured by observed class
# Factor predictor: jitter + boxplot coloured by observed class.
# smooth=TRUE is intentionally a no-op here: geom_smooth requires
# a continuous x-axis and has no meaningful interpretation for
# discrete factor levels. The boxplot IQR serves as the spread
# summary.
gg_plt[[ind]] <- gg_plt[[ind]] +
ggplot2::geom_jitter(
ggplot2::aes(
Expand Down Expand Up @@ -565,6 +569,10 @@ plot.gg_variable <- function(x, # nolint: cyclocomp_linter
)
}
} else {
# Factor predictor (multi-class): boxplot + jitter per facet.
# smooth=TRUE is intentionally a no-op here for the same reason
# as the binary factor path above β€” geom_smooth requires a
# continuous x-axis.
gg_plt[[ind]] <- gg_plt[[ind]] +
ggplot2::geom_boxplot(
ggplot2::aes(x = .data$var, y = .data$yhat),
Expand Down Expand Up @@ -605,7 +613,10 @@ plot.gg_variable <- function(x, # nolint: cyclocomp_linter
ggplot2::geom_smooth(ggplot2::aes(x = .data$var, y = .data$yhat), ...)
}
} else {
# Factor predictor: boxplot + jitter
# Factor predictor (regression): boxplot + jitter.
# smooth=TRUE is intentionally a no-op here: geom_smooth requires a
# continuous x-axis and has no meaningful interpretation for discrete
# factor levels. The boxplot IQR serves as the spread summary.
gg_plt[[ind]] <- gg_plt[[ind]] +
ggplot2::geom_boxplot(
ggplot2::aes(x = .data$var, y = .data$yhat),
Expand Down
53 changes: 53 additions & 0 deletions tests/testthat/test_gg_variable.R
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,56 @@ test_that("gg_variable.randomForest: oob=FALSE triggers a warning", {
expect_s3_class(gg, "gg_variable")
expect_true("yhat.setosa" %in% names(gg))
})

## ── smooth=TRUE is a no-op for factor predictors (all families) ──────────────

# geom_smooth requires a continuous x-axis, so smooth=TRUE has no meaning for a
# factor predictor. The contract these tests lock in: no GeomSmooth layer is
# added for a factor x. Assert that directly (rather than a brittle layer
# count) so benign plot-composition changes do not break the suite.
has_smooth_layer <- function(p) {
any(vapply(p$layers, function(l) inherits(l$geom, "GeomSmooth"), logical(1)))
}

test_that("plot.gg_variable binary classification + factor predictor: smooth=TRUE adds no smooth layer", {
skip_if_not_installed("randomForest")
set.seed(42L)
bin_data <- iris[iris$Species != "virginica", ]
bin_data$Species <- droplevels(bin_data$Species)
bin_data$size <- cut(bin_data$Petal.Length, 2L, labels = c("small", "large"))
rf <- randomForest::randomForest(Species ~ size + Sepal.Width, data = bin_data,
ntree = 25L)
gg <- gg_variable(rf)
# smooth=TRUE with a factor predictor must not error
expect_no_error(p <- plot(gg, xvar = "size", smooth = TRUE))
expect_s3_class(p, "ggplot")
expect_false(has_smooth_layer(p))
})

test_that("plot.gg_variable multi-class classification + factor predictor: smooth=TRUE adds no smooth layer", {
skip_if_not_installed("randomForest")
set.seed(42L)
iris2 <- iris
iris2$size <- cut(iris2$Petal.Length, 3L, labels = c("small", "medium", "large"))
rf <- randomForest::randomForest(Species ~ size + Sepal.Width, data = iris2,
ntree = 25L)
gg <- gg_variable(rf)
# smooth=TRUE with a factor predictor must not error
expect_no_error(p <- plot(gg, xvar = "size", smooth = TRUE))
expect_s3_class(p, "ggplot")
expect_false(has_smooth_layer(p))
})

test_that("plot.gg_variable regression + factor predictor: smooth=TRUE adds no smooth layer", {
skip_if_not_installed("randomForest")
set.seed(42L)
iris2 <- iris
iris2$size <- cut(iris2$Petal.Length, 3L, labels = c("small", "medium", "large"))
rf <- randomForest::randomForest(Sepal.Length ~ size + Sepal.Width, data = iris2,
ntree = 25L)
gg <- gg_variable(rf)
# smooth=TRUE with a factor predictor must not error
expect_no_error(p <- plot(gg, xvar = "size", smooth = TRUE))
expect_s3_class(p, "ggplot")
expect_false(has_smooth_layer(p))
})
Loading