Skip to content

Commit aafb06d

Browse files
authored
Add type checking to default discrete scales (#4470)
1 parent 6f6a8ba commit aafb06d

File tree

5 files changed

+47
-18
lines changed

5 files changed

+47
-18
lines changed

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# ggplot2 (development version)
22

3+
* Remove cross-inheritance of default discrete colour/fill scales and check the
4+
type and aesthetic of function output if `type` is a function
5+
(@thomasp85, #4149)
6+
37
* Add support for the BrailleR package for creating descriptions of the plot
48
when rendered (@thomasp85, #4459)
59

R/scale-colour.r

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,19 @@ scale_fill_binned <- function(...,
160160

161161
# helper function to make sure that the provided scale is of the correct
162162
# type (i.e., is continuous and works with the provided aesthetic)
163-
check_scale_type <- function(scale, name, aesthetic) {
163+
check_scale_type <- function(scale, name, aesthetic, scale_is_discrete = FALSE) {
164164
if (!is.ggproto(scale) || !inherits(scale, "Scale")) {
165165
abort(glue("The `type` argument of `{name}()` must return a continuous scale for the {aesthetic} aesthetic. The provided object is not a scale function."))
166166
}
167167
if (!isTRUE(aesthetic %in% scale$aesthetics)) {
168168
abort(glue("The `type` argument of `{name}()` must return a continuous scale for the {aesthetic} aesthetic. The provided scale works with the following aesthetics: {glue_collapse(scale$aesthetics, sep = ', ')}"))
169169
}
170-
if (isTRUE(scale$is_discrete())) {
171-
abort(glue("The `type` argument of `{name}()` must return a continuous scale for the {aesthetic} aesthetic, but the provided scale is discrete."))
170+
if (isTRUE(scale$is_discrete()) != scale_is_discrete) {
171+
scale_types <- c("continuous", "discrete")
172+
if (scale_is_discrete) {
173+
scale_types <- rev(scale_types)
174+
}
175+
abort(glue("The `type` argument of `{name}()` must return a {scale_types[1]} scale for the {aesthetic} aesthetic, but the provided scale is {scale_types[2]}."))
172176
}
173177

174178
scale

R/scale-hue.r

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,33 @@ scale_fill_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0
118118
#' print(cty_by_var(fl))
119119
#' })
120120
#'
121-
scale_colour_discrete <- function(..., type = getOption("ggplot2.discrete.colour", getOption("ggplot2.discrete.fill"))) {
121+
scale_colour_discrete <- function(..., type = getOption("ggplot2.discrete.colour")) {
122122
# TODO: eventually `type` should default to a set of colour-blind safe color codes (e.g. Okabe-Ito)
123123
type <- type %||% scale_colour_hue
124124
if (is.function(type)) {
125-
type(...)
125+
check_scale_type(
126+
type(...),
127+
"scale_colour_discrete",
128+
"colour",
129+
scale_is_discrete = TRUE
130+
)
126131
} else {
127132
scale_colour_qualitative(..., type = type)
128133
}
129134
}
130135

131136
#' @rdname scale_colour_discrete
132137
#' @export
133-
scale_fill_discrete <- function(..., type = getOption("ggplot2.discrete.fill", getOption("ggplot2.discrete.colour"))) {
138+
scale_fill_discrete <- function(..., type = getOption("ggplot2.discrete.fill")) {
134139
# TODO: eventually `type` should default to a set of colour-blind safe color codes (e.g. Okabe-Ito)
135140
type <- type %||% scale_fill_hue
136141
if (is.function(type)) {
137-
type(...)
142+
check_scale_type(
143+
type(...),
144+
"scale_fill_discrete",
145+
"fill",
146+
scale_is_discrete = TRUE
147+
)
138148
} else {
139149
scale_fill_qualitative(..., type = type)
140150
}

man/scale_colour_discrete.Rd

Lines changed: 2 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-scale-discrete.R

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ test_that("discrete scale defaults can be set globally", {
9696
)
9797

9898
withr::with_options(
99-
list(ggplot2.discrete.fill = c("#FFFFFF", "#000000")), {
99+
list(ggplot2.discrete.fill = c("#FFFFFF", "#000000"),
100+
ggplot2.discrete.colour = c("#FFFFFF", "#000000")), {
100101
# nlevels == ncodes
101102
two <- ggplot(df, aes(x, y, colour = two, fill = two)) + geom_point()
102103
expect_equal(layer_data(two)$colour, rep(c("#FFFFFF", "#000000"), 2))
@@ -107,13 +108,18 @@ test_that("discrete scale defaults can be set globally", {
107108
geom_point()
108109
four_hue <- four_default + scale_fill_hue()
109110
expect_equal(layer_data(four_default)$colour, layer_data(four_hue)$colour)
110-
})
111+
}
112+
)
111113

112114
withr::with_options(
113115
list(
114116
ggplot2.discrete.fill = list(
115117
c("#FFFFFF", "#000000"),
116118
c("#FF0000", "#00FF00", "#0000FF", "#FF00FF")
119+
),
120+
ggplot2.discrete.colour = list(
121+
c("#FFFFFF", "#000000"),
122+
c("#FF0000", "#00FF00", "#0000FF", "#FF00FF")
117123
)
118124
), {
119125
# nlevels == 2
@@ -125,7 +131,18 @@ test_that("discrete scale defaults can be set globally", {
125131
four <- ggplot(df, aes(x, y, colour = four, fill = four)) + geom_point()
126132
expect_equal(layer_data(four)$colour, c("#FF0000", "#00FF00", "#0000FF", "#FF00FF"))
127133
expect_equal(layer_data(four)$fill, c("#FF0000", "#00FF00", "#0000FF", "#FF00FF"))
128-
})
134+
}
135+
)
136+
})
137+
138+
test_that("Scale is checked in default colour scale", {
139+
# Check scale type
140+
expect_error(scale_colour_discrete(type = scale_colour_gradient))
141+
expect_error(scale_fill_discrete(type = scale_fill_gradient))
142+
143+
# Check aesthetic
144+
expect_error(scale_colour_discrete(type = scale_fill_hue))
145+
expect_error(scale_fill_discrete(type = scale_colour_hue))
129146
})
130147

131148
# mapped_discrete ---------------------------------------------------------

0 commit comments

Comments
 (0)