I recently parameterized hundreds of reports. The html_documents look great, but in the .md reports, which are github_documents, the images are not appearing.
.md file viewed in GitHub:
Same .md file in raw format:
The images have successfully pushed to GitHub:
Why aren't my image files mapping to my reports?
The problem lay in how I specified the location of my output files in the render() function within my for loop.
This loop specified absolute file paths and in turn the image file locations were also being specified with absolute file paths.
dir_datasets <- here::here('data', 'cooked', 'gamma_a4_b0-04')
mdes <- c(.980, .990, .995, 1.010, 1.020, 1.030)
mdes_str <- broman::myround(mdes, 3)
my_files <- list.files(dir_datasets)
for (mde in mdes) {
for (file in my_files){
TRUE_EFFECT <- extract_string_from_filename(file, 3)
MDE_TITLE <- dash4dot(mde, 3)
rmarkdown::render(
fs::path(dir_sprt_ttest, 'template.Rmd'),
output_file = fs::path(
dir_output, paste0('tte', TRUE_EFFECT, '_mde', MDE_TITLE, '.md')
),
params = list(file_name = file, mde = mde)
)
}
}
When I remove the absolute filepath from the output_file argument in render() the images were thereafter saved with relative filepaths, too, and the .md files displayed their images after being pushed to GitHub.
output_file = paste0('tte', TRUE_EFFECT, '_mde', MDE_TITLE, '.md') # note that I dropped fs::path(dir_output,
Related
I'm generating a powerpoint presentation in R using officer, and then converting this to a PDF so a user can preview slides inside the shiny golem app. But after referencing this thread and this SO answer to a similar question I'm still not quite sure how to accomplish this. I am able to display external PDFs located in inst/app/www inside an iframe, but not sure how to do this for PDFs generated inside the app itself.
Here is the relevant code snippet from my app_server.R file:
output$preview <- renderUI({
# Creates rpptx object with one slide
preview_rpptx <- add_title_slide(x = NULL, title = input_list[["title"]])
# Creates www/ directory if it doesn't exist
if (!dir_exists("www")) dir_create("www")
# Generates .pptx file
pptx_file_path <- file_temp("preview", tmp_dir = "www", ext = ".pptx")
print(preview_rpptx, pptx_file_path)
# Converts .pptx to .pdf
pdf_file_path <- file_temp("preview", tmp_dir = "www", ext = ".pdf")
convert_to_pdf(path = pptx_file_path, pdf_file = pdf_file_path)
tags$iframe(style = "height:600px; width:100%", src = str_sub(pdf_file_path, 5))
}
Running the app, I get a "Not Found" error inside the iframe. But I can see that the PDF file was generated properly in the www/ directory.
Since I don't know how to do with a file as you ask, I would encode this file to a base64 string and set this string to the src attribute:
library(base64enc)
output$preview <- renderUI({
......
pdf_file_path <- "PATH/TO/PDF_FILE"
b64 <- dataURI(file = pdf_file_path, mime = "application/pdf")
tags$iframe(
style = "height: 600px; width: 100%;", src = b64
)
}
I am using RMarkdown to create a set of 6,000 letters. I am using parameters to create custom inputs into the document. I am using a loop to render the PDFs and calling it as follows:
for (i in 1:6000) {
rmarkdown::render(
input = "/template/letter.Rmd",
output_dir = "/output/",
output_file = paste0("report", i)
)
}
Now, this creates a 6,000 separate PDFs, but I would like to have it in one long document. Does anyone have any suggestions for how to use rmarkdown::render() and have it append the current PDF it generates onto the existing one? If I set output_file = report, for example, it will simply overwrite the existing PDF in the loop.
You can merge the outputs using a toolkit for pdf files. For instance, you can use the staplr package:
library(staplr)
ofiles <- c()
for (i in 1:6000) {
ofile <- rmarkdown::render(
input = "/template/letter.Rmd",
output_dir = "/output/",
output_file = paste0("report", i)
)
ofiles <- c(ofiles, ofile)
}
staple_pdf(input_files = ofiles, output_filepath = "/output/all-in-one.pdf")
In Linux, you can also merge the pdf files using pdftk:
cd /output/
pdftk report*.pdf cat output all-in-one.pdf
I am working with a function that outputs an svg object. As I see the SVG object is essentially a string of characters.
I was wondering how to
1) plot the svg output from the function
2) save this svg object to disk under an svg extension? I tried ggsave but just resulted in an error.
I am fairly new to svg handling, so would appreciate any inputs.
Thanks!
1) I tried that for a package I was developing and it was not straightforward. In the end, I needed two libraries: rsvg and grImport2. Here is the code I used:
tfile <- tempfile(fileext = ".svg")
tfile2 <- tempfile(fileext = ".png")
cat(svg_code, file=tfile)
if (requireNamespace("rsvg", quietly = TRUE) && requireNamespace("grImport2", quietly = TRUE)) {
rsvg::rsvg_svg(svg = tfile, tfile2)
p <- grImport2::readPicture(tfile2)
grImport2::grid.picture(p)
} else {
if (systemShow == FALSE && outFile == ''){
warning("The figure cannot be rendered in the plot window. Please, use the arguments outFile and/or systemShow.")
}
}
if (systemShow){
utils::browseURL(tfile)
}
The first conditional is in case the system does not allow the installation of either package. As you can see, you first need to write the svg code (svg_code) to a file, in this case temporary (tfile). Then, rsvg_svg writes a temporary png file (tfile2). Finally, grImport2::readPicture and grImport2::grid.picture show the converted file in the plot window. I also left the part where the user can set a boolean variable (systemShow) and the package will attempt to open the file on the default system svg viewer.
2) That one is much easier. You just need to write the code to a file as text, like cat(svg_code, file='path_to_file.svg').
So I'm trying to write an html R markdown document with interactive shiny bits that allow the user to edit a graph and then download the results to a pdf. However, there is something catastrophically wrong with the way that I'm trying to do this because as soon as the html starts, it overwrites the original markdown file with the contents of the pdf - turning it into complete gibberish right in the editor.
I doubt that I've found a completely new way to fail at R but I haven't been able to find where anybody else has had this issue. Additionally, I've looked over the shiny reference material and I'm just going in circles at this point, so any help would be greatly appreciated.
I'm using Rstudio 1.0.44, rmarkdown 1.2 and shiny 0.14.2. A small (not)working example:
---
title: "Minimum Failing Example"
author: "wittyalias"
date: "December 5, 2016"
output: html_document
runtime: shiny
---
```{r echo = FALSE}
library(ggplot2)
today <- Sys.Date()
inputPanel(downloadButton("dnld", label = "Download pdf"))
renderPlot({
# Example code from http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/
p1 <<- ggplot(ChickWeight, aes(x=Time, y=weight, colour=Diet, group=Chick)) +
geom_line() +
ggtitle("Growth curve for individual chicks")
p1
})
reactive({
fname <- paste0("Chick Weight - ", today, ".pdf")
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
makethepdf <- function(fname) {
pdf(fname,
width = 14,
height = 8.5)
p1
dev.off()
}
})
```
EDIT: To be clear: I want the user to be able to download multiple pages of graphs, some of which will have different formatting. The user won't be downloading just a pdf version of the markdown document.
This happens because reasons I weren't able to identify makethepdf runs with the file = [name of the file]. Insert a print(fname) to see. The download handler isn't supposed to be inside an observer though. You need to have it outside on its own. I also failed to make pdf() dev.off() combination work for some reason so here's a working version below.
output$dnld = downloadHandler(filename = paste0("Chick Weight - ", today, ".pdf"),
content = function(file){
ggsave(file, plot = p1, width = 14, height = 8.5)
})
Use tempfile() and tempdir() to create a temporary file:
output$downloadReport = downloadHandler(
filename = function() {
normalizePath(tempfile("report_", fileext = ".docx"), winslash = "/")
},
content = function(file) {
out = rmarkdown::render("./report.Rmd",
output_file = file,
output_dir = tempdir(),
output_format = "pdf_document",
intermediates_dir = tempdir(),
envir = new.env(),
params = list( fontSize = 10)
)
})
I usually use a separate .Rmd template for my downloaded reports as the layout and text are usually similar but not identical to what works in an app.
I also find using parameters is a convenient way to pass input settings from my app to my report. See this RStudio post for details
Alright, so there are a number of problems with my code, but using some of the suggestions in the other answers I've been able to work it out.
The primary problem with this little document is that content in the downloadHandler is a function, but in my code I set content equal to the result of a function call. It looks like when the shiny app is first run it compiles content, thinking that it is a function, but actually ends up calling the function. It sends file as an arguement, which doesn't seem to exist except as a base function. Calling makethepdf with just file throws an error when I use it in the console, but for whatever reason in this app it just goes with the call, apparently with file = [name of the .Rmd] (just as OganM said).
To fix, change this:
output$dnld <- downloadHandler(filename = fname,
content = makethepdf(file))
to
output$dnld <- downloadHandler(filename = fname,
content = makethepdf)
To be clear: this code does not overwrite the .Rmd file if content calls makethepdf with any argument other than file. For instance, content = makethepdf(fnm)) causes the download button to display an object not found error and content = makethepdf(fname)) causes the download button to throw an attempt to apply non-function error when pressed.
In this following MWE on a Windows 7 machine running R 3.12
I am trying to create an md file from an Rmd. It creates the md file in my working directory, not int he specified path. The HTML file is created in the specified path instead. How can I make the md get created in deleteMe/my.md?
## Create a minimal Rmd:
dir.create("deleteMe")
cat("\nminimal", file = "deleteMe/my.Rmd")
## knit it to md
knitr::knit2html(input = "deleteMe/my.Rmd", output = "deleteMe/my.md")
## If I set the working directory to deleteME it is correct but I'm don't like to use setwd in functions
setwd("deleteMe")
knitr::knit2html(input = "deleteMe/my.Rmd", output = "deleteMe/my.md")
I realize it's a knit2html, not knit2md, but it creates an md as well. I'm open to other functions/packages/methods if this is the wrong approach. I do not want a yaml though as this is for a README.md creation that I don't want the yaml to appear in.
Looking at the source of knit2html(), you can see that when it calls knit(), it doesn't specify output=. That means that knit() is assuming you want the .md created in the working directory (hence why it works when you change working directory).
Creating a new version of knit2html() makes it work:
knit2html2 <- function (input, output = NULL, ..., envir = parent.frame(),
text = NULL, quiet = FALSE, encoding = getOption("encoding"))
{
#Specify output path in knit()
out = knit(input, output, text = text, envir = envir, encoding = encoding,
quiet = quiet)
if (is.null(text)) {
output = knitr:::sub_ext(if (is.null(output) || is.na(output))
out
else output, "html")
markdown::markdownToHTML(out, output, encoding = encoding,
...)
invisible(output)
}
else markdown::markdownToHTML(text = out, ...)
}
It seems reasonable that output= be passed on to knit() - maybe a pull request is in order