Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Figure layouts broken in LaTeX/PDF #7017

Closed
andrewheiss opened this issue Sep 26, 2023 · 12 comments
Closed

Figure layouts broken in LaTeX/PDF #7017

andrewheiss opened this issue Sep 26, 2023 · 12 comments
Assignees
Labels
bug Something isn't working crossref figures
Milestone

Comments

@andrewheiss
Copy link

Bug description

Custom figure layouts cause this error when rendering to PDF:

ERROR: 
compilation failed- error
LaTeX Error: Not in outer par mode.

Steps to reproduce

---
title: "Layout test"
format: 
  pdf:
    keep-tex: true
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```

The .tex file has this:

\begin{figure}
\begin{minipage}[t]{0.50\linewidth}
\begin{figure}
\centering{
\includegraphics{testing_files/figure-pdf/fig-charts-1.pdf}
}
\caption{\label{fig-charts-1}Charts}
\end{figure}%
\end{minipage}%
%
\begin{minipage}[t]{0.50\linewidth}
\begin{figure}
\centering{
\includegraphics{testing_files/figure-pdf/fig-charts-2.pdf}
}
\caption{\label{fig-charts-2}Charts}
\end{figure}%
\end{minipage}%
\end{figure}%

Based on a quick naive search, this StackExchange post says that adding a [H] to the inside-the-minipage-figure environments will fix it, and it does. If I edit the .tex file like so and compile it outside of Quarto, it works:

\begin{figure}
\begin{minipage}[t]{0.50\linewidth}
\begin{figure}[H]
\centering{
\includegraphics{testing_files/figure-pdf/fig-charts-1.pdf}
}
\caption{\label{fig-charts-1}Charts}
\end{figure}%
\end{minipage}%
%
\begin{minipage}[t]{0.50\linewidth}
\begin{figure}[H]
\centering{
\includegraphics{testing_files/figure-pdf/fig-charts-2.pdf}
}
\caption{\label{fig-charts-2}Charts}
\end{figure}%
\end{minipage}%
\end{figure}%
image

But I don't know if that's the true solution or how it worked in previous versions. Quarto 1.3 worked fine—some sort of regression happened at some point 🤷‍♂️

Expected behavior

Side-by-side plots should appear

Actual behavior

Nothing :)

Your environment

  • IDE: RStudio 2023.06.2+561
  • OS: macOS Ventura 13.5.2

Quarto check output

Quarto 1.4.382
[✓] Checking versions of quarto binary dependencies...
      Pandoc version 3.1.8: OK
      Dart Sass version 1.55.0: OK
      Deno version 1.33.4: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
      Version: 1.4.382
      Path: /Applications/quarto/bin

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

[✓] Checking LaTeX....................OK
      Using: TinyTex
      Path: /Users/andrew/Library/TinyTeX/bin/universal-darwin
      Version: 2022

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

[✓] Checking Python 3 installation....OK
      Version: 3.11.3
      Path: /opt/homebrew/opt/python@3.11/bin/python3.11
      Jupyter: 5.3.0
      Kernels: python3

[✓] Checking Jupyter engine render....OK

[✓] Checking R installation...........OK
      Version: 4.3.1
      Path: /Library/Frameworks/R.framework/Resources
      LibPaths:
        - /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
      knitr: 1.44
      rmarkdown: 2.25

[✓] Checking Knitr engine render......OK
@andrewheiss andrewheiss added the bug Something isn't working label Sep 26, 2023
@cscheid cscheid self-assigned this Sep 26, 2023
@cscheid cscheid added this to the v1.4 milestone Sep 26, 2023
@cscheid
Copy link
Collaborator

cscheid commented Sep 26, 2023

LaTeX Error: Not in outer par mode.

I'm just going to leave this here 😭

@andrewheiss
Copy link
Author

lol I've had like 10 typst-related tabs open for a week now, hoping to get around to figuring it out. Guess it's time 😂

@andrewheiss
Copy link
Author

ha just found a new issue when using typst, though, using the same reprex:

---
title: "Layout test"
format: typst
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```
FATAL (/Applications/quarto/share/filters/main.lua:17675) An error occurred:
PanelLayout renderer requires a float in typst output
This is a quarto bug. Please consider filing a bug report at https://github.com/quarto-dev/quarto-cli/issues
Error running filter /Applications/quarto/share/filters/main.lua:
/Applications/quarto/share/filters/main.lua:2009: attempt to call a nil value (global 'crash_with_stack_trace')
stack traceback:
	/Applications/quarto/share/filters/main.lua:1590: in function 'fail'
	/Applications/quarto/share/filters/main.lua:1582: in function 'fail_and_ask_for_bug_report'
	/Applications/quarto/share/filters/main.lua:17675: in field 'render'
	/Applications/quarto/share/filters/main.lua:670: in local 'filter_fn'
	/Applications/quarto/share/filters/main.lua:226: in function </Applications/quarto/share/filters/main.lua:216>
	(...tail calls...)
	[C]: in ?
	[C]: in method 'walk'
	/Applications/quarto/share/filters/main.lua:148: in function </Applications/quarto/share/filters/main.lua:138>
	(...tail calls...)
	/Applications/quarto/share/filters/main.lua:725: in local 'callback'
	/Applications/quarto/share/filters/main.lua:738: in upvalue 'run_emulated_filter_chain'
	/Applications/quarto/share/filters/main.lua:773: in function </Applications/quarto/share/filters/main.lua:770>
