HTML widgets alignment in rmarkdwon - r

I use the knitr::opts_chunk$set(fig.align = "center") at the beginning of the rmarkdown document to set the alignment of figures. When I output HTML files, the static figures are aligned to the center, but the HTML widgets, such as outputs from leaflet() and ggplotly() have the default alignment (to the left). Is there an option to force the HTML widgets to the center?
EDIT: example given below.
---
title: "test"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, fig.align = "center")
library(ggplot2)
library(plotly)
```
```{r static plot}
# This is aligned to center
g <- ggplot(mtcars, aes(mpg, cyl)) +
geom_point()
g
```
```{r html widget}
# html output isn't aligned
p <- ggplotly(g)
p
```

You could resize the plot to the default width of the document and then use some CSS:
---
title: "Untitled"
output: html_document
---
<style>
/* resize the widget container */
.plotly {
width: 100% !important;
}
/* center the widget */
div.svg-container {
margin: auto !important;
}
</style>
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, fig.align = "center")
library(ggplot2)
library(plotly)
```
```{r static plot}
# This is aligned to center
g <- ggplot(mtcars, aes(mpg, cyl)) +
geom_point()
g
```
```{r html widget}
p <- ggplotly(g, browser.fill = F) %>%
layout(autosize = F, width = '100%', height = '100%')
p
```

Related

Scrollbar for output chunk in Quarto

I would like to plot multiple plots from a chunk and add a scrollbar to the output of that chunk. I see here that this could be done for Code Overflow, but I am not sure how to scroll the output instead of adding all the plots below each other like in the example below:
---
title: "Scrollbar in output chunk"
format:
html:
code-overflow: wrap
---
Here is some example code:
```{r}
#| code-overflow: wrap
library(ggplot2)
for(i in unique(iris$Species)) {
print(
ggplot(iris[iris$Species == i, ], aes(x = Sepal.Length, Sepal.Width)) +
geom_point()
)
}
```
Output:
As we can see from the output, all the plots are shown below each other, but I would like to have a scrollbar chunk so it doesn't show all plot at once. So I was wondering if anyone knows how to add a scroll option to the output of a chunk in Quarto?
You can create a css file with a defined max-height and overflow-y and add it to your chunk with class. Note that this will also include the code in the scrolling section. Also note that if you want a text output to be scrollable, you should use class-output instead of class in your chunk options.
---
title: "scrollable-output"
format: html
---
```{css, echo = FALSE}
.output {
max-height: 500px;
overflow-y: scroll;
}
```
Here is some example code
```{r}
#| class: output
library(ggplot2)
for(i in unique(iris$Species)) {
print(
ggplot(iris[iris$Species == i, ], aes(x = Sepal.Length, Sepal.Width)) +
geom_point()
)
}
```
You can add a div before the chunk, e.g.
---
title: "Scrollbar in output chunk"
format: html
css: styles.css
---
Here is some example code:
:::{.scrolling}
```{r}
library(ggplot2)
for(i in unique(iris$Species)) {
print(
ggplot(iris[iris$Species == i, ], aes(x = Sepal.Length, Sepal.Width)) +
geom_point()
)
}
```
:::
styles.css
.scrolling {
max-height: 500px;
overflow-y: auto;
}
If you do not want the scrolling for the code, than you could do this:
---
title: "Scrollbar in output chunk"
format: html
css: styles.css
---
Here is some example code:
```{r}
#| eval: false
library(ggplot2)
for(i in unique(iris$Species)) {
print(
ggplot(iris[iris$Species == i, ], aes(x = Sepal.Length, Sepal.Width)) +
geom_point()
)
}
```
:::{.scrolling}
```{r}
#| echo: false
library(ggplot2)
for(i in unique(iris$Species)) {
print(
ggplot(iris[iris$Species == i, ], aes(x = Sepal.Length, Sepal.Width)) +
geom_point()
)
}
```
:::

R markdown: how to insert space between images

I want to add two images side by side in R markdown, but with some space between them.
How can I adjust the space between the images? Thank you!
![](/Users/filename/black.png){width=50%}
![](/Users/filename/gray.png){width=50%}
One option could be using ggdraw() + draw_image from {cowplot}
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r side_by_side, fig.align='center'}
library(cowplot)
ggdraw() +
draw_image("test_logo.png", width = 0.4) +
draw_image("test_animal.jpg", width = 0.4, x = 0.5)
```
Which looks like
Another option could be making white border for the images using image_border from the {magick} package so that even if there is no actual space between them, white border will look like a space.
```{r another_option, warning=FALSE, message=FALSE}
library(magick)
img1 <- image_read("test_logo.png")
bordered_img1 <- image_border(img1, "white", "20x20")
img2 <- image_read("test_animal.jpg")
bordered_img2 <- image_border(img2, "white", "20x20")
image_write(bordered_img1, "img1.png")
image_write(bordered_img2, "img2.jpg")
```
```{r side_img, out.width="50%"}
knitr::include_graphics(c("img1.png", "img2.jpg"))
```
Which looks like,

knitr cache and ggplot2::last_plot()

Is there a way of make it so that knitr caches stuff so that last_plot() works properly? For example this document:
---
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, cache = TRUE)
library(ggplot2)
```
```{r cars}
ggplot(mtcars, aes(hp, mpg)) +
geom_point()
```
The first value is `r last_plot()$data$mpg[1]`
The first time is generated, it will have one figure and the text "The first value is 21". But the second time, the last inline code will fail.

