高质量绘图方式

2020-03-19

前言

在写论文或者是博客的时候,部分内容附以图片辅助说明,可能会使文章总体上看起来更加直观、生动和详实一些,那这些博客或者说是论文当中的插图(Figures)可以由哪些好用的工具来画呢?

SVG

其实吧SVG它不是一个特定的工具,而是一种语言标准,叫做Scalable Vector Graphics,最早是由World Wide Web Consortium (W3C) 在1999指定的,现在最新的SVG标准是2011年推出的SVG 1.1,当我们说以SVG的方式作图的时候其实是说以SVG这种图形描述语言来描述图形,具体是用一个文本编辑器把这些SVG语言表述的图像描述记下来,再交由能够渲染SVG图形的软件来渲染和显示.

SVG绘图实例

首先你可以打开一个记事本(如果用的是Windows操作系统)或者是用VIM、VS Code之类的文本编辑器来新建一个文本文件,把下面这段内容粘贴上并且保存为后缀名为.svg的文件,比如说learnsvg.svg

<svg version="1.1"
     baseProfile="full"
     width="300" height="200"
     xmlns="http://www.w3.org/2000/svg">

  <rect width="100%" height="100%" fill="lightblue" />

  <circle cx="150" cy="100" r="80" fill="darkgreen" />

  <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>

</svg>

那么接下来,其实也不需要特定的SVG打开工具,用Chrome浏览器或者Firefox浏览器就能打开这个svg文件,效果是这样的

Chrome浏览器打开svg文件的效果

如果你是写博客的话,SVG绘图方式那就更加方便了,上面那段内容直接就当成HTML内容嵌入在网页中,比如说我用Hugo写博客,那么要在文章中嵌入纯HTML内容可以用{{< raw >}} ShortCode,比如说在Markdown文件中插入下面这部分

{{< raw >}}
<svg version="1.1"
     baseProfile="full"
     width="300" height="200"
     xmlns="http://www.w3.org/2000/svg">

  <rect width="100%" height="100%" fill="lightblue" />

  <circle cx="150" cy="100" r="80" fill="darkgreen" />

  <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>

</svg>
{{</ raw >}}

那Hugo渲染网页得到的效果就是

SVG

