Контекст
Я пытаюсь создать настраиваемую цветовую шкалу, которая будет вызываться, используя что-то вроде scale_fill_perso
в ggplot
. Я выполнил шаги, описанные в этой красивой записи блога . Моя дискретная шкала имеет 7 уровней.
Мне удалось правильно выставить шкалу (см. Ниже). При использовании графика с 7 уровнями я получаю ожидаемые цвета. Однако, когда я использую не так много цветов, я хотел бы, чтобы R
соблюдал порядок моей палитры и не интерполировал между значениями (см. Пример). Например, если у меня 3 цвета, я бы хотел, чтобы R
использовал первые три значения моего цветового вектора.
Я думаю, что это происходит от my_pal
, который сам использует grDevices::colorRampPalette
, который при использовании количество классов, меньшее, чем размер цветового вектора, обрезает цветной вектор, используя крайности, а не порядок.
Итак, мой вопрос: Есть ли способ зафиксировать количество классов и, если number classes < length(color vector)
не использовать colorRampPalette
интерполяцию?
Текущая реализация
Шаги следуют вышеупомянутому сообщению в блоге .
Сначала создайте цветной вектор и способ его назвать:
mycolors <- c(
`red` = "#E2447A",
`green` = "#BCE550",
`blue` = "#708DD3",
`grey` = "#666666",
`orange` = "#FFBAA8",
`violet` = "#D1A3FF",
`lightgrey` = "#B2B2B2"
)
my_cols <- function(...) {
cols <- c(...)
if (is.null(cols))
return (mycolors)
mycolors[cols]
}
call_palettes <- function(palette = "main"){
if (palette == "main"){ return(my_cols()) }
}
На данный момент есть только одна палитра, но это может измениться. Затем создайте функцию палитры, которая интерполирует значения (насколько я понял):
my_pal <- function(palette = "main", reverse = FALSE, ...) {
args <- list(...)
#return(args)
pal <- call_palettes(palette, ...)
if (reverse) pal <- rev(pal)
grDevices::colorRampPalette(pal, ...)
}
Затем создайте функцию scale_fill_perso
для использования этой палитры.
scale_fill_perso <- function(palette = "main", discrete = TRUE, reverse = FALSE, ...) {
pal <- my_pal(palette = palette, reverse = reverse)
if (discrete) {
ggplot2::discrete_scale("fill", paste0("my_pal_", palette), palette = pal, ...)
} else {
ggplot2::scale_fill_gradientn(colours = pal(256), ...)
}
}
Вывод
При использовании 7 классов проблем нет:
iris$random <- sample(1:7, nrow(iris), replace = TRUE)
ggplot2::ggplot(iris) +
ggplot2::geom_histogram(ggplot2::aes(x = Sepal.Width, y = ..density..,
fill = factor(random))) +
scale_fill_perso(palette = "main")
Однако, когда используя меньшее количество цветов, я хотел бы использовать первые три цвета моего вектора (красный-зеленый-синий), что на данный момент не так
ggplot2::ggplot(iris) +
ggplot2::geom_histogram(ggplot2::aes(x = Sepal.Width, y = ..density..,
fill = factor(Species))) +
scale_fill_perso(palette = "main")
Я определил, что это происходит из-за того, что my_pal
не принимает порядок вектора как информативный. Например, для двух цветов он берет два крайних значения вектора:
my_pal()(2)
# "#E2447A" "#B2B2B2"
mycolors
# red green blue grey orange violet lightgrey
# "#E2447A" "#BCE550" "#708DD3" "#666666" "#FFBAA8" "#D1A3FF" "#B2B2B2"
, а для трех он добавляет среднее значение:
my_pal()(3)
# "#E2447A" "#666666" "#B2B2B2"
mycolors
# red green blue grey orange violet lightgrey
# "#E2447A" "#BCE550" "#708DD3" "#666666" "#FFBAA8" "#D1A3FF" "#B2B2B2"
Как я могу обеспечить соблюдение векторный порядок, когда классы чисел <цвета числа? </p>