Использование ggplot () в другой функции в R - PullRequest
45 голосов
/ 24 февраля 2011

Я пытаюсь написать простую функцию заговора, используя библиотеку ggplot2.Но вызов ggplot не находит аргумент функции.

Рассмотрим 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 напрямую, но в конце я надеюсь, что моя функция plot сделает более сложные вещи!:))

Ответы [ 11 ]

37 голосов
/ 13 апреля 2015

Как уже правильно ответили Джорис и Чейз, стандартная лучшая практика - просто пропустить часть 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)
28 голосов
/ 13 декабря 2014

"Правильный" способ использовать 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")
}
18 голосов
/ 29 февраля 2012

Вот простой трюк, который я часто использую для определения своих переменных в своей среде функций (вторая строка):

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 также изменяется, когда разные переменные или наборы данныхиспользуются.

16 голосов
/ 24 февраля 2011

Не думаю, что вам нужно включать часть 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

15 голосов
/ 24 февраля 2011

Это пример проблемы, которая обсуждается ранее . По сути, все сводится к тому, что 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.

3 голосов
/ 13 декабря 2014

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

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)
1 голос
/ 01 апреля 2017

Вам не нужно ничего особенного. Даже не фиктивные переменные. Вам нужно только добавить print () в вашу функцию, это все равно что использовать cat (), когда вы хотите что-то показать в консоли.

myplot <- ggplot (......) + Все, что вы хотите здесь печать (myplot) </p>

Это работало для меня более одного раза внутри одной и той же функции

1 голос
/ 17 октября 2014

Другой обходной путь - определить aes (...) как переменную вашей функции:

func<-function(meansdf, aes(...)){}

Это сработало у меня на похожую тему

1 голос
/ 25 января 2012

Краткий ответ: используйте 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')
0 голосов
/ 11 января 2019

Если важно передать переменные (имена столбцов) в пользовательскую функцию построения без кавычек, в то время как разные имена переменных используются внутри функции, то другим обходным путем, который я пробовал, было использование 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)

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