标签 LaTeX 下的文章

论文图表自动编译


前情提要

老板特别喜欢在论文里面加图加表...加到最后整个论文堆了二三十张图, 一张一张手动处理我显然不太能受得了, 所以就写了个脚本来批量生成图表.

我的图表主要分为两类, 一类是柱状图, 这个主要是利用>$LaTeX$<的pgfplot包来画的, 为了批量修改图标样式, 所以利用\input给每张图配置了统一的模板; 另一类就是Visio了, 很多复杂的样式单纯使用>$LaTeX$<根本画不出来, 或者画起来很麻烦. 不过说起来, 使用>$LaTeX$<画的柱状图比起Excel生成的不知道好看到哪里去了(x

正片开始

我要实现的主要目标是, 能够自动识别我的源文件, 然后只要简单的一个make就能编译出我想要的图表.

对于>$LaTeX$<问题不大, 因为texlive本来就是命令行工具, 但是对于Visio来说就很麻烦了, 不过在万能的github上搜了搜发现了这个, 用了用发现这个本质上还是调起Visio然后自动另存为PDF= =它并不能脱离Visio单独使用
不过好在我的环境是Windows Linux Subsystem, 所以调起win32原生应用并不是一个太大的问题.

Makefile模板

# Common Command Alias
ECHO := @echo -e
MKDIR := mkdir -p
CP := cp
RMF := rm -f
RMD := rm -rf

# Function Command Alias
LATEXMK := latexmk -interaction=nonstopmode -file-line-error --outdir=output
VSDX2PDF := ../utils/OfficeToPDF.exe
PDFCROP := pdfcrop
PDF2EPS := pdftops -eps
LATEXINDENT := latexindent

主要是定义了一些常用的变量, 方便调用和修改.

  • LATEXMK是LateX的编译控制器, 会默认调用pdflatex去编译, 当然你可以通过参数选择你实际需要的编译器;
  • VSDX2PDF是之前介绍的, 可以将Visio自动转成PDF的工具;
  • PDFCROP用于自动裁剪白边, 无论是直接编译出的PDF还是VISIO转成的PDF都有白边, 手动去白边很累的;
  • PDF2EPS用于将PDF的图片转成EPS;
  • LATEXINDENT用于格式化tex文件(可能是我的强迫症

编译LATEX图表

include ../../mk/template.mk

OUTPUTDIR := output

SOURCES := .
TEXFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.tex)))
TARGETS := $(TEXFILES:.tex=)