就直接在网页上显示出来了,无需截图,这里为了美观我给svg元素加了居中效果和边框(以CSS的方式.如果要修改图形的画,可以直接修改HTML,也就是上面那段代码当中的几何参数,甚至可以通过JavaScript的方式自动修改,可以很方便地做出动画效果,仅仅是通过程序代码来修改svg元素的图形参数,而无需关系底层的像素是怎么一个个画上去的,很方便.

SVG是一种适用范围更广的标准

首推SVG方式绘图是因为SVG是一个适用范围更广的标准,它和其他更加专门的标准不一样.

MetaPost

在论文中直接插入SVG格式的图像文件其实并不是太方便,但是流行的TeX引擎如XeLaTex和LaTeX图像扩展包如graphicx对PNG格式,EPS格式和PDF格式的图形都有很好的支持.

MetaPost可以指MetaPost作为一种图形语言,也可以指MetaPost作为将MetaPost代码编译为EPS图形文件的编译器,和SVG一样,MetaPost也有一套自己的描述图形的语法,下面一段MetaPost代码

beginfig(18);
numeric u;
u = 1cm;
draw (0,2u)--(0,0)--(4u,0);
pickup pencircle scaled 1pt;
draw (0,0){up}
for i=1 upto 8: ..(i/2,sqrt(i/2))*u endfor;
label.lrt(btex $\sqrt x$ etex, (3,sqrt 3)*u);
label.bot(btex $x$ etex, (2u,0));
label.lft(btex $y$ etex, (0,u));
endfig;

可以用来画出这么一幅图像

MetaPost 产出的图像

如果输出的是EPS格式的文件,可以导入到LaTeX论文中,利用graphicx宏包:

includegraphics{metapost-test.eps}

在VS Code中会是这样的效果(用了Latex-WorkShop扩展)

MetaPost with VS Code

MetaPost的优点是比较灵活和精确,缺点是太过繁琐,当图形的数学结构非常确定的时候,我们想要声明式的画图而非命令式的画图,怎样实现呢?

Graphviz

可以使用Graphviz,一款开源的图(Graph)可视化软件,准确的说Graphviz是一系列图布局引擎和dot语言组成的,各个布局引擎根据不同的图布局算法(Layout Algorithms)来将dot语言描述的数学上的「图」转化为计算机软件能够显示的图形文件.

例如,我们希望用图形的方式表示这样的树形结构(树是图的一种):html是根节点,head节点和body节点是html节点的子节点,title节点是head节点的子节点,h1节点和p节点是body节点的子节点,字符串节点 “Hello!” 是 p 节点的子节点,字符串节点 “Greetings” 是 h1 节点的子节点,我们希望用树状图的方式描绘出这个树形结构,如何实现呢?

首先用dot语言明确定义这个树的数学结构:都有哪些节点,以及谁和谁连接:

digraph {
    node [shape=record];

    html -> {head, body};
    head -> title;
    body -> {h1, p};
    h1 -> {"\"Greetings\""};
    p -> {"\"Hello!\""};
}

如果安装了Graphviz Preview扩展,在VS Code上可以实时看到相应的预览

Graphviz Preview in VS Code

将dot代码文件保存为.gv后缀的文件(Graphviz文件),然后可以用dot布局引擎生成图形文件:

dot -Teps graphviz-demonstration.gv -O

默认文件名是原文件名加上生成格式的后缀名,这里就是graphviz-demonstration.gv.eps,可以在LaTeX论文中引用它:

Graphviz用在LaTeX论文中

也可以生成svg格式的图形放到网页上面来显示

Graphviz生成svg图形

在R软件中生成高质量的图像

可以借助ggplot2软件包实现,下面使用R软件自带的mpg数据集

library("ggplot2");
pdf(file="hwy_vs_displ-1.pdf", width=6, height=4);
ggplot(mpg, aes(displ, hwy, colour = class)) + geom_point();
dev.off()

可以得到高质量的PDF文件,PDF文件保存的是图形的数学结构(向量),是可以无限放大而不失真的:

ggplot2生成的PDF文件

如果再mac系统中想输出包含中文的图形,可以借助showtext包轻松的实现:

library("ggplot2");
library("showtext");
showtext_auto();
pdf(file="hwy_vs_displ-2.pdf", width=6, height=4);
ggplot(mpg, aes(displ, hwy, colour = class)) + geom_point() + xlab("排量") + ylab("百里油耗");
dev.off()

生成的PDF文件如下图所示

ggplot2生成的PDF文件

这里得到的PDF是可以通过graphicx宏包的/includegraphics命令导入到LaTeX论文中的.

最佳实践

建议您

  • 学习并掌握开源的绘图软件,以获得可迁移的技能
  • 尽可能通过数学方式描绘图形
  • 尽可能确保图形文件保存了图形的数学结构(向量)
  • 尽可能用描述式而非命令式的方式作图
  • 仔细阅读所使用的软件的自动化作图方式,并学习如何将所生成的图形保存为向量图文件

不建议您

  • 以位图的格式生成图形文件并保持,如JP(E)G格式,PNG格式,BMP格式等.
  • 在论文中嵌入由屏幕截图得到的图表
  • 在论文中嵌入由手机拍照保存的图表

总结

在这篇文章中我们解释了几种高质量的作图方式,它们的主要特点是能够输出高质量的向量图文件,并且这类向量图文件可以用在多种媒介中(网页、论文等),这几种作图方式各有自己擅长的和不擅长的,例如SVG作图的方式适用于网页,MetaPost适用于在论文中插入精巧和高度自定义的矢量图,Graphviz擅长以描述的方式进行图的可视化,ggplot2适用于一般数据的可视.希望你能有所收获.

参考文献

[1] Scalable Vector Graphics (SVG) 1.1 (Second Edition)

[2] 入门 - SVG | MDN

[3] MetaPost - TeX Users Group

[4] Graph drawing - Wikipedia

[5] Graphviz - Graph Visualization Software

[6] CRAN - Package ggplot2

经验分享drawingfiguresgraphics

CDN部署过程全记录:原理和实践

修复CloudCone VPS无法自动同步时间的问题