How to stack two images horizontally in R Markdown

I would like to show two images stacked horizontally in a R Markdown report, but, no matter how much I downsize them, R Markdown keeps stacking them horizontally. Any suggestions? Ideally, the solution should work independently of the output, and without having to write CSS code (CSS! :scream:). Realistically, a solution which at least works with HTML output will still be ok. Thanks!
Sample .Rmd code:

---
title: "test"
output: html_document
---

```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(echo = FALSE,
               out.width = "75%", 
               fig.align = "center")
```

## Show images

```{r image}
include_graphics(c("doggy.jpeg", "kitty.jpeg"))
```

HTML Output:

And here are the images used in this post:

kitty doggy

2 Likes

You could try the Markdown alone, without the R chunk.

## Show images
![](doggy.jpeg) ![](kitty.jpeg)
5 Likes

When you do a code chunk that produces a graphic, the way text or other images wrap around is, indeed, controlled by the CSS. So to make one code block produce parallel images you'd have to hack the CSS (god help you).

However, if we turn the images into grobs in a ggplot graphic then we can effectively make one image out of them. This depends on having the magick package installed:

library(cowplot)
library(ggplot2)

p1 <- ggdraw() + draw_image("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/5/521809ca3e81d798ffa7af902a4e06a9b9f27d39.jpeg", scale = 0.9)
p2 <- ggdraw() + draw_image("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/d/d8e5fa515558cf5edc2d140255bc36c351051b2a.jpeg", scale = 0.9)

plot_grid(p1, p2)

image

You'll have to fiddle with sizing and that sort of thing, but it's a start!

11 Likes

Yes to this. Also, I'm sure there is a way to work work ggplot's Grobs, but they scare the living hell out of me, so...

Finally, I have no knowledge of CSS, but I remember I was once able to stack 2-3 images horizontally without any problems by simply copying some CSS bit from SO, it was not painful at all.

I can't find that report anymore, but I know if I can do it - you can do it :smile:

I managed to hack the CSS in my blogdown site to add a drop shadow on all images. I'm still in therapy as a result.

6 Likes

I forgot the rule to never use the word "simply", I apologize!

I guess I was lucky with image stacking!

You can also just use the chunk parameters fig.show = "hold", out.width = "50%" (assuming you want each to be half the width of the page). For example in this post, I have the code chunk:

```{r dodge-st, fig.show = "hold", out.width = "50%"}
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar(position = position_dodge2(preserve = "single"))

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar(position = position_dodge2(preserve = "total"))
```

which results in…

I believe the same should work for draw_image().

14 Likes

Thanks to all of you folks! I need to leave the office now, and tomorrow will be a scary day, but I'll try to test your suggestions nonetheless :slight_smile:

Hi Mara,

do you mean something like

---
title: "test"
output: html_document
---

```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(echo = FALSE,
               out.width = "75%", 
               fig.align = "center")
```

## Show images

```{r image_grobs, fig.show = "hold", out.width = "50%"}
library(cowplot)
library(ggplot2)

ggdraw() + draw_image("doggy.jpeg")
ggdraw() + draw_image("kitty.jpeg")

```

? The result is

the images are still stacked horizontally. Did I misunderstand your suggestion?

@taras

## Show images 
![](doggy.jpeg) ![](kitty.jpeg)

This works! And it's also pretty simple. Do you know how can I specify the image size? Since it's not in a code chunk, I can't use chunk options such as e.g. out.width and out.height.

@jdlong

this also works! It requires installing magick, which is not exactly immediate under Ubuntu (I decided to install Ubuntu on my home laptop for a variety of reasons) but I managed to do it. Being a code chunk, I can fiddle with sizes easily. BTW, it would work the same if I used patchwork in place of cowplot, right? I like the patchwork API more...

It looks like the global chunk setting fig.align = "center" is throwing a wrench in things.

You can use fig.align = "default" for your chunk with multiple plots to get Mara's suggestion to work.

```{r image_grobs, fig.show='hold', out.width = "50%", fig.align = "default"}
library(cowplot)
library(ggplot2)

ggdraw() + draw_image("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/5/521809ca3e81d798ffa7af902a4e06a9b9f27d39.jpeg")
ggdraw() + draw_image("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/d/d8e5fa515558cf5edc2d140255bc36c351051b2a.jpeg")

``
5 Likes

Using @mara solution and @aosmith fig.align you can lose the cowplot all together and just use knitr::include_graphics:

```{r image_grobs, fig.show = "hold", out.width = "50%", fig.align = "default"}

knitr::include_graphics("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/5/521809ca3e81d798ffa7af902a4e06a9b9f27d39.jpeg")

knitr::include_graphics("https://discourse-cdn-sjc1.com/business4/uploads/default/original/2X/d/d8e5fa515558cf5edc2d140255bc36c351051b2a.jpeg")

```
10 Likes

This might be better broken off into a separate topic, but it seems like a lot of people are intimidated by slide theme customisation using CSS. I wonder if we could jam SASS into the xaringan build process and then have YAML parameters appended to or processed alongside the SASS.

It would mean that you could customise the theme directly from the YAML, and using SASS variables users would only need to make changes to a few variables set up by the theme author...

EDIT: I've moved this topic to its own thread!

2 Likes

Yes! Markdown is very simple to use and to learn. If you don't really need to run R code to generate images, I'd say stick with Markdown!
(And my hope is that @yihui would suggest the same)

As for your resizing question, you can add a tiny bit of CSS (it is not painful at all!). Something like this:

## Show images 
![](doggy.jpeg){width=50%} ![](kitty.jpeg){width=50%}

You can also specify px instead of %. E.g.

## Show images 
![](doggy.jpeg){width=200px} ![](kitty.jpeg){width=300px}
4 Likes

The only advantage, IMO, of using the code block and knitr::include_graphics is you get figure captions and references. So you can more easily link to the image later, if needed. But if you don't need figure captions and dynamic links to the figures, then I'm with @taras: just use markdown.

1 Like

Actually, Yihui Xie suggests using knitr::include_graphics since it's more portable:

https://www.rdocumentation.org/packages/knitr/versions/1.20/topics/include_graphics

Also, it appears that Yihui suggested using knitr::include_graphics + fig.show = "hold" to solve a problem very similar to mine (which I could have never googled, given the title)

But here captions are instrumental to the answer, so it could also be that he suggested it because of what you said ( knitr::include_graphics in code chunk :arrow_right: I can reference the images)

4 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.