在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行内公式

含下划线_的公式: \(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} $

将下标放到正下方

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)\),直接嵌入行内。

原文地址:https://www.cnblogs.com/wangxin37/p/8185688.html

时间: 2024-10-03 05:40:11

在Hexo中渲染MathJax数学公式的相关文章

Windows下使用GetGlyphOutline在OpenGL中渲染字体

欢迎转载,请标明出处:http://blog.csdn.net/tianyu2202/ 无图无JB,先上图.使用OpenGL绘制字体,支持多种字体,支持TrueType轮廓字体,支持自选字体纹理大小和输出大小,支持在三维空间内绘制. 关于OpenGL中字体的显示网上其实有很多的教程,不过经常用到的方式有比较简单的Bitmap方式.比较复杂的FreeType方式.而本文介绍的方式虽然只能在Windows下实现,却有着和FreeType一样的显示效果,最重要的是非常简单,仅仅200多行代码即可实现.

(转载)强行在MFC窗体中渲染Cocos2d-x 3.6

强行在MFC窗体中渲染Cocos2d-x 3.6 GuyaWeiren2015-06-29 15:14:063696 次阅读 [前言] 把Cocos2d-x渲染到另一个应用程序框架中的方法,在2.x时代有很多大神已经实现了,而3.x的做法网上几乎找不着.这两天抽空强行折腾了一下,不敢独享,贴出来供大家参考. [已知存在的问题] 程序退出时会发生非常严重的内存泄漏,博主检查了很久,但技术不够暂时无法解决.如果有大神能搞定,求告知一下做法,谢谢! 在程序从开始运行到关闭期间,有且仅有一个Cocos2

yii调用外部action与在外部action中渲染页面

// 1. 在controller中映射actionpublic function actions(){ return array( 'create' => 'application.controllers.miiuser.CreateAction', );} // 2. 在action中run方法中写逻辑,但下面的render方法显示不行,因为CAction类没有render方法class CreateAction extends CAction { public function run()

Hexo引入Mermaid流程图和MathJax数学公式

近来用Markdown写文章,越来越不喜欢插入图片了,一切能用语法解决的问题坚决不放图,原因有二: 如果把流程图和数学公式都以图片方式放到文章内,当部署到Github上后,访问博客时图片加载实在太慢,有时一篇文章需要画10来个流程图,那你就得截图10来多次,还得给这些图片想一个合适的名字,同时插入图片的时候还要注意图片的插入位置和顺序: 如果你要把文章发布到其他博客平台,如CSDN.博客园,在每一个平台上你都要插入10来多次图片,作为程序员,这种笨拙又耗时的方法,我实在不能忍. 于是愤而搜索,M

Inkscape 中使用 LaTeX 数学公式

在<关于绘图软件的一点注记>曾经提到过在 Inkscape 中可以使用 LaTeX 命令写数学公式.但 Inkscape 本身是没有这个功能的,需要借助 GhostScript 和 pstoedit 这两款软件才行.网上有关于这方面的教程 (不过大都是针对早期版本的说明,教程写的也非常繁琐),在最新版本的 Inkscape 中使用 LaTeX 已经变得非常简单了.前面提到的 GhostScript 是 PS 语言解释器,在 TeXLive 中已经集成了,但集成的是精简版的 GhostScrip

Hexo 中使用 emoji 和 tasks

替换为 markdown-it 今天在迁移博客项目的时候,发现原来在 hugo 中可以使用的 Emoji 和 tasks 功能都不能正常使用了,查询了一下原因,主要是因为 hexo 默认的解析器是 hexo-renderer-marked ,这个默认的渲染器是不支持 emoji 功能的,但是支持 tasks,但是这个渲染器是不支持扩展的,所以如果希望同时使用这两个功能的话,就需要换一个渲染器. 这里推荐的是 hexo-renderer-markdown-it 渲染器,支持扩展,采用的是 mark

如何让Hexo不渲染某些文件

Hexo博客的基本内容是一些Markdown文件,放在source/_post文件夹下,每个文件对应一篇文章.除此之外,放在source文件夹下的所有开头不是下划线的文件,在hexo generate的时候,都会被拷贝到public文件夹下.但是,Hexo默认会渲染所有的HTML和Markdown文件,导致我的README.md直接转成html格式了... 怎么样避开这个坑呢?如果只有一个HTML文件的话,可以简单地在文件开头加上layout: false一行即可: layout: false

UnityEditor扩展编辑器实现从场景中渲染得到Cubemap

(学习笔记,希望能帮助到有需要的人.) 在自定义的EditorWindow中定义2个变量,分别代表需要渲染的Cubemap 和 视点对象(通常是Camera对象) private Cubemap cubemap; private GameObject obj; 在OnGUI 函数中 <span style="white-space:pre"> </span>this.cubemap = (Cubemap) EditorGUILayout.ObjectField

强行在MFC窗体中渲染Cocos2d-x 3.6

[前言] 把Cocos2dx渲染到另一个应用程序框架中的方法,在2.x中有很多大神已经实现了,而3.x的做法网上几乎找不着.这两天抽空强行折腾了一下,不敢独享,贴出来供大家参考. [已知存在的问题] 程序退出时会发生非常严重的内存泄漏,博主检查了很久,但技术不够暂时无法解决.如果有大神能搞定,求告知一下做法,谢谢! 在程序从开始运行到关闭期间,有且仅有一个cocos2dx窗体存在时可以选择性无视内存泄漏.如果非常在意这一点,建议使用cocos2d-x 2.2.6这个版本,放在MFC中的内存泄漏很