R ggplot2 for loop plots same data

2020-04-18 05:22发布

I have put together a simple for loop to generate a series of plots and then use grid.arrange to plot them. I have two problems:

  1. The axes of the plots change correctly to the column names, but the same data is plotted on each graph. Having put in a breakpoint and stepped through the code it appears to be incrementing correctly so I'm not sure why.

  2. I have set the plot aesthetic to group on year, however this produces intermediate .5 years that appear in the legend. This hasn't happened to me before.

Should all be reproducible using mtcars.

library(ggplot2)
library(gridExtra)

result <- mtcars

for(i in 1:2) {
  nam <- paste("p", i, sep = "")
  assign(
    nam, ggplot(result, aes(x = disp, y = results[i+4], group = gear, color = gear)) +
      geom_line() +
      geom_point() +
      scale_colour_distiller(palette = "Dark2", direction = -1, guide = "legend") +
      scale_y_continuous(name = colnames(results[i+4])) +
      scale_x_continuous(name = "x")
  )
}


plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)

4条回答
可以哭但决不认输i
2楼-- · 2020-04-18 05:39

You should take full advantage of ggplot::facet_wrap

This means tidying your data to a single data frame that's interpretable to ggplot

Data

temp <- mtcars

Tidy data

library(purrr)
library(dplyr)
Names <- map_chr(1:2, ~names(temp)[.x+4])
# "drat" "wt"

data <- map_df(1:2, ~temp[,c("cyl", names(temp)[.x+4])] %>% setNames(c("cyl", "value")), .id="iteration") %>%
          mutate(iteration = Names[as.numeric(iteration)])

plot with facet_wrap

ggplot(data=data, aes(x=cyl, y=value, label=iteration)) +
  geom_line() +
  geom_point() +
  facet_wrap(~iteration)
查看更多
相关推荐>>
3楼-- · 2020-04-18 05:45

Your using results and result. And you should use aes_string and then refer to the variables by string name:

You should also avoid to make tons of assignments. Just put it all into a list()

library(ggplot2)
library(gridExtra)

result<-mtcars

for(i in 1:2) {
    nam <- paste("p", i, sep = "")
    assign(
        nam, ggplot(result,aes_string(x="disp",y=names(result)[i+4], group="gear", color="gear")) +
            geom_line() +
            geom_point() +
            scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
            scale_y_continuous(name=colnames(result[i+4])) +
            scale_x_continuous(name="x")
    )
}


plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)
查看更多
女痞
4楼-- · 2020-04-18 05:52

The problem is that the plot is generated in the for loop, but evaluated in the do.call. Since i has changed in the for loop, both are evaluated with i = 2. You can confirm this with:

i <- 3
do.call(grid.arrange, plist)

A small adjustment to your code fixes the issue:

for(i in 1:2) {
  nam <- paste("p", i, sep = "")
  coln <- colnames(result[i+4])
  assign(
    nam, ggplot(result,aes_(x=~disp,y=as.name(coln), group=~gear, color=~gear)) +
      geom_line() +
      geom_point() +
      scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
      scale_y_continuous(name=coln) +
      scale_x_continuous(name="x")
  )
}


plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)
查看更多
狗以群分
5楼-- · 2020-04-18 05:58

I think trying to access the columns by their number in the aes mapping is confusing ggplot. This works:

for(i in 1:2) {
  nam <- paste("p", i, sep = "")
  assign(
    nam, ggplot(result,aes_string(x="disp",y=colnames(result)[i+4], group="gear", color="gear")) +
      geom_line() +
      geom_point() +
      scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
      scale_y_continuous(name=colnames(result[i+4])) +
      scale_x_continuous(name="x")
  )
}

I would suggest iterating over the names though; this makes the code much clearer. Here's a version that does this and skips the detour around the environment:

plots <- lapply(c("drat", "wt"), function(column) {
  ggplot(result,aes_string(x="disp",y=column, group="gear", color="gear")) +
    geom_line() + geom_point() +
    scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
    scale_y_continuous(name=column) +
    scale_x_continuous(name="x")}) %>% 
  do.call(grid.arrange, .)
do.call(grid.arrange, plots)
查看更多
登录 后发表回答