Clay Finney
Clay Finney

Reputation: 27

Using dplyr/ggplot2 inside for loops

I am trying to filter and plot 11 different graphs based on 11 different levels from a column stored in a vector.

For a quick, reproducible example, here's basically something I've tried:

library(dplyr)
library(ggplot)
positions = c("forward", "defense")

df <- data.frame(player = c("Sergio Ramos", "Lionel Messi",
                            "Dani Alvez", "Christiano Ronaldo"),
                 position = c("forward", "defense", "defense", "forward"),
                 goals = c(12, 8, 2, 23))

for (i in 1:length(positions)) {
  df %>%
    filter(position == positions[i]) %>%
    print(ggplot(aes(x = player, y = goals)) +
      geom_bar(stat = "identity"))
}

If I just wrap the filter in print() and run it, I get both subsets:

             player position goals
1       Sergio Ramos  forward    12
2 Christiano Ronaldo  forward    23
        player position goals
1 Lionel Messi  defense     8
2   Dani Alvez  defense     2

But the code above gives me

Error: ggplot2 doesn't know how to deal with data of class uneval.

If I run the code without the loop, it graphs fine.

I want to be able to loop through the variables and publish them all in Rmd or save them all. Can someone explain why the above does not work? Thanks!

Upvotes: 1

Views: 2155

Answers (5)

OmaymaS
OmaymaS

Reputation: 1731

If you want to have all the plots in one place independently (without using facet_wrap), you can try the following:

  • split the dataframe into groups defined by position as a factor.

    dfx <- split(df,as.factor(df$position))

lapply Solution

Also you can use lapply on the splitted dataframe as follows:

  • define a function that produce the plot you want

    my_plot <- function(x){ g <- ggplot(x,aes(x = player, y = goals)) + geom_bar(stat = "identity") }

  • use lapply

ggy <- lapply(dfx,my_plot)

You will have all plots in ggy:

ggy$defense
ggy$forward

for-loop solution

  • create an empty list to keep all plots in.

    ggx <- list()

  • loop and save each plot in ggx list.

    for(i in 1:length(positions)){
        # create a barplot and save in g
        g <- ggplot(dfx[[i]],aes(x = player, y = goals)) +
                geom_bar(stat = "identity")
    
        n <- dfx[[i]]$position %>% unique() %>% as.character()
    
        # add the plot to the list
        ggx[[n]] <- g
    

    }

now you have the plots in:

ggx[[1]] or ggx$defense
ggx[[2]] or ggx$forward

You can print wherever you want, save or get information.

> ggx$defense$data
        player position goals
2 Lionel Messi  defense     8
3   Dani Alvez  defense     2

Upvotes: 2

Sotos
Sotos

Reputation: 51622

You don't really need any kind of loop to get what you need. The facet_wrap can do what you need. i.e.

ggplot(df, aes(x = player, y = goals)) + geom_bar(stat = 'identity') +facet_wrap(~position)

Upvotes: 2

DataJack
DataJack

Reputation: 415

The below will save a plot to each page of a pdf in your working directory

pdf("out.pdf", width = 7, height = 7)
for (i in 1:length(positions)) {
 print( df %>%
    filter(position == positions[i]) %>%
  ggplot(aes(x = player, y = goals)) +
            geom_bar(stat = "identity"))
}
dev.off() 

For markdown documents start with the markdown cheat sheet here.

However I think you may want to look into using the facet_grid or facet_wrap function and saving that to pdf in the same method as above

Upvotes: 1

boshek
boshek

Reputation: 4416

You could do it this way too:

for (i in positions) {
  dfplt <- df %>%
    filter(position == positions) 
    plt <- ggplot(dfplt,aes(x = player, y = goals)) +
            geom_bar(stat = "identity")
    ggsave(plt, file=paste0(i,"_plot.png"))
}

Upvotes: 0

Wojciech Książek
Wojciech Książek

Reputation: 709

Using the dplyr pipes puts the data frame in wrong place. Try like this instead:

library(dplyr)
library(ggplot2)
positions = c("forward", "defense")

df <- data.frame(player = c("Sergio Ramos", "Lionel Messi",
                            "Dani Alvez", "Christiano Ronaldo"),
                 position = c("forward", "defense", "defense", "forward"),
                 goals = c(12, 8, 2, 23))

for (i in 1:length(positions)) {
  df %>%
    filter(position == positions[i]) %>%
    ggplot(aes(x = player, y = goals)) +
            geom_bar(stat = "identity") -> g
    print(g)
}

You may also consider rewriting the loop with lapply.

Upvotes: 5

Related Questions