0
library(patchwork)
library(ggplot2)

cell_measurements = read_csv(random.csv)
measurement_types = col_names(cell_measurements)[5:9]
plot_list = list()

for (i in 1:5){
  plot_list[[i]] = ggplot(cell_measurements, aes(sapply(Injury, as.character), eval(parse(text = measurement_types[i])))) +
  geom_boxplot(aes(fill=Animal)) +
  labs(x ='Injury', y = measurement_types[i])
}

wrap_plots(plot_list)

Example data:

Animal = c(dog, dog, dog, rabbit, rabbit, rabbit)
Injury = c(0,1,0,1,0,1)
Measurement1 = c(0.1,0.2,-0.8,1.5,1.2,1.3)
Measurement2 = c(0.1,0.5,-0.9, -1.4, 1.6, -0.5)

What I expected to get were five different plots neatly arranged, instead, all five plots here are the same. They have the right labels on the x and y axis but the box plots look exactly the same.

Also, tried to each plot individually and then do wrap_plots which worked fine. Just doesn't work when I use the for loops.

shafee
  • 15,566
  • 3
  • 19
  • 47
  • Could you post a [minimal, reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) of your data, the variable `measurement_types` and any packages you are using, e.g. `patchwork`? Also it would be helpful to know what you expect the output to look like (e.g. a 5x1 grid?). As it is it looks like you could do this more simply with facets, and without the `sapply()` or `eval(parse())`, but without the data and what you're aiming for it's hard to be sure. – SamR Dec 28 '22 at 09:21
  • This does not sound like a patchwork problem, try plotting each individually and see if they're identical. Perhaps even redo the example where each step is done manually and see if the result is the same. Perhaps the issue is in your `eval(parse(...))` usage. – Oliver Dec 28 '22 at 09:22
  • @Oliver , included those please can you have another look? Thanks – codingPrincess Dec 28 '22 at 10:03

1 Answers1

2

The lazy operation of ggplot makes it so that the value of i is really only evaluated when you try to plot all three. That is, in your for loop, the i iterates over 1 through 5, but the ggplot code knows that it must reference i when it renders. Since the rendering step doesn't happen until after the for loop is done, all five instances of the lazy-ggplot objects look for i and find the same value of i = 5.

Options:

  1. Facet your plot, no need for wrap_plots. (This requires reshaping/pivoting/melting.)

    reshape2::melt(quux, c("Animal", "Injury"), variable.name = "Measurement") |>
      ggplot(aes(Injury, Measurement)) +
      geom_boxplot(aes(fill = Animal)) +
      facet_grid(Measurement ~ ., scales = "free_y")
    

    ggplot with facets

    You can use tidyr::pivot_longer in place of reshape2::melt.

    You can facet them horizontally as well, though the y-axis will be split.

  2. Use lapply in place of your for loop. While it seems relatively synonymous in effect, there value of i is actually different between the iterations.

    lapply(c("Measurement1", "Measurement2"), function(m) subset(quux, select = c("Animal", "Injury", m)) |>
      ggplot(aes(Injury, m)) +
      geom_boxplot(aes(fill = Animal))) |>
      ggplot(aes(Injury, m)) + geom_boxplot(aes(fill = Animal))) |>
      patchwork::wrap_plots()
    

    ggplot with wrap_plots


Data

quux <- structure(list(Animal = c("dog", "dog", "dog", "rabbit", "rabbit", "rabbit"), Injury = c(0, 1, 0, 1, 0, 1), Measurement1 = c(0.1, 0.2, -0.8, 1.5, 1.2, 1.3), Measurement2 = c(0.1, 0.5, -0.9, -1.4, 1.6, -0.5)), class = "data.frame", row.names = c(NA, -6L))
r2evans
  • 141,215
  • 6
  • 77
  • 149