关于绘图软件的一点注记

       这几天读了一些代码和几个宏包的说明文档,算是对画图有点小小的心得体会吧。

       一般来说图片可以分为两大类:一是点阵图,二是矢量图。所谓点阵图,说的通俗点就是放大后会引起失真有锯齿状的图片,这类图片很常见,比如 jpg,gif,bmp  等都是点阵图格式。这类图片很容易获得,当然缺点也是非常明显的,就是图片质量不高。所谓矢量图就是可以任意放缩、坐标变换而不会丢失信息,图形不会产生锯齿效果。这类图的优点自然不用说了。绝大多数绘图软件都可以生成点阵图,生成矢量图的软件相对少一些,比如 CorelDRAW、Illustrator、Inkscape 等。

      如此,绘图软件自然也可以分为两种。下面将着重介绍绘制矢量图的工具。矢量绘图软件也可以分为两类 (其实所有的绘图软件都可以这么分类): 一类是 GUI ( Graphical User Interface,图形用户界面,属于可视化 ) 的, 另一类是 CLI ( Command  lineinterface,命令行) 的,两种工具也大体代表了不同的理念。前者是 WYSIWYG  (What You See Is What You Get),所见即所得;后者是 WYTIWYG (What You Think Is What You Get),所思即所得。具体到应用上,前者以 CorelDRAW、Adobe Illustrator、Inkscape 等为代表,后者以基于 LaTeX 的各种软件或宏包为代表。本文只罗列这两类常用的软件,不涉及优劣比较。事实上,不同的软件有不同的侧重面,确实无法绝对的说哪种好哪种坏。

      一、GUI

      前面已经说过 CorelDRAW、Adobe Illustrator、Inkscape 是 GUI 绘图软件中比较常见功能也最强大的软件。CorelDRAW 和 Inkscape 我都用过,它们的界面非常像,功能也相当。不同的是 CorelDRAW 是商业软件 (网上有破解版的), 而 Inkscape 是开源跨平台的软件 (目前最新版本是 0.91)。现在一直在用的就是 Inkscape,除了因为它是开源的外,最主要的原因是它支持 LaTeX 数学公式扩展,就是用 Inkscape 画图时,其中可以使用 LaTeX 命令生成漂亮的公式标注。这是其它软件不具备的 (CorelDRAW 中使用公式需要从 Mathtype 或 Word 中复制过去)。下图就是 Inkscape 的操作界面。

       

       二、 CLI    

      目前科技论文写作大都用的是 LaTeX 排版系统,尤其是投国外 SCI 杂志,他们几乎都会要求用 LaTeX书写,可能不仅是因为它完全免费、可跨平台移植,最主要的是其排版精美漂亮甚至超过了一些商业软件。LaTeX 本身也自带了一些画图功能,不过只能画一些简单的交换图等。我们可以利用一些基于 TeX 系统的宏包或工具来实现画矢量图的目的。这其中最著名的有如下四个:

      1. Metapost
      2. Asymptote
      3. PGF/TiKZ
      4. Pstriks
 
       前两者属于离线做图工具;后两者属于在线做图工具。什么叫离线做图工具? 什么又叫在线做图工具? 简单来说,离线做图就是单独建立文件,然后生成 pdf  或 eps 等独立的图形文件,通过 \includegraphics 命令将图形文件嵌入到 LaTeX 文件中。 Metapost  和 Asymptote 属于这种。在线做图就是直接在 TeX 文件中输入相应宏包的绘图命令,经过处理后直接生成图形。PGF\TiKZ 和 Pstricks 属于此类。

       从语法上来说,Metapost 据说其语法比较怪异,很难学的精通 (我没有用过,只是听说);Asymptote 以前我用过,它的语法类似于 C/C++ (C 语言确实牛啊),后来之所以放弃主要是因为感觉离线作图不太方便 (纯个人感受);Pstricks 基于 Postscript,据说比较强大,但是我没用过,不予置评。

      从功能上来说,各有所长,Metapost 可以解方程;Asymptote 的 3D 效果很不错。这两种方式并没有优劣之别。离线做图更灵活,在线做图则更加方便,关键看个人喜好,就像比较 Vim 和 Emacs 哪个更好,我想答案只有程序员自己最明白。

      下面说一下 PGF/TiKZ,这是我现在正在用的,本身 PGF/TiKZ 是 TeX 的一个扩展宏包,使用非常方便,只需在 TeX 文档的导言区加入命令 \usepackage{tikz} 就可以使用了。目前 PGF/TiKZ 可画的图形种类很多,像流程图、有限状态机图、神经网络图、二维/三维数据图等等。利用 PGF/TiKZ 的 plot 命令可以画一些不太复杂的函数图形,如果图形很复杂我们还有办法,那就是用基于 PGF/TiKZ 的另一个宏包 pgfplots (其实 PGF/TiKZ 也可以,不过 pgfplots 更强) 和其它软件 (比如 Gnuplot,R,Matlab,Mathematica 等) 结合来绘图。你也许会问为什么不直接用 Gnuplot 这类软件画图呢,还搞得这么麻烦?那是因为虽然 Gnuplot,Matlab 这类软件画图方便,但是它们画出的图不好看,尤其是标注自定义性很差,这会导致图片与论文整体风格很不搭。这也许就是你看外国人的论文里图片都非常漂亮而自己画的图却不怎么好看的原因了。简单来说,以 Mathematica 为例,我们可以用其强大的数据处理能力生成绘图所需要的数据,先以文件形式导出 Mathematica 处理的数据( .txt 或 .dat 等),这一点很容易做到,只需要几行 Mathematica 命令就搞定了,然后用命令 \addplot{filename.dat} 调用之前处理好的数据供 pgfplots 使用就 ok 了,这样就会画出既漂亮又可以自己定义标注风格的矢量图了。如果使用 Matlab 画图,还有一个更方便的办法,那就是使用 matlab2tikz,这是一个 matlab 脚本文件,可以将图片的文件信息生成后缀为 .tkz 或 .tex 的文件,剩下的就是 \input 进 LaTeX 源文件编译就行了。是不是 so easy!再也不用担心我的图片了 。。。

      不管是 GUI 还是 CLI 的作图工具都有各种的优点和缺点。GUI 更加直观,这正是 CLI 的缺点;CLI 画图更加精确,而 GUI 则显得有些粗糙,不是那么的精细。没有哪一类工具可以通杀所有图形,二者结合起来是很明智的选择。当用 GUI 可以方便快速的画出来时,完全没有必要用 CLI 去画,反之亦然。比如下面这个 Petersen 图用 Inkscape 就很容易画出来,此时就没必要用 TiKZ 等工具来画了。

  