RMarkdown adjust height to keep bar spacing equal with plots in a loop in a single chunk

In the following RMarkdown, I would like to have each barplot print so that the text size and box width are the same in each plot, and the height adjusts accordingly.
What is happening is that in the plots with few bars the bars are extremely wide, and in the plots with many bars the bars are thin and the labels squished.
---
title: "chunk plot height"
number_sections: yes
output: html_notebook
---
# Load Libraries
\```{r}
library(tidyverse)
library(magrittr)
library(rmarkdown)
\```
# Set Knitr Options
\```{r}
knitr::opts_chunk$set(
echo=TRUE,
dpi=300,
fig.width=12
)
\```
# Plot
\```{r}
for (n in seq(10,50,10))
{
knitr::opts_chunk$set(out.height=n)
data = data.frame(
X=sapply(c(letters, LETTERS)[1:n], function(x) rep(x,3) %>% paste0(collapse=''), USE.NAMES = F),
Y=rnorm(n)
)
plt =
data %>%
ggplot(aes(x=X, y=Y)) +
geom_col(position=position_dodge(width=1, preserve='single')) +
coord_flip()
print(plt)
}
\```

Programmatically generate slides in R with xaringan and plotly

I recently started using xaringan and it's really neat. Thanks Yihui for the great package. One question I was wondering, is it possible to programmatically generate slides, each containing a plotly plot, in a for loop? I know I can generate slides of ggplots like this, where ggplot_list is a list of ggplots:
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
print(p)
}
```
This works perfectly.
I can also include individual plotly plots by calling ggplotly(ggplot_list[[1]]), which also works perfectly.
But I can't seem to get the combination of the two to work, naively doing the following generates empty slides for me.
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
ggplotly(p)
}
```
Update: here I include a minimal example of things I've tried so far.
---
title: "xaringan + plotly + loop?"
subtitle: "Does it work?"
author: "Fenfen Kan"
date: "2017/13/32"
output:
xaringan::moon_reader:
lib_dir: libs
nature:
highlightStyle: github
highlightLines: true
countIncrementalSlides: false
---
```{r setup, include=FALSE}
options(htmltools.dir.version = FALSE)
```
# Several boring ggplots
```{r, message=FALSE, warning=FALSE}
library(ggplot2)
library(plotly)
p1 <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point(aes(color=Species))
p2 <- ggplot(iris, aes(Petal.Length, Petal.Width)) +
geom_point(aes(color=Species))
p3 <- ggplot(iris, aes(Sepal.Length, Petal.Length)) +
geom_point(aes(color=Species))
ggplot_list <- list(p1, p2, p3)
```
---
# Invididual plotly works
```{r}
ggplotly(p1)
```
---
# ggplot slides in loop also works
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
print(p)
}
```
---
# plotly in loop doesn't work
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
ggplotly(p)
}
```
# print(ggplotly(p)) in loop doesn't work either
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
print(ggplotly(p))
}
```
I figured out a solution when trying to do a similar thing in knitr recently. I added it to the above example. See the last section - It generates 3 plotly slides in a loop.
---
title: "xaringan + plotly + loop?"
subtitle: "Does it work?"
author: "Fenfen Kan"
date: "2017/13/32"
output:
xaringan::moon_reader:
lib_dir: libs
nature:
highlightStyle: github
highlightLines: true
countIncrementalSlides: false
---
```{r setup, include=FALSE}
options(htmltools.dir.version = FALSE)
```
# Several boring ggplots
```{r, message=FALSE, warning=FALSE}
library(ggplot2)
library(plotly)
library(knitr)
p1 <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point(aes(color=Species))
p2 <- ggplot(iris, aes(Petal.Length, Petal.Width)) +
geom_point(aes(color=Species))
p3 <- ggplot(iris, aes(Sepal.Length, Petal.Length)) +
geom_point(aes(color=Species))
ggplot_list <- list("p1"=p1, "p2"=p2, "p3"=p3)
```
---
# Invididual plotly works
```{r}
ggplotly(p1)
```
---
# ggplot slides in loop also works
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
print(p)
}
```
---
# plotly in loop doesn't work
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
ggplotly(p)
}
```
# print(ggplotly(p)) in loop doesn't work either
```{r, message=FALSE, warning=FALSE, results='asis'}
for (p in ggplot_list) {
cat("\n\n---\n")
print(ggplotly(p))
}
```
# generate chunks, then explicitly calling `knit` works!
```{r create-markdown-chunks-dynamically, include=FALSE}
out = NULL
for (p_name in names(ggplot_list)) {
knit_expanded <- paste0("\n\n---\n## Plot: ", p_name, "\n\n```{r results='asis', echo=FALSE, warning=FALSE, message=FALSE}\n\nggplotly(ggplot_list[['", p_name, "']])\n\n```")
out = c(out, knit_expanded)
}
```
<!--- knit those table chunk statements -->
`r paste(knit(text = out), collapse = '\n')`

Resources