Execute multiline R expression from shell (with indentation) - r

I'm trying to achieve what you might naively write as:
R -e "
rmarkdown::render(
'MyDocument.Rmd',
params = list(
year = 2017
),
output_file = 'ExampleRnotebook.html'
)
"
So that I can make nicely formatted submission scripts to run on a cluster.
I've tried some variants on the below, I'm wondering if there might be an alternative approach to do this with the R -f flag?
read -r -d '' EXP << EOF
rmarkdown::render(
'MyDocument.Rmd',
params = list(
year = 2017
),
output_file = 'ExampleRnotebook.html'
)
EOF
R -e "$EXP"
but I get a series of errors that look like this:
ARGUMENT 'params~+~=~+~list(' __ignored__
for the different lines of the expression, followed by:
> rmarkdown::render(
+
+ Error: unexpected end of input
To reproduce:
MyDocument.Rmd =
---
title: "R Notebook"
output: html_notebook
params:
year: 0000
---
```{r}
params$year
```
This works fine:
read -r -d '' EXP <<- EOF
rmarkdown::render('MyDocument.Rmd', params = list(year = 2017 ), output_file = 'ExampleRnotebook.html')
EOF
R -e "$EXP"
but gets hard to read with longer param lists

This works for me (R version 3.5.0):
R --no-save <<code
for(i in 1:3) {
i +
2
}
print(i)
runif(5,
1,10)
code
Note: line-breaks and paddings are intentional.

Related

create PDF with preamble from rmarkdown::render

I am trying to create a PDF from R. I am successful from within RStudio (choosing "Knit to PDF"), but I get an error invoking from R (either with ctl-enter in Rstudio or with Rscript --vanilla invoke_from_R.R from the command line). My actual need is to create from the command line.
For example:
invoke_from_R.Rmd
---
title: "Lumber Jacks"
author: "Washington Irving"
date: "2022-09-19"
output:
pdf_document:
keep_tex: true
keep_md: true
dev: pdf
includes:
in_header: invoke_from_R_preamble.tex
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## Where are we?
Dove siamo?
invoke_from_R_preamble.tex
\newcommand\T{\rule{0pt}{2.6ex}} % Top strut
\newcommand\B{\rule[-1.2ex]{0pt}{0pt}} % Bottom strut
invoke_from_R.R
rmarkdown::render(
input = "invoke_from_R.Rmd"
, output_file = "invoke_from_R.pdf"
, output_format = rmarkdown::pdf_document(
rmarkdown::includes(in_header = "invoke_from_R_preamble.tex"),
toc = TRUE
, toc_depth = 2
, number_sections = FALSE
, keep_md = TRUE
, keep_tex = TRUE
, fig_width = 6.5
, fig_height = 4.5
, fig_crop = FALSE
)
)
The error that I get is:
$ Rscript --vanilla invoke_from_R.R
Error in !implicit_figures : invalid argument type
Calls: <Anonymous> ... <Anonymous> -> output_format -> pandoc_options -> from_rmarkdown
Execution halted
I have not yet found a workaround.
When I comment out this line:
rmarkdown::includes(in_header = "invoke_from_R_preamble.tex"),
I don't get the error, but I need to use the preamble because some of my LaTeX macros get processed even when I use the setting that is supposed to prevent this.
I am using (on Linux):
R version 4.2.1 (2022-06-23)
rmarkdown 2.14
Suggestions?
Thank you.

Rstudio pandoc issue

This example will knit on my laptop but not my desktop. Both are using the same RStudio and R versions. I have tried uninstalling R and RStudio, changing R and RStudio versions, changing 32/64 bit R, trying to install a variety of pandoc versions, setting the path to pandoc manually with Sys.setenv()... I am sort of at a loss here.
Both machines have the following:
> rmarkdown::pandoc_version()
[1] ‘1.19.2.1’
> version
_
platform x86_64-w64-mingw32
arch x86_64
os mingw32
system x86_64, mingw32
status
major 3
minor 4.3
year 2017
month 11
day 30
svn rev 73796
language R
version.string R version 3.4.3 (2017-11-30)
nickname Kite-Eating Tree
Here is a minimum non/working example. Again, it works on the laptop but not the desktop.
---
title: "Pandoc testing sandbox"
output:
html_document:
df_print: paged
number_sections: yes
toc: yes
toc_float:
collapsed: no
smooth_scroll: no
---
Here is a chunk of code to test:
```{r, results = "asis", echo = FALSE, message = FALSE}
tex2markdown <- function(texstring) {
writeLines(text = texstring,
con = myfile <- tempfile(fileext = ".tex"))
texfile <- knitr::pandoc(input = myfile, format = "html")
cat(readLines(texfile), sep = "\n")
unlink(c(myfile, texfile))
}
textable <- "
\\begin{table}[]
\\centering
\\begin{tabular}{l | c | c}
& without replacement & with replacement \\\\ \\hline
order matters & permutation: $\\frac{n!}{(n-k)!}$ & $n^k$ \\\\ \\hline
order does not matter & combination: ${n\\choose k}=\\frac{n!}{k!(n-k)!}$ & (\\textit{special case}) \\hline
\\end{tabular}
\\end{table}
"
tex2markdown(textable)
```
The error text on the desktop machine is:
Line 17 Error in knitr::pandoc(input = myfile, format = "html") :
Please install pandoc first: http://pandoc.org
Calls: <Anonymous> ... withVisible -> eval -> eval ->
tex2markdown -> <Anonymous> Execution halted
Any help with this would be greatly appreciated!
===
Edit: I did a bit more testing and ran:
rmarkdown::render("pandoctest.Rmd", "html_document")
And there was an option to "Rerun with Debug", so I did that, and the error is happening in "Function pandoc (namespace:knitr)" The line of code where the break happens in what I suppose is the pandoc function in the knitr package is:
...
if (Sys.which("pandoc") == "")
stop("Please install pandoc first: http://pandoc.org")
...
So it seems like pandoc is checking to see if it is installed itself? Or somehoe this is a pandoc function in the knitr package that is calling an actual pandoc program from somewhere else? SO it seems I need to get knitr to somehow see that I have pandoc installed.

R optparse error with command line arguments

For some reason, the optparse usage in this script breaks:
test.R:
#!/usr/bin/env Rscript
library("optparse")
option_list <- list(
make_option(c("-n", "--name"), type="character", default=FALSE,
dest="report_name", help="A different name to use for the file"),
make_option(c("-h", "--height"), type="numeric", default=12,
dest = "plot_height", help="Height for plot [default %default]",
metavar="plot_height"),
make_option(c("-w", "--width"), type="numeric", default=10,
dest = "plot_width", help="Width for plot [default %default]",
metavar="plot_width")
)
opt <- parse_args(OptionParser(option_list=option_list), positional_arguments = TRUE)
print(opt)
report_name <- opt$options$report_name
plot_height <- opt$options$plot_height
plot_width <- opt$options$plot_width
input_dir <- opt$args[1] # input directory
I get this error:
$ ./test.R --name "report1" --height 42 --width 12 foo
Error in getopt(spec = spec, opt = args) :
redundant short names for flags (column 2).
Calls: parse_args -> getopt
Execution halted
However, if I remove the "-h" from this line:
make_option(c("--height"), type="numeric", default=12,
dest = "plot_height", help="Height for plot [default %default]"
It seems to work fine;
$ ./test.R --name "report1" --height 42 --width 12 foo
$options
$options$report_name
[1] "report1"
$options$plot_height
[1] 42
$options$plot_width
[1] 12
$options$help
[1] FALSE
$args
[1] "foo"
Any ideas what might be going on here?
I am using R 3.3.0 and optparse_1.3.2 (getopt_1.20.0)
The -h flag is reserved by optparse (which is described as a feature of optparse which is not in getopt, from the getopt.R source file on Github):
Some features implemented in optparse package unavailable in getopt:
2. Automatic generation of an help option and printing of help text when encounters an "-h"
Therefore, when the user specifies -h, the sanity check for uniqueness of flags fails. The issue tracker does not seem to have any mention of the need to create a better error message for this case, however.
Finally, note that optparse seems to be invoking getopt, as they have the same author.

How to call exe program and input parameters using R?

I want to call .exe program (spi_sl_6.exe) using a command of R (system), however I can't input parameters to the program using "system". The followwing is my command and parameters:system("D:\\working\spi_sl_6.exe")
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this. Thanks in advance.
This is using the Standardized Precipitation Index software from
http://drought.unl.edu/MonitoringTools/DownloadableSPIProgram.aspx.
This seems to give a working solution using Windows (but not without warnings!)
Fisrt download the software and example files
# Create directory to download software
mydir <- "C:\\Users\\david\\spi"
dir.create(mydir)
url <- "http://drought.unl.edu/archive/Programs/SPI"
download.file(file.path(url, "spi_sl_6.exe"), file.path(mydir, "spi_sl_6.exe"), mode="wb")
# Download example files
download.file(file.path(url, "SPI_samplefiles.zip"), file.path(mydir, "SPI_samplefiles.zip"))
# extract one example file, and write out
temp <- unzip(file.path(mydir, "SPI_samplefiles.zip"), "wymo.cor")
dat <- read.table(temp)
# Use this file as an example input
write.table(dat, file.path(mydir,"wymo.cor"), col.names = FALSE, row.names = FALSE)
From page 3 of the help file basic-spi-program-information.pdf at the above link the command line code should be of the form spi 3 6 12 <infile.dat >outfile.dat, however,
neither of the following worked (just from command line not in R), and various iterations of how to pass parameters.
C:\Users\david\spi\spi_sl_6 3 <C:\Users\david\spi\wymo.cor >C:\Users\david\spi\out.dat
cd C:\Users\david\spi && spi_sl_6 3 <wymo.cor >out.dat
However, using the accepted answer from Running .exe file with multiple parameters in c#
seems to work. That is again from the command line
cd C:\Users\david\spi && (echo 2 && echo 3 && echo 6 && echo wymo.cor && echo out1.dat) | spi_sl_6
So to run this in R you can wrap this in a shell (you will need to change the path to where you have saved the exe)
shell("cd C:\\Users\\david\\spi && (echo 2 && echo 3 && echo 6 && echo wymo.cor && echo out2.dat) | spi_sl_6", intern=TRUE)
out1.dat and out2.dat should be the same.
This throws warning messages, I think from the echo (in R but not from command line) but the output file is produced.
Suppose you can automate all the echo calls sligtly, so all you need to do is input the time parameters.
timez <- c(2, 3, 6)
stime <- paste("echo", timez, collapse =" && ")
infile <- "wymo.cor"
outfile <- "out3.dat"
spiCall <- paste("cd", mydir, "&& (" , stime, "&& echo", infile, "&& echo", outfile, " ) | spi_sl_6")
shell(spiCall)
You can construct the command using sprintf :
cmd_name <- "D:\\working\spi_sl_6.exe"
param1 <- "a"
param2 <- "b"
system2(sprintf("%s %s %s",cmd_name,param1,param2))
Or using system2( I prefer this option):
system2(cmd_name, args = c(param1,param2))

Better string interpolation in R

I need to build up long command lines in R and pass them to system(). I find it is very inconvenient to use paste0/paste function, or even sprintf function to build each command line. Is there a simpler way to do like this:
Instead of this hard-to-read-and-too-many-quotes:
cmd <- paste("command", "-a", line$elem1, "-b", line$elem3, "-f", df$Colum5[4])
or:
cmd <- sprintf("command -a %s -b %s -f %s", line$elem1, line$elem3, df$Colum5[4])
Can I have this:
cmd <- buildcommand("command -a %line$elem1 -b %line$elem3 -f %df$Colum5[4]")
For a tidyverse solution see https://github.com/tidyverse/glue. Example
name="Foo Bar"
glue::glue("How do you do, {name}?")
With version 1.1.0 (CRAN release on 2016-08-19), the stringr package has gained a string interpolation function str_interp() which is an alternative to the gsubfn package.
# sample data
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)
# do the string interpolation
stringr::str_interp("command -a ${line$elem1} -b ${line$elem3} -f ${df$Colum5[4]}")
#[1] "command -a 10 -b 30 -f 4"
This comes pretty close to what you are asking for. When any function f is prefaced with fn$, i.e. fn$f, character interpolation will be performed replacing ... with the result of running ... as an R expression.
library(gsubfn)
cmd <- fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
Here is a self contained reproducible example:
library(gsubfn)
# test inputs
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)
fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## [1] "command -a 10 -b 30 -f 4"
system
Since any function can be used we could operate directly on the system call like this. We have used echo here to make it executable but any command could be used.
exitcode <- fn$system("echo -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## -a 10 -b 30 -f 4
Variation
This variation would also work. fn$f also performs substitution of $whatever with the value of variable whatever. See ?fn for details.
with(line, fn$identity("command -a $elem1 -b $elem3 -f `df$Colum5[4]`"))
## [1] "command -a 10 -b 30 -f 4"
Another option would be to use whisker.render from https://github.com/edwindj/whisker which is a {{Mustache}} implementation in R. Usage example:
require(dplyr); require(whisker)
bedFile="test.bed"
whisker.render("processing {{bedFile}}") %>% print
Not really a string interpolation solution, but still a very good option for the problem is to use the processx package instead of system() and then you don't need to quote anything.
library(GetoptLong)
str = qq("region = (#{region[1]}, #{region[2]}), value = #{value}, name = '#{name}'")
cat(str)
qqcat("region = (#{region[1]}, #{region[2]}), value = #{value}, name = '#{name}'")
https://cran.r-project.org/web/packages/GetoptLong/vignettes/variable_interpolation.html

Resources