Plotting a number of plots by looping using ggplot2

Hi all,
I am a doctoral student from India and a beginner in R for data analysis and plotting.
I have temperatures from 30 sensors which are distributed in 15 grids (2 in each grid) and I want to plot the temperature data of each grid i.e. each plot containing two geom_line from two sensors.

Here is my sample code for one grid:

ggplot(dat,aes(date))+
  geom_hline(yintercept = 0,color="black", linetype="dashed")+
  geom_line(aes(y=NIH001,colour="NIH001"))+
  geom_line(aes(y=NIH002,colour="NIH002"))+ xlab("Date") + ylab("Temperature (°C)")+
  scale_x_date(breaks = seq(as.Date("2013-09-01"), as.Date("2014-09-01"), by="1 month"),
               labels=date_format("%b-%y"))+
  scale_y_continuous(limits=c(-10,20))+
  theme_bw()+
  theme(plot.background = element_blank(), 
        panel.grid.major = element_line(), 
        panel.grid.minor = element_blank(), 
        panel.border = element_rect(size = 0.5, colour = "black"), 
        axis.line.x = element_line(size = 0.5, color = "black"),
        axis.line.y = element_line(size = 0.5, color = "black"))+
  scale_colour_manual("",
                      breaks = c("NIH001", "NIH002"),
                      values = c("red", "blue"))+
  theme(legend.position="top", 
        legend.direction="horizontal", 
        panel.background=element_rect(fill=NA,colour=NA),
        legend.key = element_rect(colour = NA, fill = NA))

In the above code NIH001,NIH002, etc are the names of sensors for one grid.

I have to run the same code 15 times.
Please help me how to loop the same code for all the 15 grids.
I hope I explained my problem!!

Here is the screenshot of my data: The first two columns belong to grid1, third and forth to grid2, and so on...

Regards
John

I'm not sure that it's the best way to go (there's a post somewhere that uses purrr to do this, but I can't seem to find it at the moment), but I did find this post, "Using loops with ggplot2," which does what you're describing.

1 Like

@mara

Thanks for commenting on my query.

Regards
John

1 Like

You could do it like this if you actually want them to be each plotted totally separate:

library(tidyverse)
library(lubridate)

set.seed(1234)

# creating a dummy data frame that looks like your data
dat <- tibble(
  date = seq.POSIXt(from = "2013-09-01" %>% as.POSIXct(.),
                    to = "2013-09-26" %>% as.POSIXct(.),
                    by = "1 day") %>% rep(., 30),
  sensor = rep(1:30, each = 26),
  # grid = rep(1:15, each = 52),
  temp = rnorm(26*30)
) %>% 
  mutate(sensor = ifelse(sensor < 10, 
                         paste0("NIH00", sensor),
                         paste0("NIH0", sensor))) %>% 
  spread(key = sensor, value = temp)


# transform data from wide to long
graphs <- dat %>% 
  gather(key = sensor, value = temp, NIH001:NIH030) %>% 
  
  # this may need to be changed based on how the sensors are grouped
  # by grid. This assumes that sensor 1 and 2 are in grid 1
  # sensor 3 and 4 are in grid 2 and so on
  # and that each sensor has the same number of data points.
  mutate(grid = rep(1:15, each = nrow(.)/15)) %>% 
  group_by(grid) %>% 
  nest() %>% 
  mutate(graphs =   map(
    data, 
    function(.x) {
      ggplot(.x, aes(date, temp, color = sensor))+
        geom_hline(yintercept = 0,color="black", linetype="dashed")+
        geom_line() +
        xlab("Date") + 
        ylab("Temperature (°C)")+
        scale_x_datetime(date_breaks = "1 month",
                     date_labels = "%b-%y")+
        scale_y_continuous(limits=c(-10,20))+
        theme_bw()+
        theme(plot.background = element_blank(), 
              panel.grid.major = element_line(), 
              panel.grid.minor = element_blank(), 
              panel.border = element_rect(size = 0.5, colour = "black"), 
              axis.line.x = element_line(size = 0.5, color = "black"),
              axis.line.y = element_line(size = 0.5, color = "black"))+
        # scale_colour_manual("",
        #                     breaks = c("NIH001", "NIH002"),
        #                     values = c("red", "blue"))+
        theme(legend.position="top", 
              legend.direction="horizontal", 
              panel.background=element_rect(fill=NA,colour=NA),
              legend.key = element_rect(colour = NA, fill = NA))
    }
  ))


graphs$graphs %>% 
  map(print)

some notes:

  1. I changed your scale_x_date to scale_x_datetime because the seq.POSIXt function I used to create the data creates datetime objects, so you may need to change it back to scale_x_date. Also, I changed the contents of this function to be less cumbersome for you.
  2. I had to change up your ggplot code since the data is not in long format and not wide format.
  3. You can change print in the last map call to something like ggsave to save each of the images. Right now it will just print 15 separate graphs to the Plots pane.

On a separate note, it might be more desirable to do multiple facets rather than multiple plots. To do this you would do something like this:

# using the same data I created above
dat %>% 
  gather(key = sensor, value = temp, NIH001:NIH030) %>% 
  mutate(grid = rep(1:15, each = nrow(.)/15)) %>% 
  ggplot(aes(date, temp, color = sensor))+
  facet_wrap(~grid, ncol = 3) +
  geom_hline(yintercept = 0,color="black", linetype="dashed")+
  geom_line() +
  xlab("Date") + 
  ylab("Temperature (°C)")+
  scale_x_datetime(date_breaks = "1 month",
                   date_labels = "%b-%y")+
  scale_y_continuous(limits=c(-10,20))+
  theme_bw()+
  theme(plot.background = element_blank(), 
        panel.grid.major = element_line(), 
        panel.grid.minor = element_blank(), 
        panel.border = element_rect(size = 0.5, colour = "black"), 
        axis.line.x = element_line(size = 0.5, color = "black"),
        axis.line.y = element_line(size = 0.5, color = "black"))+
  theme(panel.background=element_rect(fill=NA,colour=NA),
        legend.key = element_rect(colour = NA, fill = NA))

That would give you this:

Granted it is a little crowded but you could do a subset of the grids and do multiple plots either manually or in a similar fashion to what is done above

2 Likes

@tbradley

Thanks a lot for helping me.
Both the methods worked properly.

Thanks again
John