Использование ggplot() в рамках другой функции в R
Я пытаюсь написать простую функцию графика, используя библиотеку ggplot2. Но вызов ggplot не находит аргумент функции.
Рассмотрим a data.frame
, называемый means
, который хранит два условия и два средних значения, которые я хочу построить (условие появится на оси X, значит, на Y).
library(ggplot2)
m <- c(13.8, 14.8)
cond <- c(1, 2)
means <- data.frame(means=m, condition=cond)
means
# The output should be:
# means condition
# 1 13.8 1
# 2 14.8 2
testplot <- function(meansdf)
{
p <- ggplot(meansdf, aes(fill=meansdf$condition, y=meansdf$means, x = meansdf$condition))
p + geom_bar(position="dodge", stat="identity")
}
testplot(means)
# This will output the following error:
# Error in eval(expr, envir, enclos) : object 'meansdf' not found
Итак, кажется, что ggplot вызывает eval
, который не может найти аргумент meansdf
. Кто-нибудь знает, как я могу успешно передать аргумент функции ggplot?
(Примечание. Да, я могу просто вызвать функцию ggplot напрямую, но в конце я надеюсь, что моя функция графика сделает более сложные вещи!:))
Ответы
Ответ 1
Как правильно ответили Joris и Chase, стандартная передовая практика - просто опустить часть meansdf$
и напрямую обращаться к столбцам фрейма данных.
testplot <- function(meansdf)
{
p <- ggplot(meansdf,
aes(fill = condition,
y = means,
x = condition))
p + geom_bar(position = "dodge", stat = "identity")
}
Это работает, потому что переменные, упомянутые в aes
, рассматриваются либо в глобальной среде, либо в кадре данных, переданном в ggplot
. Это также причина, почему ваш примерный код - с помощью meansdf$condition
и т.д. - не работал: meansdf
не доступен в глобальной среде и не доступен в кадре данных, переданном в ggplot
, который равен meansdf
сам.
Тот факт, что переменные ищутся в глобальной среде, а не в вызывающей среде, - это фактически известная ошибка в ggplot2, которую Хэдли не считает фиксированной на момент.
Это приводит к проблемам, если вы хотите использовать локальную переменную, скажем, scale
, чтобы влиять на данные, используемые для графика:
testplot <- function(meansdf)
{
scale <- 0.5
p <- ggplot(meansdf,
aes(fill = condition,
y = means * scale, # does not work, since scale is not found
x = condition))
p + geom_bar(position = "dodge", stat = "identity")
}
Очень хороший обходной путь для этого случая предоставляется Уинстоном Чангом в заданной проблеме GitHub: Явно устанавливаю параметр environment
для текущей среды во время вызова ggplot
.
Вот как это выглядело бы для приведенного выше примера:
testplot <- function(meansdf)
{
scale <- 0.5
p <- ggplot(meansdf,
aes(fill = condition,
y = means * scale,
x = condition),
environment = environment()) # This is the only line changed / added
p + geom_bar(position = "dodge", stat = "identity")
}
## Now, the following works
testplot(means)
Ответ 2
"Правильный" способ использовать ggplot
программно - использовать aes_string()
вместо aes()
и использовать имена столбцов как символы, а не как объекты:
Для более программных применений, например, если вы хотите, чтобы пользователи могли указывать имена столбцов для различных эстетических объектов в качестве аргументов или если эта функция идет в пакете, который должен пройти R CMD CHECK
без предупреждений об именах переменных без определений, вы можете использовать aes_string()
, с столбцами, необходимыми в качестве символов.
testplot <- function(meansdf, xvar = "condition", yvar = "means",
fillvar = "condition") {
p <- ggplot(meansdf,
aes_string(x = xvar, y= yvar, fill = fillvar)) +
geom_bar(position="dodge", stat="identity")
}
Ответ 3
Вот простой трюк, который я использую для определения моих переменных в моей среде функций (вторая строка):
FUN <- function(fun.data, fun.y) {
fun.data$fun.y <- fun.data[, fun.y]
ggplot(fun.data, aes(x, fun.y)) +
geom_point() +
scale_y_continuous(fun.y)
}
datas <- data.frame(x = rnorm(100, 0, 1),
y = x + rnorm(100, 2, 2),
z = x + rnorm(100, 5, 10))
FUN(datas, "y")
FUN(datas, "z")
Обратите внимание, что метка оси Y также изменяется, когда используются разные переменные или наборы данных.
Ответ 4
Я не думаю, что вам нужно включить часть meansdf$
в свой вызов функции. Кажется, это работает на моей машине:
meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)
testplot <- function(meansdf)
{
p <- ggplot(meansdf, aes(fill=condition, y=means, x = condition))
p + geom_bar(position="dodge", stat="identity")
}
testplot(meansdf)
для создания:
![enter image description here]()
Ответ 5
Это пример проблемы, обсуждавшейся ранее . В основном, это сводится к тому, что ggplot2 кодируется для использования в глобальной среде в основном. В вызове aes() переменные ищутся либо в глобальной среде, либо в пределах указанного фрейма данных.
library(ggplot2)
means <- data.frame(means=c(13.8,14.8),condition=1:2)
testplot <- function(meansdf)
{
p <- ggplot(meansdf, aes(fill=condition,
y=means, x = condition))
p + geom_bar(position="dodge", stat="identity")
}
EDIT:
update: после просмотра другого ответа и обновления пакета ggplot2, приведенный выше код работает. Разумеется, как поясняется в комментариях, ggplot будет искать переменные в aes в глобальной среде (когда фрейм данных специально добавляется как meandf $...) или в пределах указанной среды.
Для этого убедитесь, что вы работаете с последней версией ggplot2.
Ответ 6
Это разочаровало меня в течение некоторого времени. Я хотел отправить разные кадры данных с разными именами переменных, и мне нужна возможность отображать разные столбцы из фрейма данных. Я, наконец, получил работу, создав некоторые фиктивные (глобальные) переменные, чтобы обрабатывать построение и принудительное назначение внутри функции
plotgraph function(df,df.x,df.y) {
dummy.df <<- df
dummy.x <<- df.x
dummy.y <<- df.y
p = ggplot(dummy.df,aes(x=dummy.x,y=dummy.y,.....)
print(p)
}
то в главном коде я могу просто вызвать функцию
plotgraph(data,data$time,data$Y1)
plotgraph(data,data$time,data$Y2)
Ответ 7
Короткий ответ: используйте qplot
Длинный ответ:
В сущности, вы хотите что-то вроде этого:
my.barplot <- function(x=this.is.a.data.frame.typically) {
# R code doing the magic comes here
...
}
Но у этого нет гибкости, потому что вы должны придерживаться последовательного названия столбцов, чтобы избежать раздражающих особенностей области R. Конечно, следующий логический шаг:
my.barplot <- function(data=data.frame(), x=..., y....) {
# R code doing something really really magical here
...
}
Но тогда это начинает подозрительно выглядеть, как вызов qplot(), правильно?
qplot(data=my.data.frame, x=some.column, y=some.other column,
geom="bar", stat="identity",...)
Конечно, теперь вы хотели бы изменить такие вещи, как названия шкал, но для этого функция удобна... Хорошей новостью является то, что проблемы с охватом часто больше не проходят.
my.plot <- qplot(data=my.data.frame, x=some.column, y=some.other column,...)
set.scales(p, xscale=scale_X_continuous, xtitle=NULL,
yscale=scale_y_continuous(), title=NULL) {
return(p + xscale(title=xtitle) + yscale(title=ytitle))
}
my.plot.prettier <- set.scale(my.plot, scale_x_discrete, 'Days',
scale_y_discrete, 'Count')
Ответ 8
Другим обходным решением является определение aes (...) как переменной вашей функции:
func<-function(meansdf, aes(...)){}
Это просто сработало для меня по аналогичной теме
Ответ 9
Вам ничего не нужно. Даже не фиктивные переменные. Вам нужно только добавить функцию print() внутри вашей функции, как с помощью cat(), когда вы хотите, чтобы что-то отображалось в консоли.
myplot < - ggplot (......) + Все, что вы хотите здесь
print (myplot)
Он работал у меня более одного раза внутри одной и той же функции
Ответ 10
Я просто генерирую новые переменные фрейма данных с нужными именами внутри функции:
testplot <- function(df, xVar, yVar, fillVar) {
df$xVar = df[,which(names(df)==xVar)]
df$yVar = df[,which(names(df)==yVar)]
df$fillVar = df[,which(names(df)==fillVar)]
p <- ggplot(df,
aes(x=xvar, y=yvar, fill=fillvar)) +
geom_bar(position="dodge", stat="identity")
}
Ответ 11
Если важно передать переменные (имена столбцов) в пользовательскую функцию построения без кавычек, в то время как в функции используются разные имена переменных, то другой обходной путь, который я пробовал, заключался в использовании match.call()
и eval
(как здесь также):
library(ggplot2)
meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)
testplot <- function(df, x, y) {
arg <- match.call()
scale <- 0.5
p <- ggplot(df, aes(x = eval(arg$x),
y = eval(arg$y) * scale,
fill = eval(arg$x)))
p + geom_bar(position = "dodge", stat = "identity")
}
testplot(meansdf, condition, means)
![]()
Создано в 2019-01-10 пакетом представлением (v0.2.1)
Другой обходной путь, но с передачей заключенных в кавычки переменных в пользовательскую функцию построения графиков, использует get()
:
meansdf <- data.frame(means = c(13.8, 14.8), condition = 1:2)
testplot <- function(df, x, y) {
scale <- 0.5
p <- ggplot(df, aes(x = get(x),
y = get(y) * scale,
fill = get(x)))
p + geom_bar(position = "dodge", stat = "identity")
}
testplot(meansdf, "condition", "means")
Создано в 2019-01-10 пакетом представлением (v0.2.1)