Blogging with jekyll, rmarkdown and github: how to display images - r

I try to do a blog using the trio jekyll, rmarkdown and github (as here: http://yihui.name/knitr-jekyll/)
I have all my .Rmd in _source, and I have this issue that sometimes the plots are knit in base 64 images and sometimes saved in a figure folder.
First question, why?
Second question: when my plot are saved as images, the path in the html appear to be figure/source/. Knowing that the destination folder is /blog/ (my baseurl in _config.yml), to make it work, it should be blog/figure/source.
Strangely, they are displayed locally and when I open the html with my browser.
But when I deploy my website on github, the images aren't displayed, as the path is incorrect.
How to define the path to /blog/figure instead of /figure/ ?
Edit: the link to my blog, still in development:
http://yvescr.github.io/
But the Rmd don't appear in the github account, as the folder I synchronised with github is the destination file of the jekyll generation.
_config.yml:
# Build settings
markdown: kramdown
baseurl: "/blog"
In R:
jekyll(dir = ".", input = "_source", output = "_posts", script = c("Makefile", "build.R")
, command = "jekyll build --destination ../blog")
build.r:
local({
# fall back on '/' if baseurl is not specified
baseurl = servr:::jekyll_config('.', 'baseurl', '/')
knitr::opts_knit$set(base.url = baseurl)
# fall back on 'kramdown' if markdown engine is not specified
markdown = servr:::jekyll_config('.', 'markdown', 'kramdown')
# see if we need to use the Jekyll render in knitr
if (markdown == 'kramdown') {
knitr::render_jekyll()
} else knitr::render_markdown()
# input/output filenames are passed as two additional arguments to Rscript
a = commandArgs(TRUE)
d = gsub('^_|[.][a-zA-Z]+$', '', a[1])
knitr::opts_chunk$set(
fig.path = sprintf('blog/figure/%s/', d),
cache.path = sprintf('cache/%s/', d)
)
knitr::opts_knit$set(width = 70)
knitr::knit(a[1], a[2], quiet = TRUE, encoding = 'UTF-8', envir = .GlobalEnv)
})
makefile:
all:
Rscript -e "servr::jekyll('..')"
clean:
rm -r ../blog/

I solve my issue, I post it here in case people have the same:
The jekyll() function in R compile the .rmd (in _source) in .md(in _post) with knitr(I think) then call the jekyll command.
Here, my issue was that when I changed the _config.yml file, with modification of the path, the .md are not re-created and so the path is not changed.
To make it work, I had to delete manually the .md in _source then re-run the jekyll() function.
Concerning the images, they are compiled as 64 images when I use rmarkdown without cache.
With the cache, knitr create images in a folder.

Related

Can you access css file from git/shared drive for shared use by company?

Is there a better way for programmers within a group, looking to share a common style for shiny apps or rmarkdown docs, to access a css file from a single location rather than manually copying the desired file into the subcontents of each app or document?
The ideal outcome would be to place the file(s) on a github repo, then attach it to any shiny app or rmarkdown file with its web link, is this possible?
Thanks.
It might be easier to include your stylesheets in an R package. This would eliminate the need for external request each time your app loads or doc is opened. Place your css files in a folder in inst and write a single R function that sets the resource paths to your css and loads files accordingly.
Let's say your package has the following structure. (For this example, I'm naming the package mypkg)
mypkg/
R/
use_stylesheets.R
inst/
stylesheets/
styles.min.css
...
...
In use_stylesheets.R, create a function that loads the stylesheets into the head of the document (tags$head) using tags$link.
use_stylesheets <- function() {
shiny::addResourcePath(
"styles",
system.file("stylesheets", package = "mypkg")
)
shiny::tags$head(
shiny::tags$link(rel = "stylesheet", href = "styles.min.css")
)
}
Then in your app or Rmarkdown document, you can load the files into your app using: mypkg::use_stylesheets()
After some tinkering I was able to have success (waiting on coworkers to test on their machines) using these structures for adding css or html from a package into both Shiny Apps and Rmarkdown documents.
# For attaching a css file to an Rmarkdown file
use_package_style_rmd <- function(css_file = "my_css.css"){
# css file
file_name <- paste0("/", css_file)
file_path <- paste0(system.file("stylesheets", package = "my_pkg"), file_name)
shiny::includeCSS(path = file_path)
}
# For placing an HTML headers/footers in place
use_package_header <- function(html_file = "my_header.html"){
# HTML Header
file_name <- paste0("/", html_file)
file_path <- paste0(system.file("stylesheets", package = "my_pkg"), file_name)
shiny::includeHTML(path = file_path)
}
# For attaching css to a shiny app via resourcePath
use_package_style_shiny <- function(stylesheet = "my_css.css"){
# Add Resource Path
shiny::addResourcePath(
prefix = "styles",
directoryPath = system.file("stylesheets", package = "my_pkg"))
# Link to App
shiny::tags$head(
shiny::tags$link(rel = "stylesheet",
href = paste0("styles/", stylesheet)))
}
The use_package_style_rmd function can be placed in any code chunk, whereas the header function will add the html in-place where the function is run.
For the Shiny app use-case the function should be run to establish the resource path to the folder, then in the UI under fluidpage the theme option can be set to the css file using the prefix for the Resource Path styles/my_css.css.
One issue I am still having which may be a separate question, is where to place a supporting image file, and how to add the relative path such that the image can be placed in the header or footer.

