написание функции R с помощью ggplot - PullRequest
0 голосов
/ 11 февраля 2020

Мне нужно нанести несколько наборов данных в одном формате, и после копирования кода несколько раз я решил написать функцию. Я понимаю простую функцию в R, и мне удалось написать следующее:

testplot <- function(data, mapping){
output <- ggplot(data) +
  geom_bar(mapping,
           stat="identity", 
             position='stack')
}
p <- testplot(df, aes(x=xvar, y=yvar, fill=type))

это прекрасно работает, однако мой график более сложный и требует аргумента "data" для go отдельно для каждого компонента:

output <- ggplot() +
  geom_bar(df1, mapping,
           stat="identity", 
             position='stack')+
geom_errorbar(df1, ...)+
geom+bar(df2, mapping,
...+
geom_errorbar(df2, ...)

но когда я пишу функцию и пытаюсь запустить ее как

output <- ggplot() +
  geom_bar(data, mapping,
           stat="identity", 
             position='stack')
}
p <- testplot(df, aes(x=xvar, y=yvar, fill=type))

, это выдает мне ошибку:

Error: `data` must be a data frame, or other object coercible by `fortify()`, not an S3 object with class uneval Did you accidentally pass `aes()` to the `data` argument?

Есть ли способ обойти это?

РЕДАКТИРОВАТЬ: когда я пытаюсь включить 2 кадра данных, как это:

testplot <- function(data, data2, mapping){
output <- ggplot() +
 geom_bar(data=data, mapping=mapping,
           stat="identity", 
             position='stack',
           width = barwidth)+
geom_bar(data2=data2, mapping=mapping,
           stat="identity", 
             position='stack',
           width = barwidth)
}



p <- testplot(data=df, data2=df2, mapping=aes(x=norms_number, y=coeff.BLDRT, fill=type))

он говорит: «Игнорирование неизвестных параметров: data2»

Ответы [ 3 ]

2 голосов
/ 11 февраля 2020

Большинство первых аргументов функций слоя ggplot2 зарезервированы для аргумента mapping, который взят из aes. Таким образом, в определении вашей функции у вас есть данные dataframe, неявно назначаемые переменной mapping. Чтобы обойти это, явно назначьте data = data в определениях вашей функции.

например

output <- ggplot() +
 geom_bar(data = data, mapping = mapping,
          stat="identity", 
            position='stack')
}

РЕДАКТИРОВАТЬ:

Есть много способов сделать это, и это действительно зависит от того, насколько сложной вы хотите, чтобы ваша функция была. Если вы собираетесь придерживаться глобального сопоставления aestheti c, то вы можете оставить сопоставление в главном вызове ggplot и назначить data = NULL, а затем указать, какой кадр данных будет связан с каким уровнем. Рассмотрим следующий воспроизводимый пример

library(ggplot2)
data1 <- data.frame(v1=rnorm(10, 50, 20), v2=rnorm(10,30,5))
data2 <- data.frame(v1=rnorm(10, 100, 20), v2=rnorm(10,50,10))
plot_custom_ggplot <- function(df1, df2, mapping) {
    ggplot(data = NULL, mapping = mapping) +
      geom_point(data = df1, color = "blue") +
      geom_line(data = df2, color = "red")
}

plot_custom_ggplot(data1,data2, aes(x = v1,y = v2))

В этом примере переменная отображения для каждой из функций слоя geom_* оставлена ​​пустой, и вместо этого отображение наследуется от основного вызова ggplot.

Обычно каждая функция уровня знает, какие данные использовать, потому что обычно они наследуются в основной функции ggplot. Всякий раз, когда вы указываете аргумент data или mapping, вы обычно переопределяете унаследованные значения. Любые пропущенные обязательные aes сопоставления пытаются найти в основном вызове.

