I need the output to be portable so all the file paths need to be relative to the root directory of the project not absolute paths. I also need to set the figure size so I can't fall back on markdown and just use but knitr insists on creating an absolute path in my output. I've tried setting root.dir & base.dir and fig.path in various combinations but I keep getting an absolute path in my output. Setting root.dir = "/" does change the path in my output but setting it to "" or "./" still results in an abs path so this is not helping produce a portable output.
My rmarkdown::render is being run from the same directory as the Rmd file, the output is to this same directory and the graphics files are in a sub-directory of the one with the notebook. Is the a way I can make knitr just us the paths I give it and not try to transform them in any way?
Issues with knitr & paths seem to be a common problem and there are a lot of stub Q&As out there in search results which often don't satisfactorily resolve the problem, or if they do resolve it the questioner and/or answer seem unclear on why it worked.
I've referred to https://yihui.org/knitr/ & https://bookdown.org/yihui/rmarkdown/ and I still don't have a satisfactory understanding of how to control output paths with knitr could someone help me understand how to control this or point me in the direction of a resource that can?
OK so calmed down and I tried to make a reprex, I found some interesting behaviour.
The graphics folder is a symlink to a folder in the parent directory and this works fine if I use as basic html_document output but when I use the revealjs::revealjs_presentation output I get different results in the basics document the img tag contains:
src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD......."
and in the presentation contains:
src="/home/richardjacton/project/graphics_test/example.jpg"
Now this does not work because I need to be able to move the directory containing the presentation and it's assets to somewhere else and have it work once built.
If I go in with inspect element and edit it to src="./graphics/example.jpg" that works.
Also If I make a real directory instead of a symlink to the a directory in the parent then I get src="graphics/example.jpg" in the revealjs output
---
title: "Example"
author: "Richard J. Acton"
date: "`r Sys.Date()`"
# output:
# html_document:
# df_print: paged
output:
revealjs::revealjs_presentation:
theme: dark
highlight: zenburn
center: true
self_contained: false
reveal_plugins: ["notes"]
reveal_options:
slideNumber: true
previewLinks: true
fig_caption: true
---
# Example
```{r, echo=FALSE, include=FALSE, message=FALSE}
fs::dir_create("../graphics_test/")
download.file("https://i.ytimg.com/vi/0hMr5-05bFc/maxresdefault.jpg", "../graphics_test/example.jpg")
fs::link_create("../graphics_test", "graphics")
# fs::dir_create("graphics")
# download.file("https://i.ytimg.com/vi/0hMr5-05bFc/maxresdefault.jpg", "graphics/example.jpg")
```
```{r, out.width='80%', echo=FALSE}
knitr::include_graphics("graphics/example.jpg")
```
In my real case I'm creating a presentation from inside a {targets} project that's also has a {bookdown} project in it that produces a report based on the pipeline. So the presentation lives in a sub-directory so I can exclude it from the bookdown build. I explicitly built the presentation with an rmarkdown::render call as the knit button in the gui wants to try and render the book: rmarkdown::render("test.Rmd",envir = new.env()). Also this is all in a directory mounted to a docker container that's running my RStudio server instance so I have a portable and reproducible working environment for any non-R dependencies of my pipeline.
So this is why I was looking for a resource with a more in depth explanation of what exactly happens when I make a knitr::include_graphics call because this is the sort of weird edge case I seem to encounter a lot and get stuck trying to debug. Thanks for the response #YihuiXie I love your work and use it daily - sorry for offering you the opportunity to engage with this particular headache.
Related
I'm having some trouble to compile an entire document from many Rmd files by using the bookdown approach.
If I knit individual .Rmd files then 'preamble.tex' included in YAML options is taken into account.
If I render the book (with both approaches described here), then 'preamble.tex' is ignored.
To make things concrete, consider the following mwe:
preamble.tex:
\usepackage{times}
index.Rmd:
---
title: "My paper"
site: "bookdown::bookdown_site"
output:
bookdown::pdf_document2:
includes:
in_header: "preamble.tex"
---
01-intro.Rmd:
# Introduction
This chapter is an overview of the methods that we propose to solve an **important problem**.
Then, by knitting 'index.Rmd' or '01-intro.Rmd' the font indicated in 'preamble.tex' is used.
However when rendering with bookdown::render_book('index.Rmd',"bookdown::pdf_book", new_session = T) it is simply ignored.
What is more, in my actual project there are other output options that end up ignored. For example, I use toc: false and it works when knitting single files, but fails when rendering the document.
In this simple example it would be okay to use a single file, but my actual project has many chapters with R chunks within each of them. Thus, building a single file doesn't seem a good idea.
I appreciate any hints on what I am missing here.
Thanks in advance.
What you are missing here is that in your YAML header, preamble.tex is included for the bookdown::pdf_document2 output format and not bookdown::pdf_book, the format you pass to the output_format argument in bookdown::render_book(). For this reason, other YAML options (like toc: true) do not work either.
Running
bookdown::render_book('index.Rmd', "bookdown::pdf_document2", new_session = T)
instead should work.
If I create a very basic R Markdown file with no images or code and knit this HTML, I end up with an outputted file size that is more than 700kb in size. Is there any way to reduce the HTML file size?
Minimal Example:
---
title: "Hello world!"
output:
html_document: default
html_notebook: default
---
Nothing else to say, really.
The output file from html_document is 708.6 kb in size, while html_notebook is 765.7 kb.
The reason for the big file size is that knit creates self-contained files by default and therefore includes javascript dependencies (bootstrap, highlight, jquery, navigation) as base64 encoded string. See: http://rmarkdown.rstudio.com/html_document_format.html#document_dependencies
In your simple case the javascript capabilities are not required therefore you could do the following:
---
title: "Hello world!"
output:
html_document:
self_contained: false
lib_dir: libs
---
Nothing else to say, really.
This will create a html file of size ~2.7kB and a separate libs folder with the javascript files. However the libs folder is nearly 4MB in size. And although you don't necessarily need the javascript libraries the html file still tries to load them.
If you are interested in a truly minimal version you can have a look at the html_fragment output option (http://rmarkdown.rstudio.com/html_fragment_format.html):
---
title: "Hello world!"
output:
html_fragment: default
---
Nothing else to say, really.
This will however not create a full html page but rather html content that can be included into another website. The test.html file is just 36 bytes. Still browsers will be able to display it.
As a last resort you can create a custom html template for pandoc:
http://rmarkdown.rstudio.com/html_document_format.html#custom_templates
The html_vignette format is perfect if you want a smaller file size. As described in the function documentation:
A HTML vignette is a lightweight alternative to html_document suitable for inclusion in packages to be released to CRAN. It reduces the size of a basic vignette from 100k to around 10k.
For your example:
---
title: "Hello world!"
output: rmarkdown::html_vignette
---
Nothing else to say, really.
Results in an output of 6kB:
You can read more about the package in the online documentation here.
The simplest, most direct method to prevent the unwanted insertion of the bootstrap libraries into the preamble of the HTML document is to add the additional markdown flag "theme: null".
output:
html_document:
theme: null
This is more desirable than self_contained: false because it does not prevent insertion of images or other components need to keep the portable document.
In my opinion, it is more desirable than changing to html_vignette because it does not absorb the other changes imposed by that processor.
Please remember that IF your document uses a template, the theme argument is ignored and you need to specify theme=NULL in the rmarkdown::render function.
I have a few Rmd documents that all have the same YAML frontmatter except for the title. How can I keep this frontmatter in one file and have it used for all the documents? It is getting rather large and I don't want to keep every file in step every time I tweak the frontmatter.
I want to still
use the Knit button/Ctrl+Shift+K shortcut in RStudio to do the compile
keep the whole setup portable: would like to avoid writing a custom output format or overriding rstudio.markdownToHTML (as this would require me to carry around a .Rprofile too)
Example
common.yaml:
author: me
date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
link-citations: true
reference-section-title: References
# many other options
an example document
----
title: On the Culinary Preferences of Anthropomorphic Cats
----
I do not like green eggs and ham. I do not like them, Sam I Am!
Desired output:
The compiled example document (ie either HTML or PDF), which has been compiled with the metadata in common.yaml injected in. The R code in the YAML (in this case, the date) would be compiled as a bonus, but it is not necessary (I only use it for the date which I don't really need).
Options/Solutions?
I haven't quite got any of these working yet.
With rmarkdown one can create a _output.yaml to put common YAML metadata, but this will put all of that metadata under output: in the YAML so is only good for options under html_document: and pdf_document:, and not for things like author, date, ...
write a knitr chunk to import the YAML, e.g.
----
title: On the Culinary Preferences of Anthropomorphic Cats
```{r echo=F, results='asis'}
cat(readLines('common.yaml'), sep='\n')
```
----
I do not like green eggs and ham. I do not like them, Sam I Am!
This works if I knitr('input.Rmd') and then pandoc the output, but not if I use the Knit button from Rstudio (which I assume calls render), because this parses the metadata first before running knitr, and the metadata is malformed until knitr has been run.
Makefile: if I was clever enough I could write a Makefile or something to inject common.yaml into input.Rmd, then run rmarkdown::render(), and somehow hook it up to the Knit button of Rstudio, and perhaps somehow save this Rstudio configuration into the .Rproj file so that the whole thing is portable without me needing to edit .Rprofile too. But I'm not clever enough.
EDIT: I had a go at this last option and hooked up a Makefile to the Build command (Ctrl+Shift+B). However, this will build the same target every time I use it via Ctrl+Shift+B, and I want to build the target that corresponds with the Rmd file I currently have open in the editor [as for Ctrl+Shift+K].
Have found two options to do this portably (ie no .Rprofile customisation needed, minimal duplication of YAML frontmatter):
You can provide common yaml to pandoc on the command-line! d'oh!
You can set the knit: property of the metadata to your own function to have greater control over what happens when you Ctrl+Shift+K.
Option 1: common YAML to command line.
Put all the common YAML in its own file
common.yaml:
---
author: me
date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
link-citations: true
reference-section-title: References
---
Note it's complete, ie the --- are needed.
Then in the document you can specify the YAML as the last argument to pandoc, and it'll apply the YAML (see this github issue)
in example.rmd:
---
title: On the Culinary Preferences of Anthropomorphic Cats
output:
html_document:
pandoc_args: './common.yaml'
---
I do not like green eggs and ham. I do not like them, Sam I Am!
You could even put the html_document: stuff in an _output.yaml since rmarkdown will take that and place it under output: for all the documents in that folder. In this way there can be no duplication of YAML between all documents using this frontmatter.
Pros:
no duplication of YAML frontmatter.
very clean
Cons:
the common YAML is not passed through knit, so the date field above will not be parsed. You will get the literal string "r format(Sys.time(), format='%Y-%m-%d %H:%M:%S %z')" as your date.
from the same github issue:
Metadata definitions seen first are kept and left unchanged, even if conflicting data is parsed at a later point.
Perhaps this could be a problem at some point depending on your setup.
Option 2: override the knit command
This allows for much greater control, though is a bit more cumbersome/tricky.
This link and this one mention an undocumented feature in rmarkdown: the knit: part of the YAML will be executed when one clicks the "Knit" button of Rstudio.
In short:
define a function myknit(inputFile, encoding) that would read the YAML, put it in to the RMD and call render on the result. Saved in its own file myknit.r.
in the YAML of example.rmd, add
knit: (function (...) { source('myknit.r'); myknit(...) })
It seems to have to be on one line. The reason for source('myknit.r') instead of just putting the function definition int he YAML is for portability. If I modify myknit.r I don't have to modify every document's YAML. This way, the only common YAML that all documents must repeat in their frontmatter is the knit line; all other common YAML can stay in common.yaml.
Then Ctrl+Shift+K works as I would hope from within Rstudio.
Further notes:
myknit could just be a system call to make if I had a makefile setup.
the injected YAML will be passed through rmarkdown and hence knitted, since it is injected before the call to render.
Preview window: so long as myknit produces a (single) message Output created: path/to/file.html, then the file will be shown in the preview window.
I have found that there can be only one such message in the output [not multiple], or you get no preview window. So if you use render (which makes an "Output created: basename.extension") message and the final produced file is actually elsewhere, you will need to suppress this message via either render(..., quiet=T) or suppressMessages(render(...)) (the former suppresses knitr progress and pandoc output too), and create your own message with the correct path.
Pros:
the YAML frontmatter is knitted
much more control than option 1 if you need to do custom pre- / post-processing.
Cons:
a bit more effort than option 1
the knit: line must be duplicated in each document (though by source('./myknit.r') at least the function definition may be stored in one central location)
Here is the setup for posterity. For portability, you only need to carry around myknit.r and common.yaml. No .Rprofile or project-specific config needed.
example.rmd:
---
title: On the Culinary Preferences of Anthropomorphic Cats
knit: (function (...) { source('myknit.r'); myknit(...) })
---
I do not like green eggs and ham. I do not like them, Sam I Am!
common.yaml [for example]:
author: me
date: "`r format (Sys.time(), format='%Y-%m-%d %H:%M:%S %z')`"
link-citations: true
reference-section-title: References
myknit.r:
myknit <- function (inputFile, encoding, yaml='common.yaml') {
# read in the YAML + src file
yaml <- readLines(yaml)
rmd <- readLines(inputFile)
# insert the YAML in after the first ---
# I'm assuming all my RMDs have properly-formed YAML and that the first
# occurence of --- starts the YAML. You could do proper validation if you wanted.
yamlHeader <- grep('^---$', rmd)[1]
# put the yaml in
rmd <- append(rmd, yaml, after=yamlHeader)
# write out to a temp file
ofile <- file.path(tempdir(), basename(inputFile))
writeLines(rmd, ofile)
# render with rmarkdown.
message(ofile)
ofile <- rmarkdown::render(ofile, encoding=encoding, envir=new.env())
# copy back to the current directory.
file.copy(ofile, file.path(dirname(inputFile), basename(ofile)), overwrite=T)
}
Pressing Ctrl+Shift+K/Knit from the editor of example.rmd will compile the result and show a preview. I know it is using common.yaml, because the result includes the date and author whereas example.rmd on its own does not have a date or author.
The first solution proposed by #mathematical.coffee is a good approach, but the example it gave did not work for me (maybe because the syntax had changed). As said so, this is possible by providing pandoc arguments in the YAML header. For example,
It's the content of a header.yaml file:
title: "Crime and Punishment"
author: "Fyodor Dostoevsky"
Add this to the beginning of the RMarkdown file:
---
output:
html_document:
pandoc_args: ["--metadata-file=header.yaml"]
---
See the pandoc manual for the --metadata-file argument.
I am practicing data analysis using R programming. I want my files to be on github. I am unable to figure out why github is not showing the output of .rmd files.
Here is the link to the file in my github repository Data Analysis Practice
I want the output including plots to be shown on github.
Instead of:
output: html_document
make it:
output: rmarkdown::github_document
(assuming you have the latest rmarkdown installed which you should if you're using RStudio — which I suspect you are — and keep it updated or update packages regularly).
It will create Exploring_one_variable.md and render the images as files.
When you browse to that markdown file, the images will render.
An alternative is to use:
output:
html_document:
keep_md: true
and it will render to both Exploring_one_variable.md and Exploring_one_variable.html so you'll have the best of both worlds without the local github-esque preview that the former provides.
You can get fancier and put something like the following as the first code section in the Rmd:
```{r, echo = FALSE}
knitr::opts_chunk$set(
fig.path = "README_figs/README-"
)
```
which will put the figures in a directory of your choosing.
You can see this in action here as the README.md was generated with knitr from the README.Rmd in the same directory.
There is now output: github_document
This problem just seems weird to me: I have several plots and tables being produced in my RMarkdown doc, so I'd like to cache to save on compiling/knitting time. When I change all of the cache options to cache=TRUE, it creates two folders in my directory: "Figures_Full_Study_cache" and "Figures_Full_Study_figures" as it should. Problem is, while the former (_cache) remains, the latter (_figures) deletes itself after compiling.
As it's happening, I can see both the "Figures_Full_Study_cache" and "Figures_Full_Study_figures" folders being created. I can even go into the "Figures_Full_Study_figures" folder and see each individual .png being produced in real time. However, once Markdown/pandoc is done, the "Figures_Full_Study_figures" file is immediately deleted (I have screenshots of all of this, but I'm too new to stack overflow to post images).
Of course, once this file disappears along with the .png images, R generates an error when I try to run it again using cache=TRUE because those files don't exist (the tables work just fine). Any ideas why my cached file is deleting itself? I've included a representative example of how my plots are made using ggplot2 and entered into RMarkdown:
```{r,echo=FALSE, warning=FALSE, fig.width=5,fig.height=3.5,cache=TRUE}
ggplot(Demographics, aes(x=Exp)) +
geom_histogram(binwidth=2,fill="slateblue1", color="black", alpha=.9) +
theme_general # Defined previously, not relevant to this discussion
# My apologies for not being able to post the data... protected research.
```
And here are the options for the Markdown doc in case needed:
---
title: "Figures Full Study"
author: "Name"
date: "Wednesday, August 13, 2014"
output:
html_document: default
---