[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
MathGL library can be used by several manners. Each has positive and negative sides:
Positive side is the possibility to view the plot at once and to modify it (rotate, zoom or switch on transparency or lighting) by hand or by mouse. Negative sides are: the need of X-terminal and limitation consisting in working with the only one set of data at a time.
Positive aspects are: batch processing of similar data set (for example, a set of resulting data files for different calculation parameters), running from the console program (including the cluster calculation), fast and automated drawing, saving pictures for further analysis (or demonstration). Negative sides are: the usage of the external program for picture viewing. Also, the data plotting is non-visual. So, you have to imagine the picture (view angles, lighting and so on) before the plotting. I recommend to use graphical window for determining the optimal parameters of plotting on the base of some typical data set. And later use these parameters for batch processing in console program.
In this case the programmer has more freedom in selecting the window libraries (not only FLTK, Qt or GLUT), in positioning and surroundings control and so on. I recommend to use such way for “stand alone” programs.
Here one can use a set of standard widgets which support export to many file formats, copying to clipboard, handle mouse and so on.
MathGL drawing can be created not only by object oriented languages (like, C++ or Python), but also by pure C or Fortran-like languages. The usage of last one is mostly identical to usage of classes (except the different function names). But there are some differences. C functions must have argument HMGL (for graphics) and/or HMDT (for data arrays) which specifies the object for drawing or manipulating (changing). Fortran users may regard these variables as integer. So, firstly the user has to create this object by function mgl_create_*() and has to delete it after the using by function mgl_delete_*().
Let me consider the aforesaid in more detail.
2.1.1 Using MathGL window | ||
2.1.2 Drawing to file | ||
2.1.3 Animation | ||
2.1.4 Drawing in memory | ||
2.1.5 Using QMathGL | ||
2.1.6 MathGL and PyQt | ||
2.1.7 MathGL and MPI |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The “interactive” way of drawing in MathGL consists in window creation with help of class mglWindow
or mglGLUT
(see “Оконные” классы) and the following drawing in this window. There is a corresponding code:
#include <mgl2/window.h> int sample(mglGraph *gr) { gr->Rotate(60,40); gr->Box(); return 0; } //----------------------------------------------------- int main(int argc,char **argv) { mglWindow gr(sample,"MathGL examples"); return gr.Run(); }
Here callback function sample
is defined. This function does all drawing. Other function main
is entry point function for console program. For compilation, just execute the command
gcc test.cpp -lmgl-wnd -lmgl
Alternatively you can create yours own class inherited from class mglDraw
and re-implement the function Draw()
in it:
#include <mgl2/window.h> class Foo : public mglDraw { public: int Draw(mglGraph *gr); }; //----------------------------------------------------- int Foo::Draw(mglGraph *gr) { gr->Rotate(60,40); gr->Box(); return 0; } //----------------------------------------------------- int main(int argc,char **argv) { Foo foo; mglWindow gr(&foo,"MathGL examples"); return gr.Run(); }
Or use pure C-functions:
#include <mgl2/mgl_cf.h> int sample(HMGL gr, void *) { mgl_rotate(gr,60,40,0); mgl_box(gr); } int main(int argc,char **argv) { HMGL gr; gr = mgl_create_graph_qt(sample,"MathGL examples",0,0); return mgl_qt_run(); /* generally I should call mgl_delete_graph() here, * but I omit it in main() function. */ }
The similar code can be written for mglGLUT
window (function sample()
is the same):
#include <mgl2/glut.h> int main(int argc,char **argv) { mglGLUT gr(sample,"MathGL examples"); return 0; }
The rotation, shift, zooming, switching on/off transparency and lighting can be done with help of tool-buttons (for mglWindow
) or by hot-keys: ‘a’, ‘d’, ‘w’, ‘s’ for plot rotation, ‘r’ and ‘f’ switching on/off transparency and lighting. Press ‘x’ for exit (or closing the window).
In this example function sample
rotates axes (Rotate()
, see section Матрица преобразования) and draws the bounding box (Box()
). Drawing is placed in separate function since it will be used on demand when window canvas needs to be redrawn.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Another way of using MathGL library is the direct writing of the picture to the file. It is most usable for plot creation during long calculation or for using of small programs (like Matlab or Scilab scripts) for visualizing repetitive sets of data. But the speed of drawing is much higher in comparison with a script language.
The following code produces a bitmap PNG picture:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; gr.Alpha(true); gr.Light(true); sample(&gr); // The same drawing function. gr.WritePNG("test.png"); // Don't forget to save the result! return 0; }
For compilation, you need only libmgl library not the one with widgets
gcc test.cpp -lmgl
This can be important if you create a console program in computer/cluster where X-server (and widgets) is inaccessible.
The only difference from the previous variant (using windows) is manual switching on the transparency Alpha
and lightning Light
, if you need it. The usage of frames (see Animation) is not advisable since the whole image is prepared each time. If function sample
contains frames then only last one will be saved to the file. In principle, one does not need to separate drawing functions in case of direct file writing in consequence of the single calling of this function for each picture. However, one may use the same drawing procedure to create a plot with changeable parameters, to export in different file types, to emphasize the drawing code and so on. So, in future I will put the drawing in the separate function.
The code for export into other formats (for example, into vector EPS file) looks the same:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; gr.Light(true); sample(&gr); // The same drawing function. gr.WriteEPS("test.eps"); // Don't forget to save the result! return 0; }
The difference from the previous one is using other function WriteEPS()
for EPS format instead of function WritePNG()
. Also, there is no switching on of the plot transparency Alpha
since EPS format does not support it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Widget classes (mglWindow
, mglGLUT
) support a delayed drawing, when all plotting functions are called once at the beginning of writing to memory lists. Further program displays the saved lists faster. Resulting redrawing will be faster but it requires sufficient memory. Several lists (frames) can be displayed one after another (by pressing ‘,’, ‘.’) or run as cinema. To switch these feature on one needs to modify function sample
:
int sample(mglGraph *gr) { gr->NewFrame(); // the first frame gr->Rotate(60,40); gr->Box(); gr->EndFrame(); // end of the first frame gr->NewFrame(); // the second frame gr->Box(); gr->Axis("xy"); gr->EndFrame(); // end of the second frame return gr->GetNumFrame(); // returns the frame number }
First, the function creates a frame by calling NewFrame()
for rotated axes and draws the bounding box. The function EndFrame()
must be called after the frame drawing! The second frame contains the bounding box and axes Axis("xy")
in the initial (unrotated) coordinates. Function sample
returns the number of created frames GetNumFrame()
.
Note, that such kind of animation is rather slow and not well suitable for visualization of running calculations. For the last case one can use Update()
function. The most simple case for doing this is to use mglDraw
class and reimplement its Calc()
method.
#include <mgl2/window.h> class Foo : public mglDraw { mglPoint pnt; // some result of calculation public: mglWindow *Gr; // graphics to be updated int Draw(mglGraph *gr); void Calc(); } foo; //----------------------------------------------------- void Foo::Calc() { for(int i=0;i<30;i++) // do calculation { sleep(2); // which can be very long pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1); Gr->Update(); // update window } } //----------------------------------------------------- int Foo::Draw(mglGraph *gr) { gr->Line(mglPoint(),pnt,"Ar2"); gr->Box(); return 0; } //----------------------------------------------------- int main(int argc,char **argv) { mglWindow gr(&foo,"MathGL examples"); foo.Gr = &gr; foo.Run(); return gr.Run(); }
Previous sample can be run in C++ only since it use C++ class mglDraw. However similar idea can be used even in Fortran or SWIG-based (Python/Octave/...) if one use FLTK window. Such limitation come from the Qt requirement to be run in the primary thread only. The sample code will be:
int main(int argc,char **argv) { mglWindow gr("test"); // create window gr.RunThr(); // run event loop in separate thread for(int i=0;i<10;i++) // do calculation { sleep(1); // which can be very long pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1); gr.Clf(); // make new drawing gr.Line(mglPoint(),pnt,"Ar2"); char str[10] = "i=0"; str[2] = '0'+i; gr.Puts(mglPoint(),""); gr.Update(); // update window when you need it } return 0; // finish calculations and close the window }
Pictures with animation can be saved in file(s) as well. You can: export in animated GIF, or save each frame in separate file (usually JPEG) and convert these files into the movie (for example, by help of ImageMagic). Let me show both methods.
The simplest methods is making animated GIF. There are 3 steps: (1) open GIF file by StartGIF()
function; (2) create the frames by calling NewFrame()
before and EndFrame()
after plotting; (3) close GIF by CloseGIF()
function. So the simplest code for “running” sinusoid will look like this:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; mglData dat(100); char str[32]; gr.StartGIF("sample.gif"); for(int i=0;i<40;i++) { gr.NewFrame(); // start frame gr.Box(); // some plotting for(int j=0;j<dat.nx;j++) dat.a[j]=sin(M_PI*j/dat.nx+M_PI*0.05*i); gr.Plot(dat,"b"); gr.EndFrame(); // end frame } gr.CloseGIF(); return 0; }
The second way is saving each frame in separate file (usually JPEG) and later make the movie from them. MathGL have special function for saving frames – it is WriteFrame()
. This function save each frame with automatic name ‘frame0001.jpg, frame0002.jpg’ and so on. Here prefix ‘frame’ is defined by PlotId variable of mglGraph
class. So the similar code will look like this:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; mglData dat(100); char str[32]; for(int i=0;i<40;i++) { gr.NewFrame(); // start frame gr.Box(); // some plotting for(int j=0;j<dat.nx;j++) dat.a[j]=sin(M_PI*j/dat.nx+M_PI*0.05*i); gr.Plot(dat,"b"); gr.EndFrame(); // end frame gr.WriteFrame(); // save frame } return 0; }
Created files can be converted to movie by help of a lot of programs. For example, you can use ImageMagic (command ‘convert frame*.jpg movie.mpg’), MPEG library, GIMP and so on.
Finally, you can use mglconv
tool for doing the same with MGL scripts (see section Utilities for parsing MGL).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The last way of MathGL using is the drawing in memory. Class mglGraph
allows one to create a bitmap picture in memory. Further this picture can be displayed in window by some window libraries (like wxWidgets, FLTK, Windows GDI and so on). For example, the code for drawing in wxWidget library looks like:
void MyForm::OnPaint(wxPaintEvent& event) { int w,h,x,y; GetClientSize(&w,&h); // size of the picture mglGraph gr(w,h); gr.Alpha(true); // draws something using MathGL gr.Light(true); sample(&gr,NULL); wxImage img(w,h,gr.GetRGB(),true); ToolBar->GetSize(&x,&y); // gets a height of the toolbar if any wxPaintDC dc(this); // and draws it dc.DrawBitmap(wxBitmap(img),0,y); }
The drawing in other libraries is most the same.
For example, FLTK code will look like
void Fl_MyWidget::draw() { mglGraph gr(w(),h()); gr.Alpha(true); // draws something using MathGL gr.Light(true); sample(&gr,NULL); fl_draw_image(gr.GetRGB(), x(), y(), gr.GetWidth(), gr.GetHeight(), 3); }
Qt code will look like
void MyWidget::paintEvent(QPaintEvent *) { mglGraph gr(w(),h()); gr.Alpha(true); // draws something using MathGL gr.Light(true); gr.Light(0,mglPoint(1,0,-1)); sample(&gr,NULL); // Qt don't support RGB format as is. So, let convert it to BGRN. long w=gr.GetWidth(), h=gr.GetHeight(); unsigned char *buf = new uchar[4*w*h]; gr.GetBGRN(buf, 4*w*h) QPixmap pic = QPixmap::fromImage(QImage(*buf, w, h, QImage::Format_RGB32)); QPainter paint; paint.begin(this); paint.drawPixmap(0,0,pic); paint.end(); delete []buf; }
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
MathGL have several interface widgets for different widget libraries. There are QMathGL for Qt, Fl_MathGL for FLTK. These classes provide control which display MathGL graphics. Unfortunately there is no uniform interface for widget classes because all libraries have slightly different set of functions, features and so on. However the usage of MathGL widgets is rather simple. Let me show it on the example of QMathGL.
First of all you have to define the drawing function or inherit a class from mglDraw
class. After it just create a window and setup QMathGL instance as any other Qt widget:
#include <QApplication> #include <QMainWindow> #include <QScrollArea> #include <mgl2/qmathgl.h> int main(int argc,char **argv) { QApplication a(argc,argv); QMainWindow *Wnd = new QMainWindow; Wnd->resize(810,610); // for fill up the QMGL, menu and toolbars Wnd->setWindowTitle("QMathGL sample"); // here I allow to scroll QMathGL -- the case // then user want to prepare huge picture QScrollArea *scroll = new QScrollArea(Wnd); // Create and setup QMathGL QMathGL *QMGL = new QMathGL(Wnd); //QMGL->setPopup(popup); // if you want to setup popup menu for QMGL QMGL->setDraw(sample); // or use QMGL->setDraw(foo); for instance of class Foo:public mglDraw QMGL->update(); // continue other setup (menu, toolbar and so on) scroll->setWidget(QMGL); Wnd->setCentralWidget(scroll); Wnd->show(); return a.exec(); }
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Generally SWIG based classes (including the Python one) are the same as C++ classes. However, there are few tips for using MathGL with PyQt. Below I place a very simple python code which demonstrate how MathGL can be used with PyQt. This code is mostly written by Prof. Dr. Heino Falcke. You can just copy it to a file mgl-pyqt-test.py
and execute it from python shell by command execfile("mgl-pyqt-test.py")
from PyQt4 import QtGui,QtCore from mathgl import * import sys app = QtGui.QApplication(sys.argv) qpointf=QtCore.QPointF() class hfQtPlot(QtGui.QWidget): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.img=(QtGui.QImage()) def setgraph(self,gr): self.buffer='\t' self.buffer=self.buffer.expandtabs(4*gr.GetWidth()*gr.GetHeight()) gr.GetBGRN(self.buffer,len(self.buffer)) self.img=QtGui.QImage(self.buffer, gr.GetWidth(),gr.GetHeight(),QtGui.QImage.Format_ARGB32) self.update() def paintEvent(self, event): paint = QtGui.QPainter() paint.begin(self) paint.drawImage(qpointf,self.img) paint.end() BackgroundColor=[1.0,1.0,1.0] size=100 gr=mglGraph() y=mglData(size) #y.Modify("((0.7*cos(2*pi*(x+.2)*500)+0.3)*(rnd*0.5+0.5)+362.135+10000.)") y.Modify("(cos(2*pi*x*10)+1.1)*1000.*rnd-501") x=mglData(size) x.Modify("x^2"); def plotpanel(gr,x,y,n): gr.SubPlot(2,2,n) gr.SetXRange(x) gr.SetYRange(y) gr.AdjustTicks() gr.Axis() gr.Box() gr.Label("x","x-Axis",1) gr.Label("y","y-Axis",1) gr.ClearLegend() gr.AddLegend("Legend: "+str(n),"k") gr.Legend() gr.Plot(x,y) gr.Clf(BackgroundColor[0],BackgroundColor[1],BackgroundColor[2]) gr.SetPlotFactor(1.5) plotpanel(gr,x,y,0) y.Modify("(cos(2*pi*x*10)+1.1)*1000.*rnd-501") plotpanel(gr,x,y,1) y.Modify("(cos(2*pi*x*10)+1.1)*1000.*rnd-501") plotpanel(gr,x,y,2) y.Modify("(cos(2*pi*x*10)+1.1)*1000.*rnd-501") plotpanel(gr,x,y,3) gr.WritePNG("test.png","Test Plot") qw = hfQtPlot() qw.show() qw.setgraph(gr) qw.raise_()
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For using MathGL in MPI program you just need to: (1) plot its own part of data for each running node; (2) collect resulting graphical information in a single program (for example, at node with rank=0); (3) save it. The sample code below demonstrate this for very simple sample of surface drawing.
First you need to initialize MPI
#include <stdio.h> #include <mgl2/mgl.h> #include <mpi.h> int main(int argc, char *argv[]) { // initialize MPI int rank=0, numproc=1; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD,&numproc); MPI_Comm_rank(MPI_COMM_WORLD,&rank); if(rank==0) printf("Use %d processes.\n", numproc);
Next step is data creation. For simplicity, I create data arrays with the same sizes for all nodes. At this, you have to create mglGraph
object too.
// initialize data similarly for all nodes mglData a(128,256); mglGraph gr;
Now, data should be filled by numbers. In real case, it should be some kind of calculations. But I just fill it by formula.
// do the same plot for its own range char buf[64]; sprintf(buf,"xrange %g %g",2.*rank/numproc-1,2.*(rank+1)/numproc-1); gr.Fill(a,"sin(2*pi*x)",buf);
It is time to plot the data. Don’t forget to set proper axis range(s) by using parametric form or by using options (as in the sample).
// plot data in each node gr.Clf(); // clear image before making the image gr.Rotate(40,60); gr.Surf(a,"",buf);
Finally, let send graphical information to node with rank=0.
// collect information if(rank!=0) gr.MPI_Send(0); else for(int i=1;i<numproc;i++) gr.MPI_Recv(i);
Now, node with rank=0 have whole image. It is time to save the image to a file. Also, you can add a kind of annotations here – I draw axis and bounding box in the sample.
if(rank==0) { gr.Box(); gr.Axis(); // some post processing gr.WritePNG("test.png"); // save result }
In my case the program is done, and I finalize MPI. In real program, you can repeat the loop of data calculation and data plotting as many times as you need.
MPI_Finalize(); return 0; }
You can type ‘mpic++ test.cpp -lmgl && mpirun -np 8 ./a.out’ for compilation and running the sample program on 8 nodes. Note, that you have to set enable-mpi=ON at MathGL configure to use this feature.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by Autobuild on September 28, 2013 using texi2html 1.82.