Skip to content

Commit 88c4beb

Browse files
authored
Named palettes (#448)
1 parent 0c50869 commit 88c4beb

12 files changed

+296
-8
lines changed

NAMESPACE

+6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Generated by roxygen2: do not edit by hand
22

33
S3method(as_continuous_pal,"function")
4+
S3method(as_continuous_pal,character)
45
S3method(as_continuous_pal,default)
56
S3method(as_continuous_pal,pal_discrete)
67
S3method(as_discrete_pal,"function")
8+
S3method(as_discrete_pal,character)
79
S3method(as_discrete_pal,default)
810
S3method(as_discrete_pal,pal_continuous)
911
S3method(fullseq,Date)
@@ -98,6 +100,7 @@ export(extended_breaks)
98100
export(format_format)
99101
export(format_log)
100102
export(fullseq)
103+
export(get_palette)
101104
export(gradient_n_pal)
102105
export(grey_pal)
103106
export(hms_trans)
@@ -177,6 +180,7 @@ export(pal_seq_gradient)
177180
export(pal_shape)
178181
export(pal_viridis)
179182
export(palette_na_safe)
183+
export(palette_names)
180184
export(palette_nlevels)
181185
export(palette_type)
182186
export(parse_format)
@@ -195,10 +199,12 @@ export(rescale_max)
195199
export(rescale_mid)
196200
export(rescale_none)
197201
export(rescale_pal)
202+
export(reset_palettes)
198203
export(reverse_trans)
199204
export(scientific)
200205
export(scientific_format)
201206
export(seq_gradient_pal)
207+
export(set_palette)
202208
export(shape_pal)
203209
export(show_col)
204210
export(sqrt_trans)

NEWS.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# scales (development version)
22

3+
* The scales package now keeps track of known palettes. These can be retrieved
4+
using `get_palette()` or registered using `set_palette()` (#396).
35
* `label_log()` has a `signed` argument for displaying negative numbers
46
(@teunbrand, #421).
57

R/colour-manip.R

+8
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ alpha <- function(colour, alpha = NA) {
8787
show_col <- function(colours, labels = TRUE, borders = NULL, cex_label = 1,
8888
ncol = NULL) {
8989
n <- length(colours)
90+
if (n == 1 && (is.function(colours) || !is_color(colours))) {
91+
colours <- as_discrete_pal(colours)
92+
n <- palette_nlevels(colours)
93+
n <- if (is.na(n)) 16 else n
94+
colours <- colours(n = n)
95+
n <- length(colours)
96+
}
97+
9098
ncol <- ncol %||% ceiling(sqrt(length(colours)))
9199
nrow <- ceiling(n / ncol)
92100

R/pal-.R

+16
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ as_discrete_pal.pal_continuous <- function(x, ...) {
156156
)
157157
}
158158

159+
#' @export
160+
as_discrete_pal.character <- function(x, ...) {
161+
if (length(x) > 1) {
162+
return(pal_manual(x))
163+
}
164+
as_discrete_pal(get_palette(x, ...))
165+
}
166+
159167
## As continuous palette --------------------------------------------------
160168

161169
#' @rdname new_continuous_palette
@@ -197,3 +205,11 @@ as_continuous_pal.pal_discrete <- function(x, ...) {
197205
)
198206
)
199207
}
208+
209+
#' @export
210+
as_continuous_pal.character <- function(x, ...) {
211+
if (length(x) > 1) {
212+
return(colour_ramp(x))
213+
}
214+
as_continuous_pal(get_palette(x, ...))
215+
}

R/palette-registry.R

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
.known_palettes <- new_environment(parent = empty_env())
2+
3+
#' Known palettes
4+
#'
5+
#' The scales packages keeps track of a set of palettes it considers 'known'.
6+
#' The benefit of a known palette is that it can be called by name in functions
7+
#' as `as_continuous_pal()` or `as_discrete_pal()`.
8+
#'
9+
#' @param name A string giving the palette name.
10+
#' @param palette A [palette][new_continuous_palette], `function` or character
11+
#' vector.
12+
#' @param warn_conflict A boolean which if `TRUE` (default), warns when
13+
#' replacing a known palette.
14+
#' @param ... Additional arguments to pass to palette when it is a function
15+
#' but not a palette class function.
16+
#'
17+
#' @return The `get_palette()` function returns a palette. The `set_palette()`
18+
#' function is called for side effects and returns nothing.
19+
#' @export
20+
#'
21+
#' @examples
22+
#' # Get one of the known palettes
23+
#' get_palette("hue")
24+
#'
25+
#' # Set a new custom palette
26+
#' cols <- c("palegreen", "deepskyblue", "magenta")
27+
#' set_palette("aurora", palette = cols)
28+
#'
29+
#' # Palette is now known
30+
#' "aurora" %in% palette_names()
31+
#' as_continuous_pal("aurora")
32+
#'
33+
#' # Resetting palettes
34+
#' reset_palettes()
35+
get_palette <- function(name, ...) {
36+
37+
name <- tolower(name)
38+
if (!exists(name, envir = .known_palettes)) {
39+
cli::cli_abort("Unknown palette: {name}")
40+
}
41+
42+
pal <- env_get(.known_palettes, name)
43+
44+
# Palette could be factory, in which case we want the product, or
45+
# palette can be a palette function that isn't registered as such,
46+
# in which case we want the colours it gives
47+
if (is_function(pal) && !is_pal(pal)) {
48+
pal <- try_fetch(
49+
pal(...),
50+
error = function(cnd) {
51+
cli::cli_abort("Failed to interpret {name} as palette.", parent = cnd)
52+
}
53+
)
54+
}
55+
if (is.character(pal)) {
56+
pal <- manual_pal(pal, type = "colour")
57+
}
58+
if (is_pal(pal)) {
59+
return(pal)
60+
}
61+
cli::cli_abort("Failed to interpret {name} as palette.")
62+
}
63+
64+
#' @export
65+
#' @rdname get_palette
66+
set_palette <- function(name, palette, warn_conflict = TRUE) {
67+
name <- tolower(name)
68+
if (!is_function(palette) && !is_character(palette)) {
69+
cli::cli_abort(
70+
"The {.arg palette} argument must be a {.cls function} or \\
71+
{.cls character} vector."
72+
)
73+
}
74+
if (warn_conflict & exists(name, envir = .known_palettes)) {
75+
cli::cli_warn("Overwriting pre-existing {.val {name}} palette.")
76+
}
77+
env_bind(.known_palettes, !!name := palette)
78+
invisible(NULL)
79+
}
80+
81+
#' @export
82+
#' @rdname get_palette
83+
palette_names <- function() {
84+
names(.known_palettes)
85+
}
86+
87+
#' @export
88+
#' @rdname get_palette
89+
reset_palettes <- function() {
90+
env_unbind(.known_palettes, palette_names())
91+
init_palettes()
92+
}
93+
94+
init_palettes <- function() {
95+
register_hcl_pals()
96+
register_base_pals()
97+
register_viridis_pals()
98+
register_brewer_pals()
99+
register_dichromat_pals()
100+
set_palette("grey", pal_grey, warn_conflict = FALSE)
101+
set_palette("hue", pal_hue, warn_conflict = FALSE)
102+
}
103+
104+
on_load(init_palettes())
105+
106+
register_hcl_pals <- function(n = 31) {
107+
names <- grDevices::hcl.pals()
108+
for (name in names) {
109+
fun <- colour_ramp(grDevices::hcl.colors(n, palette = name))
110+
set_palette(name, fun, warn_conflict = FALSE)
111+
}
112+
invisible(NULL)
113+
}
114+
115+
register_base_pals <- function() {
116+
if (getRversion() < "4.0.0") {
117+
return(invisible(NULL))
118+
}
119+
names <- utils::getFromNamespace("palette.pals", "grDevices")()
120+
palette <- utils::getFromNamespace("palette.colors", "grDevices")
121+
for (name in names) {
122+
fun <- manual_pal(palette(palette = name), type = "colour")
123+
set_palette(name, fun, warn_conflict = FALSE)
124+
}
125+
invisible(NULL)
126+
}
127+
128+
register_viridis_pals <- function() {
129+
names <- c("magma", "inferno", "plasma", "viridis",
130+
"cividis", "rocket", "mako", "turbo")
131+
for (name in names) {
132+
fun <- pal_viridis(option = name)
133+
set_palette(name, fun, warn_conflict = FALSE)
134+
}
135+
invisible(NULL)
136+
}
137+
138+
register_brewer_pals <- function() {
139+
names <- rownames(RColorBrewer::brewer.pal.info)
140+
for (name in names) {
141+
fun <- pal_brewer(palette = name)
142+
set_palette(name, fun, warn_conflict = FALSE)
143+
}
144+
invisible(NULL)
145+
}
146+
147+
register_dichromat_pals <- function() {
148+
if (!is_installed("dichromat")) {
149+
return(invisible(NULL))
150+
}
151+
names <- names(dichromat::colorschemes)
152+
for (name in names) {
153+
fun <- manual_pal(dichromat::colorschemes[[name]], type = "colour")
154+
set_palette(name, fun, warn_conflict = FALSE)
155+
}
156+
invisible(NULL)
157+
}

R/utils.R

+4
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ recycle_common <- function(..., size = NULL, call = caller_env()) {
100100
x[to_recycle] <- lapply(x[to_recycle], rep_len, length.out = size)
101101
x
102102
}
103+
104+
.onLoad <- function(lib, pkg) {
105+
run_on_load()
106+
}

_pkgdown.yml

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ reference:
6868
- contains("col")
6969
- muted
7070
- alpha
71+
- get_palette
7172

7273
- title: Non-colour palette functions
7374
desc: >

man/get_palette.Rd

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

man/label_pvalue.Rd

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

man/pvalue_format.Rd

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

man/transform_boxcox.Rd

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

0 commit comments

Comments
 (0)