1
1
# ' Evenly spaced colours for discrete data
2
2
# '
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.
6
5
# '
7
6
# ' @param na.value Colour to use for missing values
8
7
# ' @inheritDotParams discrete_scale -aesthetics
@@ -65,22 +64,80 @@ scale_fill_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0
65
64
}
66
65
67
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).
68
85
# ' @export
69
- # ' @inheritParams scale_colour_hue
70
- # ' @param codes a vector of color codes defining a qualitative color palette. These codes
71
- # ' are used so long as the number of codes is greater or equal to the number of values they encode.
72
- scale_colour_discrete <- function (... , codes = okabeIto , h = c(0 , 360 ) + 15 , c = 100 , l = 65 , h.start = 0 ,
73
- direction = 1 , na.value = " grey50" , aesthetics = " colour" ) {
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
+ # TODO: export?
131
+ scale_colour_qualitative <- function (... , codes = NULL , h = c(0 , 360 ) + 15 , c = 100 , l = 65 , h.start = 0 ,
132
+ direction = 1 , na.value = " grey50" , aesthetics = " colour" ) {
74
133
discrete_scale(
75
134
aesthetics , " qualitative" , qualitative_pal(codes , h , c , l , h.start , direction ),
76
135
na.value = na.value , ...
77
136
)
78
137
}
79
138
80
- # ' @export
81
- # ' @inheritParams scale_colour_discrete
82
- scale_fill_discrete <- function (... , codes = okabeIto , h = c(0 , 360 ) + 15 , c = 100 , l = 65 , h.start = 0 ,
83
- direction = 1 , na.value = " grey50" , aesthetics = " fill" ) {
139
+ scale_fill_qualitative <- function (... , codes = NULL , h = c(0 , 360 ) + 15 , c = 100 , l = 65 , h.start = 0 ,
140
+ direction = 1 , na.value = " grey50" , aesthetics = " fill" ) {
84
141
discrete_scale(
85
142
aesthetics , " qualitative" , qualitative_pal(codes , h , c , l , h.start , direction ),
86
143
na.value = na.value , ...
@@ -89,12 +146,36 @@ scale_fill_discrete <- function(..., codes = okabeIto, h = c(0, 360) + 15, c = 1
89
146
90
147
qualitative_pal <- function (codes , h , c , l , h.start , direction ) {
91
148
function (n ) {
92
- if (n < = length(codes )) {
93
- codes [seq_len(n )]
94
- } else {
95
- scales :: hue_pal(h , c , l , h.start , direction )(n )
149
+ if (! length(codes )) {
150
+ return (scales :: hue_pal(h , c , l , h.start , direction )(n ))
151
+ }
152
+ codes_list <- if (! is.list(codes )) list (codes ) else codes
153
+ if (! all(vapply(codes_list , is.character , logical (1 )))) {
154
+ stop(" codes must be a character vector or a list of character vectors" , call. = FALSE )
155
+ }
156
+ codes_lengths <- vapply(codes_list , length , integer(1 ))
157
+ # If there are more levels than color codes default to hue_pal()
158
+ if (max(codes_lengths ) < n ) {
159
+ return (scales :: hue_pal(h , c , l , h.start , direction )(n ))
160
+ }
161
+ # Use the minimum length vector that exceeds the number of levels (n)
162
+ codes_list <- codes_list [order(codes_lengths )]
163
+ i <- 1
164
+ while (length(codes_list [[i ]]) < n ) {
165
+ i <- i + 1
96
166
}
167
+ codes_list [[i ]][seq_len(n )]
97
168
}
98
169
}
99
170
100
- okabeIto <- c(" #E69F00" , " #009E73" , " #0072B2" , " #CC79A7" , " #999999" , " #D55E00" , " #F0E442" , " #56B4E9" )
171
+ # prismatic::check_color_blindness(okabeIto)
172
+ okabeIto <- c(
173
+ " #E69F00" ,
174
+ " #56B4E9" ,
175
+ " #009E73" ,
176
+ " #F0E442" ,
177
+ " #0072B2" ,
178
+ " #D55E00" ,
179
+ " #CC79A7" ,
180
+ " #999999"
181
+ )
0 commit comments