loopslatexknitrrnw

Knitr: Use nested loops to generate multiple reports


A previous post on StackOverflow had a very useful guide on how to use a template .Rnw file to produce multiple reports. I'd like to duplicate this, except I'd have 4 loops rather than just the one used in the example.

In my case, these are the loops that I'm using to produce the reports:

Here is a sample of the template code, which works without any issues when I supply all of the necessary variables that would be provided in the loops:

\begin{document}
This is a test in which the \texttt{\Sexpr{varname}} variable is used in this report. If successful, further reports can be generated using a loop with this same script!

First, a plot of the CDFs, with Kolmogorov-Smirnov statistics:
\begin{figure}[h]
\centering
<<cdf-plots,dev='png',out.width='0.5\\linewidth',echo=FALSE,warning=FALSE,fig.align='centering'>>=
 chart_stats(varname,data_vec,labs,season,s,h,colvec=colvec,cdf_plot=TRUE)
 cap1=paste('Cumulative distribution functions for the counts,',season,s,h)
@
\caption{\Sexpr{cap1}}
\end{figure}
<<ks_calc,warning=FALSE,results='asis',echo=FALSE>>=
library(xtable)
ks=chart_stats(varname,data_vec,labs,season,s,h,ks_test=TRUE,dval=TRUE)
cap=paste('D-values for',season,h,s)
print(xtable(ks,caption=cap))
@

For the sake of being able to see my output, each file is currently generated as a separate .tex file as shown:

library(knitr)
setwd("~/data_netcdf")
load("loaded_data.Rdata")
source("~/tempestextremes/test/chart_stats.R")

data_vec<-c("ERA", "climo", "2xCO2","SSTplus2","SSTplus2_2xCO2")

seasons_vec<-c("DJF","JJA","MAM","SON")
sec=c("ATL","PAC")
hemi=c("NH","SH")
var=c('centlat','centlon','area')

for (varname in var){
  }
  for (season in seasons_vec){
    for (h in hemi){
      for (s in sec){
        output_name=paste(varname,'_',season,'_',h,'_',s,'_report.tex',sep="")
        knit2pdf("~/data_netcdf/report_test.Rnw",output=output_name)
      }
    }   
  }
}

There is a knitr example that makes use of child files to combine outputs into one document, which sounds similar to what I'd like to do, and here's what I've tried:

<<test-main,include=FALSE>>= 
[removed for length]

#testing on just one variable name
var=c('centlat')
for (varname in var){
  out=NULL
  for (season in seasons_vec){
    for (h in hemi){
      for (s in sec){
        out=c(out,knit_child("~/data_netcdf/report_test.Rnw"))
      }
    }
  }
}
@

\Sexpr(paste(out,collapse='\n'))

but I'm getting the following error, probably due to the fact that I have multiple levels of loops which are all using the same chunk label names as references for the figures:

Error in parse_block(g[-1], g[1], params.src) : 
  duplicate label 'cdf-plots'
Calls: knit ... process_file -> split_file -> lapply -> FUN -> parse_block

Can someone please explain this error message? Do I need to somehow alter the label names so that it differentiates between each time it loops? Or should I implement the 3 inner loops within the template file? Or, perhaps combining all of the .tex files after the fact?

I would appreciate help in figuring out the best workflow for this.


Solution

  • I have come up with a solution! Some notes:

    1) the template file cannot have the \begin{document}...\end{document} tags or anything in the preamble, this must be in the main .Rnw file.

    2) As of this moment, it only works for a single variable (rather than looping over the vector of variables), but it's a trivial matter to scale this up.

    So here is an example of the template:

    <<{{prefix}}-setup>>=
    varname='{{varname}}'
    season='{{season}}'
    h='{{h}}'
    s='{{s}}'
    @
    
    First, a plot of the CDFs, with Kolmogorov-Smirnov statistics:
    \begin{figure}[h]
    \centering
    <<'{{prefix}}-cdf-plots',dev='png',fig.lp='{{prefix}}',out.width='0.5\\linewidth',echo=FALSE,warning=FALSE,fig.align='centering'>>=
    colvec=c("blue","red","green","purple","pink")
    chart_stats(varname,data_vec,labs,season,s,h,colvec=colvec,cdf_plot=TRUE)
    cap1=paste('Cumulative distribution functions for the counts,',season,s,h)
    @
    \caption{\Sexpr{cap1}}
    \end{figure}
    

    And then the main document:

    \documentclass{article}
    \usepackage[margin=0.5in]{geometry}
    \begin{document}
    
    <<test-main,include=FALSE>>=
    library(knitr)
    setwd("~/data_netcdf")
    load("loaded_data.Rdata")
    source("~/tempestextremes/test/charts_stats.R")
    [other stuff]
    @
    ...
    <<generate-code,echo=FALSE>>=
      varname='centlat'
      out=NULL
      for (season in seasons_vec){
        for (h in hemi){
          for (s in sec){
            prefix=paste(season,h,s,sep="_")
            out=c(out,knit_expand("~/data_netcdf/report_test_1.Rnw"))
          }
        }
      }
    @
    
    \Sexpr{paste(knit(text=out),collapse='\n')}
    \end{document}
    

    I should note that the inspiration came from the knitr-examples section, specifically this one.