0
votes

I have an .Rnw file, containing R code chunks and LaTeX commands. So far, I have been developing and testing this code in Rstudio: clicking on "compile PDF" to obtain some output files and a PDF file generated.

I would now like to use commandArgs() to be able to give my .Rnw one single argument: a YAML file. This file contains all sorts of parameters that are needed by the script.

To give some context:

  • My .Rnw script is a pipeline script which was designed to be as "generic" as possible.

  • My .Rnw script requires a number of parameters each time - these will be the parameters varying between each project. To supply these parameters, I currently (already) use a YAML configuration file. This means the first thing my .Rnw script does is import the YAML file, and then it starts doing things.

My problem is: can I used "Rscript", "commandArgs()" and knitr all together. I was hoping that my addind some commandArgs() to my .Rnw script, I would be able to run everything (i.e. give argument on command line to supply YAML file and compile PDF) like so:

Rscript script.Rnw params.yaml

However, I have getting this error about a "\", which I strongly suspect is something to do with the fact I'm using a .Rnw file (and the very first thing in it a LaTeX command). I then saw potential solution on other posts such as:

 Rscript -e "library(knitr); knit('script.Rnw')"
 pdflatex script.tex

However, this also fails - unsurprisingly I suppose because I haven't given it my configuration YAML file.