stack traceback:
	/Applications/quarto/share/filters/main.lua:148: in function </Applications/quarto/share/filters/main.lua:138>
	(...tail calls...)
	/Applications/quarto/share/filters/main.lua:725: in local 'callback'
	/Applications/quarto/share/filters/main.lua:738: in upvalue 'run_emulated_filter_chain'
	/Applications/quarto/share/filters/main.lua:773: in function </Applications/quarto/share/filters/main.lua:770>

@cscheid
Copy link
Collaborator

cscheid commented Sep 26, 2023

That one is a duplicate of #6965 :)

@cscheid
Copy link
Collaborator

cscheid commented Sep 26, 2023

Turns out this is broken in HTML as well:

---
title: "Layout test"
format: html
keep-md: true
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```

See @fig-charts.

Busted output and missing crossrefs:

image

@cscheid
Copy link
Collaborator

cscheid commented Sep 26, 2023

Hmmm. @cderv, this is the keep-md output for that HTML example. It doesn't look right to me (there's no fig-charts reference and the caption is repeated across the subfigures). Could this be a knitr bug or a bug in quarto's rmd.R?

.qmd

---
title: "Layout test"
format: html
keep-md: true
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```

See @fig-charts.

.html.md

---
title: "Layout test"
format: html
keep-md: true
---


::: {.cell layout="[1, 1]"}

```{.r .cell-code}
plot(cars)
plot(pressure)
```

