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)
но что, если у нас гораздо больше столбцов "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()
Примечание: это не ответ, просто очень частичное объяснение того, что происходит за кулисами, что может установить Вас на правильном пути. Я должен признать, что мое понимание 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
оценивается совместно на всех итерациях