前言
在写论文或者是博客的时候,部分内容附以图片辅助说明,可能会使文章总体上看起来更加直观、生动和详实一些,那这些博客或者说是论文当中的插图(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文件,效果是这样的
如果你是写博客的话,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元素加了居中效果和边框(以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;
可以用来画出这么一幅图像
如果输出的是EPS格式的文件,可以导入到LaTeX论文中,利用graphicx
宏包:
includegraphics{metapost-test.eps}
在VS Code中会是这样的效果(用了Latex-WorkShop扩展)
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上可以实时看到相应的预览
将dot代码文件保存为.gv
后缀的文件(Graphviz文件),然后可以用dot布局引擎生成图形文件:
dot -Teps graphviz-demonstration.gv -O
默认文件名是原文件名加上生成格式的后缀名,这里就是graphviz-demonstration.gv.eps
,可以在LaTeX论文中引用它:
也可以生成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文件保存的是图形的数学结构(向量),是可以无限放大而不失真的:
如果再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文件如下图所示
这里得到的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