Как вручную установить цвета *условно* в aes() И локальном geom_xxx() в ggplot?

Я пытаюсь создать функцию, которая может принимать либо одну группу, либо несколько групп, используя один аргумент colour. Однако, похоже, есть проблема с указанием colour как глобально (в aes()), так и локально (в geom_smooth()). Похоже, aes() не принимает colour=NULL или просто оставил пустым colour=.

Сюжет без групп (работает)

scatterfunction <- function (Data=mtcars,Predictor=mtcars$wt,Response=mtcars$mpg,what.Colour="purple") {
  library(ggplot2)
  ggplot(Data,aes(x=Predictor,y=Response)) +
    geom_smooth(method="lm",colour=what.Colour)
}
scatterfunction()

одиночная группа

Сюжет с группами (работает)

groupscatterfunction <- function (Data=mtcars,Predictor=mtcars$wt,Response=mtcars$mpg,Group.variable=factor(mtcars$cyl),what.Colour=c("purple", "yellow", "brown")) {
  library(ggplot2)
  ggplot(Data,aes(x=Predictor,y=Response,colour=Group.variable)) +
    geom_smooth(method="lm") +
    scale_color_manual(values=what.Colour)
}
groupscatterfunction()

3группы

График без групп, условный (работает при has.Groups=F)

conditionalscatterfunction <- function (Data=mtcars,Predictor=mtcars$wt,Response=mtcars$mpg,Group.variable=factor(mtcars$cyl),has.Groups=F,what.Colour="purple") {
  library(ggplot2)
  ggplot(Data,aes(x=Predictor,y=Response,colour= if(has.Groups==T) {Group.variable})) +
    geom_smooth(method="lm",colour= if(has.Groups==F){what.Colour}) +
    if (has.Groups==T) {scale_color_manual(values=what.Colour)}
}
conditionalscatterfunction()

одиночная группа

График с группами, условный (не работает, когда has.Groups=T)

conditionalscatterfunction(Data = mtcars,
                           Predictor = mtcars$wt,
                           Response = mtcars$mpg,
                           has.Groups = TRUE,
                           Group.variable = factor(mtcars$cyl),
                           what.Colour = c("purple", "yellow", "brown"))

Error: Aesthetics must be either length 1 or the same as the data (80): colour

Использование альтернативного оператора switch() работало у меня раньше, но не здесь:

conditionalscatterfunction <- function (Data=mtcars,Predictor=mtcars$wt,Response=mtcars$mpg,Group.variable=factor(mtcars$cyl),has.Groups=T,what.Colour=c("purple", "yellow", "brown")) {
  library(ggplot2)
  ggplot(Data,aes(x=Predictor,y=Response,colour= switch(has.Groups, Group.variable))) +
    geom_smooth(method="lm",colour= if(has.Groups==F){what.Colour}) +
    if (has.Groups==T) {scale_color_manual(values=what.Colour)}
}
conditionalscatterfunction()

Error: Aesthetics must be either length 1 or the same as the data (80): colour

Кажется, что пока я добавляю оператор «colour=» в aesthetics(), независимо от того, оставлю ли я его пустым или = NULL, я получаю эту ошибку. Каково его значение по умолчанию, если оно не вызывается явно?

Я бы предпочел не повторять весь вызов снова, потому что у меня также есть эта проблема с geom_points(), geom_shape() и т. д., и мне нужно будет повторить ее для каждой комбинации элементов...

Вопрос. Как решить эту проблему?


person RemPsyc    schedule 10.09.2019    source источник
comment
Просто отвечая на ваш первый абзац, вы пробовали colour = NA вместо colour = NULL?   -  person aosmith    schedule 10.09.2019
comment
Интересно, что он действительно работает автономно, как aes(colour=NA), но не при включении в оператор switch() или ifelse()... Может быть, aes() просто не может принимать операторы switch() или ifelse() вообще?   -  person RemPsyc    schedule 10.09.2019
comment
Будет проще, если вы сначала выполните предварительную обработку данных, используя dplyr, а затем добавите еще один столбец color, используя условия if-else. Затем вы сможете сослаться на столбец color в ggplot2.   -  person yusuzech    schedule 10.09.2019
comment
@YifuYan Я не знаю, хотели ли вы, чтобы я это сделал, но я добавил этот вызов в функцию: ifelse(has.Groups==T,(mtcars$colour.col = Group.variable),(mtcars$colour.col = what.Colour)). Затем я поменял на aes(colour=mtcars$colour.col). Работает, если я удалю аргумент colour= в geom_smooth, но не иначе... Правильно ли я сделал?   -  person RemPsyc    schedule 10.09.2019


Ответы (1)


Есть много способов снять шкуру с этого кота, но самый простой способ — просто предварительно определить geom_smooth с помощью if {} else {}. Например.:

conditionalscatterfunction <- function (Data, Predictor, Response, Group.variable, col = c("purple", "yellow", "brown")) {
  require(ggplot2)

  if (missing(Group.variable)) {
    smooth <- geom_smooth(method = "lm", color = col[1])
  } else {
    smooth <- geom_smooth(aes(color = {{Group.variable}}), method = "lm")
  }

  ggplot(Data, aes(x = {{Predictor}},y = {{Response}})) +
    smooth +
    scale_color_manual(values = col)
}

conditionalscatterfunction(mtcars, wt, mpg)
conditionalscatterfunction(mtcars, wt, mpg, factor(cyl))

Оба работают нормально.

person Axeman    schedule 10.09.2019
comment
Да, хорошо, спасибо, @Axeman. Однако, как упоминалось в моем посте, я бы здесь дублировал вызов geom_smooth... Нет ли способа использовать вызов ifelse() внутри самого вызова geom_smooth? В противном случае мне пришлось бы повторять это для всех остальных вариантов и комбинаций: geom_points(), geom_jitter, geom_shape(), geom_line и т. д., что не соответствовало бы принципу DRY, верно? Рассмотрим дополнительный оператор ifelse() has.points == TRUE, который потребует 2 дубликатов для цвета для каждого из T и F, что приведет к 4 дубликатам для одного вызова... Или я ошибаюсь? :3 - person RemPsyc; 10.09.2019
comment
Вы не можете легко сделать это, потому что, когда вы определяете групповую переменную, вам не разрешается передавать что-либо в color вне aes. Передача NULL вызывает ошибку, а передача NA приводит к исчезновению строки. - person Axeman; 10.09.2019
comment
Я понимаю. Так что моя фактическая функция может быть очень длинной, но у меня может не быть выбора в конце концов... Что ж, если это единственный способ, то сойдет! :) - person RemPsyc; 10.09.2019
comment
Это немного зависит от того, что является условным. Некоторые вещи вы можете легко определить на лету. См., например. stackoverflow.com/questions/22915337/ - person Axeman; 10.09.2019