Ted Mosby
Ted Mosby

Reputation: 1456

plot each row in a data.frame in a list using ggplot

I have a list of data.frames and I want to plot each row of each data.frame using ggplot. I'm looking to store these into a variable so then I can plot these in a png in a 20x12 format. Meaning 20 graphs across and 12 down.

Each data.frame in the list would get it's own png file.

df = data.frame(matrix(rnorm(n=240), nrow = 240, ncol = 602))
df_list = list(df,df,df)
plots=list(list(list()))
for (i in 1:length(df_list)){
  for (k in 1:240){
    testdf = as.numeric(t(df[[i]][k,2:ncol(df[[i]])]))
    testtime = seq_along(df[[i]])
    test =((cbind(testtime,testdf)))
    test = as.data.frame(test)
    plots[[k]]=ggplot(aes(`1`,testdf),data=test)+geom_line()
  }
  plots[i]=rbind(plots[[k]],plots)
}

The following code gets me the last loop of [i] but it doesnt save the first few loops. Any ideas?

Bonus Points if you know how to plot each [i] into separate png files in a matrix of plots measuring 20x12.

Upvotes: 2

Views: 2179

Answers (2)

Gregor Thomas
Gregor Thomas

Reputation: 146110

Okay. I don't like your data - it's all boring straight lines. Let's generate some new data - and since it's all numeric I'll leave it as a matrix instead of converting to data frame:

input = replicate(
    n = 3,
    matrix(rnorm(n = 240 * 602), nrow = 240, ncol = 602),
    simplify = F
)

Just like in Mark's answer, I'll convert it to long format. Since it's a matrix, we don't need all the data frame editing tools, I'll just as.vector the matrix and add on the index and id columns.

The plotting code is mostly untouched from Mark's answer.

plots <- lapply(input, function(mm) { 
    # if you really need to start with data frames, not matrices
    # just put here: mm = as.matrix(mm) 
    df_long = data.frame(id = 1:nrow(mm), index = rep(1:ncol(mm), each = nrow(mm)), value = as.vector(mm))
    ggplot(df_long, aes(x = index, y = value)) +
        geom_line() +
        facet_wrap(~id, nrow = 20) +
        theme(strip.text = element_blank())
})

Now, these plots are big! You've got 240 subplots in each list item - I would advise against trying to look at them too much in the GUI. Instead, let's save them as nicely compressed pngs and view the files.

for (i in seq_along(plots)) {
    ggsave(filename = sprintf("myplot%s.png", i),
           plot = plots[[i]],
           height = 30, width = 18)
}

I can't upload a plot because it exceeds the maximum filesize - and even then each subplot is pretty small. You may want to up the height and width even more.

This answer is very close to Mark's excellent answer - the only differences are the method of reshaping the data and the extra bit on saving.

Upvotes: 1

Mark Peterson
Mark Peterson

Reputation: 9570

If you are willing to tidy your data, you can use this, which will automatically generate the 20x12 layout for each of the data.frames:

library(tidyverse)

df = data.frame(matrix(rnorm(n=240), nrow = 240, ncol = 602)) %>%
  mutate(id = 1:nrow(.)) %>%
  gather(index, value, -id) %>%
  mutate(index = parse_number(index))

df_list = list(df,df,df)

catch <- lapply(df_list, function(df){
  ggplot(df
         , aes(x = index
               , y = value)) +
    geom_line() +
    facet_wrap(~id
               , nrow = 20
               , ncol = 12) +
    theme(strip.text = element_blank())
})

One of the plots:

enter image description here

Note that you will want to make thematic changes, particularly if you want to be able to label the individuals, but this at least generates the layout you wanted.

Upvotes: 3

Related Questions