Skip to content

Commit b71d67d

Browse files
committed
Add ability to set default scale_[fill/colour]_discrete() via type=getOption('ggplot2.discrete.[fill/colour]') argument, closes #3826
1 parent 37ed660 commit b71d67d

File tree

4 files changed

+184
-19
lines changed

4 files changed

+184
-19
lines changed

R/scale-hue.r

+118-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#' Evenly spaced colours for discrete data
22
#'
3-
#' This is the default colour scale for categorical variables. It maps each
4-
#' level to an evenly spaced hue on the colour wheel. It does not generate
5-
#' colour-blind safe palettes.
3+
#' Maps each level to an evenly spaced hue on the colour wheel.
4+
#' It does not generate colour-blind safe palettes.
65
#'
76
#' @param na.value Colour to use for missing values
87
#' @inheritDotParams discrete_scale -aesthetics
@@ -63,3 +62,119 @@ scale_fill_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0
6362
discrete_scale(aesthetics, "hue", hue_pal(h, c, l, h.start, direction),
6463
na.value = na.value, ...)
6564
}
65+
66+
67+
#' Discrete colour scales
68+
#'
69+
#' Colour scales for discrete data default to the values of the `ggplot2.discrete.fill`
70+
#' and `ggplot2.discrete.colour` options. By default these scales attempt to use
71+
#' a colour-blind safe (or a custom) palette, but if the number of levels is
72+
#' large, they fallback to [scale_fill_hue()]/[scale_colour_hue()].
73+
#'
74+
#' @param ... Additional parameters passed on to the scale type,
75+
#' @param type One of the following:
76+
#' * A character vector of color codes. The codes are used for a 'manual' color
77+
#' scale as long as the number of codes exceeds the number of data levels
78+
#' (if there are more levels than codes, [scale_colour_hue()]/[scale_fill_hue()]
79+
#' are used to construct the default scale).
80+
#' * A list of character vectors of color codes. The minimum length vector that exceeds the
81+
#' number of data levels is chosen for the color scaling. This is useful if you
82+
#' want to change the color palette based on the number of levels.
83+
#' * A function that returns a discrete colour/fill scale (e.g., [scale_fill_hue()],
84+
#' [scale_fill_brewer()], etc).
85+
#' @export
86+
#' @rdname
87+
#' @examples
88+
#' # Template function for creating densities grouped by a variable
89+
#' cty_by_var <- function(var) {
90+
#' ggplot(mpg, aes(cty, colour = factor({{var}}), fill = factor({{var}}))) +
91+
#' geom_density(alpha = 0.2)
92+
#' }
93+
#' # The default color scale for three levels
94+
#' cty_by_var(class)
95+
#'
96+
#' # Define custom palettes for when there are 1-2, 3, or 4-6 levels
97+
#' opts <- options(
98+
#' ggplot2.discrete.fill = list(
99+
#' c("skyblue", "orange"),
100+
#' RColorBrewer::brewer.pal(3, "Set2"),
101+
#' RColorBrewer::brewer.pal(6, "Accent")
102+
#' )
103+
#' )
104+
#' cty_by_var(year)
105+
#' cty_by_var(drv)
106+
#' cty_by_var(fl)
107+
#' cty_by_var(class)
108+
#' options(opts)
109+
#'
110+
scale_colour_discrete <- function(..., type = getOption("ggplot2.discrete.colour", getOption("ggplot2.discrete.fill"))) {
111+
type <- type %||% okabeIto
112+
if (is.function(type)) {
113+
type(...)
114+
} else {
115+
scale_colour_qualitative(..., codes = type)
116+
}
117+
}
118+
119+
#' @rdname scale_colour_discrete
120+
#' @export
121+
scale_fill_discrete <- function(..., type = getOption("ggplot2.discrete.fill", getOption("ggplot2.discrete.colour"))) {
122+
type <- type %||% okabeIto
123+
if (is.function(type)) {
124+
type(...)
125+
} else {
126+
scale_fill_qualitative(..., codes = type)
127+
}
128+
}
129+
130+
scale_colour_qualitative <- function(..., codes = NULL, h = c(0, 360) + 15, c = 100, l = 65, h.start = 0,
131+
direction = 1, na.value = "grey50", aesthetics = "colour") {
132+
discrete_scale(
133+
aesthetics, "qualitative", qualitative_pal(codes, h, c, l, h.start, direction),
134+
na.value = na.value, ...
135+
)
136+
}
137+
138+
scale_fill_qualitative <- function(..., codes = NULL, h = c(0, 360) + 15, c = 100, l = 65, h.start = 0,
139+
direction = 1, na.value = "grey50", aesthetics = "fill") {
140+
discrete_scale(
141+
aesthetics, "qualitative", qualitative_pal(codes, h, c, l, h.start, direction),
142+
na.value = na.value, ...
143+
)
144+
}
145+
146+
qualitative_pal <- function(codes, h, c, l, h.start, direction) {
147+
function(n) {
148+
if (!length(codes)) {
149+
return(scales::hue_pal(h, c, l, h.start, direction)(n))
150+
}
151+
codes_list <- if (!is.list(codes)) list(codes) else codes
152+
if (!all(vapply(codes_list, is.character, logical(1)))) {
153+
stop("codes must be a character vector or a list of character vectors", call. = FALSE)
154+
}
155+
codes_lengths <- vapply(codes_list, length, integer(1))
156+
# If there are more levels than color codes default to hue_pal()
157+
if (max(codes_lengths) < n) {
158+
return(scales::hue_pal(h, c, l, h.start, direction)(n))
159+
}
160+
# Use the minimum length vector that exceeds the number of levels (n)
161+
codes_list <- codes_list[order(codes_lengths)]
162+
i <- 1
163+
while (length(codes_list[[i]]) < n) {
164+
i <- i + 1
165+
}
166+
codes_list[[i]][seq_len(n)]
167+
}
168+
}
169+
170+
# prismatic::check_color_blindness(okabeIto)
171+
okabeIto <- c(
172+
"#E69F00",
173+
"#56B4E9",
174+
"#009E73",
175+
"#F0E442",
176+
"#0072B2",
177+
"#D55E00",
178+
"#CC79A7",
179+
"black"
180+
)

R/zxx.r

+1-11
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
# Default scales -------------------------------------------------------------
22

3-
#' @export
4-
#' @rdname scale_hue
5-
#' @usage NULL
6-
scale_colour_discrete <- scale_colour_hue
7-
83
#' @export
94
#' @rdname scale_viridis
105
#' @usage NULL
@@ -64,11 +59,6 @@ scale_colour_date <- function(...,
6459
#' @usage NULL
6560
scale_color_date <- scale_colour_date
6661

67-
#' @export
68-
#' @rdname scale_hue
69-
#' @usage NULL
70-
scale_fill_discrete <- scale_fill_hue
71-
7262
#' @export
7363
#' @rdname scale_viridis
7464
#' @usage NULL
@@ -143,7 +133,7 @@ scale_color_binned <- scale_colour_binned
143133
#' @export
144134
#' @rdname scale_hue
145135
#' @usage NULL
146-
scale_color_discrete <- scale_colour_hue
136+
scale_color_discrete <- scale_colour_discrete
147137

148138
#' @export
149139
#' @rdname scale_gradient

man/scale_colour_discrete.Rd

+63
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_hue.Rd

+2-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)