quarto-dev / quarto-cli

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

Latex equation error when rendering pdf #6282

Closed aelmokadem closed 12 months ago

aelmokadem commented 1 year ago

Bug description

Hi,

When I try to render a pdf I get an error that seems to be related to latex equation rendering using Julia code:

using Catalyst, ModelingToolkit
rn = @reaction_network begin
    λ, 0 --> T
    d, T --> 0
    k*V, T --> 0
    k*V*T, 0 --> I
    δ, I --> 0
    p*I, 0 --> V
    c, V --> 0 
end

latexify(rn)

The error message I get upon quarto render is:

compilation failed- error
Undefined control sequence.
<argument>  \varnothing &\xrightleftharpoons 
                                             [d]{\lambda } \mathrm {T} \\ \m...
l.3145  \end{align*}

Rendering the html works fine and I get the expected output:

Screenshot 2023-07-19 at 10 46 36 PM

Another related yet different error is when I try to convert that reaction network system to ODEs using:

convert(ODESystem, rn)

The error I get in this case is:

compilation failed- error
Package amsmath Error: Erroneous nesting of equation structures;
(amsmath)                trying to recover with `aligned'.

See the amsmath package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.3150 \end{align}

Once again the html rendering works fine and gives me what I expect:

Screenshot 2023-07-19 at 11 42 43 PM

Appreciate the help figuring this issue!

Best, Ahmed.

Steps to reproduce

---
jupyter: julia-1.9
format: pdf
---

```{julia}
using ModelingToolkit, Catalyst, Latexify
rn = @reaction_network begin
    λ, 0 --> T
    d, T --> 0
    k*V, T --> 0
    k*V*T, 0 --> I
    δ, I --> 0
    p*I, 0 --> V
    c, V --> 0 
end

First error reproduced by running this chunk. To render this one to see what happens when you run the following chunk, just set output: false to this chunk

latexify(rn)

Second error reproduced by running this chunk

convert(ODESystem, rn)


### Expected behavior

_No response_

### Actual behavior

_No response_

### Your environment

- OS: MacOS 13.4.1
- IDE: Visual Studio Code 1.78.2

### Quarto check output

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

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

[✓] Checking Python 3 installation....OK
      Version: 3.9.6
      Path: /usr/local/bin/python3
      Jupyter: 5.3.0
      Kernels: julia-1.6, julia-1.8, julia-1.9, julia-1.5, 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-x86_64/Resources/library
      knitr: 1.43
      rmarkdown: 2.23

[✓] Checking Knitr engine render......OK
mcanouil commented 1 year ago

Thanks for the report!

Could you share a small self-contained "working" (reproducible) example to work with, i.e., a complete Quarto document or a Git repository? Thanks.

You can share a Quarto document using the following syntax, i.e., using more backticks than you have in your document (usually four ````).

````qmd
---
title: "Reproducible Quarto Document"
format: html
---

This is a reproducible Quarto document using `format: html`.
It is written in Markdown and contains embedded R code.
When you run the code, it will produce a plot.