I realise my design is likely flawed: by using commandAgrs() AND knitr together, I am making things quite complicated. I also realise that knitr may have not be truly designed for making reports for scripts that are used as pipelines (at least that's my impression). The reason I want to use it is so that for each project, a quick PDF can be generated with all the results.

I would appreciate any advice. Here is a sample of my code:

\documentclass[12pt, a4paper]{article}

\usepackage[utf8]{inputenc}
\usepackage{hyperref}
\hypersetup{
colorlinks   = true, %Colours links instead of ugly boxes
urlcolor     = blue, %Colour for external hyperlinks
linkcolor    = blue, %Colour of internal links
citecolor   = blue %Colour of citations
 }
\usepackage{caption}
\setlength{\parindent}{0pt}
\usepackage{authblk}
\usepackage[nomarkers, nolists]{endfloat} %Positions figures at the end of the document and add no list of names (requires that chunk have fig.cap option)
\usepackage{soul} % Allows underline lines to be broken (use \ul{} instead of \underline{})

\usepackage{helvet} %Set up Arial as font
\renewcommand{\familydefault}{\sfdefault}

\newcommand{\Rfunction}[1]{{\texttt{#1}}}
\newcommand{\Rpackage}[1]{{\textit{#1}}}

\title{\textbf{Report}}
\author{Author}
\date{\today}



\begin{document}

\maketitle

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in table of contents
\tableofcontents
\endgroup

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in list of figures
\listoffigures
\endgroup



\newpage
\section{Introduction} 
This report blah blah blah

\newpage
\section{Results}

<<importing-lib, echo=FALSE, message=FALSE, cache=TRUE>>=

###################################################
# Obtain command-line YAML file and set directory #
###################################################

#!/usr/bin/env Rscript
args= commandArgs(trailingOnly=TRUE)

if (length(args) == 0) {
 stop("this script requires a configuration file (.yaml) as input")

 } else if (length(args) > 1) {
  stop("this script requires only one input: a configuration file (.yaml)")

}

params <-  yaml.load_file(args[1])

setwd(params$workdir)

if (dir.exists(file.path(params$workdir, "results")) == FALSE) {
  dir.create(file.path(params$workdir, "results","edgeR"), recursive = TRUE)
  dir.create(file.path(params$workdir, "results", "gsea", "input_files"), recursive = TRUE)
}

print("Hello!")
@

\end{document}
1
You're on the right track, but you have to separate the configuration script from the .Rnw file, i.e. you have to take the code from your importing-lib chunk and put it in its own .R file, add the knitr commands to that file, and invoke it with Rscript.Alexis
@Alexis thanks, I did what you suggested. I have put an answer with the 2 methods which I have found to work. Not sure 100% which one is best but the method you suggested is better I think.mf94

1 Answers

0
votes

Ok so I have found 2 ways in which it seems to work:

Method 1: using command line knitr() and pdflatex

In this case, everything is one script (called script.Rnw) still but it looks like so:

\documentclass[12pt, a4paper]{article}

\usepackage[utf8]{inputenc}
\usepackage{hyperref}
\hypersetup{
colorlinks   = true, %Colours links instead of ugly boxes
urlcolor     = blue, %Colour for external hyperlinks
linkcolor    = blue, %Colour of internal links
citecolor   = blue %Colour of citations
 }
\usepackage{caption}
\setlength{\parindent}{0pt}
\usepackage{authblk}
\usepackage[nomarkers, nolists]{endfloat} %Positions figures at the end of the document and add no list of names (requires that chunk have fig.cap option)
\usepackage{soul} % Allows underline lines to be broken (use \ul{} instead of \underline{})

\usepackage{helvet} %Set up Arial as font
\renewcommand{\familydefault}{\sfdefault}

\newcommand{\Rfunction}[1]{{\texttt{#1}}}
\newcommand{\Rpackage}[1]{{\textit{#1}}}

\title{\textbf{Test report}}
\date{\today}



\begin{document}

\maketitle

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in table of contents
\tableofcontents
\endgroup

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in list of figures
\listoffigures
\endgroup



\newpage
\section{Introduction} 
This is the introduction.

\newpage
\section{Results}

This is the results.

<<importing-lib, echo=FALSE, message=FALSE>>=

###################################################
# Obtain command-line YAML file and set directory #
###################################################

#!/usr/bin/env Rscript
args= commandArgs(trailingOnly=TRUE)

if (length(args) == 0) {
  stop("this script requires a configuration file (.yaml) as input")

  # } else if (length(args) > 1) {
  # stop("this script requires only one input: a configuration file (.yaml)")

}

library(yaml)
params <- yaml.load_file(args[1])

dir <- getwd()

if (dir.exists(file.path(dir, "results")) == FALSE) {
  dir.create(file.path(dir, "results","part1"), recursive = TRUE)
  dir.create(file.path(dir, "results", "part2", "input_files"), recursive = TRUE)
}

print("Hello!")
print(params$project)
@



\newpage
\section{End}

This is the end!

\end{document}

To run the pipeline:

Rscript -e "library(knitr); knit('script.Rnw')" params.yaml && pdflatex script.tex

Method 2: separating code into a .Rnw file and .R launch file

The script.Rnw looks like so:

\documentclass[12pt, a4paper]{article}

\usepackage[utf8]{inputenc}
\usepackage{hyperref}
\hypersetup{
colorlinks   = true, %Colours links instead of ugly boxes
urlcolor     = blue, %Colour for external hyperlinks
linkcolor    = blue, %Colour of internal links
citecolor   = blue %Colour of citations
 }
\usepackage{caption}
\setlength{\parindent}{0pt}
\usepackage{authblk}
\usepackage[nomarkers, nolists]{endfloat} %Positions figures at the end of the document and add no list of names (requires that chunk have fig.cap option)
\usepackage{soul} % Allows underline lines to be broken (use \ul{} instead of \underline{})

\usepackage{helvet} %Set up Arial as font
\renewcommand{\familydefault}{\sfdefault}

\newcommand{\Rfunction}[1]{{\texttt{#1}}}
\newcommand{\Rpackage}[1]{{\textit{#1}}}

\title{\textbf{Test report}}
\date{\today}



\begin{document}

\maketitle

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in table of contents
\tableofcontents
\endgroup

\begingroup
\hypersetup{linkcolor=black} % force independent link colours in list of figures
\listoffigures
\endgroup



\newpage
\section{Introduction} 
This is the introduction.

\newpage
\section{Results}

This is the results.

<<first-chunk, echo=FALSE, message=FALSE>>=

print("Hello!")
print(params$project)
@



\newpage
\section{End}

This is the end!

\end{document}

The launch.R script looks like so:

#!/usr/bin/env Rscript

library(yaml)
library(knitr)

args= commandArgs(trailingOnly=TRUE)

if (length(args) == 0) {
  stop("this script requires a configuration file (.yaml) as input")

  # } else if (length(args) > 1) {
  # stop("this script requires only one input: a configuration file (.yaml)")

}

params <- yaml.load_file(args[1])

dir <- getwd()

if (dir.exists(file.path(dir, "results")) == FALSE) {
  dir.create(file.path(dir, "results","edgeR"), recursive = TRUE)
  dir.create(file.path(dir, "results", "gsea", "input_files"), recursive = TRUE)
}

knit2pdf('script.Rnw')

To run the script:

Rscript launch.R params.yaml

One difference between the methods: method 1 generates more files (*tex, *toc, *out, *log, *aux), presumably because it's technically 2 commands. Method 2 only generates a .tex and a .pdf file.