Rmarkdown, shiny app : pdf edition fail with kable_styling option - r

I am currently trying to generate and export a pdf file from a shiny app.
I generate a table by using kable (it works).
When I add kable_styling options to my table (kable_styling(latex_options = c("scale_down"))), it cannot generate my pdf file with this error :
Error : pandoc document conversion failed with error 43
Note : I have check my pandoc version is to date.
Any idea?
Thanks a lot
here is my input.rmd
---
title: ""
output: pdf_document
---
```{r echo=T}
library(kableExtra)
library(knitr)
dt <- mtcars[1:5, 1:4]
kable(cbind(dt,dt, dt, dt, dt), "markdown") %>%
kable_styling(latex_options = c("scale_down"))
kable(dt, format = "latex", booktabs = T, caption = "Demo Table") %>%
add_header_above(c(" ", "Group 1" = 2, "Group 2[note]" = 2)) %>%
add_footnote(c("table footnote"))
test3<-kable(dt, "markdown")
kable_styling(test3, font_size=14)
```
Tableau2
`r test3`
and the shiny app :
library(rmarkdown)
library(knitr)
shinyApp(
ui = fluidPage(
basicPage(
downloadButton('report'))
),
server = function(input, output) {
output$report = downloadHandler(
filename = 'myreport.pdf',
content = function(file) {
out = render('input.Rmd', clean = TRUE, encoding='utf-8')
file.rename(out, file) # move pdf to file for downloading
},
contentType = 'application/pdf'
)
}
)

Related

how to download quarto pdf reports from R Shiny application

I am trying to download pdf/docx/html reports based on the inputs provided by user. To do that I created a Shiny app and a qmd file with parameters. qmd file is working fine when i render it separately. But if i render the same document and try to download it from Shiny it is not working. Here is my downloadHandler chunk
output$report <- downloadHandler(
filename = function() {
paste("report", input$report_file_type, sep = ".")
},
content = function(file) {
output <- quarto::quarto_render(
input = 'report_template.qmd',
output_format = input$report_file_type,
execute_params = list(name = input$author_name,
report_title = input$report_title)
)
file.copy(output, file)
}
)
Edit: here is the qmd report template
---
title: "`r params$report_title`"
author: "`r params$name`"
date: "`r format(Sys.time(), '%d %B, %Y')`"
format: html
embed-resources: true
params:
report_title: "report title"
name: "author name"
p_list: list("A", "B")
---
Printing each element of the list...
```{r}
#| echo: true
for(p in eval(parse(text = params$p_list))){
print(p)
}
```
Printing the list...
```{r}
#| echo: true
print(eval(parse(text = params$p_list)))
```
I am not getting any error but at the same nothing is being written to downloads folder. It seems like rendered document is not being assigned to output. Perhaps that's why the coping line is not working. what could be the problem and how to solve it? thanks in advance.
quarto::quarto_render does not return the generated file or anything and so output in your code is NULL and hence you are not getting any output.
Now to get this code working, we need to copy the file generated by quarto::quarto_render to the file parameter of the function passed to content argument of downloadHandler.
shinyApp(
# UI -----------------------------------------------------------
ui = fluidPage(
textInput("author_name", "Author Name", "John Doe"),
textInput("report_title", "Report Title", "Quarto From Shiny"),
radioButtons(
inputId = "report_file_type",
label = "Report Type",
choices = c("HTML" = "html", "PDF" = "pdf")
),
downloadButton("report", "Generate report")
),
# SERVER --------------------------------------------------------
server = function(input, output) {
output$report <- downloadHandler(
filename = function() {
paste("report", input$report_file_type, sep = ".")
},
content = function(file) {
quarto::quarto_render(
input = "report_template.qmd",
output_format = input$report_file_type,
execute_params = list(
name = input$author_name,
report_title = input$report_title
)
)
# copy the quarto generated file to `file` argument.
generated_file_name <- paste("report_template", input$report_file_type,
sep = ".")
file.copy(generated_file_name, file)
}
)
}
)

kable and kableExtra not rendering in pdf from markdown document

