#r #list #user-defined-functions #purrr
Вопрос:
Я хочу вызвать функцию wrap_vr
с помощью map
или pmap
purrr
библиотеки.
Во-первых, я не понимаю, почему я должен использовать df$v1
и df$v2
передавать переменные в функцию. Почему нет v1
и v2
только?
Во-вторых, в чем моя ошибка, когда я пытался использовать pmap
?
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
ggplot(data = df, aes(date, all_of(vr)))
geom_line(color = "steelblue", size = 1)
labs(title = tit,
y = ylab, x = "")
facet_wrap(~ cy)
}
wrap_vr(df, df$v1, "title_1", "ylabel_1")
wrap_vr(df, df$v2, "title_2", "ylabel_2")
list_1 <- list(df, list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
# This gives an error
pmap(list_1, ~wrap_vr(.x))
#> Error: Element 2 of `.l` must have length 1 or 4, not 2
Created on 2021-07-06 by the reprex package (v2.0.0)
Комментарии:
1. Я полагаю, что проблема с purrr заключается в том, что ваш набор данных читается как список. Попробуй
list(list(df), ...
вместоlist(df, ...
этого . Для передачи переменных в функцию на основе ggplot2 вы можете оказаться в месте, где было бы полезно прочитать о программировании с помощью tidyverse/ggplot2 и аккуратной оценки. Я чаще всего использую строки при передаче переменных в функции на основе ggplot2 и поэтому использую.data
местоимение. Нравитсяaes(x = data, y = .data[[vr]])
, а затем передайте строкиwrap_var(df, "v1", "t1", "y1")
.2. Спасибо. Использование
.data
местоимения привело к этому, но превращениеdf
вlist(df)
не произошло.3. @sbac, ваш df является константой для всех итераций, поэтому его следует передавать за пределы списка.
4. @sbac Да, я пропустил один шаг. Затем сделайте
pmap(list_1, wrap_vr)
, чтобы передать вещи из списка в функцию (нет.x
). Я согласен с другими, что если df будет исправлен, вы сможете сделать его частью своей функции.5. Рори правильно это показал. Однако также рекомендуется, чтобы другие имена столбцов не использовались в качестве констант.
Ответ №1:
Изменение нескольких вещей в вашем коде устраняет эту проблему. Во-первых, ваш набор данных не должен читаться как список, поэтому вы можете его удалить list_1
.
list_1 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
Оттуда вы можете сформулировать свой вызов pmap следующим образом, чтобы получить нужные вам результаты:
pmap(list_1, ~wrap_vr(df, ..1, ..2, ..3))
Ответ №2:
Помимо двух перечисленных проблем есть еще одна проблема, вы передаете столбцы даты и cy как постоянные, предполагая, что они всегда будут там.
Тем не менее, я предлагаю использовать эти столбцы в качестве имен по умолчанию.
так
- ваша первая проблема может быть решена с помощью
.data[[vars]]
- вашу вторую проблему можно решить, удалив df из списка
- кроме того, предлагается дополнительно изменить вашу пользовательскую функцию, используя еще два аргумента, хотя и со значениями по умолчанию.
- Также предлагается использовать аргумент df в последнем со значением по умолчанию
- Таким образом, в вашей функции вам придется передать ей три аргумента, другие будут использовать значения по умолчанию.
ДЕМОНСТРАЦИЯ
library(tidyverse)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function( vr, tit, ylab, c1 = 'date', c2 = 'cy', df = df){
df %>% ggplot(aes(.data[[c1]], .data[[vr]]))
geom_line(color = "steelblue", size = 1)
labs(title = tit,
y = ylab, x = "")
facet_wrap(~ .data[[c2]])
}
wrap_vr( 'v1', "title_1", "ylabel_1")
wrap_vr( 'v2', "title_2", "ylabel_2")
list_1 <- list(list('v1', 'v2'), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pmap(list_1, ~wrap_vr(..1, ..2, ..3))
#> [[1]]
#>
#> [[2]]
Создано 2021-07-06 пакетом reprex (v2.0.0)
Ответ №3:
Использование pmap
в этом случае приведет к печати пустых списков в консоли (или внутри уценки). Поскольку wrap_vr()
вызывается побочными эффектами (показывает графику) и ничего не возвращает, лучше использовать pwalk()
такую функцию:
Что касается записи v1
вместо df$v1
того, чтобы нам нужно будет изменить a wrap_vr()
, чтобы учесть тот факт, что v1
его нужно хранить внутри списка в виде выражения (чтобы избежать ошибки «объект v1 не найден»).
library(tidyverse)
library(rlang)
df <- tibble(cy = c('a', 'a', 'b', 'b'),
date = c(1,2,1,2),
v1 = c(1,2,3,1),
v2 = c(5,3,2,1))
wrap_vr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, all_of(vr)))
geom_line(color = "steelblue", size = 1)
labs(title = tit,
y = ylab, x = "")
facet_wrap(~ cy))
}
list_1 <- list(list(df, df), list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_1, wrap_vr)
Вариант 2
#to avoid calling df twice inside the list
list_2 <- list(list(df$v1, df$v2), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_2, wrap_vr, df = df)
вариант 3
#or quoting the column names
#because column names will go inside a list, we'll need a mechanism to avoid evaluation.
wrap_vr_expr <- function(df, vr, tit, ylab){
print(
ggplot(data = df, aes(date, eval_tidy(vr)))
geom_line(color = "steelblue", size = 1)
labs(title = tit,
y = ylab, x = "")
facet_wrap(~ cy))
}
list_3 <- list(list(df, df), list(expr(v1), expr(v2)), list("title_1", "title_2"), list("ylabel_1", "ylabel_2"))
pwalk(list_3, wrap_vr_expr)