quarto-dev / quarto-cli

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

enhancement: add MathJax equation numbering for math environments in html #4136

Open eeholmes opened 1 year ago

eeholmes commented 1 year ago

By default, MathJax does not have equation numbers when the LaTeX math environments are used. This:

---
title: "test6"
format: html
---

\begin{equation}\label{eq-a}
a
\end{equation}

produces this:

image

instead of this (with numbers)

image

The reason is that the default behavior for MathJax is to not show the equation numbers. This causes endless confusion for those who use the math environment, which is used for more complex math.

It'd be great if Quarto turned on equation numbering in math environments by default so that html and PDF output behaves the same. All that is needed is to have this script in the header if the equation engine is mathjax:

<script>
MathJax = { 
    tex: { 
        tags: 'ams'  // should be 'ams', 'none', or 'all' }
     };
</script>

Obviously you can turn this on manually with

---
title: "test5"
  html:
    include-in-header: mathjax.html
---

with mathjax.html having the script above but most users spend hours and hours trying to debug lack of numbers until they stumble upon the right solution. What is worse, is that the solution depends on the MathJax version. The above is the method for the version being used by Quarto (by default).

I don't think there is any reason to have the numbering turned off. Anyone using the LaTeX math environment is likely to be a LaTeX user and we have a standard methods for selectively turning off numbers on an equation if that were wanted.

cscheid commented 1 year ago

Thanks for the feedback! I think what you're saying makes sense. We need to check how these interact with our crossref systems, but I'll take a look at that as we're overhauling crossrefs internals in any case.

eeholmes commented 1 year ago

Hi @cscheid Feel free to reach out to me for any feedback on the math side of the crossref system. I am heavily invested in the LateX-Quarto interface (with quarto_titlepage and other mathy templates). I have years of experience in complex math in the Rmd ecosystem. Did this heavily in bookdown but since migrated to Quarto. As an applied mathematician, I am familiar with how those who do complex math would expect math cross-referencing to work.

Re the MathJax options

I am guessing it is probably better to set math options in the metadata rather than hard-coding anything in header.

html-math-method:
  method: mathjax
  number-equations: true
  add-to-equation: section

For example adding section numbers to equations numbers is common but the MathJax setting to add section numbers to equation numbers is complex. Note in LaTeX it's \numberwithin{equation}{section} but doesn't work in html output, only PDF.

Re, cross-referencing in math equations

In the spirit of not re-inventing the wheel, LaTeX (which MathJax and ilk know) already has a system for complex math (latex math environments) and how to cross-ref. Anyone who puts this kind of math in their documents knows and uses the LaTeX/AMS syntax for math equations. The $$ $$ {#eq-num} is great actually but only for simple stuff, after that one goes to \begin{math-env} .... With MathJax (and other LaTeX/AMS to html JS libraries), I have found that I can just write normal LaTeX/AMS syntax and everything works same in html and pdf. It's beautiful. The only common thing that MathJax doesn't do is the subequations environment, but maybe that is kind of niche, or at least there hasn't been enough community effort to robustly solve it.

I think it is key to have have LaTeX/AMS users give feedback in order not to get "painted in a corner" by doing a math cross-ref system that will not allow the core cross-ref syntax that every math user will want. Like, numbering of sub-equations in a math environment and the different ways one does that in the LaTeX/AMS syntax (there really only 2). Even if your first system can't do that in the beginning, I bet there are ways to design things so that that will be a doable update in the future versus having to rebuild the whole system from the ground up.

BTW, currently Quarto works for fine for complex math and equation cross-refs. I just have to be careful to never use $$ $$ {#eq-math} (and @eq-math) and only use LaTeX math environments (no $$ $$) and use LaTeX eqn cross-ref syntax. So like \label{eq-num} and \ref{eq-num}. Sadly I have to avoid \eqref{eq-num} but that is a Pandoc problem with only recognizing newly defined LaTeX commands in $ $ environment (grrr). It is weird to have to use @ for figs and tables but \ref{} for equations but it's not that a big of a deal.

Cheers!

cscheid commented 1 year ago

I will do, and thank you for the long, thoughtful followup.

eeholmes commented 1 year ago

Adding a couple more notes (more for myself). MathJax fully supports amsmath so if you are having trouble with your cross-refs showing up, double check that your amsmath syntax is correct. Note if you happen to land on this thread and you are working with RMarkdown, be aware that in May 2023, RMarkdown still uses MathJax 2.7 (from 2017!) and the configuration syntax for that is completely different than MathJax 3+. Scroll all the way to the bottom to see how to use a different version of MathJax.

Just numbers 1 to infinity

Example mathjax1.html (to include in header for html output)

<script>
  MathJax = {
    tex: {
      tags: 'ams'  // should be 'ams', 'none', or 'all'
    }
  };
</script>

Example qmd

---
title: "Test"
format: 
  html: 
    html-math-method: mathjax
    include-in-header: mathjax1.html
---

# Intro

This report discusses the computation of the variance of the conditional model and state residuals for MARSS models of the  form:
\begin{equation}\label{eq:residsMARSS}
\begin{gathered}
a+b\\
c+d
\end{gathered}
\end{equation}
The state and model residuals are respectively
\begin{equation}\label{eq:resids}
a+g
\end{equation}
Equation \ref{eq:residsMARSS} and \ref{eq:resids}.

If you want your $$ ... $$ equations numbered, change ams to all however note that you cannot cross-ref your equations if you do this. $$a+b \label{eq:a}$$ with this \ref{eq:a} won't work.

<script>
MathJax = {
  tex: {
    tags: 'all',
    }
};
</script>

Add section numbers to your equation numbers

If by chance you landed here while searching for how to do this for PDF output, all you do is add \numberwithin{equation}{section} to your pdf header (in your yaml). Look here https://quarto.org/docs/output-formats/pdf-basics.html#latex-includes it's easy. Make you set number_sections: true.

If you need your equations numbered by section, so like 1.2 and 3.1. Then you need to follow this awful mathjax.html file https://github.com/mathjax/MathJax/issues/2427 Basically 1) Set up a variable called MathJax.config.section (in start up), 2) Make a LaTeX function to update that with each section, 3) Tell MathJax to add that variable to the equation number.

Then after each section # you add <div style="display:none">$\nextSection$</div> to update MathJax.config.section

Your mathjax.html file

<!-- For MathJax 3+ Eqns nums with section numbers -->
<script>
MathJax = {
  loader: {load: ['[tex]/tagformat']},
  section: 1,
  tex: {
    tags: 'ams',
    packages: {'[+]': ['tagformat', 'sections']},
    tagformat: {
      number: (n) => MathJax.config.section + '.' + n
    }
  },
  startup: {
    ready() {
      const Configuration = MathJax._.input.tex.Configuration.Configuration;
      const CommandMap = MathJax._.input.tex.SymbolMap.CommandMap;
      new CommandMap('sections', {
        nextSection: 'NextSection'
      }, {
        NextSection(parser, name) {
          MathJax.config.section++;
          parser.tags.counter = parser.tags.allCounter = 0;
        }
      });
      Configuration.create(
        'sections', {handler: {macro: ['sections']}}
      );
      MathJax.startup.defaultReady();
    }
  }
};</script>

Here is an example qmd file:

---
title: "Test"
format: 
  html: 
    number-sections: true
    number-depth: 2
    html-math-method: mathjax
    include-in-header: mathjax.html
---

# Intro

This report discusses the computation of the variance of the conditional model and state residuals for MARSS models of the  form:
\begin{equation}\label{eq:residsMARSS}
\begin{gathered}
a+b\\
c+d
\end{gathered}
\end{equation}
The state and model residuals are respectively
\begin{equation}\label{eq:resids}
a+g
\end{equation}
Equation \ref{eq:residsMARSS} and \ref{eq:resids}.

# Section 2
<div style="display:none">$\nextSection$</div>

"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

\begin{equation}\label{a}
a+g
\end{equation}
Eq \ref{a}. Equation \ref{eq:residsMARSS} and \ref{eq:resids}.

# Test section
<div style="display:none">$\nextSection$</div>

\begin{equation}\label{b}
a+g
\end{equation}

Ack I need PDF output too, and now it complains about \nextSection! Add \newcommand{\nextSection}{} to your header in your PDF section of your yaml.

Help for RMarkdown users

Quarto users ignore this: This is for the poor Rmd folks who might land on this thread in desperation. As of May 2023, the default MathJax js file that getting imported for Rmd is MathJax 2.7. You need to use a more recent version of MathJax to get proper support for equation numbering and cross-refs. Use this in your yaml:

output: 
  html_document: 
    mathjax: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js"
    includes:
      in_header: mathjax.html

with the mathjax.html files above depending on what you need.

ute commented 1 year ago

Thank you so much for sharing, @eeholmes ! The newer mathjax also supports changing equation numbers to custom tags, and \eqref is equally supported. That makes migration from LaTeX to quarto so so much easier :-) (in my case: tons of course notes with complex mathematics) I will throw together a filter that also takes care of markdown $$-equations.

My addition here to the wish list for quarto crossref (@cscheid :-)): a mechanism for \tagging. For equations, one could keep LaTeX syntax, that is what presumably most users of such a feature already are familiar with.

ute commented 1 year ago

Here is a first version of the filter: https://github.com/ute/mathjax3eqno :-) Although I do not load a specific mathjax version, it works on my machine with quarto 1.3.353. I can see that quarto loads MathJax3 👍 I have not tried it with earlier versions of quarto

cscheid commented 1 year ago

See also #2275

dhodge180 commented 7 months ago

Thanks @ute your extension is great, I've been searching around for something that allows equation numbering to work out-of-the-box. I don't have any great need for the numbering my chapter etc... but the lua script function (Para) is great, It replaces

$$
  stuff
$$ {#eq-xx}

with

\begin{equation}
  stuff \label{eq-xx}
\end{equation}

thus allowing usage of Markdown $$ syntax when that's all I need. But for more complex numbering I can still use LaTeX syntax via a math environment. The only drawback is we don't have a filter for \[ .... \] environments. So we just have to use either $$...$$ or specific math environments like align, equation, etc..

For anyone just finding this thread, you only need to include the mathjax1.html file (in the header) to enable to ams labelling, and then use Ute's nice Para function (see the filter mathjax3eqno.lua).

In my writing I'd like to be able to use Markdown format most of the time, but fallback on LaTeX/MathJax for things that Markdown cannot do (like number some lines in an align, but not others). While I wait for Quarto to get its act together and support numbering of equations in a more complete way. Is there any sign that Quarto will be updated to allow for richer equation numbering?

I'll be checking back to see if you have any success with making it compatible with Quarto books (or if Quarto fixes it all before then).

ute commented 7 months ago

@dhodge180 , there are two problems with books, due to the fact that chapters are rendered kind of independently:

a. mathjax does not know the chapter number, and uses chapter sections as prefix for equation numbers,

b. cross-references between chapters cannot be resolved by mathjax

Problem a. could be fixed with tweaking mathjax, but b. amounts to rewriting the crossreferencing mechanism (which also would solve a). I believe the quarto team will come up with a solution soon-ish.

I also need this equation numbering in a book right now, and currently work around by setting latex tags manually. This works with mathjax.

dhodge180 commented 7 months ago

@dhodge180 , there are two problems with books, due to the fact that chapters are rendered kind of independently:

a. mathjax does not know the chapter number, and uses chapter sections as prefix for equation numbers,

b. cross-references between chapters cannot be resolved by mathjax

Problem a. could be fixed with tweaking mathjax, but b. amounts to rewriting the crossreferencing mechanism (which also would solve a). I believe the quarto team will come up with a solution soon-ish.

I also need this equation numbering in a book right now, and currently work around by setting latex tags manually. This works with mathjax.

Thanks! I've had a play with your code to see if I can help with a. but I'm not good enough with Lua I don't think. I can't work out yet why the $$...$$ {#eq-1} equations already have hard-coded \qquad(1.1) style tags. Probably pandoc processing before your filter gets hold of them.

For the meantime for a book I think you're saying the answer is probably to use (display) $$...$$ {#eq-1} and (inline) $...$ as per Quarto standard, and if I ever need to label multiple lines of an equation to perhaps give them non-numeric names via \tag{$\dagger_1$}, \tag{$\dagger_2$} etc... this way when Quarto does provide a way to support better numbering I won't have to change all my code, only these special cases?

ute commented 6 months ago

@dhodge180, I have updated my extension with a workaround for books. It is still not possible to cross reference between chapters, but it works within a chapter now. You have to provide the chapter number manually with the first equation, then all equation numbers im that chapter are prefixed with chapter number. Crossref between chapters works only in pdf. It would be quite epic to implement this for html books.