I'd like to create a pdf report for each cylinder ('cyl') between the 3 possibilities (4, 6 and 8) in a separate table. But, I need to create one table for each cylinder in a loop and for this I try to do:
library(knitr)
library (rmarkdown)
data(mtcars)
id.cyl <-unique(mtcars$cyl)
for(i in 1:id.cyl){
mtcars.sub<-
mtcars[mtcars$cyl==id.mtcars[i],]
kagle(mtcars.sub)
}
render("my_loop_report.pdf",
pdf_document())
This code doesn't work and I need some suggestions to solve it. Please any help with it?
Create an .rmd file that generates the report, and pass the cylinder as a value.
Here is the .rmd file (say, cylinder.rmd)
---
title: "cylinder_report"
author: "author_name"
date: "2023-01-25"
output: pdf_document
params:
cylinder: 0
---
``{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
df = mtcars
``
## Cylinder `r params$cylinder`
``{r output, echo=FALSE}
knitr::kable(df[df$cyl == params$cylinder,])
``
Separately, you can then loop through the cylinder values, each time passing the cylinder value
cyls = unique(mtcars$cyl)
for(cyl in cyls) {
rmarkdown::render(
input = "cylinder.Rmd",
output_file = paste0("cylinder_report_", cyl),
params = list(cylinder = cyl)
)
}
This will produce cylinder_report_4.pdf, cylinder_report_6.pdf, and cylinder_report_8.pdf.
(Note, in this toy example, you don't even have to pass the parameter; in fact, loading mtcars into df and subsetting it within the .rmd is not necessary. When you use `rmarkdown::render(), objects in the environment are available to the .rmd file, so you could also subset the data in the loop outside the rmd file, like this,
cyls = unique(mtcars$cyl)
for(cyl in cyls) {
df = mtcars[mtcars$cyl == cyl,]
rmarkdown::render(
input = "cylinder.Rmd",
output_file = paste0("cylinder_report_", cyl)
)
}
and the .rmd could be simplifed to this (note, no parameter, no creation of df, no subsetting, etc:
---
title: "cylinder_report"
author: "author_name"
date: "2023-01-25"
output: pdf_document
---
``{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
``
## Cylinder `r cyl`
``{r output, echo=FALSE}
knitr::kable(df)
``
)
Related
I have a list of many (can be dozens of) tables created with the gt package in R. I would like to export them all as a single HTML file with a little space between each table. Currently, I have been exporting each table individually, reading them into an RMarkdown with the xfun package, and knitting to a single HTML file. I'm curious if there is a method to cut out the intermediate step of saving each table individually and reading into the Rmd.
Example:
library(gt)
library(tidyverse)
tbl_list <- list(mtcar_tbl = mtcars %>% gt(),
iris_tbl = iris %>% gt(),
cars_tbl = cars %>% gt())
purrr::map(seq_along(tbl_list), function(rownum){
htmltools::save_html(html = tbl_list[[rownum]],
file = paste0("test",rownum,".html"))
})
RMarkdown to combine and export tables:
---
title: ""
output: html_document
---
```{r, echo=FALSE,message=FALSE,warning=FALSE}
library(xfun)
```
```{r echo=FALSE}
htmltools::includeHTML("test1.html")
```
<br><br>
```{r echo=FALSE}
htmltools::includeHTML("test2.html")
```
<br><br>
```{r echo=FALSE}
htmltools::includeHTML("test3.html")
```
One option would be to use purrr::walk with chunk option results="asis" to directly print your tables without the intermediate step. To add the line breaks after each table use cat("<br><br>"):
Note: For the reprex I just print the head of each table.
---
title: "Untitled"
output: html_document
date: "2022-09-19"
---
```{r echo=FALSE, results='asis', warning=FALSE, message=FALSE}
library(gt)
library(tidyverse)
tbl_list <- list(mtcar_tbl = mtcars,
iris_tbl = iris,
cars_tbl = cars)
tbl_list <- purrr::map(tbl_list, ~ head(.x) %>% gt() )
purrr::walk(tbl_list, function(x) { print(x); cat("<br><br>") })
```
I'm trying to incorporate an Rmd I have been using into a flexdashboard. I'm curious if it is possible to isolate an uploaded file and use it as-is rather than writing a bunch of reactive functions. If this is my template, is it possible to get a static object named df that the child document can go ahead and run with?
---
title: "help"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: columns
---
```{r}
fileInput("data", "select data")
df <- isolate(input$data)
```
```{r, child="some_code.Rmd"}
```
My real example does something completely different but let's say some_code.Rmd looks like this:
---
title: "some code"
output: html_document
---
```{r packages, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE)
library(tidyverse)
```
The data looks like this:
```{r}
as_tibble(df)
```
The numeric data can be summarized with the following means
```{r}
df |>
summarise(across(where(is.numeric), mean)) |>
gather()
```
This ended up working:
knitr::knit() + markdown::markdownToHTML() + HTML() ---> renderUI()
---
title: "help"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
---
Sidebar {.sidebar}
==============================================
```{r file-input}
fileInput("data", "select data")
```
Row
==============================================
```{r knit-child}
observeEvent(input$data, {
df <- isolate(read.csv(input$data$datapath))
new_env <- list2env(list(df = df))
output$res <- renderUI({
knitr::knit("some_code.Rmd", quiet = TRUE, envir = new_env) |>
markdown::markdownToHTML() |>
HTML()
})
})
uiOutput("res")
```
I often want to print out the dataframes contained in a list as paged tables in my rmarkdown documents. Calling each dataframe individually renders the desired ouptut if the right df_print option is selected. However, the point of having a list is that the number of dataframes varies depending on the parameters passed to the rmarkdown document; so that's no real solution.
Based on Vincent Guyader's answer to this question and on this example of rmarkdown::paged_table, I've tried to do the following without success.
Is there a way to achieve this at all? I'd be happy to use any package that supports pagination remotely resembling the df_print option.
---
title: "Printing paged tables from a list of dataframes in Rmarkdown"
output:
html_document:
df_print: paged
---
```{r}
library(DT)
library(rmarkdown)
library(purrr)
library(knitr)
df_list <- list("cars" = mtcars, "flowers" = iris)
knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE, results='asis')
```
### Desired output but impossible to generalise
```{r}
df_list[["cars"]]
```
```{r}
df_list[["flowers"]]
```
### datatable shows as blanks on the page
```{r}
map(df_list, ~DT::datatable(.x) %>%
htmltools::tagList() %>%
print())
```
### rmarkdown outputs dataframe contents as one very long string
```{r}
map(df_list, rmarkdown::paged_table)
```
The issue is that the JS dependencies needed to render the Datatable are not included in the HTML output. A workaround which I borrowed from here is to add a code chunk
```{r init-step, include=FALSE}
DT::datatable(mtcars)
```
outside of the loop or map statement which ensures that the JS dependencies are included. Also, I would recommend to switch to purrr::walk as using map has the effect that the tables are plotted twice.
---
title: "Printing paged tables from a list of dataframes in Rmarkdown"
output:
html_document:
df_print: paged
---
```{r}
library(DT)
library(rmarkdown)
library(purrr)
library(knitr)
df_list <- list("cars" = mtcars, "flowers" = iris)
knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE, results='asis')
```
### Desired output but impossible to generalise
```{r}
df_list[["cars"]]
```
```{r}
df_list[["flowers"]]
```
### datatable shows as blanks on the page
```{r init-step, include=FALSE}
DT::datatable(mtcars)
```
```{r}
walk(df_list, ~DT::datatable(.x) %>%
htmltools::tagList() %>%
print())
```
When using results='asis' argument, the renderer (here DT) has to be initialized once before being applied on a asis list.
This seems to be a general problem, see here with leaflet, and here with Highcharter.
The answer to this general question has been given here.
In this case:
---
title: "Printing paged tables from a list of dataframes in Rmarkdown"
output:
html_document:
df_print: paged
---
```{r,}
library(DT)
library(rmarkdown)
library(purrr)
library(knitr)
df_list <- list("cars" = mtcars, "flowers" = iris)
knitr::opts_chunk$set(echo = FALSE, warning = FALSE, message = FALSE, results='asis')
# initialize the renderer
data.frame() %>%
DT::datatable() %>%
knitr::knit_print() %>%
attr('knit_meta') %>%
knitr::knit_meta_add() %>%
invisible()
```
```{r , results='asis'}
#Remove already printed element and print the rest
df_list[[1]] <- NULL
map(df_list, ~DT::datatable(.x) %>%
htmltools::tagList() %>%
print())
```
I'm trying to create multiple tables using kable from a csv file, but the requirement is that I need to also put an image in the table as per the below image. The entire image needs to be in the left column. Is this possible?
The dataframe looks like this:
df<-data.frame(Amount= c('$25', '$45', '$75'),
Rate = c('1%', '1%', '3%'),
Location = c('Germany', 'Switzerland', 'England'),
ImageName= c('GE.png', 'BE.png', 'CE.png'),
Status = c('Sold','Unsold','Sold')
)
So far my R code is
---
output:
word_document:
reference_docx: ReferenceDoc.docx
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
df<-read.csv('Productdata.csv')
```
```{r loops, echo=F, results='asis'}
library(knitr)
for (i in 1:nrow(df))
{
print(kable(df[i,]))
}
```
Im really not sure how I can enter an image like that in my RMarkdown for WORD.
Here's an approach using kable, along with kableExtra functions to take care of some of the formatting. So far, I've only been able to render this properly to html. I'll update if I can make this work in Word. In the code below, I used some images I happened to have lying around. Just run the same sprintf function on your original ImageName column to get the appropriate rmarkdown tagging for your images.
---
output:
html_document:
df_print: paged
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, warning=FALSE, message=FALSE)
library(knitr)
library(kableExtra)
library(tidyverse)
#df<-read.csv('Productdata.csv')
df<-data.frame(Amount= c('$25', '$45', '$75'),
Rate = c('1%', '1%', '3%'),
Location = c('Germany', 'Switzerland', 'England'),
ImageName= c('GE.png', 'BE.png', 'CE.png'),
Status = c('Sold','Unsold','Sold')
)
# Change to names of my local images
df$ImageName =c("mal2.jpg",
"serenity2.jpg",
"blue_sun2.jpg")
# Add appropriate rmarkdown tagging
df$ImageName = sprintf("![](%s)", df$ImageName)
```
```{r loops, echo=F, results="asis"}
for (i in 1:nrow(df)) {
# Select desired row
d = df[i, ]
# Change name of ImageName column to Status value
names(d)[grep("ImageName", names(d))] = as.character(d[["Status"]])
# Convert data to "long" format
d = d %>%
select(-Status) %>%
gather(Product, value, Amount:Location) %>%
rename(` ` = value)
# Render table using kableExtra for formatting
print(kable(d, format="html") %>%
kable_styling(full_width=FALSE) %>%
collapse_rows(columns=1, valign="top"))
}
```
And here's what the html output file looks like:
I think this may bump up against the limits of kable, but here is a very not elegant way to do something similar with htmlTable. Notice that the images are relative to the directory you are running the Rmd from, or you can use links to URLs.
---
output:
html_document:
df_print: paged
word_document:
reference_docx: ReferenceDoc.docx
---
```{r setup, echo=FALSE, message=FALSE, warning=FALSE, results='asis'}
library(knitr)
library(dplyr)
library(magrittr)
library(htmlTable)
x <- 0
df <- data.frame( Status = c('Sold','Unsold','Sold'),
Image = c('images/fwhm1.jpg', 'images/ridges-shade.jpg', 'images/sep16-2018.jpg'),
Amount= c('$25', '$45', '$75'),
Rate = c('1%', '1%', '3%'),
Location = c('Germany', 'Switzerland', 'England')
)
df$Image <- sprintf('![](%s){width=150px}', df$Image)
for (i in 1:nrow(df)) {
x <- t(df[i,])
new.df <- data.frame(matrix(ncol=2,nrow=2))
new.df[1,1] <- paste(x[1],x[2],sep="<br>")
new.df[1,2] <- paste0(rownames(x)[3:5], ": ", x[3:5], collapse="<br>")
colnames(new.df) <- NULL
rownames(new.df) <- NULL
print( htmlTable(new.df,
css.cell="padding-left: .5em; padding-right: .5em; align: left; align: left; vertical-align: top;",
rnames=FALSE) )
}
```
Here is what it looks like:
I also opened the HTML file that was rendered in Word, and was able to shrink the images and add borders -- the table structure was retained. It looked like this:
When using rmarkdown to render pdf document, we can use three options for printing data.frame: default, kable and tibble (see here)
With the default option, it is possible to limit the number of rows printed, with the option: max.print
For tibble, we can use: dplyr.print_max
I can't find a way to limit the number of rows for kable. Is it possible?
kable renders the full data frame passed to it as a table in the output document. AFAIK there's no argument that will limit the number of rows. However, you can preselect the number of rows in the output table (for example, kable(head(dat)) or kable(dat[1:5, ])). If you want to avoid having to select the rows each time, you could write a helper function to limit the number of rows printed. For example:
---
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(knitr)
```
```{r}
my_kable = function(x, max.rows=6, ...) {
kable(x[1:max.rows, ], ...)
}
```
```{r}
my_kable(mtcars, caption="My first caption")
```
```{r}
iris$Sepal.Length = 1000 * iris$Sepal.Length
my_kable(iris, 3, caption="My second caption", format.args=list(big.mark=","))
```
A really simple solution is to wrap kable around head:
kable(head(mtcars, n = 5))
You can create a custom method for printing data frames like this.
Adapted from Yihui Xie's explanation here
---
title: "Untitled"
output: html_document
---
```{r include=FALSE}
knit_print.data.frame <- function(x, ...) {
head(x, 5) |>
knitr::kable() |>
paste(collapse = "\n") |>
knitr::asis_output()
}
registerS3method(
genname = "knit_print",
class = "data.frame",
method = knit_print.data.frame,
envir = asNamespace("knitr")
)
```
```{r}
iris
tibble::as_tibble(iris)
```