knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
library(xmerit)

The LaTex Equation hangdling and rendering

要求在多种输出格式下,统一代码风格地进行LaTex公式显示,这是一项具有挑战性的工作。尤其是对于复杂数学公式,其中的细节、区别和难度都会快速地放大到令人惊异的程度。

这里我们进行综合性的比较,并得到当前可行的解决路径和方案。

Basic Knowlege about LaTex Equation

Equation environment

(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 and numbering

公式引用(cross-reference)的前提是正确地设定公式代码中的标签(label)指令,例如\label{eq1}

公式标号(numbering)分为手动标号和自动标号。手动标号需要设定公式代码中手动标号(tag)指令,例如\tag{1}。要实现公式自动标号,则需要考虑具体适用场景,例如:写作文档.qmd还是.rmd?输出格式htmlpdf还是docx?同样输出docx,采用不同R包bookdown::word2_document()、还是Rmarkdown::word_document()

Complicate LaTex Equation

LaTex语言能很好定义复杂数学公式及版式风格

Nested Equation

(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}

Align/arrange style

(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}

Writing tools and habits

MathJax version and Writing tools

#| eval: false
url_rmd <- "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
url_qmd <- "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"

v_rmd <- read_html(url_rmd) %>%
  html_text() %>%
  str_extract(., "(?<=MathJax.version=).*(?=;MathJax.fileversion)") %>%
  str_extract(., "\\d\\.\\d\\.\\d{1,2}")

v_qmd <- read_html(url_qmd) %>%
  html_text() %>%
  str_extract(., "(?<=mathjaxVersion=).*(?=,r.url)")%>%
  str_extract(., "\\d\\.\\d\\.\\d{1,2}")
v_qmd <- "3.2.1"
v_rmd <- "2.7.2"

对于数学公式的支持,RStudio的 .Rmd 文档和Quarto的.qmd文档都默认调用MathJax进行公示渲染和呈现。

二者对于MathJax版本及调用是不同的:

Traditional LaTex writing

传统LaTex写作者会严格遵从Latex语法规则:

::: {.callout-tip}

这里显示的是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格式,因此不会正确显示公式标号和公式引用。具体原因后面会进一步解释。

:::

Modern Markdown writing

当代Markdown写作者会遵从Quarto官方的说明文档语法书写公式:

::: {.callout-tip}

$$
a  = b + c + 5
$$ {#eq-add}

$$ a = b + c + 5 $$ {#eq-add}

引用公式语法@eq-add显示为 @eq-add。

:::

Hybrid syntax writing

混合语法写作者可能不严格遵守上述任何一个语法体系,而是更加关注便利性和最终显示效果。

$$
\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} $$

以下的混用情形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} $$ {#eq-hybrid}

For Rmarkdown/bookdown/.Rmd Writing

Basic Syntax

bookdown解决的Rmarkdown生态下公式书写中自动标号和交叉引用的问题。

对于.docx格式输出,bookdown下公式语法规则如下:

经验规则bookdown::word_document2输出.docx使用情境下,任何时候都不建议使用双美元符号对$$...$$环境。

Rules of Nested environment

经测试,如下嵌套环境规则是受到支持的(也正是自定义R包xmerit(版本0.0.11)目前所采用的语法规则):

a)equation环境

\begin{equation}
  ...
\end{equation}

b)align环境

\begin{align}
  ...
\end{align}

a)局部对齐排列的嵌套环境

\begin{align} 
  \begin{split}
   ... 
  \end{split} 
\end{align}

b)完全对齐排列的嵌套环境

\begin{equation} 
  \begin{alignedat}{999}
   ... 
  \end{alignedat} 
\end{equation}

xmerit function and syntax

Dataset and model

library(xmerit)

data(mtcars)
df <- mtcars
mod <- mpg ~ cyl + disp + wt +gear
lm.fit <- lm(formula = mod, data = df)
summary(lm.fit)

xvars <- all.vars(mod)[-1]
yvars <- all.vars(mod)[1]

xmerit::lx.psm : align+split

xmerit::lx.psm()函数默认形式为嵌套结构\begin{align}内含\begin{split}

lx.out <- xmerit::lx.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 = TRUE)
\begin{align}
\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
(\#eq:lx-psm)
\end{align}

引用语法 `\@ref(eq:lx-psm)`显示为 \@ref(eq:lx-psm)。

\begin{align} \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 (#eq:lx-psm) \end{align}

引用语法 \@ref(eq:lx-psm)显示为 \@ref(eq:lx-psm)。

xmerit::lx.est: equation + alignedat

xmerit::lx.est()函数默认形式为嵌套结构\begin{equation}内含\begin{alignedat}{999}

lx.out <- lx.est(lm.mod = mod,lm.dt = df,lm.n = 3,lm.label = "lx-est", lm.tag = "lx.est",
                 no_dollar = TRUE)

\begin{equation} \begin{alignedat}{999} &\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{alignedat} \quad \text{(lx.est)}\quad (#eq:lx-est) \end{equation}

引用语法 \@ref(eq:lx-est)显示为 \@ref(eq:lx-est)。

For Quarto/.qmd Writing

News of the xmerit release

xmerit包在版本>0.0.12以后,增加了对Quarto文档公式风格的支持。主要使用的函数包括:

xmerit包说明

xmerit包在版本>0.0.12以后,增加了对Quarto文档公式风格的支持。主要使用的函数包括:

library(xmerit)

data(mtcars)
df <- mtcars
mod <- mpg ~ cyl + disp + wt +gear
lm.fit <- lm(formula = mod, data = df)
summary(lm.fit)

xvars <- all.vars(mod)[-1]
yvars <- all.vars(mod)[1]

xmerit::qx.psm: aligned + split

xmerit::qx.psm()函数默认形式为嵌套结构\begin{aligned}内含\begin{split}

::: {.panel-tabset}

R chunk

#| results = 'asis',
#| echo = TRUE,
#| 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)

source style

$$
\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 。

render effect

$$ \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 。

:::

xmerit::qx.est: alignedat + split

xmerit::qx.est()函数默认形式为嵌套结构\begin{alignedat}{999}内含\begin{split}

::: {.panel-tabset}

R chunk

#| results = 'asis',
#| echo = TRUE,
#| 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)

source style

$$
\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 。

render effect

$$ \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 。

:::

Other utilities of functions



huhuaping/xmerit documentation built on Nov. 10, 2023, 4:34 a.m.