26

When using bookdown (single document), figures are numbered automatically as:

Figure 1 Text of figure caption.

In chemistry, the convention is to label main Figures as:

Figure 1. Text of figure caption.

and for the supporting information document:

Figure S1. Text of figure caption.

Also in the figure reference in the text we need:

...as can be seen in Figure 1, ...

so the reference text should not be bold.

Question

How can i make bookdown (or rmarkdown) produce figure and table captions like so: "Figure S1. Some text." and "Table S1. Some text." ?

I need this to be in MS Word format.

Example/ Attempted Solution

So far i tried to modify the _bookdown.yml document as follows:

language:
  label:
    fig: "**Figure S**"
    tab: "**Table S**"

This gives: Figure S1 Some text... and the inline reference when using:

Figure S\@ref(fig:Xray)

is Figure S1 which is ok.

Here is a minimal example:

---
title: Supporting Information
subtitle: "Iron(I) etc"
author: "Some people here"
abstract: "Added the addresses here since there is no abstract in the SI"
output:
  bookdown::word_document2:
    fig_caption: yes
    toc: yes
    toc_depth: 1
---

## Reaction of etc.
Some text  (Figure S\@ref(fig:Xray)). Some text followed by a figure:

```{r Xray, fig.cap="Single-crystal X-ray structure of some text", echo=FALSE}
plot(cars)
```
Some text etc. followed by a table:

```{r DipUVvis, echo=FALSE, tab.cap="Table caption"}
df<-data.frame(Entry=c('AMM 51$3^a$','AMM 52^*a*^'),
               Precat=c('[FeBr~2~(dpbz)~2~] (4.00)','[FeBr~2~(dpbz)~2~] 
(2.00)'))

kable(head(df), format = "markdown")
```

The code above produces Figure S1 in the figure caption but NOT Figure S1. (Note it is all bold and a full stop in the end).

Phil
  • 7,287
  • 3
  • 36
  • 66
Outlander
  • 533
  • 7
  • 12
  • Please provide an example YAML header at least so we can generate a document that is close to your configuration. – Martin Schmelzer Aug 22 '18 at 07:31
  • @MartinSchmelzer Hi guys, i have tried to to modify the question based on your comments any other information necessary let me know. I am trying to learn this so please bear with me, and thank you for your help! – Outlander Aug 22 '18 at 07:35
  • 1
    @AMM I’ve edited the question a bit to make it easier for others to help. I currently haven’t got time to look for a solution unfortunately. Also, I’ve removed the aspects asking about creating the schema. It was making the question overly complex and SO posts should only ask a single question. I’d recommend you ask a separate post on this second question of yours. Hope that helps! – Michael Harper Aug 29 '18 at 08:39
  • 1
    @MikeyHarper This is very helpful, thank you very much! Will make sure to integrate your feedback in future questions! – Outlander Aug 29 '18 at 08:54

6 Answers6

10

While there is no method to style figure caption prefixes via bookdown, it is possible to do this by applying a custom Lua filter (which requires pandoc 2.0 or later).

Lua-Filters

Assuming that you are starting from

Figure 1 Text of figure caption.

