using a for loop to generate a series of plots in new powerpoint slides using quarto - r-markdown

I am creating a quarto powerpoint presentation and want to use a dataset to iterate over all the classes in a variable and do a plot for each class on a new slide. However, my plot doesn't seem to show up
---
title: "test_quarto_presentation"
format: pptx
editor: visual
---
## Quarto
Trying to iterate over each species and print the distributions on slides
```{r}
library(tidyverse)
```
```{r, results='asis'}
for (species in unique(iris$Species)){
cat(paste0('## ', species))
print("test")
print(iris %>%
filter(Species == "virginica") %>%
ggplot(aes(x = Petal.Length)) +
geom_histogram())}
```

Here is an option by producing the plots beforehand using purrr based on this discussion:
---
title: "test_quarto_presentation"
format: pptx
---
```{r, include=FALSE}
library(tidyverse)
spec_name <- unique(iris$Species)
make_hist <- function(spec) {
iris |>
filter(Species == spec) |>
ggplot(aes(x = Petal.Length)) +
geom_histogram()
}
list_hist <- map(spec_name, make_hist)
df <- tibble(spec = spec_name, plots = list_hist)
```
```{r}
#| output: asis
res <- pmap_chr(df, \(spec, plots) {
knitr::knit_child(text = c(
"## `r spec`",
"```{r}",
"#| echo: false",
"plots",
"```",
""), envir = environment(), quiet = TRUE)
})
cat(res, sep = '\n')
```
Output:

Related

Dynamically generating figures with captions in Word output from Rmarkdown document

I'm trying to generate a Word document with figures. I use {officedown} and {officer} packages. I need to do it dynamically, in a loop since I don't know how many figures there will be. This is my Rmarkdown code:
---
output:
officedown::rdocx_document:
plots:
caption:
style: Table Caption
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
```
```{r}
library(dplyr)
library(flextable)
library(officer)
```
```{r}
block_toc(seq_id = "fig")
```
```{r results='asis'}
ttp <- c(3, 7)
test_items <- c("item A", "item B", "item C")
fpars <- lapply(test_items, function(ti) {
fpar(
ftext("Application of "),
ftext(ti),
ftext(" Variable text - describe any test item-related effects"),
ftext(" (see "),
run_reference("fig:results1"),
ftext(")."),
fp_p = fp_par(padding.bottom = 12)
)
})
do.call(block_list, fpars)
```
```{r}
titles <- lapply(seq_len(length(ttp)), function(i) {
sprintf(
"My custom figure caption with %s, having %s side effects",
paste(test_items, collapse = ", "),
ttp[i]
)
})
```
```{r}
tmps <- lapply(seq_len(length(ttp)), function(i) {
tmp <- tempfile(fileext = ".png")
png(tmp, width = 6, height = 5, units = "in", res = 120)
plot(iris[sample(1:150, 30), i + 1:2])
dev.off()
return(tmp)
})
```
```{r}
fpars <- lapply(seq_len(length(ttp)), function(i) {
fpar(
run_autonum(
seq_id = "fig",
pre_label = "Figure ",
bkm = paste0("fig:results", i),
bkm_all = TRUE,
prop = fp_text(bold = TRUE, font.size = 12)
),
titles[[i]],
external_img(src = tmps[[i]], width = 6, height = 5)
)
})
do.call(block_list, fpars)
```
The problem is when I generate the table of figures in the rendered document. It looks like this:
An entry is kept together with the image itself, I don't know why.
I save temporary png files to be able to use them inside fpar function. Using plot function directly inside fpar causes bad effects. Maybe there's another/better way?
I found this construction useful, but unfortunately it puts captions under the figures by default. My goal is figure captions behave more like table captions, i.e. a caption is above a figure.
```{r fig.cap=unlist(titles)}
plot(iris[1:10, 1:2])
```
How can I generate the plots with captions dynamically with {officedown} or {officer} packages?
The only issue is about the last lapply, you need to put the image in a separate paragraph, so a for loop will be easier to stack 2 paragraphs into a list instead of 1 for each iteration.
---
output:
officedown::rdocx_document:
plots:
caption:
style: Table Caption
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
```
```{r}
library(dplyr)
library(flextable)
library(officer)
library(officedown)
```
```{r}
block_toc(seq_id = "fig")
```
```{r}
ttp <- c(3, 7)
test_items <- c("item A", "item B", "item C")
fpars <- lapply(test_items, function(ti) {
fpar(
ftext("Application of "),
ftext(ti),
ftext(" Variable text - describe any test item-related effects"),
ftext(" (see "),
run_reference("fig:results1"),
ftext(")."),
fp_p = fp_par(padding.bottom = 12)
)
})
do.call(block_list, fpars)
```
```{r}
titles <- lapply(seq_len(length(ttp)), function(i) {
sprintf(
"My custom figure caption with %s, having %s side effects",
paste(test_items, collapse = ", "),
ttp[i]
)
})
```
```{r}
tmps <- lapply(seq_len(length(ttp)), function(i) {
tmp <- tempfile(fileext = ".png")
png(tmp, width = 6, height = 5, units = "in", res = 120)
plot(iris[sample(1:150, 30), i + 1:2])
dev.off()
return(tmp)
})
```
```{r}
fpars <- list()
for (i in seq_along(ttp)) {
fpars[[length(fpars)+1]] <- fpar(
run_autonum(
seq_id = "fig",
pre_label = "Figure ",
bkm = paste0("fig:results", i),
bkm_all = TRUE,
prop = fp_text(bold = TRUE, font.size = 12)
),
titles[[i]]
)
fpars[[length(fpars)+1]] <- fpar(
external_img(src = tmps[[i]], width = 6, height = 5)
)
}
do.call(block_list, fpars)
```
This is an answer for "how to do it with officer" from scratch.
But the following is much more simple. There is an option fig.topcaption that do the same thing.
---
output:
officedown::rdocx_document:
plots:
caption:
style: Table Caption
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
```
```{r}
library(dplyr)
library(flextable)
library(officer)
library(officedown)
```
```{r}
block_toc(seq_id = "fig")
```
```{r fig.cap = "miaou", fig.topcaption=TRUE}
plot(cars)
```
```{r fig.cap = "ouaf", fig.topcaption=TRUE}
plot(cars)
```

