Lapply и цикл for дают разные результаты при динамическом создании графиков

впервые задаю вопрос здесь, поэтому, если я что-то напутаю, дайте мне знать, я буду рад исправить это.

Пытаясь динамически создать несколько графиков, сгенерированных ggplot2, а затем распечатать графики с помощью gridExtra::grid.arrange, я заметил, что использование цикла for или lapply дает разные результаты.

Удивительно, но в то время как lapply дает ожидаемый результат, графики, созданные с помощью цикла for, в конечном итоге содержат все те же данные y.

Вот воспроизводимый пример:

library(ggplot2)
library(gridExtra)

gen.plot <- function(df, x.colName, y.colName, title,
                            movavg.period) {
  # print(y.colName)
  p <- ggplot(df, aes(x = df[[x.colName]],
                      y = df[[y.colName]])) +
    geom_line() +
    xlab("Time") +
    ylab("Value") +
    ggtitle(title)

  return(p)
}

titles <- c("down", "mid", "up")
df <- data.frame(tick = seq(0, 10, 1),
                 down = seq(2, 1, -0.1),
                 mid = rep(3, 11),
                 up = seq(5,6, 0.1))

plots.list <- list()
for(t in titles) {
  plots.list[[length(plots.list) + 1]] <- gen.plot(df, "tick", 
                                            t, t, 2)
}
grid.arrange(grobs = plots.list, nrow = 3)

plots.list <- lapply(titles, FUN =  function(t, lapply.df) {
  gen.plot(lapply.df, "tick", 
        t, t, 2)
}, lapply.df = df)

grid.arrange(grobs = plots.list, nrow = 3)

Теперь, когда это становится действительно странным, так это то, что если вы раскомментируете вызов print в функции, которая выводит переменную y.colName, цикл for будет работать должным образом. Но это работает, только если вы распечатываете эту конкретную переменную, а не любую другую функциональную переменную. Кроме того, как вы можете видеть в коде, переменная y.colName используется в заголовке графика, и заголовок правильный для каждого графика.

Кроме того, я попытался извлечь код из функции, но он дает те же результаты, и трюк с вызовом print больше не работает.

Я не могу опубликовать изображение без 10 репутации, поэтому ссылки должны быть.

Вот что я получаю с помощью цикла for: forloop

Вот что я получаю с lapply: lapply

Вот мой sessionInfo():

R version 3.4.3 (2017-11-30)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=English_Ireland.1252  LC_CTYPE=English_Ireland.1252   
[3] LC_MONETARY=English_Ireland.1252 LC_NUMERIC=C                    
[5] LC_TIME=English_Ireland.1252    

attached base packages:
  [1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
  [1] gridExtra_2.3 ggplot2_2.2.1

loaded via a namespace (and not attached):
[1] labeling_0.3     colorspace_1.3-2 scales_0.5.0     compiler_3.4.3  
[5] lazyeval_0.2.0   plyr_1.8.4       tools_3.4.3      pillar_1.2.1    
[9] gtable_0.2.0     tibble_1.4.2     yaml_2.1.14      Rcpp_0.12.16    
[13] grid_3.4.3       rlang_0.2.0      munsell_0.4.3 

Пожалуйста, если вы понимаете, что здесь происходит, объясните мне это, помогите мне снова уснуть.


person Quentin    schedule 23.11.2018    source источник
comment
Когда вы используете цикл for, отображается только последняя итерация. Вы можете прочитать объяснение к аналогичному вопросу здесь. Это также хорошее прочтение о том, как ggplot создает график.   -  person Z.Lin    schedule 30.11.2018


Ответы (1)


Попробуй это:

gen.plot <- function(df, x.colName, y.colName, title,
                     movavg.period) {
  # print(y.colName)
  p <- ggplot(df, aes_string(x = x.colName,
                             y = y.colName)) +
    geom_line() +
    xlab("Time") +
    ylab("Value") +
    ggtitle(title)

  return(p)
}

Он должен давать согласованные и правильные результаты независимо от того, какой метод вы используете для его реализации (т. Е. lapply или for цикл). Использование ggplot2 таким образом позволяет вам указывать имена переменных с помощью строки. И вы должны указывать имена переменных, а не указывать aes весь столбец из фрейма данных.

person Lyngbakr    schedule 23.11.2018
comment
Спасибо, что ответили на @Lyngbakr. Он дает одинаковые результаты для lapply и for с использованием aes_string. Однако меня больше интересует, почему он не дает тех же результатов в случае, который я показал ранее. В чем основная разница между for и lapply, которая заставляет код работать в одном случае, а не в другом, а также почему печать содержимого переменной меняет результат кода. - person Quentin; 23.11.2018