Проверить или заменить значение аргумента «палитра» в функции ggplot2 :: discrete_scale ()? - PullRequest
0 голосов
/ 01 октября 2019

Заранее хочу извиниться за плохой английский ...

Я определил именованные, пользовательские цветовые палитры и хочу легко вызывать их с помощью собственной функции при создании графика с помощью функции ggplot (). Поэтому я кодировал «scale_function ()», для которого нужны только 3 параметра:

type       (character. "color" or "fill" for aesthetic mapping)

palette    (character. Name of an available palette)

discrete   (logical. TRUE for discrete data and FALSE for continuous data)

. С помощью второй функции я использую (grDevices: :) colorRampPalette () для интерполяции заданных цветов палитры.

Пока все работает нормально, как и планировалось. Теперь я заметил очень специфическую проблему при использовании моей функции:

Допустим, мы хотим создать график, в котором нам нужно меньше цветов (n), чем на самом деле имеет моя выбранная цветовая палитра (c). Это означает, что n

palette_catalog является списком, а "palette_x" включает в себя 6 различных цветов в виде шестнадцатеричных кодов

palette_catalog[["palette_x"]]
# [1] "#d11141" "#00b159" "#00aedb" "#f37735" "#ffc425" "#cccccc"

plot

test <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

Теперь, если япроверка выбранных цветов на графике «тест». Я обнаружил следующую проблему:

Первый и последний цвет (шестнадцатеричный код) определенной палитры используется правильно, но промежуточный цвет будет интерполирован, потому чтоиспользования colorRampPalette ... следовательно, исходный шестнадцатеричный код перезаписывается интерполированным новым шестнадцатеричным кодом. -> это главная проблема! В целях согласованности ggplot2 :: discrete_scale () не должна вести себя так ...

Если на графике нужно больше цветов, чем может предложить палитра (n> c), результат будет абсолютно хорошим иправильно, но я бы хотел обойти интерполяцию, когда n

palette_catalog <- list(
  palette_x = c(
    "#d11141" (first value),
    "#00b159",
    "#00aedb",
    "#f37735",
    "#ffc425",
    "#cccccc" (last value)
  )
)

В двух словах: если для графика требуется, например, 3 значения цвета, то яхочу, чтобы discrete_scale () выбрал первое, второе и третье значение «palette_x» вместо первого, интерполированного среднего и последнего значения ...

Мне очень жаль, что я запутался в английском, я пробовалвсе возможное, чтобы описать мою проблему, и, надеюсь, вы поймете мою точку зрения ...

############### некоторый код, который должен работать (уменьшен до минимума), просто скопируйте вставить вВаш RStudio
palette_catalog <- list(
  palette_x = c(
    "#d11141",
    "#00b159",
    "#00aedb",
    "#f37735",
    "#ffc425",
    "#cccccc"
  )
)


interpolate <- function(palette = "palette_x", ...) {
  x <- palette_catalog[[palette]]
  colorRampPalette(x, ...)
}

scale_function <- function(
    type = "color",
    palette = "palette_x",
    discrete = TRUE,
    ...) {

  count <- length(palette_catalog[[palette]])
  pal <- interpolate(palette)

  if(type == "color") {    
    if(discrete) {
      discrete_scale("color", palette, palette = pal, ...)
    } else {
      scale_color_gradientn(colors = pal(count), ...)
    }
  }
}


### use this code on this standard plot with iris dataset:

ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

enter image description here

## you can print the used colors of a plot with the following code:
plot <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

gg <- ggplot_build(plot)

unique(gg$data[[1]]["colour"])
#      colour
# 1   #D11141
# 51  #799288
# 101 #CCCCCC

ожидаемые (обязательные) цвета, используемые для 3 различных видов:

первые тризначения цвета "palette_x" в таком порядке:

"#d11141",
"#00b159",
"#00aedb"

фактические, неправильные цвета, использованные для графика:

, как уже дразнили в начале, график использует первый, средний (интерполированный)и последние значения цвета ...

"#d11141",
"#799288",
"#cccccc

Как вы видитеЗначение второго цвета недопустимо, поскольку оно является результатом интерполяции и не совпадает с фактическим вторым значением «palette_x», которое должно быть «# 00b159».

Кроме того, третье значение цвета также не запрашивается. Вместо этого должно было быть выбрано фактическое третье значение, которое является "# 00aedb".

Я действительно надеюсь, что кто-то может помочь мне и найти решение! Я уверен, что есть одно.

Я пробовал несколько решений, но ни одно из них не сработало ...

Код работает просто отлично, как я уже сказал. Просто этот крошечный конкретный случай - боль в заднице, и R сводит меня с ума в этот момент ... потому что ничто не работает так, как я ожидаю, что это должно ...

Буду признателен за вашу помощь и поддержку!

Ответы [ 2 ]

0 голосов
/ 01 октября 2019

Я думаю, что следующее даст вам примерно то, что вы, я думаю, вы ищете. Мы просто пишем новую функцию внутри функции, которая возвращает первые значения 1: n, когда n <= длина палитры, и иначе интерполирует цвета. </p>

scale_function <- function(type = "color", palette = "palette_x", discrete = TRUE, ...) {

  pal <- interpolate(palette)

  palfun <- function(n) {
    if (n > length(palette_catalog[[palette]])) {
      return(pal(n))
    } else {
      return(palette_catalog[[palette]][seq_len(n)])
    }
  }

  if(type == "color") {    
    if(discrete) {
      discrete_scale("color", palette, 
                     palette = palfun, 
                     ...)
    } else {
      scale_color_gradientn(colors = pal(count), ...)
    }
  }
}

Ваш пример теперь будет выглядеть следующим образом:

g <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")
g

enter image description here

со следующими цветами:

unique(layer_data(g)[["colour"]])
[1] "#d11141" "#00b159" "#00aedb"

И если вы превысите количество цветов впалитра, он должен начать интерполяцию:

df <- iris
# Random discrete variable
df$catvar <- sample(LETTERS[1:10], size = 150, replace = T)

g2 <- ggplot(df, aes(Sepal.Width, Sepal.Length, color = catvar)) +
  geom_point() +
  scale_function(palette = "palette_x")

enter image description here

unique(layer_data(g2)[["colour"]]) # Not in right order due to random sampling
 [1] "#FDBB26" "#00B067" "#BC8359" "#00AFAF" "#E8C76F" "#CCCCCC" "#D11141" "#F6902F" "#5C694E" "#35A1B6"
0 голосов
/ 01 октября 2019

Простите за недоразумение, но я считаю, что вы все еще можете использовать colorRampPalette(), но в качестве функции:

pal_domains <- brewer.pal(name = "Set3", n = 12)
pal_function <- colorRampPalette(pal_domains)


ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_color_manual(values = pal_function(3))


, и вы можете использовать pal_function() с любым количеством значений и изменить палитруимя, в соответствии с которым вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...