I'm trying to run markdown (with parameters) in a for loop. If i don't specify the output directory it works just fine, but if I specify a different directory from the working directory I get an error on compiling.
My code is similar to this:
n_report<-c(1,2,3,5)
for (n in n_report){
rmarkdown::render(input = "C:/Users/.../report.Rmd",
output_dir = "//192.168.5.4/.../.../.../REPORT", #removing this line the code works
output_format = "pdf_document",
output_file = paste0("ST", n, ".pdf"),
params = list(n=n)
}
The output pdf must be saved on an internal server, I think that the problem depends on a wrong interpretation of the firs two "//", on console I get this error:
Error: Failed to compile \\192.168.5.4/.../.../.../REPORT/ST1.tex. See https://yihui.name/tinytex/r/#debugging for debugging tips.
With everything else markdown::render the path works perfectly.
The "report.Rmd" generate an output in pdf with kableExtra package.
Can someone help me?
Related
I am working on a project which is developed by our team. We share the codes in a repository. Every team member is using his/her own machine with his/her own working directories. That is why we use relative paths in our projects. Usually we use something like
setwd("MyUser/MyProject/MyWD/myCodesDir") # local
...
MyReportingPath <- "../ReportsDir" # in repository
Now I try to render a markdown report to this directory:
rmarkdown::render(input = "relevantPath/ReportingHTML.Rmd",
output_file = paste0(MyReportingPath, "/ReportingHTML.html"))
This doesn't work. It only works if I type in the full path of the output file ("/home/User/..../ReportingHTML.html")
This is one of the issues I would like to clarify: is there any possibility to use relative paths in any way for Markdown?
Second issue is that if I type in an non-existing directory in the output_file, pandoc throws me an error instead of creating this directory with my output file. Is there any possibility to do a dynamic output directory creation? (except for doing system(paste0("mkdir ", reportPath), intern = T) before rendering)
P.S. It is important for me to render the markdown document in a separate R function, where I create the whole environment which is inherited by my Markdown document.
Trivial issue - since you're using paste0 you need to provide the / delimiter between your output directory and output file.
You wrote:
rmarkdown::render(input = "relevantPath/ReportingHTML.Rmd",
output_file = paste0(MyReportingPath, "ReportingHTML.html"))
Instead, try:
rmarkdown::render(input = "relevantPath/ReportingHTML.Rmd",
output_file = paste0(MyReportingPath, "/", "ReportingHTML.html"))
More broadly:
For your first issue (settting the path for the input file) - I also suggest using here::here(). If you need to navigate up from your working directory you can break down the path as follows:
parent_dir <- paste(head(unlist(strsplit(here::here(), "/", fixed = TRUE)), -1), collapse = "/")
grandparent_dir <- paste(head(unlist(strsplit(here::here(), "/", fixed = TRUE)), -2), collapse = "/")
However - it might be easier to set the working directory to a higher level, then build up your code and results directories, for example:
project_dir <- here::here()
codefile <- paste(project_dir, "code", "myreport.Rmd", sep = "/")
outfile <- paste(project_dir, "results", "myreport.html", sep = "/")
rmarkdown::render(input = codefile,
output_file = outfile))
For your second issue (creating the directory for output) - using dir.create("MyReportingPath", recursive = TRUE) will create the output directory and any intermediate levels. You will get a warning if the directory exists which can be suppressed using showWarnings = FALSE.
I just ran into this myself, and as it turns out, there's one additional complication here: You really do need to use an absolute path for the output if your input file being rendered isn't in your current working directory. You also need to use absolute paths for anything else during rendering, for example images like ![](path.png).
This looks to be because rmarkdown::render temporarily sets your working directory to the directory containing the input file, so it interprets a relative directory as relative to that path, not your initial working directory. (EDIT: There's currently an open issue for this on github.)
For example if you have this setup:
subdir/test.Rmd
outdir
And you do this:
rmarkdown::render(
input = "subdir/test.Rmd",
output_file = "outdir/out.html")
You get the error:
Error: The directory 'outdir' does not not exist.
Execution halted
Instead, you could do:
output_path <- file.path(normalizePath("."), "outdir/out.html")
rmarkdown::render(
input = "subdir/test.Rmd",
output_file = output_path)
...and that should work.
You might think you could just use normalizePath("outdir/out.html"), but you can't, because that function only works when the path already exists. You also might think you could do this:
rmarkdown::render(
input = "subdir/test.Rmd",
output_file = file.path(normalizePath("."), "outdir/out.html"))
but you can't, because R only gets around to interpreting the value of output_file once the working directory has already been changed.
I have written a function in R to print any message both to log file and console. But if there is any unexpected error while running the code, then error is displayed only to console. Is there any way to write error message to both console and log file? Here is the function..
log_con <- file("Text1.txt", open="a")
loggerfn<-function(Message,LogConnection=log_con){
cat(Message, file = LogConnection)
cat(Message)
}
Here is the sample code to...
for (i in 1:10)
{
loggerfn("loop begins\n",log_con)
a <- rnorm(n = 100, mean = i, sd = 5)
loggerfn(mean(a),log_con)
loggerfn("loop Completed\n",log_con)
if(i==8){
sdfs
}
}
In above code I have intentionally introduced error by providing undefined object sdfd.Below provided Error message is shown only in console, is there any way to write error message to both console and logfile?
Error: object 'sdfs' not found
use sink() to divert messages as well as warnings to a file. The trick is to set the argument type="message"
refer http://www.statmethods.net/interface/io.html
and Output error/warning log (txt file) when running R script under command line
https://stat.ethz.ch/R-manual/R-devel/library/base/html/sink.html
The sink( ) function defines the direction of the output.
Description
sink diverts R output to a connection (and stops such diversions).
sink.number()
reports how many diversions are in use.
sink.number(type = "message") reports the number of the connection currently being used for error messages.
Usage
sink(file = NULL, append = FALSE, type = c("output", "message"),
split = FALSE)
sink.number(type = c("output", "message"))
direct output to a file
sink("myfile", append=FALSE, split=FALSE)
return output to the terminal
sink()
The append option controls whether output overwrites or adds to a file. The split option determines if output is also sent to the screen as well as the output file.
Here are some examples of the sink() function.
output directed to output.txt in c:\projects directory.
output overwrites existing file. no output to terminal.
sink("c:/projects/output.txt")
output directed to myfile.txt in cwd. output is appended
to existing file. output also send to terminal.
sink("myfile.txt", append=TRUE, split=TRUE)
When redirecting output, use the cat( ) function to annotate the output.
Problem
I want to knit multiple PDFs from a single data frame. Therefore I've tried various solutions, but my knowledge in R, R Studio, LaTex, knitr is very limited so I wasn't able to adapt some solution approaches and finally tried it on my own. I actually think my code is absolutely not the way you actually use to achieve what I want to achieve. So, please feel free to tell me where and what I can/should improve.
I would be really grateful for some help. I've been googling for hours now and I would also appreciate if you could recommend me any tutorial/guide/explanation. I don't even know where to start.
Current State: Solved
Code
main.R
for(i in 1:nrow(mtcars)) {
g_title <- rownames(mtcars)[i]
knit2pdf(input = "main.Rnw",
output = paste0("output\\", g_title, ".pdf"),
quiet = FALSE,
envir = parent.frame())
}
template.Rnw
\documentclass{article}
\usepackage[ngerman]{babel}
\begin{document}
\begin{titlepage}
Titlepage
\end{titlepage}
\tableofcontents
\newpage
\section{Topic 1}
\newpage
\section{Topic 2}
\end{document}
Solution Approaches
Global Variables
I tried to create global variables which are altered by a for loop. These variables are then used in the .Rnw file in form of a function. I wasn't able to get this working due unknown errors.
Code in the .R file:
printPlot <- function() {
print(g_plot)
}
for(i in 1:nrow(mtcars)) {
g_title <- rownames(mtcars)[i]
g_plot <- ggplot(mtcars[i,], aes(x = cyl, y = disp) ) +
geom_point()
knit2pdf(input = "main.Rnw",
output = paste0("output\\", g_title, ".pdf"),
quiet = FALSE,
envir = parent.frame())
}
Code in the .Rnw file:
<<>>=
printPlot()
#
Errors:
The PDFs are created, but their contents are messed up. You can see it in the image under 'Current State'.
I also receive several error/warning messages, e.g.:
Warning messages:
1: running command '"C:\Users\Marc\AppData\Local\Programs\MIKTEX~1.9\miktex\bin\x64\texify.exe"
--quiet --pdf "Mazda RX4.pdf" --max-iterations=20 -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/tex/latex" -I
"C:/PROGRA~1/R/R-33~1.2/share/texmf/bibtex/bst"' had status 1
2: running command '"C:\Users\Marc\AppData\Local\Programs\MIKTEX~1.9\miktex\bin\x64\texify.exe"
--quiet --pdf "Mazda RX4 Wag.pdf" --max-iterations=20 -I "C:/PROGRA~1/R/R-33~1.2/share/texmf/tex/latex" -I
"C:/PROGRA~1/R/R-33~1.2/share/texmf/bibtex/bst"' had status 1
MakeFile
I just read the first time about makefile. Maybe this could help solving the problem.
If I got it right makefile is used with Markdown and not directly with LaTex. This seems to be a massive loss in performance. This point is quite important to me, so I will try to find another solution.
Other SO Questions
In most of the cases I tried to adapt the code, but simply failed, because I am missing knowledge to understand the given solution approaches.
R Knitr PDF: Is there a posssibility to automatically save PDF reports (generated from .Rmd) through a loop?
Using loops with knitr to produce multiple pdf reports… need a little help to get me over the hump
Can Sweave produce many pdfs automatically?
From the question, I'm not entirely sure about the expected output, but there concept is clear. And although the task itself is quite simple, surprisingly many things can go wrong.
Code:
code.R
library(knitr)
library(ggplot2)
dir.create(path = "output/")
opts_knit$set(base.dir = "output/")
for(i in 1:nrow(mtcars)) {
filename <- rownames(mtcars)[i]
knit(input = "template.Rnw", output = paste0("output/", filename, ".tex"))
tools::texi2pdf(paste0("output/", filename, ".tex"), clean = TRUE)
file.copy(from = paste0(filename, ".pdf"), to = paste0("output/", filename, ".pdf"))
# file.remove(paste0(filename, ".pdf")) # this will DELETE filename.pdf from the current working directory (should be safe because we just created this file)
}
template.Rnw
\documentclass{article}
\begin{document}
<<>>=
ggplot(mtcars[i,], aes(x = cyl, y = disp) ) + geom_point()
#
\end{document}
We need to set base.dir because the current working directory is one level above the directory where the document is created. This would lead to wrong figure paths: knitr produces the plots in figure/ but they should be in output/figure/. Consequently, compilation will fail.
For some reason knit2pdf cannot compile the generated intermediate TEX file. Therefore I use knit to produce a TEX file and then tools::texi2pdf to compile this file to PDF.
Note how variables from code.R are visible to the code in the template document. That's why i can be used in template.Rnw.
I have a .Rnw file that I am able to compile into a PDF using the "Compile PDF" button in RStudio (or Command+Shift+k). However, when I use knit2pdf the graphics are not created and the complete PDF is not created. Why would this happen? How do you specifically set where the images will be stored so that pdflatex can find them?
Here is an example. I am aware that this question that I posted a few days ago has a similar example, but in my mind these are two different questions.
This file will run just fine and produce a PDF if I hit "Compile". I don't get any errors, the figure is produced in the /figure directory, and all is well.
%test.Rnw
\documentclass{article}
\usepackage[margin=.5in, landscape]{geometry}
\begin{document}
This is some test text!
<<setup, include=FALSE, results='hide', cache=FALSE>>=
opts_chunk$set(echo=FALSE, warning = FALSE, message = FALSE,
cache = FALSE, error = FALSE)
library(ggplot2)
#
<<printplotscreen, results='asis'>>=
ggplot(diamonds) +
geom_bar(aes(x = color, stat = "bin"))
#
\end{document}
However, when I run this script that is intended to do exactly the same thing as hitting "Compile" (is it?) the figure is not created and I get the not-surprising error below about not being able to find it.
#test.R
library("knitr")
knit2pdf(input = "~/Desktop/thing/test.Rnw",
output=paste0('~/Desktop/thing/test','.tex'))
Error in texi2dvi(file = file, pdf = TRUE, clean = clean, quiet = quiet, :
Running 'texi2dvi' on 'test.tex' failed.
LaTeX errors:
! LaTeX Error: File `figure/printplotscreen-1' not found.
NOTE: If you are trying to reproduce this (and thanks!) then make sure you run the knit2pdf script FIRST to see that it doesn't create the figures. If you hit "Compile" first then the figures will be there for knit2pdf to use, but it will not accurately represent the situation.
The solution: Make sure to set the working directory to the project directory before using knit2pdf, then shorten the "input" path to just the .Rnw file. Thus...
test.R
library("knitr")
diamonds = diamonds[diamonds$cut != "Very Good",]
setwd("/Users/me/Desktop/thing")
knit2pdf(input = "test.Rnw", output = "test.tex")
Here are some references on this issue:
Changing working directory will impact the location of output #38
;
make sure the output dir is correct (#38)
It seems that when using knit2pdf(), it automatically set your output files to the directory where your input file in. And the author doesn't recommend us changing work-directory during the middle of a project.
So the current solution for me is to save the working directory as old one(getwd()), change the working directory to where you want to save the output files, use knit2pdf() to output files, and change the working directory to the original one finally.
A script that has been running seamlessly for over a month stopped adding my child Latex code into my main document following an upgrade to R 3.0.1. The following snippet used to include the text from the compiled test.rnw file in my main document (so that it could be compiled as one document). Now it just includes the filenames of the compiled rnw files.
<<run-all, include=FALSE>>=
out = NULL
for (i in 1:10) {
out = c(out, knit_child('test.rnw', sprintf('test-template-%d.tex', i)))
}
#
\Sexpr{paste(out, collapse = '\n')}
When I try to run the knit_child command interactively, I get this error:
> knit_child('test.rnw', sprintf('test-template-%d.tex', i))
Error in setwd(opts_knit$get("output.dir")) : character argument expected
Running knit() alone will compile the Latex code, if I then run knin_child() there is not error but the "out" object just contains the filename of the child file instead of the contents.
Any ideas how to fix this?
You are not supposed to use knit_child() interactively. It was designed to be called inside knit().
As you have noted, knit_child() in the latest version of knitr returns the content of the child document if you do not provide the second argument. By explicitly providing the second argument sprintf('test-template-%d.tex', i), you mean "please write the output to this file and return the filename".
To fix the problem, you need to remove the second argument:
<<run-all, include=FALSE>>=
out = NULL
for (i in 1:10) {
out = c(out, knit_child('test.rnw'))
}
#
\Sexpr{paste(out, collapse = '\n')}