13

I am trying to understand how to use walk to silently (without printing to the console) return ggplot2 plots in a pipeline.

library(tidyverse)

# EX1: This works, but prints [[1]], [[2]], ..., [[10]] to the console
10 %>%
  rerun(x = rnorm(5), y = rnorm(5)) %>%
  map(~ data.frame(.x)) %>%
  map(~ ggplot(., aes(x, y)) + geom_point())

# EX2: This does not plot nor print anything to the console
10 %>%
  rerun(x = rnorm(5), y = rnorm(5)) %>%
  map(~ data.frame(.x)) %>%
  walk(~ ggplot(., aes(x, y)) + geom_point())

# EX3: This errors: Error in obj_desc(x) : object 'x' not found
10 %>%
  rerun(x = rnorm(5), y = rnorm(5)) %>%
  map(~ data.frame(.x)) %>%
  pwalk(~ ggplot(.x, aes(.x$x, .x$y)) + geom_point())

# EX4: This works with base plotting
10 %>%
  rerun(x = rnorm(5), y = rnorm(5)) %>%
  map(~ data.frame(.x)) %>%
  walk(~ plot(.x$x, .x$y))

I was expecting example #2 to work, but I must be missing or not understanding something. I want the plots from #1 without the console output.

JasonAizkalns
  • 20,243
  • 8
  • 57
  • 116
  • 2
    `walk` doesn't return or print anything, so if you want to print your plots, you need to say that explicitly. You can wrap the `ggplot` statement inside a `print` call – camille May 09 '18 at 15:38
  • 1
    @camille - ah, thank you, feel free to answer -- however, still slightly confused -- added example #4 which works with base plotting. – JasonAizkalns May 09 '18 at 15:41
  • 2
    `walk` returns its input invisibly. Using your EX2, if you run `p = 10 %>% rerun(x = rnorm(5), y = rnorm(5)) %>% map(~ data.frame(.x)) %>% walk(~ ggplot(., aes(x, y)) + geom_point())` and then type `p`, you'll see that `p` contains the input list of data frames. – eipi10 May 09 '18 at 15:43
  • 1
    EX1 will not print the individual plots or the list element numbers to the console if you pipe it into something else. For example, `library(gridExtra); 10 %>% rerun(x = rnorm(5), y = rnorm(5)) %>% map(~ data.frame(.x)) %>% map(~ ggplot(., aes(x, y)) + geom_point()) %>% grid.arrange(grobs=., ncol=5)`. Or, with a single call to map: `10 %>% rerun(x = rnorm(5), y = rnorm(5)) %>% map(~ data.frame(.x) %>% ggplot(aes(x, y)) + geom_point()) %>% grid.arrange(grobs=., ncol=5)`. – eipi10 May 09 '18 at 15:48

2 Answers2

17

I'm not sure why it works with base R plot in your 4th example honestly. But for ggplot, you need to explicitly tell walk that you want it to print. Or as the comments suggest, walk will return plots (I misspoke in my first comment on that) but not print them. So you could use walk to save the plots, then write a second statement to print them. Or do it in one walk call.

Two things here: I'm using function notation inside walk, instead of purrr's abbreviated ~ notation, just to make it clearer what's going on. I also changed the 10 to 4, just so I'm not flooding everyone's screens with tons of plots.

library(tidyverse)

4 %>%
    rerun(x = rnorm(5), y = rnorm(5)) %>%
    map(~ data.frame(.x)) %>%
    walk(function(df) {
        p <- ggplot(df, aes(x = x, y = y)) + geom_point()
        print(p)
    })

Created on 2018-05-09 by the reprex package (v0.2.0).

camille
  • 16,432
  • 18
  • 38
  • 60
  • 1
    Not directly related but as some migh make the same mistakes as I did, note that one can't pipe a `%>% print` statement to your `ggplot` chain, as because of operator precedence it will print only the last element of the chain (`geom_point` here). So one must either start the whole chain with `print(` or use an additional line like in this answer. – moodymudskipper Jun 27 '18 at 10:37
-2

This should work

10 %>%
  rerun(x = rnorm(5), y = rnorm(5)) %>%
  map(~ data.frame(.x)) %>%
  map(function(x) {
      ggplot(x, aes(x, y)) + geom_point()
  })
lcgodoy
  • 763
  • 5
  • 14