TEMPLATES := template
TEMPLATEFILES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/$(TEMPLATES)/*.tex))

.PHONY: all install clean clean_aux $(TARGETS)
.PRECIOUS: $(OUTPUTDIR)/%.pdf $(OUTPUTDIR)/%.dvi $(OUTPUTDIR)/%.eps

all: $(TARGETS)
    $(ECHO) "\033[36mBuilding $@...\033[0m"

$(OUTPUTDIR):
    $(MKDIR) $(OUTPUTDIR)

$(TARGETS): %: $(OUTPUTDIR)/%.pdf $(OUTPUTDIR)/%.dvi $(OUTPUTDIR)/%.eps | $(OUTPUTDIR)
    $(ECHO) "\033[36mBuilding $@...\033[0m"
    @$(LATEXMK) -c $@.tex >> /dev/null 2>&1

$(OUTPUTDIR)/%.pdf: %.tex $(TEMPLATEFILES) | $(OUTPUTDIR)
    $(ECHO) "\033[36mBuilding $@...\033[0m"
    $(LATEXMK) -pdf $<

$(OUTPUTDIR)/%.dvi: %.tex $(TEMPLATEFILES) | $(OUTPUTDIR)
    $(ECHO) "\033[36mBuilding $@...\033[0m"
    $(LATEXMK) -dvi $<

$(OUTPUTDIR)/%.eps: $(OUTPUTDIR)/%.pdf | $(OUTPUTDIR)
    $(ECHO) "\033[36mBuilding $@...\033[0m"
    $(PDFCROP) $(OUTPUTDIR)/$(*F).pdf $(OUTPUTDIR)/$(*F).pdf
    $(PDF2EPS) $(OUTPUTDIR)/$(*F).pdf

install: $(TARGETS:%=../pdf/%.pdf) $(TARGETS:%=../dvi/%.dvi) $(TARGETS:%=../eps/%.eps)
    $(ECHO) "\033[36mInstalling Files...\033[0m"

$(TARGETS:%=../pdf/%.pdf): ../pdf/%.pdf: $(OUTPUTDIR)/%.pdf
    $(CP) $< $@

$(TARGETS:%=../dvi/%.dvi): ../dvi/%.dvi: $(OUTPUTDIR)/%.dvi
    $(CP) $< $@

$(TARGETS:%=../eps/%.eps): ../eps/%.eps: $(OUTPUTDIR)/%.eps
    $(CP) $< $@

clean_aux:
    $(ECHO) "\033[36mCleaning aux files...\033[0m"
    $(RMF) \
        $(OUTPUTDIR)/*.fdb_latexmk \
        $(OUTPUTDIR)/*.aux \
        $(OUTPUTDIR)/*.fls \
        $(OUTPUTDIR)/*.log \
        $(OUTPUTDIR)/*.synctex.gz

clean:
    $(ECHO) "\033[36mCleaning all files...\033[0m"
    $(RMD) $(OUTPUTDIR)

流程主要是这样子的:

  1. 扫描SOURCES目录下的.tex文件获得已有的TARGETS
  2. 扫描TEMPLATES目录下.tex文件获得已有的TEMPLATEFILES
  3. TARGETS目标转换为OUTPUTDIR/TARGET.pdf触发实际编译
  4. $(OUTPUTDIR)/%.pdf同时依赖源文件和TEMPLATEFILES, 实现源文件/模板修改后触发所有图表自动更新
  5. $(TARGETS:%=../pdf/%.pdf)的目标是为了将OUTPUTDIR下的输出文件安装到父目录的对应文件夹下

这样就可以实现自动识别目录下的源文件并自动编译了, 同时修改文件可以及时且不遗漏的触发增量编译.

编译VISIO图表

include ../../mk/template.mk

OUTPUTDIR := output

SOURCES := .
VSDXFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.vsdx)))
TARGETS := $(VSDXFILES:.vsdx=)

.PHONY: all install clean $(TARGETS)
.PRECIOUS: $(OUTPUTDIR)/%.pdf $(OUTPUTDIR)/%.eps

all: $(TARGETS)
    $(ECHO) "\033[36mBuilding $@...\033[0m"

$(OUTPUTDIR):
    $(MKDIR) $(OUTPUTDIR)

$(TARGETS): %: $(OUTPUTDIR)/%.pdf $(OUTPUTDIR)/%.eps | $(OUTPUTDIR)
    $(ECHO) "\033[36mBuilding $@...\033[0m"

$(OUTPUTDIR)/%.pdf: %.vsdx | $(OUTPUTDIR)
    $(VSDX2PDF) $< $@

$(OUTPUTDIR)/%.eps: $(OUTPUTDIR)/%.pdf | $(OUTPUTDIR)
    $(PDFCROP) $< $<
    $(PDF2EPS) $<

install: $(TARGETS:%=../pdf/%.pdf) $(TARGETS:%=../eps/%.eps)
    $(ECHO) "\033[36mInstalling Files...\033[0m"

$(TARGETS:%=../pdf/%.pdf): ../pdf/%.pdf: $(OUTPUTDIR)/%.pdf
    $(CP) $< $@

$(TARGETS:%=../eps/%.eps): ../eps/%.eps: $(OUTPUTDIR)/%.eps
    $(CP) $< $@

clean:
    $(ECHO) "\033[36mCleaning all files...\033[0m"
    $(RMD) $(OUTPUTDIR)

VISIO的编译流程与LATEX的类似, 只不过没有模板和DVI文件.

图表根目录

include ../mk/template.mk

SOURCES := BarChart DiscTree Visio 
OUTPUTS := pdf dvi eps

.PHONY: all clean $(SOURCES) $(SOURCES:%=clean_%)

all: $(SOURCES)
    $(ECHO) "\033[36mBuilding $@...\033[0m"

$(SOURCES): | $(OUTPUTS)
    $(ECHO) "\033[36mBuilding $@...\033[0m"
    make -C $@ all 
    make -C $@ install

$(OUTPUTS):
    $(MKDIR) $@

clean: $(SOURCES:%=clean_%)
    $(ECHO) "\033[36mCleaning all files...\033[0m"
    $(RMD) pdf dvi eps

$(SOURCES:%=clean_%):
    make -C $(@:clean_%=%) clean

这里的$(SOURCES:%=clean_%)是为了能使用类似于make clean_BarChart来单独清理BarChart子目录.

将各个子目录编译出的文件合并到根目录上并没有在根目录上来控制而是在各个子目录里install到根目录上来. 因为在根目录上很难做到这一点, 因为在编译开始前我对每个子目录到底有哪些目标文件是未知的, 只有在实际的编译流程开始以后才能知道, make(gnu)提供的控制指令有着很大的局限性, 如果用python编写类似的脚本是可以做到类似的需求的.

总结与思考

虽然说调试整个一套编译脚本花费了一定的时间(还包括论文的自动编译以及其他的一些, 不过都很类似), 但是对于整体效率的提升是非常巨大的.

在这之前, 对于LaTeX图表我需要单独每个编译出PDF, 对于Visio我需要每一个文件都点开然后另存为PDF. 同时, 对于裁白边, 都是通过Adobe Illustrator CC打开PDF, 然后全选内容导出资源为PDF, 非常累, 还可能碰到字体的问题. 此外, 还要再用Adobe Acrobat DC打开裁掉白边的PDF将其另存为eps.

图表比较少, 修改不大的时候, 这一套流程下来还可以接受, 但是图表一多, 简直要疯. 然后, 现在只要打开WSL然后make, 只要花上个厕所的时间, 就可以一键自动编译图表及论文了w

思考

  • WSL能够在运行Linux程序的前提下运行win32原生程序是一大优势
  • 以前编译OpenCV以及ROS的时候不知道为什么还要用cmakepython来控制编译, 现在深入用过一遍make以后觉得主要还是make存在着比较大的局限性

最后:

CLI大法好!

给博客增加MathJax支持


MathJax是一个非常著名的用于在网页中显示公式的JS库, 主要是你用类似于>$\LaTeX$<的语法写下公式他就会自动帮你渲染非常方便. 比如:

$$ E=mc^2 $$

或者更加复杂一点:

$$ \normalsize \varepsilon=\sum_{i=1}^{n-1} \frac1{\Delta x}\int\limits_{x_i}^{x_{i+1}}\left\{\frac1{\Delta x}\big[ (x_{i+1}-x)y_i^\ast+(x-x_i)y_{i+1}^\ast\big]-f(x)\right\}^2dx $$

以前我也弄过这个, 不过用的是第三方的插件, 然后和Markdown混合渲染问题也很多, 最近发现直接在footer.php里添加脚本来加载就好了. 地址用的是一个国内的CDN, 有空再把地址配置到服务器上去把Orz

然后我把行内触发的标签从$$改成了>$$<, 因为两个美元符号还是蛮容易误触发的...

<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        extensions: ["tex2jax.js"],
        jax: ["input/TeX", "output/HTML-CSS"],
        tex2jax: {
            inlineMath: [ ['>$','$<']],
            displayMath: [ ['$$','$$']],
            processEscapes: true
        },
        "HTML-CSS": { fonts: ["TeX"] }
    });
</script>
<script src='https://cdn.bootcss.com/mathjax/2.7.5/latest.js?config=TeX-MML-AM_CHTML' async></script>

顺便推荐一个MathTeX的参考网站参考书籍, 非常好使


利用VSCode构建简单的>$\LaTeX$<编辑器


起因

起因是因为要开始论文初稿的撰写, 然后需要使用>$\LaTeX$<. 虽然老板想让我在OverLeaf上写, 但是作为一个Vim党, 可能习惯了Vim的操作习惯以后就再也回不到纯文本的编辑上去了吧[笑]. 抛弃掉TexLive自带的TexWorks也是同理, VSCode的Vim插件总的来说还是挺好用的(虽然由于VSCode本身机制的问题会和一些插件不兼容, 比如acejump.

经过

现在是8102年了, 所以你需要的安装的是TexLive而不是CTex. 事实上, 对于中文现在TexLive也可以正常处理, 只要配置好字体就可以了1, 而且CTex也已经很久都没有更新过. 至于其他的发行版, 我只要求能用而且足够好用就可以了所以懒得圣战.

所以你需要的工具有:

安装方法非常简单:

  1. 安装VScode
  2. 安装TexLive2
  3. 安装Perl
  4. 打开终端运行tex看是否找到命令
  5. 安装VSCode的LaTeX Workshop插件
  6. 输入下列测试代码1保存:

    \documentclass[UTF8]{ctexart}
    \begin{document}
    你好,world!
    \end{document}
  7. 尝试运行左侧边栏的Build LaTeX Project - Recipe: latexmk/Recipe: pdflatex -> bibtex -> pdflatex*2应该都能够输出pdf
  8. 尝试运行左侧边栏的View LaTeX PDF - View in VSCode Tab/View in web browser就可以分别在VSCode的新标签页和浏览器打开了, 而且是会根据你编辑的内容实时刷新哟

其他的一些可能设置:

  • 输出到指定目录(比如./output)而不是根目录

    • 修改latex-workshop.latex.tools

          {
              "name": "latexmk",
              "command": "latexmk",
              "args": [
                  "-synctex=1",
                  "-interaction=nonstopmode",
                  "-file-line-error",
                  "-pdf",
                  "--outdir=output",
                  "%DOC%"
              ]
          },
    • 修改latex-workshop.latex.outputDir./output即可
  • 编译后清理掉中间文件

    • 修改latex-workshop.latex.tools

          {
              "name": "latexmk_build",
              "command": "latexmk",
              "args": [
                  "-synctex=1",
                  "-interaction=nonstopmode",
                  "-file-line-error",
                  "-pdf",
                  "--outdir=output",
                  "%DOC%"
              ]
          },
          {
              "name": "latexmk_clean",
              "command": "latexmk",
              "args": [
                  "-c",
                  "--outdir=output",
                  "%DOC%"
              ]
          },
    • 修改latex-workshop.latex.recipes

          {
              "name": "latexmk",
              "tools": [
                  "latexmk_build",
                  "latexmk_clean"
              ]
          },
  • 比如想要使用xelatex来排版

    • 打开VSCode的配置文件
    • latex-workshop.latex.recipes中加入如下内容:

      {
          "name": "xelatex",
          "tools": [
              "xelatex"
          ]
      },
    • latex-workshop.latex.tools中加入如下内容:

      {
          "name": "xelatex -> bibtex -> xelatex*2",
          "tools": [
              "xelatex",
              "bibtex",
              "xelatex",
              "xelatex"
          ]
      },
      {
          "name": "xelatex",
          "tools": [
              "xelatex",
          ]
      },
    • 重启VScode, 你就可以在Build LaTeX Project下看到新添加的Recipe了~

      xelatex -> bibtex -> xelatex*2用于处理需要bbl的情况, xelatex则用于纯>$\LaTeX$<环境下使用.
  • 在工作区排除掉LaTeX编译中间文件的显示

    • 加入如下配置到配置文件即可:

      "files.exclude": {
          "**/*.aux": true,
          "**/*.fdb_latexmk": true,
          "**/*.fls": true,
          "**/*.log": true,
          "**/*.synctex.gz": true,
          "**/*.bbl": true,
          "**/*.blg": true
      },
  • 补充一下自动clean的文件

    • latex-workshop.latex.clean.fileTypes中加入如下内容:

      "latex-workshop.latex.clean.fileTypes": [
          "*.aux",
          "*.bbl",
          "*.blg",
          "*.idx",
          "*.ind",
          "*.lof",
          "*.lot",
          "*.out",
          "*.toc",
          "*.acn",
          "*.acr",
          "*.alg",
          "*.glg",
          "*.glo",
          "*.gls",
          "*.ist",
          "*.fls",
          "*.log",
          "*.fdb_latexmk",
          "*.synctex.gz"
      ],
  • 其他的一些额外的有用的提示

    • 在VSCode的输出面板有LaTex WorkshopLaTeX Compiler两个输出选项, LaTex Workshop是LaTeX输出插件的日志, LaTeX Compiler是LaTeX编译器的输出日志
    • 如果没有pdf文件输出请检查编译器的日志, 查看VSCode是否找到了编译器是否正确编译
    • 如果有pdf文件, 但是pdf文件没有被打开请检查插件日志, 默认是打开主tex文件下同名pdf文件, 如果配置了输出目录需要修改配置latex-workshop.latex.outputDir

总结

VSCode不愧是一个全能型轻量级IDE, 通过各种插件的组合能够实现IDE的基本功能, 当然缺点主要是打开反应慢(和Sublime相比), 而且有些操作逻辑很迷(比如拖出标签页是保存文件???).

不过通过这一系列配置之后基本能实现实时预览和编写, 而且支持VScode完善的现代编辑器操作, 还是非常好评的w