该绘图工具的应用也很广,但是之前一直都没有能够接触到。现在才将相关的内容补充到笔记当中,希望这是一个非常有效的绘图的工具。
MathGL在Ubuntu下的安装是一件简单的事,安装mathgl关键字开头的程序、文档、头文件与库文件、面向Python语言的python-mathgl库,以及udav可视化工具即可。MathGL支持几种不同的编程方式,面向C、C++、Fortran、Octave或者Python。根据需要,应当安装上不同的接口。也许有一天,支持R也是可行的。此外,MathGL工具还可以分析一种称为MGL的脚本文件,该脚本文件可以方便地完成MathGL中的一些绘图操作,是值得学习的一种操作方式。
在绘图过程中,MathGL有自己的字体系统,但是尽量可以做到与TeX的兼容。不仅可以方便地选择字体,而且提供了大量的数学符号。这些对于初学者及一般的应用都是非常充足的。
MathGL有很多优点。如脚本化的绘图语言、C++的执行效率、多语言接口、支持输出多种图形格式、内建多种绘图方法、支持MPI等编程接口、与C++等宿主语言的数据结构融合。这些使它成为很有吸引力的一个绘图库。
MathGL基础操作
首先我们介绍在MathGL在C++下的使用。像C++这类接口,一般要安装lib*这样的软件包,而不只mathgl软件包一个,这样g++在编译的时候,才可能与正确的库文件链接。这是一个需要注意的地方。如果下面的MathGL C++程序出错,根据编译器反馈的错误信息,我们应当能够发现错误、纠正错误。
#include <mgl2/mgl.h>
int main(int argc, char* argv[])
{
mglGraph graph;
graph.FPlot("sin(pi*x)");
graph.WriteFrame("test.png");
return 0;
}编译、运行mathgl1.cpp,查看图片所使用的Bash命令建议为:
g++ -lmgl mathgl1.cpp -o mathgl1
./mathgl1
eog sample.png
注:如果使用了其它的绘图接口,可能需要使用 -lmgl-wnd 等库。
MathGL的绘图画布中使用帧、子图等概念,因此一个 mglGraph对象可以创造出多个子图的组合,以及多个帧的组合。后者使MathGL有制作动画的能力。
使用MGL脚本的时候,MathGL中有 mglconv 工具和 mglview工具可以使用。它们 是运行MGL脚本的宿主环境。
MathGL库支持的输出方式,包括向图形终端输出,此方式下可以完成一些交互式的动作;直接写入到点阵或者矢量图形格式,此方式下直接运行MathGL的C++程序以得到结果。
窗口绘图、GLUT绘图与输出到文件
绘图到一个单独的窗口,或者使用GLUT库输出,道理是一样的。
#include <mgl2/mgl.h>
#include <mgl2/window.h>
int do_draw(mglGraph *graph)
{
graph->Rotate(60,40);
graph->Box();
return 0;
}
int main(int argc, char* argv[])
{
mglWindow window(do_draw, "MathGL Window example');
int status = window.Run();
return status;
}原理就是如此了,不过在Ubuntu上有些错误,可能是安装MathGL的问题。
使用GLUT作为后端的时候,更为简单,因为不用WX组件了。
#include <mgl2/mgl.h>
#include <mgl2/glut.h>
int do_draw(mglGraph *graph)
{
graph->Rotate(60,40);
graph->Box();
return 0;
}
int main(int argc, char* argv[])
{
mglGLUT window(do_draw, "MathGL Window example");
return 0;
}在编译的时候,调用
g++ mglut.cpp -o mglut -lmgl -lmgl-glut
如果将 -lmgl 选项放在 mglut.cpp的前面,似乎总会出现连接错误。这个问题 目前还不知道是怎么样的一回事。
在GLUT界面中,使用aswd按键旋转图形,使用r与f切换透明(transparency)与光照(lighting)状态。按键x可以退出窗口。
说明:以后我们的绘图的时候,就使用上面的代码所提供的方法,把绘图的代码都放在 do\_draw() 函数里面,然后由 mglGLUT对象调用。这样可以使我们更 专心于图形的绘制。
如果是输出到文件,那么调用 mglGraph 对象的 WritePNG()、 WriteEPS() 等 函数即可。在使用g++编译的时候,除了-lmgl 选项,其它都不用。
动画的制作使用 mglGraph对象的多帧功能。如果是保存GIF格式,在绘出每帧 之前,就应当使用mglGraph 的 StartGIF() 函数保存文件,并在完成所有的帧的绘制之后使用 CloseGIF() 函数关闭GIF文件的描述符。
保存动画还有另一种方法,就是绘制完当前帧后,以frameXX.jpg的格式保存当前帧,然后切换到下一帧。所有的帧都各自输出成JPEG格式后,使用ImageMagick提供的convert命令将JPEG制作成MPG。
MathGL也支持在Qt绘图画布中绘图,图形作为Qt窗口的一部分。但是那并非MathGL绘图语言的核心。现在不讲,或许以后结合PyQt库使用MathGL的时候这个功能我们会用到。
MathGL对子图绘制的支持
MathGL采用“选中-绘制”的方法支持子图的绘制,也就是一个mglGraph 对象使用 SubPlot()方法选中一块子图区域,之后还是使用 mglGraph 对象的Title()等函数来操作绘图,此时图形会自动绘制在当前的子图上。在绘制子图的时候,另一种编程实现是“切换-绘制”的方法。该方法是调用当前绘图对象的方法产生一个子图对象,通过操作子图对象的方法在子图上绘图。Asymptote与Mathplotlib等都是采用这种方法。MathGL是前一种方法,因此要与后一种实现方式区分开。
int do_draw(mglGraph *g)
{
g->SubPlot(2,2,0); g->Box();
g->Puts(mglPoint(-1,1,1),:"Just box", ":L");
g->InPlot(0.2,0.5,0.7,1,false);
g->Box();
g->Puts(mglPoint(0,1.2), "InPlot Example");
g->SubPlot(2,2,1);
g->Title("Rotate only");
g->Rotate(50,60);
g->Box();
g->SubPlot(2,2,2);
g->Title("Rotate and Aspect");
g->Rotate(50,60);
g->Aspect(1,1,2);
g->Box();
g->SubPlot(2,2,3);
g->Title("Aspect in other direction");
g->Rotate(50,60);
g->Aspect(1,2,2);
g->Box();
return 0;
}更复杂的子图绘制方式,可以参考 MultiPlot() 、StickPlot() 等函数。
剩下的就是具体各种图形的绘制了。
使用MathGL绘制动画示例
int do_draw(mglGraph *gr)
{
gr->NewFrame();
gr->Rotate(60,40);
gr->Box();
gr->EndFrame();
gr->NewFrame();
gr->Box();
gr->Axis("xy");
gr->EndFrame();
return gr->GetNumFrame();
}使用MGL脚本语言
MGL脚本语言其实是很方便的一个东西。该语言每一行都代表一个命令,类似于tcl脚本,而且连注释的格式都是与tcl语言相同的:从#开始直到行尾。另一方面,MGL脚本按行分析语句,语句的第一个单词代表一个命令,像Bash中那样。而MGL脚本中的字符串用成对的单引号括起来,如果需要跨行,则使用反斜杠加换行表示将本行与下一行联系在一起。
MGL脚本中的命令都来自 mglGraph的成员函数,因此只要我们了解了MathGL面向C++的库的用法,自然就知道如何写MGL脚本文件。
除此之外,MGL还有一些定义函数、声明变量的语句。它们都转成相应的C++的语法。在C++中使用MGL语言也是可行的,因为MGL脚本会通过 Parse()函数 被解析,由 Execute()函数执行。(两个函数都在mgl2/mgl.h头文件中)。
A. A. Balakin所蓍的《MathGL官方文档》中的《MathGL core》一章,既介绍了MathGL语言(C++库的函数),同时又介绍了MGL的命令,是MGL语言与MathGL库的最标准的参考手册。
MathGL所提供的mglconv工具可以将MGL脚本转换成PGF/TikZ、EPS、PRC、SVG等格式,因此也可以作为一个实用的面向TeX文档的接口。这样一来,可能在MathGL中文字处理变得更简单了。