R-Markdown: input and output with relative pathes

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.

When using servr::jekyll() on R, where should I save my Rmd files?

With the Rmd files on root (eg. on my /knitr-jekyll/) they are turning into md files, but not on html files. Thus, they appear as simple markdown text.
I tried to put them on /_source and on /_posts but it get's worse, in this case I also don't get the md files.
I found creating a separate folder all together solves the problem.
/kintr-jekyll/_rmd/test.Rmd
But do remember that when you knit your Rmd to md that you knit to the _post folder if you using the standard bootstrap template. Also make sure that you specified your figure output. Easiest is to write some function which does this for you:
KnitPost <- function(input, base.url = "/") {
require(knitr)
opts_knit$set(base.url = base.url)
fig.path <- paste0("figures/", sub(".Rmd$", "", basename(input)), "/")
opts_chunk$set(fig.path = fig.path)
opts_chunk$set(fig.cap = "center")
render_jekyll()
knit(input, envir = parent.frame())
Lastly, go make sure in your .md file in knitr-jekyll/_post that the figures are clearly referenced. This should be within your test.md:
<img align="middle" src="/figures/test/test_image.jpg">
This link might help: R-Bloggers post about jekyll

Difference between "Compile PDF" and knit2pdf

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.

Why doesn't knitr respect RStudio project details?

In all other cases, when I am working within an RStudio project, I can make references relative to the project root in scripts. So I can, for example, dfX = read.csv("Data/somefile.csv"), where the folder Data is relative to my project root.
The same code in a knitr chunk does not find the file. I guess this is because knitr creates a bunch of temporary directories that it needs to refer to relative to the file location. Is there an easy way to change this behavior? Obviously, I would not like to add the entire path to the project folder -- I am aware that I can easily do this using knitr::opts_knit$set(root.dir = rootPath). That completely breaks maintainability across machines and OSs.
Edit: This seems closely linked to this question.
Presumably you know the path to the package directory when you call 'knit', so how about:
ENV <- new.env()
assign("workingDirectory", getcwd(), envir = ENV)
knitr::knit(...,
# THE ENVIRONMENT IN WHICH THE CODE CHUNKS ARE TO BE EVALUATED
envir=ENV)
Then in your rmd file you can do:
```{r] print(workingDirectory)```
If you're searching for the location of the current install, you can use:
PATH = NULL
for(libPath in .libPaths())
if('myPackage' %in% list.dirs(libPath,FALSE,FALSE)){
PATH = file.path(libPath,'myPackage')
}
if(is.null(PATH))
stop('could not find package directory')
ENV <- new.env()
assign("workingDirectory", PATH, envir = ENV)
knitr::knit(...,
# THE ENVIRONMENT IN WHICH THE CODE CHUNKS ARE TO BE EVALUATED
envir=ENV)
My guess is that the document that you are "knitting" is in a subdirectory itself. It seems that, when you click "Knit PDF", RStudio or knitr will setwd() to the directory containing the file being knitted. So you may need to do something like dfX = read.csv("../Data/somefile.csv") to get the reference right.
I have a working example here.

Resources