ggplot: AES vs AES string или как программно указать имена столбцов?

предположим у нас есть следующий фрейм данных

data <- data.frame(time=1:10, y1=runif(10), y2=runif(10), y3=runif(10))

и мы хотим создать сюжет такой:

p <- ggplot(data, aes(x=time))
p <- p + geom_line(aes(y=y1, colour="y1"))
p <- p + geom_line(aes(y=y2, colour="y2"))
p <- p + geom_line(aes(y=y3, colour="y3"))
plot(p)

enter image description here

но что, если у нас гораздо больше столбцов "y", и мы не знаем их точного названия. Возникает вопрос: как мы можем перебирать все столбцы программно и добавлять их в график? В основном цель:

otherFeatures <- names(data)[-1]
for (f in otherFeatures) {
  # what goes here?
}

Неудачных Попыток

до сих пор я нашел много способов, что делать не работать. Например (все следующие примеры показывают только строку кода в приведенном выше цикле for):

моя первая попытка была просто использовать aes_string вместо aes для того, чтобы указать имя столбца с переменной цикла f:

p <- p + geom_line(aes_string(y=f, colour=f))

но это не дает того же результата, потому что теперь colour не будет фиксированным цветом для каждой строки (aes_string растолкует f в среде фрейма данных). В результате легенда станет цветовой полосой, и делает не содержит разных имен столбцов. Моей следующей догадкой было mix aes и aes_string, пытаясь установить colour фиксированная строка:

p <- p + geom_line(aes_string(y=f), aes(colour=f))

но это Error: ggplot2 doesn't know how to deal with data of class uneval. Моей следующей попыткой было использовать colour "абсолютно" (не в пределах aes) такой:

p <- p + geom_line(aes_string(y=f), colour=f)

но это дает Error: invalid color name 'y1' (и я не хочу выбирать некоторые правильные имена цветов вручную). Следующей попыткой было вернуться в aes только с использованием ручного подход:

p <- p + geom_line(aes(y=data[[f]], colour=f))

это не дает ошибки, но будет отображать только последний столбец. Это имеет смысл, так как aes вероятно, называть substitute, и выражение всегда будет оцениваться с последним значением f в цикле (rm f перед вызовом plot(p) дает ошибку, указывая, что оценка происходит после петли).

перефразируя вопрос: Что за substitute/eval/quote магия нужна для скопировать простой код сверху в петлю?

3 ответов


это старый сейчас, но в случае, если кто-то еще сталкивается с ним, у меня была очень похожая проблема, которая сводила меня с ума. Решение я нашел был передать aes_q() to geom_line() С помощью . Вы можете найти подробную информацию о aes_q() здесь. Ниже приведен способ решения этой проблемы, хотя тот же принцип должен работать в цикле. Обратите внимание, что я добавляю несколько переменных с geom_line() как список здесь, который обобщает лучше (в том числе до одного переменная.)

varnames <- c("y1", "y2", "y3")
add_lines <- lapply(varnames, function(i) geom_line(aes_q(y = as.name(i), colour = i)))

p <- ggplot(data, aes(x = time))
p <- p + add_lines
plot(p)

надеюсь, что это поможет!


Вы можете melt (спасибо, что напомнили мне об этой функции, rawr) все ваши данные в несколько столбцов. Например, это может выглядеть так:

library(reshape2)    
data2 <- melt(data, id = "time")
head(data2)
#    time variable       value
# 1     1       y1 0.353088575
# 2     2       y1 0.621565368
# 3     3       y1 0.696031085
# 4     4       y1 0.507112969
# 5     5       y1 0.009560710
# 6     6       y1 0.158993988
ggplot(data2, aes(x = time, y = value, color = variable)) + geom_line()

enter image description here


Примечание: это не ответ, просто очень частичное объяснение того, что происходит за кулисами, что может установить Вас на правильном пути. Я должен признать, что мое понимание NSE все еще очень основное.

я боролся и все еще борюсь с этой конкретной проблемой. Я сузил этот вопрос до NSE. Я не знаком с родной заменой/цитатой / eval R, поэтому я собираюсь продемонстрировать использование lazyeval пакет.

library(lazyeval)

a <- lapply(c(1:9,13), function(i) lazy(i))

head(a)
# [[1]]
# <lazy>
#   expr: c(1, 2, 3, 4, 5, 6, 7, 8, 9, 13)[[10L]]
#   env:  <environment: 0x25889a00>
# 
# [[2]]
# <lazy>
#   expr: c(1, 2, 3, 4, 5, 6, 7, 8, 9, 13)[[10L]]
#   env:  <environment: 0x25889a00>
#
# ...........

lazy_eval(a[[1]])
# [1] 13

lazy_eval(a[[2]])
# [1] 13

Я думаю, это происходит потому, что lazy(i) связывает с обещанием i. К тому времени, когда мы доберемся до оценки любого из них i оценки, i это то, что было последним назначено ему - в этом случае,13. Возможно, это связано с окружающей средой, в которой i оценивается совместно на всех итерациях