the following filter should do what you want (see https://pandoc.org/lua-filters.html#inline for additional formatting options):

function Image (img)
  img.caption[1] = pandoc.Strong(img.caption[1])
  img.caption[3] = pandoc.Strong(pandoc.Str(string.gsub(img.caption[3].text, ":", ".")))
  return img
end

(Assuming that img.caption[2] is the white space between Figure)

As another example, if instead you are starting from

Figure 1 Text of figure caption.

the following filter should do what you want (see https://pandoc.org/lua-filters.html#inline for additional formatting options):

function Image (img)
  img.caption[1] = pandoc.Strong(img.caption[1])
  img.caption[3] = pandoc.Strong(img.caption[3])
  img.caption[4] = pandoc.Strong(".  ")
  return img
end

(Assuming that img.caption[2] is the white space between Figure and the number and img.caption[4] is the white space between the number and the caption)

Applying a Lua-filter

Assuming you place this filter in a file called figure_caption_patch.lua in the directory of your rmarkdown document you can apply it by adding a pandoc argument in the YAML front matter:

output:
  bookdown::word_document2:
    pandoc_args: ["--lua-filter", "figure_caption_patch.lua"]

This should yield the desired caption style.

Figure 1. Text of figure caption.

crsh
  • 1,699
  • 16
  • 33
  • This works great, but how do you remove the colon in `img.caption[3]`. In mine, I have "Figure 1:". So when I apply the pandoc function in my Rmarkdown, it returns "**Figure 1:.**". It works great, but just need to remove the colon. – AndrewGB Jul 23 '21 at 22:00
  • 2
    Looks like there was a change in rmarkdown which adds a colon by default so that your solution does not work anymore. See https://community.rstudio.com/t/how-to-change-the-figure-table-caption-style-in-bookdown/110397. But you could do `img.caption[3] = pandoc.Strong(pandoc.Str(string.gsub(img.caption[3].text, ":", ".")))`to replace the `:`. by a `.`. See https://stackoverflow.com/questions/68505608/how-remove-colon-in-figure-caption-when-using-pandoc-and-bookdown-in-rmarkdown/68508668#68508668. – stefan Jul 24 '21 at 09:34
  • 1
    Thanks @stefan, I updated my answer and incorporated your suggested fix. – crsh Jul 26 '21 at 08:04
  • Does this also work on pdf output? – Our Mar 15 '22 at 11:34
  • For PDF output it is better to do this via LaTeX. See https://tex.stackexchange.com/questions/276795/how-to-change-figure-1-to-bold-fig-1-in-latex – crsh Dec 16 '22 at 15:46
  • 1
    Thanks a lot for your answer, which also helped me a lot! I would like to mention that *RMarkdown* or *Bookdown* by default added a `` tag at the beginning of my figure captions and the filter initially didn't seem to work. Therefore, I had to start counting with 2 as in `img.caption[2] = pandoc.Strong(img.caption[2]), which made the filter also do a great job in my case. – NicolasBourbaki Jun 10 '23 at 09:40
8

To my knowledge, you cannot control figure/table captions to do what you want with rmarkdown/bookdown. You can use the package captioner to achieve it, with a catch: it works fine with rmarkdown outputs, but you'll need to do post-processing with bookdown outputs. Here is the Rmd file that produces your desired caption style:

---
title: Supporting Information
subtitle: "Iron(I) etc"
author: "Some people here"
abstract: "Added the addresses here since there is no abstract in the SI"
output:
  word_document:
    fig_caption: yes
---

```{r, include=F}
library(captioner)
tables <- captioner(prefix = "Table S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)
figures <- captioner(prefix = "Figure S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)

figures("Xray1", "Single-crystal X-ray structure of some text (1)", display=FALSE)
figures("Xray2", "Single-crystal X-ray structure of some text (2)", display=FALSE)
figures("Xray3", "Single-crystal X-ray structure of some text (3)", display=FALSE)
```

## Reaction of etc.
Some text. Some text followed by `r figures("Xray1", display="cite")`, which is the same figure as  `r figures("Xray3", display="cite")` but comes after `r figures("Xray2", display="cite")`.

```{r Xray, fig.cap=figures("Xray1"), echo=FALSE}
plot(cars)
```

```{r Xray2, fig.cap=figures("Xray2"), echo=FALSE}
plot(cars)
```

```{r Xray3, fig.cap=figures("Xray3"), echo=FALSE}
plot(cars)
```

Some text etc. followed by `r tables("tab-DipUVvis", display="cite")`:

```{r DipUVvis, echo=FALSE}
df<-data.frame(Entry=c('AMM 51$3^a$','AMM 52^*a*^'),
               Precat=c('[FeBr~2~(dpbz)~2~] (4.00)','[FeBr~2~(dpbz)~2~] 
(2.00)'))

knitr::kable(head(df), caption=tables("tab-DipUVvis", "Table Caption"))
```

However, if you switch to use bookdown::word_document2 output, the figure caption becomes "Figure 1: Figure S1. ...". I haven't found a way to suppress "Figure 1:" and have to do post-processing in my output to search and replace all "Figure ?:" with "".

LmW.
  • 1,364
  • 9
  • 16
  • Have you tried specifying language: `label: fig: ""` in the bookdown YAML to get rid of the duplicated `Figure 1:`...I guess you'd still get `1:`, though... :-/ @AMM: You also indicated a solution via `captioner` - How did you do it? – mschilli Sep 02 '18 at 21:18
  • @mschilli Sorry for late reply, had a deadline yesterday. My workaround is similar to the above. Note that: 1. Need to install the captioner package from git hub not cran and 2. Captioner cant handle referencing Figs further down the document. So if you want to say: this and that are presented in Figure 1 to Figure 5, then the Figure 5 reference will be numbered as Figure 2. For this i use: to Figure S ``r as.numeric(fig('DipFeOrder4', display = 'num'))+4``. In combination with zotero, flextable and a macro to convert markdown syntax in the table you can get really good word output. – Outlander Sep 03 '18 at 06:58
  • @AMM: Are you still planning to write up your solution as an answer? Otherwise, I'd suggest you accept LmW.'s solution if you think it's good enough (it deserves an upvote either way I assume). – mschilli Sep 03 '18 at 07:38
  • @mschilli I was planning to but i think that LmW has covered it pretty much so +1 for that. However, lets wait it out a bit to see if indeed there is no integrated solution. I find it very surprising for bookdown or bookdownplus not having such a feature somewhere, since lack of it makes them both redundant for scientific paper writing with word output. This is especially true considering that most scientific journals (in chemistry at least) require word documents for submission. – Outlander Sep 03 '18 at 08:06
  • 1
    AFAIK, @yihui does not put too much time into supporting Word output as he prefers HTML for himself and it's hard to support each and every feature in Word. That said, I'm sure a pull-request on github would be welcome. ;-) – mschilli Sep 03 '18 at 08:41
  • 2
    @AMM, I think the "problem" you described with `captioner` is because it assigns the figure/table number the first time a unique value is passed to the "name" argument, no matter what the value of the "display" argument is. A better solution to is to define your figures in your desired order with "display=FALSE" and then cite or display them wherever you want. I modified my sample code to include such an example. – LmW. Sep 03 '18 at 21:34
  • @mschilli, since you'll still need to remove "1:" anyway even with the `label: fig: ""`, I find it easier to search & replace in MS Word for wildcard "Figure [0-9]@:" with "", as there may be other occurrences of "1:" in the text. – LmW. Sep 03 '18 at 21:46
  • @mschilli Not putting too much time in supporting word? I thought that was one of the "selling" points of Markdown. HTML is completely useless for people in physical sciences (chemistry at least) in terms of publication. It is either word or, in some occasions, Latex. Anyhow, i think we can now assume the the only way is by using captioner and, to be honest, it has worked great for me so far, so accepted the answer. Thanks to everyone for contributions and help with this! – Outlander Sep 07 '18 at 18:48
  • @AMM, I'm similarly not satisfied with the support of Word in Rmarkdown/pandoc: the output is a mess when you need to include complex tables (such as a table of regression results). But there is no viable alternative to Word for some disciplines or when you need to collaborate with people not tech savvy. – LmW. Sep 07 '18 at 21:59
  • @LmW. Yes, tables was the other nightmare. The best way I found so far was using flextable with markdown format in order to use subscript etc in the table cells. Then use a macro in word to translate the markdown format to the proper output. Once past these difficulties however it works great, especially when having a ton of graphs to include of similar data type. – Outlander Sep 08 '18 at 16:01
7

Following this guide to set Word (.docx) style, you could make fig. and tab. captions boldface, though the whole caption line can be bold... I mean we have a way to create a caption in .docx via RMarkdown like this automatically:

Figure S1: Single-crystal X-ray structure of some text (1)

However, still it seems difficult to make one like this:

Figure S1: Single-crystal X-ray structure of some text (1)

I imagine that you do want to boldface only "Figure/Table S1" section, not the whole caption line. Nevertheless, if you are interested in formatting .docx file with Rmarkdown, you can check the link I added above and see the following description.

1. Knit the .Rmd file @LmW. provided us to get the first .docx output.

If you have some problem with captioner package, you can also use the following one.

---
title: Supporting Information
subtitle: "Iron(I) etc"
author: "Some people here"
abstract: "Added the addresses here since there is no abstract in the SI"
output:
  word_document:
     fig_caption: yes
---

```{r, include=F}
library(captioner)
#`captioner` package (Ver. 2.2.3) in my envionment returns the following error messages:
#Error in captioner(prefix = "Table S", suffix = ". ", style = "b", style_prefix = TRUE,  : 
#  unused arguments (suffix = ". ", style = "b", style_prefix = TRUE)

#Error in captioner(prefix = "Figure S", suffix = ". ", style = "b", style_prefix =     TRUE,  : 
#  unused arguments (suffix = ". ", style = "b", style_prefix = TRUE)

#tables <- captioner(prefix = "Table S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)
#figures <- captioner(prefix = "Figure S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)

tables <- captioner(prefix = "Table S",  auto_space = FALSE)
figures <- captioner(prefix = "Figure S", auto_space = FALSE)

figures("Xray1", "Single-crystal X-ray structure of some text (1)", display=FALSE)
figures("Xray2", "Single-crystal X-ray structure of some text (2)", display=FALSE)
figures("Xray3", "Single-crystal X-ray structure of some text (3)", display=FALSE)
```

## Reaction of etc.
Some text. Some text followed by `r figures("Xray1", display="cite")`, which is the same figure as  `r figures("Xray3", display="cite")` but comes after `r figures("Xray2", display="cite")`.

```{r Xray, fig.cap=figures("Xray1"), echo=FALSE}
plot(cars)
```

```{r Xray2, fig.cap=figures("Xray2"), echo=FALSE}
plot(cars)
```

```{r Xray3, fig.cap=figures("Xray3"), echo=FALSE}
plot(cars)
```

Some text etc. followed by `r tables("tab-DipUVvis", display="cite")`:

```{r DipUVvis, echo=FALSE}
df<-data.frame(Entry=c('AMM 51$3^a$','AMM 52^*a*^'),
               Precat=c('[FeBr~2~(dpbz)~2~] (4.00)','[FeBr~2~(dpbz)~2~] 
               (2.00)'))

knitr::kable(head(df), caption=tables("tab-DipUVvis", "Table Caption"))
```

2. Set Image Caption and Table Caption as boldface.

In the first .docx file,

  1. Select an image caption or a table caption;
  2. Make it bold (Ctrl + B or Command + B);
  3. Click the lower right corner of Styles setting in Home tab. Or press Alt + Ctrl + Shift + S;
  4. Find Image Caption or Table Caption;
  5. Click its drop-down menu and click Update Title to match selection.

If you have done the steps above in both Image and Table Caption, be sure to save the .docx file as word-styles-reference-01.docx in your working directory.

Selecting an image caption to make it bold

3. Knit the .Rmd file adding the reference_docx line to get your final .docx output.

Add reference_docx: word-styles-reference-01.docx under word_document: line. See Line 7 in the following example.

---
title: Supporting Information
subtitle: "Iron(I) etc"
author: "Some people here"
abstract: "Added the addresses here since there is no abstract in the SI"
output:
  word_document:
    reference_docx: word-styles-reference-01.docx
    fig_caption: yes
---

```{r, include=F}
library(captioner)
#`captioner` package (Ver. 2.2.3) in my envionment returns the following error messages:
#Error in captioner(prefix = "Table S", suffix = ". ", style = "b", style_prefix = TRUE,  : 
#  unused arguments (suffix = ". ", style = "b", style_prefix = TRUE)

#Error in captioner(prefix = "Figure S", suffix = ". ", style = "b", style_prefix =     TRUE,  : 
#  unused arguments (suffix = ". ", style = "b", style_prefix = TRUE)

#tables <- captioner(prefix = "Table S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)
#figures <- captioner(prefix = "Figure S", suffix = ". ", style="b", style_prefix=TRUE, auto_space = FALSE)

tables <- captioner(prefix = "Table S",  auto_space = FALSE)
figures <- captioner(prefix = "Figure S", auto_space = FALSE)

figures("Xray1", "Single-crystal X-ray structure of some text (1)", display=FALSE)
figures("Xray2", "Single-crystal X-ray structure of some text (2)", display=FALSE)
figures("Xray3", "Single-crystal X-ray structure of some text (3)", display=FALSE)
```

## Reaction of etc.
Some text. Some text followed by `r figures("Xray1", display="cite")`, which is the same figure as  `r figures("Xray3", display="cite")` but comes after `r figures("Xray2", display="cite")`.

```{r Xray, fig.cap=figures("Xray1"), echo=FALSE}
plot(cars)
```

```{r Xray2, fig.cap=figures("Xray2"), echo=FALSE}
plot(cars)
```

```{r Xray3, fig.cap=figures("Xray3"), echo=FALSE}
plot(cars)
```

Some text etc. followed by `r tables("tab-DipUVvis", display="cite")`:

```{r DipUVvis, echo=FALSE}
df<-data.frame(Entry=c('AMM 51$3^a$','AMM 52^*a*^'),
               Precat=c('[FeBr~2~(dpbz)~2~] (4.00)','[FeBr~2~(dpbz)~2~] 
               (2.00)'))

knitr::kable(head(df), caption=tables("tab-DipUVvis", "Table Caption"))
```
Carlos Luis Rivera
  • 3,108
  • 18
  • 45
  • Does this also work with a free office alternative? Or would I have to buy Windows/MacOS + MS Word just to adjust the template? – mschilli Sep 06 '18 at 09:03
  • 1
    @mschilli Although I haven't used a free office for this purpose, I think you can do Step 2 in my post with other "Word" like softwares. For example, if you use Writer of LibreOffice, you will find [Styles setting](https://help.libreoffice.org/Writer/Styles_in_Writer) and could [update](https://help.libreoffice.org/Writer/Updating_Styles_From_Selections) the style you want to modify. – Carlos Luis Rivera Sep 06 '18 at 10:24
  • @mschilli If you want to get MS Office, it is recommendable checking whether your affiliation has a formal (organization-wide) license with Microsoft to download Office free, like [University of Oxford offers](https://it.manor-road.ox.ac.uk/software/office-365.html). – Carlos Luis Rivera Sep 06 '18 at 10:28
  • Thx for the directions but I'm just not interested in setting up an operating system and an office suite just to change the formatting of a report. ;-) – mschilli Sep 06 '18 at 10:42
  • Thank you for your contribution, what you describe is one of the first things i tried and as you found out it result in the whole caption being bold which is not the desired outcome. Journals have strict formatting guidelines so details like that matter a lot. So i think so far using the captioner package is the best way forwards. – Outlander Sep 06 '18 at 12:39
2

The easiest solution ever, originally posted as an answer here from @canovasjm:

To change the Figure X description to Figure SX throught out the document, and export it as pdf file, simply use LaTex commands under header-includes: in the YAML section:

---
title: "Untitled"
output: pdf_document
header-includes:
  - \renewcommand{\figurename}{Figure S}
  - \makeatletter
  - \def\fnum@figure{\figurename\thefigure}
  - \makeatother
---

```{r, fig.cap="This is my figure description", fig.height=3}
plot(pressure)
```

```{r, fig.cap="Another figure description", fig.height=3}
plot(iris$Sepal.Length, iris$Petal.Width)
```

enter image description here

maycca
  • 3,848
  • 5
  • 36
  • 67
2

It's been a while since the question was posted, but to change the numbering of figures from 'Figure 1' to 'Figure S1', you can use the following:

- \usepackage{caption}                            
- \DeclareCaptionLabelFormat{Sformat}{#1 S#2}     
- \captionsetup[table]{labelformat=Sformat}  
- \captionsetup[figure]{labelformat=Sformat} 
Emilio M. Bruna
  • 297
  • 1
  • 3
  • 14
0

Following suggestions posted elsewhere, you could use expressions in the file _bookdown.yml (in the same directory as MyFile.Rmd):

language:
  label:
    fig: !expr function(x) sprintf("**Figure S%s.** ", x)
    tab: !expr function(x) sprintf("**Table S%s.** ", x)

Full documentation of this feature is available here.

Martin Smith
  • 3,687
  • 1
  • 24
  • 51