::: {.cell-output-display}
![Charts](7017_files/figure-html/fig-charts-1.png){#fig-charts-1 width=672}
:::

::: {.cell-output-display}
![Charts](7017_files/figure-html/fig-charts-2.png){#fig-charts-2 width=672}
:::
:::


See @fig-charts.

@cderv
Copy link
Collaborator

cderv commented Sep 27, 2023

Could this be a knitr bug or a bug in quarto's rmd.R?

There are two things here

  • there's no fig-charts reference
  • the caption is repeated across the subfigures

I'll start by the second

Repeated caption

This is not a bug in knitr but a feature 😅 . When there is several plots in same chunk, some figure options are recycled. Source here: https://github.com/yihui/knitr/blob/1a6adb7f866171c923bde27a41169738178c5b0b/R/plot.R#L267-L270
There is not really notion of sub figure in R Markdown and knitr (except for PDF maybe with LaTeX hence fig.scap exists).
So regarding matching R Markdown behavior this makes sense.

So it is possible this behavior explain why this is the case in .qmd doc too. If we don't want that, we need a way to prevent the recycling is this happens.

I believe for Jupyter if you only provide one fig-cap you'll get an empty for the other one.

Let's note that if no fig-subcap, fig-cap is used for plots in layout

```{python}
#| layout-ncol: 2
#| fig-cap: 
#|   - "Line Plot 1"
#|   - "Line Plot 2"

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

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

image

```{python}
#| layout-ncol: 2
#| fig-cap: 
#|   - "Line Plot 1"

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

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

image

This are examples from our docs: https://quarto.org/docs/authoring/figures.html#layout

I believe for Python it almost works. See the numbering which is not quite correct

---
title: "Layout test"
format: html
keep-md: true
---

```{python}
#| label: fig-charts
#| layout-ncol: 2
#| fig-cap: 
#|   - "Line Plot 1"
#|   - "Line Plot 2"

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

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


See @fig-charts.

image

Intermediates .md
::: {#cell-fig-charts .cell layout-ncol='2' execution_count=1}
``` {.python .cell-code}
import matplotlib.pyplot as plt
plt.plot([1,23,2,4])
plt.show()

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

::: {.cell-output .cell-output-display}
![Line Plot 1](test2_files/figure-html/fig-charts-output-1.png){#fig-charts width=566 height=404}
:::

::: {.cell-output .cell-output-display}
![Line Plot 2](test2_files/figure-html/fig-charts-output-2.png){#fig-charts width=566 height=404}
:::
:::


See @fig-charts.

#fig-charts is duplicated on all plots and #cell-fig-charts is used on the all div. Which means the resolve happens to one of the subplots...

No reference resolved with several layout in chunk with knitr

I am looking into that as we speak.

It seems we never set an #id on the output div with knitr and figures (line 648 below - we pass NULL and no label at all)

# generate markdown for image
md <- sprintf("![%s](%s)%s", figure_cap(options), x, attr)
# enclose in link if requested
link <- options[["fig.link"]]
if (!is.null(link)) {
md <- sprintf("[%s](%s)", md, link)
}
# result = "asis" specific
if (identical(options[["results"]], "asis")) return(md)
# enclose in output div
output_div(md, NULL, classes)
}

This is quite some change to do it... but it seems there should always be a label right ?
I believe there is always one with Jupyter

I am looking into this... 👀

happy to fix the R side in Quarto but we need to discuss to be on the same page on how it should work

@mcanouil mcanouil added latex LaTeX engines related libraries and technologies and removed latex LaTeX engines related libraries and technologies labels Sep 27, 2023
@cderv cderv added needs-discussion Issues that require a team-wide discussion before proceeding further and removed needs-discussion Issues that require a team-wide discussion before proceeding further labels Sep 28, 2023
@ptram
Copy link

ptram commented Sep 29, 2023

but it seems there should always be a label right ?

A quick user intrusion, here: academic and scientific styles usually require figures to have a caption, made of a Figure [#] premise and a descriptive caption. Something like:

Figure 2: My beautiful plot

Other styles, like the one required for end-user manuals, don't require it. The figure can only include images, but have no captions (being an extensive description the core of the preceding or following text).

In my view, an empty caption (![](my-image.png)) should result in a figure with no caption. In Typst, it could be something like (if I'm using the correct syntax):

#figure(
  image("my-image.png", width: 80%),
  caption: none,
) <my-image>

@cscheid
Copy link
Collaborator

cscheid commented Sep 29, 2023

@ptram that is working on typst now in main:

image
---
title: test
format: typst
---

An elephant:

![](./elephant.jpg)

Other stuff.

@cscheid
Copy link
Collaborator

cscheid commented Sep 29, 2023

In the meantime, the following workaround syntax works:

---
title: "Layout test"
format: 
  pdf:
    keep-tex: true
---

::: {#fig-charts layout="[3, 1]"}

```{r}
#| echo: false
plot(cars)
```

```{r}
#| echo: false
plot(pressure)
```

Charts

:::

Producing this:

image

@cscheid
Copy link
Collaborator

cscheid commented Nov 29, 2023

I think it'll be really hard to support this with the precise syntax you want. In the 1.4 prereleases, this is what we get:

---
title: "Layout test"
format: pdf
keep-tex: true
keep-md: true
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```
image
---
title: "Layout test"
format: pdf
keep-tex: true
keep-md: true
---

```{r}
#| label: fig-charts
#| fig-cap: "Charts"
#| fig-subcap: true
#| layout: "[1, 1]"

plot(cars)
plot(pressure)
```
image

None of these are ideal. The first recycles the captions, and the second has empty subcaptions. I think my proposed workaround is the best way to do this going forward. We might revisit this syntax in the future, but this already didn't work in 1.3, so it's not an urgent regression.

@cscheid
Copy link
Collaborator

cscheid commented May 8, 2024

We've had other reports of users who now expect the empty captions, so I think this bug has officially become a feature. 🎉 🫠

@cscheid cscheid closed this as completed May 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working crossref figures
Projects
None yet
Development

No branches or pull requests

5 participants