ebb
ebb

Reputation: 274

r - create plots sequentially and arrange over multiple pages

I need to create plots sequentially from all files in a folder, add certain information from calculated values to the plot (e.g. Mean SOC, TNPP, ANPP, BNPP), and arrange them over as many pages as needed to array them in a 5 x 3 layout.

Please, find a sample folder with trial files here: https://www.dropbox.com/sh/evty00a0t9a062b/AAABG-rIq3Uhtlf-yOWo2fNGa?dl=0

Following different online sources and other threads, I have tried:

path <- "C:/Users/.../trialFiles"
dfs <- dir(path, "*.csv", full.names = FALSE, ignore.case = TRUE, all.files = TRUE)

plotModel <- function(df) {
    dat <- read.csv(paste(path, df, sep = "/"), header = TRUE, sep = ",") 
    Time <- dat$time
    SOC <- dat$somtc
    AGBM <- dat$agcprd
    BGBM <- dat$bgcjprd
    time_frame <- Time >= oT & Time <= fT
    sTime <- Time[time_frame]
    sSOC <- SOC[sTime]
    sAGBM <- AGBM[sTime]
    sBGBM <- BGBM[sTime]

    iM_AGBM <- mean(sAGBM)
    iM_BGBM <- mean(sBGBM)
    iMSOC <- mean(sSOC)
    iTNPP <- sum(iM_AGBM, iM_BGBM)

    plot(Time, SOC)
    legend("bottomright", bty = "n", legend = paste(df, "\n\n",
                                                    "SOC =", format(iMSOC, digits = 6), "\n",
                                                    "TNPP =", format(iTNPP, digits = 6), "\n", 
                                                    "ANPP =", format(iM_AGBM, digits = 5), "\n",
                                                    "BNPP =", format(iM_BGBM, digits = 5), sep = ""))

}

eq_plot <- lapply(dfs, plotModel)

nPlot <- length(eq_plot)
cols <- 3
layout <- matrix(seq(1, cols * ceiling(nPlot/cols)),
                ncol = cols, nrow = ceiling(nPlot/cols))

grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))

for (i in 1:nPlot) {
  matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))

  print(eq_plot[[i]], vp = viewport(layout.pos.row = matchidx$row,
                                  layout.pos.col = matchidx$col))
}

It does not give me an error, but is not showing the graphs either, just displays the text specified in the legend.

I have also tried with ggplot as follows:

dfs <- dir(period, "*.csv", full.names = FALSE, ignore.case = TRUE, all.files = TRUE)

plotModel <- function(df) {
    dat <- read.csv(paste(period, df, sep = "/"), header = TRUE, sep = ",") 
    Time <- dat$time
    SOC <- dat$somtc
    AGBM <- dat$agcprd
    BGBM <- dat$bgcjprd
    time_frame <- Time >= oT & Time <= fT
    sTime <- Time[time_frame]
    sSOC <- SOC[sTime]
    sAGBM <- AGBM[sTime]
    sBGBM <- BGBM[sTime]

    iM_AGBM <- mean(sAGBM)
    iM_BGBM <- mean(sBGBM)
    iMSOC <- mean(sSOC)
    iTNPP <- sum(iM_AGBM, iM_BGBM)

    ggplot(dat, aes(x=Time, y=SOC)) +
    geom_line() +
    ggtitle(df, subtitle = paste("SOC =", format(iMSOC, digits = 6), "\n",
                                            "TNPP =", format(iTNPP, digits = 6), "\n", 
                                            "ANPP =", format(iM_AGBM, digits = 5), "\n",
                                            "BNPP =", format(iM_BGBM, digits = 5), sep = ""))
}

eq_plot <- lapply(dfs, plotModel)
multi.page <- ggarrange(eq_plot, nrow = 5, ncol = 3)
ggexport(multi.page, filename = "diag_plots")

But I get the following error message: ggplot2 doesn't know how to deal with data of class uneval.

Please, forgive if cross posting. I have tried following the examples but there's something I am doing wrong.

Thanks

Upvotes: 2

Views: 716

Answers (1)

Katia
Katia

Reputation: 3914

You need to save the plot within your function in an object and then return it. Here is the solution for the first 3 files in that directory. You will need to adjust the last 2 lines of this code to handle all your plots:

library(ggplot2)
library(ggpubr)

path <- "C:/Users/.../path/to/your/dir"
dfs <- dir(path, "*.csv", full.names = FALSE, ignore.case = TRUE, all.files = TRUE)

# define oT and fT
oT=100
fT=1000

plotModel <- function(df) {
  dat <- read.csv(paste(path, df, sep = "/"), header = TRUE, sep = ",") 

  # This part can be optimized, see below the simplified version of the function
  Time <- dat$time
  SOC <- dat$somtc
  AGBM <- dat$agcprd
  BGBM <- dat$bgcjprd
  time_frame <- Time >= oT & Time <= fT
  sTime <- Time[time_frame]
  sSOC <- SOC[sTime]
  sAGBM <- AGBM[sTime]
  sBGBM <- BGBM[sTime]

  iM_AGBM <- mean(sAGBM)
  iM_BGBM <- mean(sBGBM)
  iMSOC <- mean(sSOC)
  iTNPP <- sum(iM_AGBM, iM_BGBM)

  # save graph in an object
  g<- ggplot(dat, aes(x=Time, y=SOC)) +
    geom_line() +
    ggtitle(df, 
            subtitle = paste("SOC =", format(iMSOC, digits=6), "\n",
                             "TNPP =", format(iTNPP, digits=6), "\n", 
                             "ANPP =", format(iM_AGBM, digits=5), "\n",
                             "BNPP =", format(iM_BGBM, digits=5), sep = ""))
  return(g)
}

eq_plot <- lapply(dfs, plotModel)

ggarrange(eq_plot[[1]], eq_plot[[2]], eq_plot[[3]], nrow = 1, ncol = 3) %>%
ggexport(filename = "diag_plots.png")
dev.off()

enter image description here

The body of the function can be simplified for clarity and efficiency:

plotModel <- function(df) {

  dat <- read.csv(paste(path, df, sep = "/"), header = TRUE, sep = ",") 
  var.means <- colMeans(dat[dat$time >= oT & dat$time <= fT, c("agcprd","bgcjprd","somtc")])

  # save graph in an object
  g<- ggplot(dat, aes(x=time, y=somtc)) +
    geom_line() +
    ggtitle(df, 
            subtitle = paste("SOC =", format(var.means["somtc"], digits=6), "\n",
                             "TNPP =", format(var.means["agcprd"] + var.means["bgcjprd"], digits=6), "\n", 
                             "ANPP =", format(var.means["agcprd"], digits=5), "\n",
                             "BNPP =", format(var.means["bgcjprd"], digits=5), sep = ""))
  return(g)
}

Upvotes: 1

Related Questions