How do you filter a data frame in a shiny document and display a datatable?

I'm trying to filter a data frame and then do some simple ggplots off of the data. I've tried to leverage the R studio example on Shiny documents along with the following SO post on the subject:
Reactively filtering/subsetting a data frame in shiny
Here is my code.
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r}
library(tidyverse)
library(shiny)
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
cdat <- reactive({
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
data %>%
filter(x %in% input$n_break)
output$table <- DT::renderDT({
cdat()
}, options = list(scrollX = TRUE))
})
```
Can anyone point out where I'm going wrong? When I run the code I get my dropdown box, but that is all. No errors. Just no filtered datatable.
Thanks.
The closing brackets of your reactive are at the wrong place. They should close once you have filtered the data.
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup}
knitr::opts_chunk$set(
echo = FALSE
)
```
```{r}
library(tidyverse)
library(shiny)
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
cdat <- reactive({
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
data %>% filter(x %in% input$n_break)
})
DT::renderDT({
cdat()
}, options = list(scrollX = is ))
```
A remark on the reactive: if you plan to extend this futher, such that the filtered data is used elsewhere, it makes sense to do the filtering in a reactive function. However, if this is not the case I would just do the filtering inside the renderDT:
---
title: "Shiny Filter Test"
author: "Novice"
date: "12/13/2019"
output: html_document
runtime: shiny
---
```{r setup}
knitr::opts_chunk$set(
echo = FALSE
)
```
```{r}
library(tidyverse)
library(shiny)
data <- tibble(x = c(10,20,35), y = c("a","b","c"))
inputPanel(
selectInput("n_break", label = "Number of bins:",
choices = c(10, 20, 35, 50), selected = 10)
)
DT::renderDT({
data %>% filter(x %in% input$n_break)
}, options = list(scrollX = TRUE))
```