```{r}
plot(cars)

The end.

baptiste commented 1 year ago

It's likely that LaTeX needs to load a package not included by default in Quarto (I'm guessing mathtools). You could narrow it down by using keep-tex: true in your document and checking what the LaTeX document needs to compile without errors. Html rendering using Mathjax probably has these macros built-in.

mcanouil commented 1 year ago

It's likely that LaTeX needs to load a package not included by default in Quarto (I'm guessing mathtools).

Quarto does not include LaTeX packages. This is completely up to user LaTeX distribution.

This being said, Quarto highly recommends to use TinyTex which can be installed through Quarto by default only for Quarto to use, but can also be installed system-wide (see https://quarto.org/docs/output-formats/pdf-engine.html).

Now the suggestion of keep-tex: true can allow you to figure out what's wrong in your LaTeX (which we can't do without the fully and complete reproducible example requested before).

cderv commented 1 year ago

I believe you are using Latexify.jl underthehood (even if not loaded in your example).

See documentation at : https://korsbo.github.io/Latexify.jl/stable/tutorials/DiffEqBiological/#Chemical-arrow-notation

The default output is meant to be rendered directly on the screen. This rendering is typically done by MathJax. To get the chemical arrow notation to render automatically, I have included a MathJax command (\require{mhchem}) in the output string. If you want to use the output in a real LaTeX document, you can pass the keyword argument mathjax=false and this extra command will be omitted. In such case you should also add \usepackage{mhchem} to the preamble of your latex document.

So first thing is to add mchem as a requirement

format: 
  pdf:
    include-in-header: 
      text: \usepackage{mhchem}

and then \require will be an issue so usually setting latexify(rn; mathjax=false) should work with this.

However, it seems this does not work with Julia Catalyst itself as they will also hardcode require{mchem} https://github.com/SciML/Catalyst.jl/blob/43fb26f10d241b678eaef5aa6d7cbfd41ed6daea/src/latexify_recipes.jl#L134-L136

    # test if in IJulia since their mathjax is outdated...
    # VSCODE uses Katex and doesn't have this issue.
    if mathjax || (isdefined(Main, :IJulia) && Main.IJulia.inited &&
        !any(s -> occursin("VSCODE", s), collect(keys(ENV))))
        str *= "\\require{mhchem} \n"
    end

Not sure how one can deactivate Mathjax for Catalyst tool. Do they really allow outputing LaTeX for real LaTeX rendering ? It seems they do output for Mathjax. I would open an issue with them. It is possible their condition above ((isdefined(Main, :IJulia) && Main.IJulia.inited) causes issue as it will insert the require call.

So I believe this is an issue for Jupyter & Catalyst and how LaTeX is written: Can Catalyst create Non-Mathjax LaTeX code ? IF so how ?

I think you could try

I am not Julia expert but it seems something in the output for LaTeX is not ok. And Quarto expect the output of Jupyter Notebook execution to be valid LaTeX. Maybe we can do something but the Julia package must be correctly output for LaTeX output (not just HTML mathjax (as that would be the main thing to do for Jupyter notebook printing.

We can work with Catalyst or Latexify author to help make things work in Quarto. Other existing issue with Latexify and quarto already:

baptiste commented 12 months ago

I imagine \require{} could be redefined as a dummy macro doing nothing, as a temporary workaround.

I tried the code and the LaTeX I'm getting is garbled:

\begin{align} \varnothing &\xrightleftharpoons[d]{\lambda} \mathrm{T} \
  \mathrm{T} &\xrightarrow{V k} \varnothing \ \varnothing
  &\xrightleftharpoons[\delta]{k T V} \mathrm{I} \ \varnothing
  &\xrightleftharpoons[c]{I p} \mathrm{V} \end{align}arnothing
\&\xrightleftharpoons[c]{I p} \mathrm{V} \textbackslash end\{align\}

(some backslashes missing, others replaced by textbackslash, braces escaped, etc. Fixing it manually in the tex file works,

\begin{align} \varnothing &\xrightleftharpoons[d]{\lambda} \mathrm{T} \\ 
\mathrm{T} &\xrightarrow{V k} \varnothing \\
 \varnothing &\xrightleftharpoons[\delta]{k T V} \mathrm{I} \\
  \varnothing &\xrightleftharpoons[c]{I p} \mathrm{V} 
\end{align}

Screenshot 2023-07-21 at 09 25 28

I'm using this input file (with knitr because I can never figure out how to tell jupyter to use the right environment)

---
title: latexify
format: 
  pdf:
    latex-tinytex: false
    keep-tex: true
    include-in-header: 
      text: \usepackage{mhchem,mathtools}
engine: knitr
---

```{julia, results='asis'}
using Catalyst, ModelingToolkit, Symbolics, Markdown
rn = @reaction_network begin
    λ, 0 --> T
    d, T --> 0
    k*V, T --> 0
    k*V*T, 0 --> I
    δ, I --> 0
    p*I, 0 --> V
    c, V --> 0 
end

# Symbolics.latexify(rn) |> Markdown.parse   # this fails

# this workaround seems to work
Markdown.parse(replace(Symbolics.latexify(rn), "\\"^2=>"\\"^4))
aelmokadem commented 12 months ago

Thank you all for your input and my apologies for not providing a MWE from the beginning. I updated my comment above to include that.

aelmokadem commented 12 months ago

@baptiste @cderv @mcanouil The code below was inspired by your comments and it works

---
jupyter: julia-1.9
format: 
  pdf:
    latex-tinytex: false
    keep-tex: true
    include-in-header: 
      text: \usepackage{mhchem,mathtools}
---

```{julia}
using ModelingToolkit, Catalyst, Latexify
rn = @reaction_network begin
    λ, 0 --> T
    d, T --> 0
    k*V, T --> 0
    k*V*T, 0 --> I
    δ, I --> 0
    p*I, 0 --> V
    c, V --> 0 
end;
latexify(rn)

Seems that for the following, saving the object then using latexify avoids using the Catalyst latexification and solves the issue!

rn_ode = convert(ODESystem, rn)
latexify(rn_ode)


Here is the generated pdf:

<img width="560" alt="Screenshot 2023-07-20 at 11 36 19 PM" src="https://github.com/quarto-dev/quarto-cli/assets/31896854/56292f54-f6e0-4987-84d4-d213784ce581">
mcanouil commented 12 months ago

Glad you solved the issue with your LaTeX generated code. Closing the issue.