I am trying to render a table into a pdf using kable in a markdown document generated from a shiny app. It renders OK until I use any functionality from kableExtra (column_spec in the code below) at which point I get the following error:
! LaTeX Error: Illegal character in array
arg.
The problem seems pretty basic and I'm not the first to have this issue, but other solutions (such as this and this) haven't helped. The table renders OK as HTML but it seems that kableExtra doesn't seem to know that it is rendering latex. If I change the knitr.table.format to "pandoc" it renders but still errors of the column_spec line. Any ideas?
UI.R
fluidPage(
title = 'Download a PDF report',
sidebarLayout(
sidebarPanel(
helpText(),
div("Create a Mark Down Document"),
radioButtons('format', 'Document format', c('PDF', 'HTML'),
inline = TRUE),
downloadButton('downloadReport')
),
mainPanel(
plotOutput('regPlot')
)
)
)
Server.R
library(rmarkdown)
library(shiny)
library(magrittr)
library(kableExtra)
function(input, output) {
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html'
))
},
content = function(file) {
src <- normalizePath('report.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document()
))
file.rename(out, file)
}
)
}
Report.Rmd
Test kable:
```{r}
auto_set_format <- function() {
if (knitr::is_latex_output()) {
options(knitr.table.format = "latex")
} else {
options(knitr.table.format = "html")
}
}
auto_set_format()
tbl <- knitr::kable(mtcars[1:6, 1:6], caption = 'A subset of mtcars.')
# THIS LINE CAUSES THE PROBEM WHEN WRITING TO PDF. COMMENT OUT AND IT WORKS OK
tbl <- tbl %>% column_spec(3, color = "#62BD19")
tbl
```
For column_spec() you need to give an additional Latex package to knitr, i.e. change your report to
---
title: "Example Table"
header-includes:
- \usepackage{dcolumn}
---
Test kable:
```{r}
auto_set_format <- function() {
if (knitr::is_latex_output()) {
options(knitr.table.format = "latex")
} else {
options(knitr.table.format = "html")
}
}
auto_set_format()
tbl <- knitr::kable(mtcars[1:6, 1:6], caption = 'A subset of mtcars.') %>%
column_spec(3, color = "#62BD19")
tbl
```
and you will be able to produce both reports.

Generating downloadable reports from Shiny app