Knitr and/or Kableextra: Global Table Options?

Is it possible to instruct Rmarkdown to default all tables to my styled output? Here is my attempt:
---
title: 'Test Kable Global Styling'
output:
html_document:
df_print: kable
---
```{r}
library(knitr)
library(kableExtra)
kable <- function(data) {
message("YES, IT BITES! (not sortable, but styled.)\n")
knitr::kable(data, digits=3) %>% kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
}
```
## Testing
```{r}
d <- data.frame( x=1:3, y=rnorm(3) )
```
### Explicit Invokation
```{r}
kable(d)
```
### Implicit Invokation Fails
```{r}
d
```
The output looks like this:
[possibly related to How to set knitr::kable() global options in markdown for reuse, but defining my own kable function is not enough for Rmarkdown to select it.
thanks, mystery user for the complete solved update to the above problem. alas, could it generalize to :
```{r}
library(knitr)
library(DT); p <- function(...) DT::datatable(...)
knit_print.data.frame <- function(x, ...) asis_output( paste( c("",p(x)) , collapse="\n" ) )
registerS3method("knit_print", "data.frame", knit_print.data.frame)
```
# Test Code
```{r}
d <- data.frame( x=1:3, y=rnorm(3) )
```
## Print
```{r}
p(d)
d
```
done
As you saw, How to set knitr::kable() global options in markdown for reuse describes how to do this with an explicit call to kable, but doesn't handle implicit displays. The way to do that is described in the ?knitr::knit_print help page. You need code like this early in your document:
kable <- function(data, ...) {
message("YES, IT BITES! (not sortable, but styled.)\n")
knitr::kable(data, digits=3, ...) %>% kable_styling(bootstrap_options = "striped", full_width = F, position = "center")
}
knit_print.data.frame <- function(x, ...) {
res <- paste(c("", "", kable(x)), collapse = "\n")
asis_output(res)
}
registerS3method("knit_print", "data.frame", knit_print.data.frame)

hw_grid widget function not working in flexdashboard

Because of this issue want to put 6 highcharter graphs in one row like do they over here. It seems to work fine outside of flexdashboard
data(diamonds, package = "ggplot2")
diamonds <- diamonds[-6]
map(names(diamonds), function(x){
diamonds[[x]] %>%
hchart(showInLegend = FALSE) %>%
hc_add_theme(hc_theme_smpl()) %>%
hc_title(text = x) %>%
hc_yAxis(title = list(text = ""))
}) %>%
hw_grid(rowheight = 225, ncol = 3) %>% browsable()
please find a simple example here how it's not working within flexdashboard :
---
title: "test"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
---
```{r}
library(highcharter)
library(data.table)
library(ggplot2)
library(htmltools)
```
### trying to render with hw_grid
```{r}
sliderInput('ncol','ncol',min = 1,max=4,value = 2)
```
```{r}
renderHighchart({
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
hw_grid(lst, rowheight = 300,ncol = input$ncol) %>% browsable()
})
```
### hw_grid example without rendering
```{r}
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
ncol <- 4
# ncol <- input$ncol # need to have a render as this will triger the error: Operation not allowed without an active reactive context....
hw_grid(lst, rowheight = 300,ncol = ncol) %>% browsable()
```
### rendering example
```{r}
renderHighchart({
x <- hchart(data.table(a=c(input$ncol*1:5),b=c(.5 * input$ncol * 1:5)), type='column', hcaes(x=a,y=b))
})
```
Try using renderUI and htmlOutput together like so:
---
title: "test"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
vertical_layout: fill
---
```{r}
library(highcharter)
library(data.table)
library(ggplot2)
library(htmltools)
library(purrr)
library(shiny)
```
### trying to render with hw_grid
```{r}
sliderInput('ncol','ncol',min = 1,max=4,value = 2)
```
```{r}
output$chart1 <- renderUI({
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(x,x,x,x)
hw_grid(lst, rowheight = 300,ncol = input$ncol)
})
htmlOutput('chart1')
```
### hw_grid example without rendering
```{r}
x <- hchart(data.table(a=c(1:5),b=c(1:5)), type='column', hcaes(x=a,y=b))
lst <- list(
x,
x,
x,
x
)
ncol <- 4
# ncol <- input$ncol # need to have a render as this will triger the error: Operation not allowed without an active reactive context....
hw_grid(lst, rowheight = 300,ncol = ncol) %>% browsable()
```
### rendering example
```{r}
renderHighchart({
x <- hchart(data.table(a=c(input$ncol*1:5),b=c(.5 * input$ncol * 1:5)), type='column', hcaes(x=a,y=b))
})
```

Xtable grey rows overwritting vertical lines

---
title: "Title"
author: ''
date: ''
output:
pdf_document:
template: default.tex
geometry: top=0.5cm, bottom=0.5cm, left=0.5cm, right=0.5cm
header-includes: null
fontsize: 4pt
classoption: portrait
sansfont: Calibri Light
---
#Name1: `r "Name1"`
#Name2: `r "Name2"`
```{r, echo=FALSE, message=FALSE, warning=FALSE, results='asis'}
df <- mtcars
n = nrow(df)
hlines=c(-1,0,(n-1),n)
my_align = "c|c|c|ccccc|ccc|c|"
rws <- seq(1, (n-1), by = 2)
col <- rep("\\rowcolor[gray]{.90} ", length(rws))
xtable::print.xtable(xtable(df
, align = my_align)
, add.to.row = list(pos = as.list(rws), command = col)
, booktabs = F
, hline.after = hlines, type = "latex")
```
I am using an Rmarkdown to print a table which has a lot of formatting. When I add the add.to.rwo part to get grey and white alternate rows the vertical lines are removed in the grey rows.
How do I correct this? It is very difficult to create a reproducible example but hopefully the same problem will apply to any df (with the correct Latex packages behind it)
Thanks :)
Try comparing these two tables. The first is your table as you coded it, the second is done by pixiedust with the hhline option set to TRUE.
---
title: "Title"
author: ''
date: ''
output:
pdf_document:
geometry: top=0.5cm, bottom=0.5cm, left=0.5cm, right=0.5cm
header-includes:
- \usepackage{amssymb}
- \usepackage{arydshln}
- \usepackage{caption}
- \usepackage{graphicx}
- \usepackage{hhline}
- \usepackage{longtable}
- \usepackage{multirow}
- \usepackage[dvipsnames,table]{xcolor}
fontsize: 4pt
classoption: portrait
sansfont: Calibri Light
---
#Name1: `r "Name1"`
#Name2: `r "Name2"`
```{r, echo=FALSE, message=FALSE, warning=FALSE, results='asis'}
library(xtable)
df <- mtcars
n = nrow(df)
hlines=c(-1,0,(n-1),n)
my_align = "c|c|c|ccccc|ccc|c|"
rws <- seq(1, (n-1), by = 2)
col <- rep("\\rowcolor[gray]{.90} ", length(rws))
xtable::print.xtable(xtable(df
, align = my_align)
, add.to.row = list(pos = as.list(rws), command = col)
, booktabs = F
, hline.after = hlines, type = "latex")
```
```{r}
library(pixiedust)
dust(df,
hhline = TRUE,
keep_rownames = TRUE) %>%
medley_bw() %>%
sprinkle_colnames(.rownames = "") %>%
sprinkle(cols = c(".rownames", "mpg", "cyl", "qsec", "gear", "carb"),
border = "right") %>%
sprinkle(rows = nrow(mtcars),
border = "top") %>%
sprinkle(bg_pattern_by = "rows")
```