前言
“Wealth consists not in having great possessions, but in having few wants.” ― Epictetus
要求在多种输出格式下,统一代码风格地进行LaTex公式显示,这是一项具有挑战性的工作。尤其是对于复杂数学公式,其中的细节、区别和难度都会快速地放大到令人惊异的程度。
这里我们进行综合性的比较,并得到当前可行的解决路径和方案。
公式环境
(1)对于传统的LaTex
写作用户,主要输出格式为.pdf。而LaTex对公式环境 (equation environments)做了多样化的定义和分类,如\begin{align} ... \end{align}
;\begin{aligned} ... \end{aligned}
等。
\begin{align}
a = b + c
\end{align}
(2)对于当代的Markdown
写作用户,天然要求多格式输出(.ppdf、.html、.docx)。.Rmd
文档和.qmd
文档都默认以双美元符号($$...$$
)对定义数学公式代码块
(equation block)。
$$
a = b + c + 5
$$
公式引用和标号
公式引用 (cross-reference)的前提是正确地设定公式代码中的标签(label)指令,例如\label{eq1}
。
公式标号 (numbering)分为手动标号和自动标号。手动标号需要设定公式代码中手动标号(tag)指令,例如\tag{1}
。要实现公式自动标号,则需要考虑具体适用场景,例如:写作文档.qmd
还是.rmd
?输出格式html
、pdf
还是docx
?同样输出docx
,采用不同R包bookdown::word2_document()
、还是Rmarkdown::word_document()
?
传统LaTex
写作
传统LaTex
写作者会严格遵从Latex语法规则:
这里显示的是Quarto写作 .qmd
渲染为html格式的效果:
\begin{align}
a = b + c \label{eq1}
\end{align}
\[\begin{align}
a = b + c \label{eq1}
\end{align}\]
引用公式语法\eqref{eq1}
显示为\(\eqref{eq1}\) ;或引用公式语法\ref{eq1}
,显示为\(\ref{eq1}\)
注意 :因为这里是.qmd
渲染为html格式,因此不会正确显示公式标号和公式引用。具体原因后面会进一步解释。
当代Markdown
写作
当代Markdown
写作者会遵从Quarto官方的说明文档语法书写公式:
$$
a = b + c + 5
$$ {#eq-add}
\[
a = b + c + 5
\tag{1}\]
引用公式语法@eq-add
显示为 式 1 。
混合语法写作
混合语法 写作者可能不严格遵守上述任何一个语法体系,而是更加关注便利性和最终显示效果。
$$
\begin{align}
a & = b + c \label{eq2} \\
c & = d + e \label{eq3}
\end{align}
$$
\[
\begin{align}
a & = b + c \label{eq2} \\
c & = d + e \label{eq3}
\end{align}
\]
混用情形1:双美元符号对$$...$$
内部蕴含了典型的Latex语法\label{}
。
公式引用效果1:引用方法\eqref{eq2}
,显示\(\eqref{eq2}\) 。
副作用1:a.以上语法在.qmd
文档内不能正常预览该公式。b.在html输出下,引用语法\eqref{eq2}
无法显示,且两个子方程不会自动标号(但在pdf输出下能正常显示,具体可参看节pdf测试 )。
以下的混用情形2是禁止使用的:
$$
\begin{align}
a & = b + c +4 \label{eq4} \\
c & = d + e +5 \label{eq5}
\end{align}
$$ {#eq-hybrid}
\[
\begin{align}
a & = b + c \label{eq2} \\
c & = d + e \label{eq3}
\end{align}
\tag{2}\]
混用情形2:双美元符号对$$...$$
结合#eq-hybrid
标签,但是内部蕴含了典型的Latex语法\label{}
。
公式引用效果2:引用方法\eqref{eq2}
,显示\(\eqref{eq2}\) 。引用方法@eq-hybrid
,显示 式 2 。
副作用2:a.以上语法在.qmd
文档内不能正常预览该公式。b.在html输出下,引用语法\eqref{eq2}
无法显示。c.无论是html还是pdf输出,都不会显示公式!html输出会仅仅显示源代码,而pdf输出则会直接报错无法渲染!!
复杂公式
LaTex语言能很好定义复杂数学公式及版式风格
嵌套公式
(1)\begin{split} ... \end{split}
嵌套于\begin{aligned} ... \end{aligned}
\begin{aligned}
\begin{split}
a & = 0.01 b + 4c \\
c & = 1.4321 d + 2.22 e
\end{split}
\text{(方程1)}
\\
\begin{split}
m & = b + c +d \\
p & = d + e
\end{split}
\text{(方程2)}
\end{aligned}
\[\begin{aligned}
\begin{split}
a & = 0.01 b + 4c \\
c & = 1.4321 d + 2.22 e
\end{split}
\text{(方程1)}
\\
\begin{split}
m & = b + c +d \\
p & = d + e
\end{split}
\text{(方程2)}
\end{aligned}\]
版式风格
(1)版式风格\begin{align} ... \end{align}
:
\begin{align}
a & = 0.01 b + 4c \\
c & = 1.4321 d + 2.22 e
\end{align}
\[\begin{align}
a & = 0.01 b + 4c \\
c & = 1.4321 d + 2.22 e
\end{align}\]
(2)版式风格\begin{alignedat}{number} ... \end{alignedat}
:
\begin{alignedat}{999}
&e_t^2=&& + \alpha_{1} && + \alpha_{2} lquan&&
+ \alpha_{3} mon&& + \alpha_{4} tue\\
& && + \alpha_{5} wed&& + \alpha_{6} thu&&
+ \alpha_{7} stormy&& + \alpha_{8} cold\\
& && + \alpha_{9} change&& + \alpha_{10} (lquan)^2&&+v_t\\
\end{alignedat}
\[\begin{alignedat}{999}
&e_t^2=&& + \alpha_{1} && + \alpha_{2} lquan&&
+ \alpha_{3} mon&& + \alpha_{4} tue\\
& && + \alpha_{5} wed&& + \alpha_{6} thu&&
+ \alpha_{7} stormy&& + \alpha_{8} cold\\
& && + \alpha_{9} change&& + \alpha_{10} (lquan)^2
&&+v_t\\
\end{alignedat}\]
\begin{alignedat}{999}
&\widehat{lprice}=&&+0.65&&-0.10lquan_i&&-0.08mon_i&&-0.08tue_i\\
&(s)&&(0.4408)&&(0.0501)&&(0.1042)&&(0.1048)\\
&(t)&&(+1.48)&&(-1.95)&&(-0.80)&&(-0.80)\\
&(cont.)&&-0.07wed_i&&+0.05thu_i&&+0.29stormy_i&&+0.09cold_i\\
&(s)&&(0.1077)&&(0.1008)&&(0.0815)&&(0.0713)\\
&(t)&&(-0.68)&&(+0.53)&&(+3.60)&&(+1.21)\\
&(cont.)&&-0.15change_i && && &&\\
&(s)&&(0.0738) && && &&\\
&(t)&&(-2.00) && && &&
\end{alignedat}
\[\begin{alignedat}{999}
&\widehat{lprice}=&&+0.65&&-0.10lquan_i&&-0.08mon_i&&-0.08tue_i\\
&(s)&&(0.4408)&&(0.0501)&&(0.1042)&&(0.1048)\\
&(t)&&(+1.48)&&(-1.95)&&(-0.80)&&(-0.80)\\
&(cont.)&&-0.07wed_i&&+0.05thu_i&&+0.29stormy_i&&+0.09cold_i\\
&(s)&&(0.1077)&&(0.1008)&&(0.0815)&&(0.0713)\\
&(t)&&(-0.68)&&(+0.53)&&(+3.60)&&(+1.21)\\
&(cont.)&&-0.15change_i && && &&\\
&(s)&&(0.0738) && && &&\\
&(t)&&(-2.00) && && &&
\end{alignedat}\]
MathJax
版本
对于数学公式的支持,RStudio的 .Rmd
文档和Quarto的.qmd
文档都默认调用MathJax
进行公示渲染和呈现。
二者对于MathJax
版本及调用是不同的:
xmerit包公式测试
xmerit
包说明
xmerit
包在版本>0.0.12
以后,增加了对Quarto文档公式风格的支持。主要使用的函数包括:
Warning: replacing previous import 'stats::filter' by 'dplyr::filter' when
loading 'xmerit'
Warning: replacing previous import 'stats::lag' by 'dplyr::lag' when loading
'xmerit'
Call:
lm(formula = mod, data = df)
Residuals:
Min 1Q Median 3Q Max
-4.9159 -1.2484 -0.3566 1.4719 5.9253
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 43.539847 4.860059 8.959 1.42e-09 ***
cyl -1.784296 0.613889 -2.907 0.00722 **
disp 0.006944 0.012007 0.578 0.56782
wt -3.792867 1.081819 -3.506 0.00161 **
gear -0.490445 0.790285 -0.621 0.54007
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 2.624 on 27 degrees of freedom
Multiple R-squared: 0.835, Adjusted R-squared: 0.8105
F-statistic: 34.15 on 4 and 27 DF, p-value: 3.36e-10
xmerit::qx.psm
xmerit::qx.psm()
函数默认形式为嵌套结构\begin{aligned}
内含\begin{split}
。
Show the code
```{r}
#| results: asis
#| code-fold: show
#| eval: false
qx.out <- xmerit::qx.psm(
x = xvars, y = yvars,
begin = 0,
#greek.n = length(xvars)+1,
n.row = 3,
lm.label = "lx-psm",
lm.tag = "lx.psm",
no_dollar = FALSE)
```
$$
\begin{aligned}
\begin{split}
mpg_i=&+\beta_{0}+\beta_{1}cyl_i+\beta_{2}disp_i\\&+\beta_{3}wt_i+\beta_{4}gear_i+u_i
\end{split}
\quad \text{(lx.psm)}\quad
\end{aligned}
$$ {#eq-lx-psm}
引用语法`见 @eq-lx-psm` 显示为见 @eq-lx-psm 。
\[
\begin{aligned}
\begin{split}
mpg_i=&+\beta_{0}+\beta_{1}cyl_i+\beta_{2}disp_i\\&+\beta_{3}wt_i+\beta_{4}gear_i+u_i
\end{split}
\quad \text{(lx.psm)}\quad
\end{aligned}
\tag{3}\]
引用语法见 @eq-lx-psm
显示为见 式 3 。
xmerit::qx.est
xmerit::qx.est()
函数默认形式为嵌套结构\begin{alignedat}{999}
内含\begin{split}
。
Show the code
```{r}
#| results: asis
#| code-fold: show
#| eval: false
qx.out <- qx.est(
lm.mod = mod, lm.dt = df,
lm.n = 3, lm.label = "lx-est",
lm.tag = "lx.est",
no_dollar = FALSE)
```
$$
\begin{alignedat}{999}
\begin{split}
&\widehat{mpg}=&&+43.54&&-1.78cyl_i&&+0.01disp_i\\
&(s)&&(4.8601)&&(0.6139)&&(0.0120)\\
&(t)&&(+8.96)&&(-2.91)&&(+0.58)\\
&(cont.)&&-3.79wt_i&&-0.49gear_i &&\\
&(s)&&(1.0818)&&(0.7903) &&\\
&(t)&&(-3.51)&&(-0.62) &&
\end{split}
\quad \text{(lx.est)}\quad
\end{alignedat}
$$ {#eq-lx-est}
引用语法`见 @eq-lx-est` 显示为见 @eq-lx-est 。
\[
\begin{alignedat}{999}
\begin{split}
&\widehat{mpg}=&&+43.54&&-1.78cyl_i&&+0.01disp_i\\
&(s)&&(4.8601)&&(0.6139)&&(0.0120)\\
&(t)&&(+8.96)&&(-2.91)&&(+0.58)\\
&(cont.)&&-3.79wt_i&&-0.49gear_i &&\\
&(s)&&(1.0818)&&(0.7903) &&\\
&(t)&&(-3.51)&&(-0.62) &&
\end{split}
\quad \text{(lx.est)}\quad
\end{alignedat}
\tag{4}\]
引用语法见 @eq-lx-est
显示为见 式 4 。
总结与展望
概括小结
Quarto的Markdown公式语法对于复杂公式的支持比较有限。例如对一个公式环境下的两个子公式分别标号和分别引用就难以轻松做到。简单地,Quarto的Markdown公式语法的简洁性、统一性,需要付出对复杂公式情形良好支持的代价!尽管Quarto团队还在进行更多努力改进。
明确自己的最终写作输出格式(.html
、.pdf
、.docx
)是最为关键的。例如,LaTex
写作风格下,添加\label
命令,html输出不会显示公式标号,但是pdf输出下则会正常显示公式标号。概括地说,简单而明确的输出需求——例如尽量不采用多格式同时如安然输出——会让事情更加容易掌控!
.html
格式输出,对于公式语法要求相对最为宽松。
.pdf
格式和.docx
格式输出,对于公式语法有各自的要求。但是总体而言,能够在.pdf
输出正常显示的公式语法,也能在.docx
输出下正常显示。
eeholmes
经验法则(参看eeholmes的问答 ):
If you only need to render to both html and PDF, then I would say never use $$ $$
and @eq-
for equations. Stick to the equation environments (which btw is what LaTeX users would normally use) and use \eqref{}
and \ref{}
. If you need to render to word though….only $$ $$
is recognized; equations in equation environments are completely removed!
后续工作
(1)对于R包xmerit
的开发,在Quarto写作工具下的公式显示支持,可以考虑设定新的参数quarto = TRUE
。
(2)R包xmerit
的开发,建议使用的语法情景为:
坚持Quarto的语法指引,使用双美元符号对$$
和{#eq-}
风格
嵌入公式使用:split嵌入aligned;或者split嵌入alignedat。目前不要使用align
、alignat
、equation
这样的公式环境(Quarto的语法指引下,pdf输出将不支持这类公式环境)!
不适用复杂的公式系统。任何复杂公式系统,都可以考虑拆分转换为简单的多个公式,并分别加以书写、渲染和呈现。
参考资料
referencing equations inside $$ \begin{align}
environment. 参看github问题提交 #2275
enhancement: add MathJax equation numbering for math environments in html. 参看github问题提交#4136
Specify LaTeX Parameters in R Markdow. 参看网页链接