I made an R script that allows to get an R Markdown report with a certain type of dataset. Now I would like other people to be able to use this script in order to get an automated report with their data but without using this script (especially for people who don't master R).
I try to go through Shiny hoping to make an interface that loads a dataset and would make my script automatically but I can't make the link between Shiny and my Rmd.
How can I tell my Rmd that the dataset to be processed is not the one that my Rmd script was going to look for in a directory but the one that was loaded on the Shiny interface?
Thanks
Here is the Shiny script with my Rmd called "traitemant_bis.Rmd" :
library(shiny)
library(rmarkdown)
ui <- fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(
inputId = "file1", label = "Choose CSV File",
multiple = FALSE,
accept = c("text/csv", "text/comma-separated-values,text/plain", ".csv")
),
radioButtons("format", "Document format", c("PDF", "HTML", "Word"), inline = TRUE)
),
mainPanel(
tableOutput("contents"),
downloadButton("downloadReport")
)
)
)
server <- function(input, output) {
dataset <- reactive({
req(input$file1)
read.csv(file = input$file1$datapath,
na.strings = ".",
sep = ";",
header = TRUE,
nrows=10)
})
output$contents <- renderTable({
req(dataset())
head(dataset())
})
output$downloadReport <- downloadHandler(
filename = function() {
paste("my-report", sep = ".", switch(
input$format, PDF = "pdf", HTML = "html", Word = "docx"
))
},
content = function(file) {
src <- normalizePath("traitemant_bis.Rmd")
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, "traitemant_bis.Rmd", overwrite = TRUE)
out <- render("traitemant_bis.Rmd", switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
}
shinyApp(ui, server) ```
I'm giving a simple example showing how you can achieve this. Basically, you can pass any of your data from shiny to Rmd as params.
If you have multiple data frames or any data convert them to a single list and pass as params, you can extract individual data later in the RMarkdown
app.R
library(shiny)
ui <- fluidPage(
# Application title
titlePanel("RMD example"),
downloadButton("btn", "Generate Report")
)
# Define server logic required to draw a histogram
server <- function(input, output) {
data <- reactive({
mtcars
})
output$btn <- downloadHandler(
filename = function(){"myreport.docx"},
content = function(file) {
tempReport <- file.path(tempdir(),"markdown.Rmd")
file.copy("markdown.Rmd", tempReport, overwrite = TRUE)
rmarkdown::render("markdown.Rmd", output_format = "word_document", output_file = file,
params = list(table = data()), # here I'm passing data in params
envir = new.env(parent = globalenv()),clean=F,encoding="utf-8"
)
}
)
}
# Run the application
shinyApp(ui = ui, server = server)
Rmd file
---
title: "Untitled"
author: "Mohan"
date: "2/17/2021"
params:
table: [some object]
output: word_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.
When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
```{r cars}
params$table -> data
data
summary(data)
```

Table of contents in render markdown by shinyapp

I have problems generating table of contents in the markdown generated by my shinyapp.
I have tried to set in the YAML toc = TRUE but it doesn't work.
the app is something like this, an interface where some data is uploaded and a markdown where some graphics are rendered.
the problem is that when generating the pdf, html or word the table of contents is not generated.
app.R
library(shiny)
library(dplyr)
library(qcc)
library(ggplot2)
library(readxl)
library(kableExtra)
library(knitr)
shinyApp(ui =
fluidPage(fileInput("file", "Cargar Datos", multiple = FALSE),
radioButtons('format', 'Formato del documento', c('PDF', 'HTML', 'Word'),inline = TRUE),
downloadButton('downloadReport')),
server = function(input, output, session){
myData <- reactive({ infile <- input$file
if(is.null(infile)) return(NULL)
data <- read_excel(infile$datapath)
data})
plotData <- function(){plot(myData}
output$downloadReport <- downloadHandler(
filename = function() {
paste('my-report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html', Word = 'docx'
))
},
content = function(file) {
src <- normalizePath('report.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'report.Rmd', overwrite = TRUE)
library(rmarkdown)
out <- render('report.Rmd', switch(
input$format,
PDF = pdf_document(), HTML = html_document(), Word = word_document()
))
file.rename(out, file)
}
)
########################################
####
})
report.Rmd
---
title: "title"
subtitle: "subtitle"
output:
toc: true
toc_depth: 4
number_sections: true
author:
- "a1"
- "a2"
date: "`r format(Sys.Date(), '%B %d, %Y')`"
params:
p1: "p1"
p2: "p2"
---
# section1
## section1.1
# section2
```{r}
plotData()
Try passing the options as arguments to the rendering function, e.g.
rmarkdown::render('report.Rmd', rmarkdown::pdf_document(toc = TRUE, toc_depth = 4, number_sections = TRUE))
answered by stefan in a comment on the question.

Getting an error when trying to produce pdf table ,using the kableExtra package, after importing csv file in a shiny app

Hello I have this simple shiny app which includes 3 files(ui,server,kable), in which i want to be able to produce a table with kable() after importing a csv file. I can make it work when i produce it in html but it cannot be converted to pdf. Specifically i get this error: Error : pandoc document conversion failed with error 43
#ui.r
library(shiny)
library(rmarkdown)
fluidPage(sidebarLayout(
sidebarPanel(
fileInput("file1", "Input CSV-File"),
downloadButton('downloadReport')
),
mainPanel(tableOutput("table"))
))
#server.r
function(input, output) {
output$downloadReport <- downloadHandler(
filename = "my-report.pdf",
content = function(file) {
src <- normalizePath('kable.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'kable.Rmd', overwrite = TRUE)
out <- render('kable.Rmd', params = list(file = input$file1$datapath))
file.rename(out, file)
}
)
output$table <- renderTable({
inFile <- req(input$file1)
read.csv(inFile$datapath)
})
}
#kable.rmd
---
params:
file: "mtcars.csv"
output: pdf_document
---
```{r echo = FALSE, message = FALSE, include = FALSE}
library(kableExtra)
library(knitr)
```
```{r nice-tab, tidy = FALSE, echo = FALSE, message = FALSE}
csvdata <- read.csv(file = params$file)
kable(csvdata, caption = 'REPORT TABLE',
booktabs = TRUE, longtable = TRUE,format = "latex", escape = FALSE) %>%
kable_styling(full_width = T, font_size = 10 ) %>%
row_spec(row = 0, bold = T, background = "gray")
```

Resources