然而,如果是下面这幅图呢?显而易见,如果使用 Inkscape 等 GUI 工具的话是非常麻烦的。

而如果使用 TiKZ 的话只需要下面这些代码就可以完成:

 1 \documentclass{minimal}
 2 \usepackage{tikz}
 3 \usetikzlibrary{calc}
 4 
 5 \begin{document}
 6 \pgfdeclarelayer{background}
 7 \pgfdeclarelayer{foreground}
 8 \pgfsetlayers{background,main,foreground}
 9 \xdefinecolor{darkgreen}{RGB}{175, 193, 36}
10 \newcounter{cntShader}
11 \newcounter{cntRoot}
12 \setcounter{cntShader}{20}
13 \def\couleur{darkgreen}
14 
15 \begin{tikzpicture}
16     \foreach \y in {86,38,15}{
17         \setcounter{cntShader}{1}
18         \coordinate (a) at (0,0);
19         \coordinate (b) at (0:1);
20         \foreach \x in {1,...,\y}{%
21             \coordinate (c) at ($ (b)!1cm!270:(a) $);
22             \begin{pgfonlayer}{background}
23                 \draw[fill=\couleur!\thecntShader] (a)--(b)--(c)--cycle;
24             \end{pgfonlayer}
25             \setcounter{cntRoot}{\x}
26             \addtocounter{cntRoot}{1}
27             \node[fill=white,draw,circle,inner sep=1pt] at (c)
28                 {$\sqrt{\thecntRoot}$};
29             \coordinate (b) at (c);
30             \pgfmathsetcounter{cntShader}{\thecntShader+4}
31             \setcounter{cntShader}{\thecntShader}
32        }
33     }
34     \node[fill=white,draw,circle,inner sep=1pt] at (0:1) {$\sqrt{1}$};
35 \end{tikzpicture}
36 
37 \end{document} 
posted @ 2015-06-15 12:42  LaTeXmath  阅读(1610)  评论(0编辑  收藏  举报