library(ggplot2)
data1 <- data.frame(v1=rnorm(10, 50, 20), v2=rnorm(10,30,5))
data2 <- data.frame(v1=rnorm(10, 100, 20), v2=rnorm(10,50,10), z = c("A","B"))
plot_custom_ggplot <- function(df1, df2, mapping) {
    ggplot(data = NULL, mapping = mapping) +
      geom_point(data = df1, color = "blue") +
      geom_line(data = df2, mapping = aes(color = z)) #inherits x and y mapping from main ggplot call.
}

plot_custom_ggplot(data1,data2, aes(x = v1,y = v2))

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

plot_custom_ggplot(df1 = data2, df2 = data1, aes(x = v1, y = v2))
#Error in FUN(X[[i]], ...) : object 'z' not found
#
#the column z is not present in data1 object - 
#R then looked globally for a z object and didnt find anything.

Я считаю, что рекомендуется использовать аккуратные данные при работе с ggplot, потому что все становится слишком много Полегче. Существует обычно нет причин использовать несколько фреймов данных. Особенно, если вы планируете использовать один набор отображений для всех фреймов данных. Хорошее исключение - если вы пишете функцию построения для пользовательского объекта R, в котором вы знаете, как он определен.

В противном случае рассмотрите и сравните, как эти две функции работают в этом примере:

data1 <- data.frame(v1=rnorm(20, 50, 20), v2=rnorm(20,30,5), letters= letters[1:20], id = "df1")
data2 <- data.frame(v1=rnorm(20, 100, 20), v2=rnorm(20,50,10), letters = letters[17:26], id = "df2")

set.seed(76)
plot_custom_ggplot2 <- function(df, mapping) {
  ggplot(data = df, mapping = mapping) +
    geom_bar(stat = "identity",
             position="stack") 
}

plot_custom_ggplot <- function(df1, df2, mapping) {
  ggplot(data = NULL, mapping = mapping) +
    geom_bar(data = df1, stat = "identity",
         position="stack") +
    geom_bar(data = df2, stat = "identity",
         position="stack")
}

plot_custom_ggplot(data1,data2, aes(x = letters,y = v2, fill = id))
plot_custom_ggplot2(rbind(data1,data2), aes(x = letters, y = v2, fill = id))

На первом графике красные полосы для q, r, s и t скрыты за синими полосами. Это потому, что они добавляются друг на друга как layers. На втором графике эти значения фактически складываются, потому что эти значения были добавлены вместе в один слой, а не в два отдельных.

Надеюсь, это даст вам достаточно информации для написания вашей функции ggplot.

0 голосов
/ 16 февраля 2020

Причина, по которой я разбил свой фрейм данных, заключалась в том, что я хотел сгруппировать и сложить график и использовал этот вопрос: Как построить гистограмму с накоплением и сгруппированными данными в ggplot?

Отображение должен отличаться, чтобы они не оказывались друг на друге сверху (так что x = var1, а затем x = var1 + barwidth)

В любом случае, я могу построить график с несколькими geom_bar, но это последующий geom_errorbar, который не работает ни в одной функции. Я просто добавил полосы ошибок отдельно в конце, и, возможно, я посмотрю другие варианты в другой раз.

Я понимаю, что это уже функции, поэтому, вероятно, не предназначены для использования таким образом, и, возможно, это почему я не могу сделать несколько geom_errorbar в одной функции. Я просто хотел, чтобы мой код был более читабельным, потому что мне приходилось рисовать одну и ту же вещь 12 раз, с очень небольшими различиями, и это было очень долго. Возможно, есть более элегантный способ сделать это.

0 голосов
/ 12 февраля 2020
library(tidyverse)

testplot <- function(df1, df2, mapping){

  a <- ggplot() + 
    geom_point(data = df1, mapping = mapping) +
    geom_point(data = df2, mapping = mapping)

  return(a)

}

mtcars2 <- mtcars / 100 # creating a separate dataframe to provide the function

testplot(mtcars, mtcars2, mapping = aes(x = drat, y = vs))

Из вашего примера у вас есть «data2 = data2» - geom_bar не имеет аргумента «data2», только данные. Я получил вышеупомянутое, чтобы работать, так что адаптация для ваших целей тоже должна работать!

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