在Hexo中渲染MathJax數學公式
最近學機器學習涉及很多的數學公式,公式如果用截圖顯示,會比較low而且不方便。因此需要對Hexo做些配置,支持公式渲染。同時文末整理了各種公式的書寫心得,比如矩陣、大小括號、手動編號、上下角標和多行對其等,有興趣的可以看看。
通過hexo-math插件安裝MathJax
有個插件hexo-math,可以給Hexo博客添加MathJax公式支持,GitHub地址 https://github.com/hexojs/hexo-math
安裝方法可其他hexo插件一樣,在博客根目錄執行npm install hexo-math --save安裝,配置見GitHub說明頁,這裏我沒有通過這種方式安裝,而是直接在主題配置中添加MathJax的js來安裝的。
在主題中手動添加js安裝MathJax
類似所有第三方js插件,js加載方式有兩種:
- 第一種,通過連接CDN加載js代碼。好處是省了本地配置js代碼,並且每次加載都是最新的,缺點是一旦連接的CDN出問題,可能卡住頁面的js加載。
- 第二種,將js代碼下載下來,放到主題的js文件夾中,通過本地相對目錄加載。優缺點和第一種方法正相反。
這裏我選擇通過CDN加載,因為把代碼下載下來後發現有好多js,搞不清楚其中的引用關系,還是直接用官方給出的通過CDN加載的簡便方法吧:Getting Started with MathJax
又綜合了網上其他人給出的一些配置,最終代碼如下。
在themes/free2mind/layout/_partial 目錄中新建mathjax.ejs,填入如下js代碼:
<!-- MathJax配置,可通過單美元符號書寫行內公式等 -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
"HTML-CSS": {
preferredFont: "TeX",
availableFonts: ["STIX","TeX"],
linebreaks: { automatic:true },
EqnChunk : (MathJax.Hub.Browser.isMobile ? 10 : 50)
},
tex2jax: {
inlineMath: [ ["$", "$"], ["\\(","\\)"] ],
processEscapes: true,
ignoreClass: "tex2jax_ignore|dno",
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
},
TeX: {
equationNumbers: { autoNumber: "AMS" },
noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } },
Macros: { href: "{}" }
},
messageStyle: "none"
});
</script>
<!-- 給MathJax元素添加has-jax class -->
<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function() {
var all = MathJax.Hub.getAllJax(), i;
for(i=0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>
<!-- 通過連接CDN加載MathJax的js代碼 -->
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
只在有公式的頁面才加載MathJax
有公式才加載MathJax,這點比較重要,沒有公式仍然加載js渲染公式,會影響頁面加載速度。
在所有有公式的文章的front-matter中增加一項配置 mathjax: true,例如:
---
title: 結構化機器學習項目
tags:
- 機器學習
categories:
- 機器學習
date: 2017-10-9 22:22:00
toc: false
mathjax: true
---
然後在themes/free2mind/layout/_partial/footer.ejs 中通過此配置變量決定是否加載mathjax.ejs :
<!-- 根據頁面mathjax變量決定是否加載MathJax數學公式js -->
<% if (page.mathjax){ %>
<%- partial('mathjax') %>
<% } %>
解決MarkDown與MathJax渲染沖突
添加MathJax後寫幾個公式發現渲染出了很多問題,原因是Hexo默認先使用hexo-renderer-marked引擎渲染MarkDown,然後再交給MathJax渲染。hexo-renderer-marked會把一些特殊的markdown符號轉換為相應的html標簽,比如在markdown語法中,下劃線 _ 代表斜體,會被轉化為< em>標簽,\\也會被轉義成一個\。而類Latex格式書寫的數學公式下劃線 _ 表示角標,\\表示公式換行,有特殊的含義,所以MathJax引擎在渲染數學公式的時候就會出錯。
解決方法有人提出更換Hexo的MarkDown渲染引擎,用hexo-renderer-kramed 替換默認的hexo-renderer-marked引擎,但我看了下hexo-renderer-kramed的文檔說明,如果用這個引擎的話,要改變我的MarkDown書寫習慣,還是不用了,並且換了這個引擎還是沒有完全解決問題。
最終解決方法是參考一篇博文中修改hexo-renderer-marked渲染引擎的js腳本,去掉對 _ 和\\的轉義。
Hexo默認的MarkDown渲染引擎hexo-renderer-marked會調用marked模塊的marked.js腳本進行最終的解釋,這個腳本在Hexo安裝後的node_modules\marked\lib\目錄中。
有兩點修改:
針對下劃線的問題,取消_作為斜體轉義,因為marked.js中*也是斜體的意思,所以取消掉_的轉義並不影響使用markdown,我平時一般不用斜體,就是用也更習慣用*作為斜體標記。
針對marked.js與Mathjax對於個別字符二次轉義的問題,我們只要不讓marked.js去轉義\\,\{,\}在MathJax中有特殊用途的字符就行了。
編輯node_modules\marked\lib\marked.js 腳本,
【第一步】
將451行的escape: /^\\([\\`*{}\[\]()# +\-.!_>])/,
替換為
escape: /^\\([`*\[\]()# +\-.!_>])/,
這一步取消了對\\,\{,\}的轉義(escape)
【第二步】
將459行的em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
替換為
em:/^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
這一步取消了對斜體標記_的轉義
這樣帶來一個問題就是,以後每次更換電腦,在新電腦上安裝完Hexo環境後,都要手動修改marked.js文件。
MathJax公式書寫
公式書寫依然按照MarkDown語法來,基本上也和LaTeX相同,單\$符引住的是行內公式,雙\$符引住的是行間公式。
- MathJax公式書寫參考
http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
MathJax行內公式
含下劃線_的公式: \(x_mu\)
$x_mu$
希臘字符: \(\sigma\)
$\sigma$
行內公式: \(y=ax+b\)
$y=ax+b$
行內公式: \(\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta\)
$\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta$
行內公式: \(M(\beta^{\ast}(D),D) \subseteq C\)
$M(\beta^{\ast}(D),D) \subseteq C$
MathJax行間公式
行間公式:
$$ \sum_{i=0}^n i^2 = \frac{(n^2+n)(2n+1)}{6} $$
\[ \sum_{i=0}^n i^2 = \frac{(n^2+n)(2n+1)}{6} \]
行間公式:
$$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$
\[ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} \]
MathJax大括號右多行賦值
雙\\公式內換行,cases實現大括號右多行賦值,&用來對齊:
$$
f(n) =
\begin{cases}
n/2, & \text{if $n$ is even} \\
3n+1, & \text{if $n$ is odd}
\end{cases}
$$
\[ f(n) = \begin{cases} n/2, & \text{if $n$ is even} \3n+1, & \text{if $n$ is odd} \end{cases} \]
MathJax多行公式對齊
比如多行公式推導中常用的等號對齊
begin{split} 表示開始多行公式,end{split}表示結束;公式中用\\表示回車到下一行,&表示對齊的位置。
$$
\begin{equation}
\begin{split}
\frac{\partial^2 f}{\partial{x^2}} &= \frac{\partial(\Delta_x f(i,j))}{\partial x} = \frac{\partial(f(i+1,j)-f(i,j))}{\partial x} \\
&= \frac{\partial f(i+1,j)}{\partial x} - \frac{\partial f(i,j)}{\partial x} \\
&= f(i+2,j) -2f(f+1,j) + f(i,j)
\end{split}
\nonumber
\end{equation}
$$
\[ \begin{equation} \begin{split} \frac{\partial^2 f}{\partial{x^2}} &= \frac{\partial(\Delta_x f(i,j))}{\partial x} = \frac{\partial(f(i+1,j)-f(i,j))}{\partial x} \&= \frac{\partial f(i+1,j)}{\partial x} - \frac{\partial f(i,j)}{\partial x} \&= f(i+2,j) -2f(f+1,j) + f(i,j) \end{split} \nonumber \end{equation} \]
MathJax公式自動編號
要想MathJax支持公式編號,需添加AMS支持,在腳本中添加如下MathJax配置項:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: { equationNumbers: { autoNumber: "AMS" } }
});
</script>
我上面mathjax.ejs腳本中已加入公式編號的配置。
書寫時只要使用begin{equation}環境就會自動編號:
$$
\begin{equation}
\end{equation}
$$
註意此時會自動將文檔內的所有begin{equation}公式連續編號,例如:
$$
\begin{equation}
\sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 )
\end{equation}
$$
$$
\begin{equation}
\beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i))
\end{equation}
$$
\[
\begin{equation}
\sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 )
\end{equation}
\]
\[
\begin{equation}
\beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i))
\end{equation}
\]
禁止自動編號
在end{equation}前加\nonumber可禁止對此公式自動編號,例如:
$$
\begin{equation}
\sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 )
\nonumber
\end{equation}
$$
$$
\begin{equation}
\beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i))
\end{equation}
$$
\[
\begin{equation}
\sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 )
\nonumber
\end{equation}
\]
\[
\begin{equation}
\beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i))
\end{equation}
\]
MathJax公式手動編號
可以在公式書寫時使用\tag{手動編號}添加手動編號,例如:
$$
\begin{equation}
\sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 ) \tag{1.2.3}
\end{equation}
$$
\[ \begin{equation} \sum_{i=0}^n F_i \cdot \phi (H, p_i) - \sum_{i=1}^n a_i \cdot ( \tilde{x_i}, \tilde{y_i}) + b_i \cdot ( \tilde{x_i}^2 , \tilde{y_i}^2 ) \tag{1.2.3} \end{equation} \]
不加\begin{equation}, \end{equation}也可以,例如:
$$
\beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i)) \tag{我的公式3}
$$
\[ \beta^*(D) = \mathop{argmin} \limits_{\beta} \lambda {||\beta||}^2 + \sum_{i=1}^n max(0, 1 - y_i f_{\beta}(x_i)) \tag{我的公式3} \]
行內公式加\tag{}後會自動成為行間公式,例如:
$z = (p_0, ..... , p_n) \tag{公式21} $
$z = (p_0, ..... , p_n) \tag{公式21} $
又如:
$ s = r cos(a+b) = r cos(a) cos(b) - r sin(a) sin(b) \tag{1.1} $
$ t = r sin(a+b) = r sin(a) cos(b) - r cos(a) sin(b) \tag{1.2} $
$ s = r cos(a+b) = r cos(a) cos(b) - r sin(a) sin(b) \tag{1.1} $
$ t = r sin(a+b) = r sin(a) cos(b) - r cos(a) sin(b) \tag{1.2} $
- 參考Automatic Equation Numbering
http://docs.mathjax.org/en/latest/tex.html#automatic-equation-numbering
將下標放到正下方
1、如果是數學符號,那麽直接用\limits命令放在正下方,如Max函數下面的取值範圍,需要放在Max的正下方。可以如下實現:
$ \max \limits_{a<x<b}\{f(x)\} $
$ \max \limits_{a<x<b}{f(x)} $
2、若是普通符號,那麽要用\mathop先轉成數學符號再用\limits,如
$ \mathop{a}\limits_{i=1} $
$ \mathop{a}\limits_{i=1} $
MathJax矩陣輸入
無括號矩陣:
$$
\begin{matrix}
1 & x & x^2 \\
1 & y & y^2 \\
1 & z & z^2 \\
\end{matrix}
$$
\[ \begin{matrix} 1 & x & x^2 \1 & y & y^2 \1 & z & z^2 \\end{matrix} \]
矩陣運算:
$$
\left(
\begin{array}{c}
s \\
t
\end{array}
\right)
=
\left(
\begin{array}{cc}
cos(b) & -sin(b) \\
sin(b) & cos(b)
\end{array}
\right)
\left(
\begin{array}{c}
x \\
y
\end{array}
\right)
$$
\[ \left( \begin{array}{c} s \ t \end{array} \right) = \left( \begin{array}{cc} cos(b) & -sin(b) \ sin(b) & cos(b) \end{array} \right) \left( \begin{array}{c} x \ y \end{array} \right) \]
有括號有豎線矩陣:
$$
\left[
\begin{array}{cc|c}
1&2&3\\
4&5&6
\end{array}
\right]
$$
\[ \left[ \begin{array}{cc|c} 1&2&3\ 4&5&6 \end{array} \right] \]
行內小矩陣:
$\bigl( \begin{smallmatrix} a & b \\ c & d \end{smallmatrix} \bigr)$
這是一個行內小矩陣\(\bigl( \begin{smallmatrix} a & b \\ c & d \end{smallmatrix} \bigr)\),直接嵌入行內。
在Hexo中渲染MathJax數學公式