简体   繁体   中英

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, ie 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)
```

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM