quarto-dev / quarto-cli

Open-source scientific and technical publishing system built on Pandoc.
https://quarto.org
Other
3.98k stars 328 forks source link

Incorrect Subcaption Numbering in Figures for PDF Output #11293

Open produnis opened 3 weeks ago

produnis commented 3 weeks ago

Bug description

When plotting multiple figures in a single chunk with parameters such as layout-ncol: 3 and fig-subcap, the subcaption numbering is incorrect in the PDF output. All subcaptions start with "a)" instead of incrementing as expected ("a)", "b)", "c)", etc.).

Steps to reproduce

Create and render this document to PDF.

---
title: "Test subcaption"
author: "me"
format: 
  pdf:
    keep-tex: true
  html: default
---

::: {.callout-note appearance="default"}
test
:::

::: {.callout-important appearance="simple"}
here come some plots
:::

```{r}
#| layout-ncol: 3
#| fig-subcap: 
#|   - This
#|   - is a
#|   - test
x <- c(1:100)
y <- x+x+2
plot(x, y)
hist(y, breaks=5)
barplot(table(x,y))

Or use minimal example here https://github.com/produnis/minimal_examples/tree/subcaption

Expected behavior

The 3 figures are numbered "a)", "b)", "c)"

Actual behavior

The 3 figures are numbered as "a)" "a)" "a)".

Your environment

archlinux, quarto 1.6.32 and 1.5.57

Quarto check output

$ quarto check
Quarto 1.6.32
[✓] Checking environment information...
      Quarto cache location: /home/produnis/.cache/quarto
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.4.0: OK
      Dart Sass version 1.70.0: OK
      Deno version 1.46.3: OK
      Typst version 0.11.0: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.6.32
      Path: /opt/quarto/bin

[✓] Checking tools....................OK
      Chromium: 869685
      TinyTeX: (not installed)

[✓] Checking LaTeX....................OK
      Using: Installation From Path
      Path: /sbin
      Version: undefined

[✓] Checking basic markdown render....OK

[✓] Checking Python 3 installation....OK
      Version: 3.12.7
      Path: /sbin/python3
      Jupyter: (None)

      Jupyter is not available in this Python installation.
      Install with python3 -m pip install jupyter

[✓] Checking R installation...........OK
      Version: 4.4.2
      Path: /usr/lib64/R
      LibPaths:
        - /home/produnis/R/x86_64-pc-linux-gnu-library/4.4
        - /usr/lib/R/library
      knitr: 1.48
      rmarkdown: 2.27

[✓] Checking Knitr engine render......OK
cderv commented 3 weeks ago

This works for cross referencable figure when fig-cap is provided

---
title: "Test subcaption"
author: "me"
format: 
  pdf:
    keep-tex: true
  html: default
keep-md: true
---

```{r}
#| label: fig-test
#| layout-ncol: 3
#| fig-cap: main caption
#| fig-subcap: 
#|   - This
#|   - is a
#|   - test
x <- c(1:100)
y <- x+x+2
plot(x, y)
hist(y, breaks=5)
barplot(table(x,y))

![Image](https://github.com/user-attachments/assets/34be7268-c4ee-4aa7-9fcb-4c71821066af)

I believe without `fig-cap`, and only `fig-subcap`, this will be considered as three figures, and `fig-subcap` will be passed as `fig-cap`, just using letters instead of numbers (because `\subcaption{}` is used instead if `\caption{}`). 

I think this falls under both of this next work
- https://github.com/quarto-dev/quarto-cli/issues/7670
- https://github.com/quarto-dev/quarto-cli/issues/7062

We need to document the canonical markdown produced for this case, and check **knitr** is doing the right thing. 

Out of curiosity I looked in past version for this content
````markdown
```{r}
#| layout-ncol: 3
#| fig-subcap: 
#|   - This
#|   - is a
#|   - test
x <- c(1:100)
y <- x+x+2
plot(x, y)
hist(y, breaks=5)
barplot(table(x,y))

* Quarto 1.4.555
    ![Image](https://github.com/user-attachments/assets/9994b357-4536-4138-abe3-451dceb8b83c)
* Quarto v1.3.450
    ![Image](https://github.com/user-attachments/assets/7d11baec-73ce-4bf0-a9fe-a2bb57143de7)
* Quarto v1.2.475
    ![Image](https://github.com/user-attachments/assets/8e68560f-f61a-44f5-83d7-8da3b45bc6b5)

So we have various behaviors over time. 

Though our doc for subcaptions (https://quarto.org/docs/authoring/figures.html#subcaptions) uses `optionnaly` for the `fig-` label 
> You can create subcaptions for computational output by combining the fig-cap and fig-subcap options. When applying captions to computational output you can **optionally** include a label with a fig- prefix—if you do this then the figure will be numbered and [cross-referenceable](https://quarto.org/docs/authoring/cross-references.html).

But `label: fig-` seems to be needed for this to work
Doing 
````markdown
```{r}
#| layout-ncol: 3
#| fig-cap: Main Caption
#| fig-subcap: 
#|   - This
#|   - is a
#|   - test
x <- c(1:100)
y <- x+x+2
plot(x, y)
hist(y, breaks=5)
barplot(table(x,y))

yields 
![Image](https://github.com/user-attachments/assets/72ec3cb5-af77-4ae5-a386-350b1c895ebb)

which is not what is document 🤔 
cderv commented 3 weeks ago

I think this falls under both of this next work

Definitely related to Jupyter vs Knitr logic because too.

I check Jupyter behavior for this

---
title: "Test subcaption"
author: "me"
format: 
  pdf:
    keep-tex: true
  html: default
keep-md: true
---

```{python}
#| fig-subcap: 
#|   - "First"
#|   - "Second"
#| layout-ncol: 2

import matplotlib.pyplot as plt
plt.plot([1,23,2,4])
plt.show()

plt.plot([8,65,23,90])
plt.show()

`fig-subcap` is just ignored when no `fig-cap`. This is because `fig-subcap` is known by **knitr** historically before Quarto so it is supported as a way to pass fig cap to figure. Two behavior should be align

For `fig-cap` and `fig-subcap`, numbering problem is similar 

````markdown
---
title: "Test subcaption"
author: "me"
format: 
  pdf:
    keep-tex: true
  html: default
keep-md: true
---

```{python}
#| fig-cap: Main
#| fig-subcap: 
#|   - "First"
#|   - "Second"
#| layout-ncol: 2

import matplotlib.pyplot as plt
plt.plot([1,23,2,4])
plt.show()

plt.plot([8,65,23,90])
plt.show()


![Image](https://github.com/user-attachments/assets/1b43c2be-2753-479f-868c-51dc0c18c490)

Adding `label: fig-test` fixes it 

![Image](https://github.com/user-attachments/assets/adc9e7f3-902e-4ba1-8e55-f1dc5ebed131)

So for both Jupyter and Knitr, it does not behave like documented and `fig-subcap` requires label to work. 

We need to decide which is expected behavior here, and if this is possible or not to correctly create the LaTeX code that allows fig-scap to work, when not a cross referenced figures. 🤔