Robotsystem from Robot Group Leipzig: gnuplot.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Directories
- Examples

- File List
- File Members

# gnuplot.h

Go to the documentation of this file.

    00001
    00002 // -*- C++ -*-
    00003 /** \file
    00004  * Simple C++ interface to gnuplot.
    00005  * Send your data via pipe to gnuplot, resulting in online diagrams of your experimental data.
    00006  */
    00007
    00008
    00009
    00010 #ifndef GNUPLOT_H
    00011 #define GNUPLOT_H
    00012
    00013 #include <cstdio>
    00014 #include <map>
    00015 #include <utility>
    00016 #include <string>
    00017 #include <sstream>
    00018 #include <list>
    00019
    00020 #define GNUPLOT_ONLY_INCLUDES
    00021 // these includes define FILE* OpenGnuplot(void) and void CloseGnuplot(FILE*)
    00022 #ifdef _WIN32
    00023 #include "gnuplot_win32.h"
    00024 #else
    00025 #include "gnuplot_unix.h"
    00026 #endif
    00027 #undef GNUPLOT_ONLY_INCLUDES
    00028
    00029 /** \defgroup baseclasses Base classes
    00030 */
    00031 /// \ingroup baseclasses
    00032
    00033 /**
    00034    Open a Gnuplot window and always show last n values of arbitrary defined channels.
    00035    T can be std::string or int or anything else supports the << of streams.
    00036    (It is used as name for a channel.)
    00037 */
    00038
    00039
    00040 template<class T> class Gnuplot {
    00041
    00042 /// these includes define FILE* OpenGnuplot(void) and void CloseGnuplot(FILE*)
    00043 #ifdef _WIN32
    00044 #include "gnuplot_win32.h"
    00045 #else
    00046 #include "gnuplot_unix.h"
    00047 #endif
    00048 public:
    00049     typedef std::list<T> nameslist;
    00050     /** which data type is our template */
    00051     typedef T channel_name_type;
    00052
    00053 protected:
    00054     /** data buffer for one channel, organized as ring buffer */
    00055     class Dataset{
    00056         double *buffer;
    00057         int buffersize;
    00058         int current;
    00059     public:
    00060         std::string title;
    00061         std::string style;
    00062         bool show;
    00063         /** contruct a data buffer with (gnuplot) title and style. */
    00064         Dataset(const std::string& title="",const std::string& style="",int buffersize=256)
    00065             :buffersize(buffersize),title(title),style(style){
    00066             buffer=new double[buffersize];
    00067             for(int i=0;i<buffersize;++i)
    00068                 buffer[i]=0.0;
    00069             current=0;
    00070             show=true;
    00071         };
    00072         ~Dataset(){
    00073             delete []buffer;
    00074         };
    00075         /** put new data in (ring) buffer */
    00076         void putData(double v){
    00077             buffer[current++]=v;
    00078             current=current%buffersize;
    00079         };
    00080         /** print buffer content to file pointer, usually a pipe */
    00081         void plot(FILE* f, int start=0, int end=0){
    00082             int _start=current+start;
    00083             int _end=current+((end<=0)?buffersize:end);
    00084             for(int i=_start;i<_end;++i)
    00085                 fprintf(f,"%f\n",buffer[i%buffersize]);
    00086         };
    00087         /** get buffer content */
    00088         double getData(int i){
    00089             return buffer[(i+current)%buffersize];
    00090         };
    00091
    00092     };
    00093
    00094     FILE* pipe;
    00095     /** data type of container storing   channel->data  relation */
    00096     typedef std::map<T, Dataset*> dataset_map;
    00097     dataset_map datasets;
    00098     nameslist namesets;
    00099     int buffersize;
    00100     int start;
    00101     int end;
    00102 public:
    00103
    00104     Gnuplot(int buffersize=256):buffersize(buffersize),start(0),end(buffersize){
    00105         pipe=OpenGnuplot();
    00106     };
    00107     ~Gnuplot(){
    00108         for(typename dataset_map::iterator i=datasets.begin();i!=datasets.end();++i){
    00109             delete i->second;
    00110         }
    00111         if(pipe)CloseGnuplot(pipe);
    00112     };
    00113     /** send arbitrary command to gnuplot.
    00114         like "set zeroaxis" or other stuff */
    00115     void command(const std::string& cmd){
    00116         fprintf(pipe,"%s\n",cmd.data());
    00117         fflush(pipe);
    00118     };
    00119     /** add new channel with name.
    00120         currently uses name as title if not given.  */
    00121     void addChannel(const T& name,const std::string& title="",const std::string& style="lines"){
    00122         if(title != "")
    00123             datasets.insert(std::make_pair(name,new Dataset(title,style,buffersize)));
    00124         else {
    00125             std::ostringstream str;
    00126             str << name;
    00127             datasets.insert(std::make_pair(name,new Dataset(str.str(),style,buffersize)));
    00128         }
    00129         namesets.push_back(name);
    00130     };
    00131     /** add new data value to buffer for channel.
    00132         if channel not exists nothing happens.
    00133         So you can select channels in your program by commenting out the addChannel() call */
    00134     void putData(const T& channel, double data){
    00135         typename dataset_map::iterator i = datasets.find(channel);
    00136         if(i!=datasets.end())
    00137             i->second->putData(data);
    00138     };
    00139
    00140     /** returns channel names */
    00141     const nameslist& getNames(){
    00142         return namesets;
    00143     };
    00144
    00145     /** get title  */
    00146     std::string getTitle(const T& channel){
    00147         typename dataset_map::iterator i = datasets.find(channel);
    00148         if(i!=datasets.end())
    00149             return i->second->title;
    00150         return "";
    00151     };
    00152
    00153     /** switch showing of this channel on or off */
    00154     void show(const T& channel, bool on=true){
    00155         typename dataset_map::iterator i = datasets.find(channel);
    00156         if(i!=datasets.end())
    00157             i->second->show=on;
    00158     };
    00159
    00160     /** switch showing of this channel off */
    00161     void hide(const T& channel){
    00162         show(channel, false);
    00163     };
    00164
    00165     /** switch showing all channels on or off */
    00166     void show_all(bool on=true){
    00167         for(typename dataset_map::iterator i=datasets.begin();i!=datasets.end();++i)
    00168             i->second->show=on;
    00169     };
    00170
    00171     /** switch showing all channels off */
    00172     void hide_all(){
    00173         show_all(false);
    00174     };
    00175
    00176     /** set title */
    00177     void setTitle(const T& channel, const std::string& title){
    00178         typename dataset_map::iterator i = datasets.find(channel);
    00179         if(i!=datasets.end())
    00180             i->second->title=title;
    00181     };
    00182
    00183     /** set style */
    00184     void setStyle(const T& channel, const std::string& style){
    00185         typename dataset_map::iterator i = datasets.find(channel);
    00186         if(i!=datasets.end())
    00187             i->second->style=style;
    00188     };
    00189
    00190     /** make gnuplot plot selected content of data buffers */
    00191     void plot(int start, int end){
    00192         // calculate real values for start and end
    00193         int _start=buffersize-end;
    00194         int _end=buffersize-start;
    00195         fprintf(pipe,"plot ");
    00196         bool first=true;
    00197         for(typename dataset_map::iterator i=datasets.begin();i!=datasets.end();++i){
    00198             Dataset* dataset=i->second;
    00199             if(dataset->show){
    00200                 if(first) first=false;
    00201                 else fprintf(pipe,", ");
    00202                 fprintf(pipe,"'-'");
    00203                 fprintf(pipe," title '%s'",dataset->title.data());
    00204                 fprintf(pipe," with %s",dataset->style.data());
    00205             }
    00206         }
    00207         fprintf(pipe,"\n");
    00208         for(typename dataset_map::iterator i=datasets.begin();i!=datasets.end();++i){
    00209             Dataset* dataset=i->second;
    00210             if(dataset->show){
    00211                 dataset->plot(pipe,_start,_end);
    00212                 fprintf(pipe,"e\n");
    00213             }
    00214         }
    00215         fflush(pipe);
    00216     };
    00217     /** make gnuplot plot content of data buffers */
    00218     void plot(){ plot(start,end); }
    00219
    00220
    00221     /** set start of plot area
    00222         @param n steps in history (must be smaller than end)
    00223     */
    00224     void setStart(int n){ start=n; };
    00225
    00226     /** set end of plot area
    00227         @param n steps in history (must be larger than start)
    00228     */
    00229     void setEnd(int n){ end=n; };
    00230
    00231     /** returns buffersize */
    00232     int getBuffersize() { return buffersize; };
    00233
    00234     /** make gnuplot XY plot content of x against y data buffers
    00235         use it as follow:
    00236         <pre>
    00237         T x[]={a,b,c};
    00238         T y[]={x,y,z};
    00239         plotXY(x,y,3);
    00240         </pre>
    00241     */
    00242     void plotXY(const T *x, const T *y,int size){
    00243         fprintf(pipe,"plot ");
    00244         bool first=true;
    00245         for(int i=0;i < size; ++i){
    00246             typename dataset_map::iterator iX = datasets.find(x[i]);
    00247             typename dataset_map::iterator iY = datasets.find(y[i]);
    00248             // check if both channels exist
    00249             if(iX==datasets.end() || iY==datasets.end())
    00250                 continue;
    00251             if(first) first=false;
    00252             else fprintf(pipe,", ");
    00253             Dataset* datasetX=iX->second;
    00254             Dataset* datasetY=iY->second;
    00255             fprintf(pipe,"'-'");
    00256             fprintf(pipe," title '%s'",std::string(datasetX->title + "<->" + datasetY->title).data());
    00257             fprintf(pipe," with %s",datasetY->style.data());
    00258         }
    00259         fprintf(pipe,"\n");
    00260         for(int i=0;i < size; ++i){
    00261             typename dataset_map::iterator iX = datasets.find(x[i]);
    00262             typename dataset_map::iterator iY = datasets.find(y[i]);
    00263             // check if both channels exist
    00264             if(iX==datasets.end() || iY==datasets.end())
    00265                 continue;
    00266             for(int i2=0; i2<buffersize; ++i2)
    00267                 fprintf(pipe,"%f %f\n",iX->second->getData(i2),iY->second->getData(i2));
    00268             fprintf(pipe,"e\n");
    00269         }
    00270         fflush(pipe);
    00271     };
    00272
    00273     /** make gnuplot XY plot content of x against y data buffers */
    00274     void plotXY(const T& x, const T& y){
    00275         plotXY(&x,&y,1);
    00276     };
    00277
    00278     /** save content of all data buffers in files
    00279         ( file names are: name + channel_name + ext )  */
    00280     void printToFile(const std::string name="", const std::string ext=".log"){
    00281         for(typename dataset_map::iterator i=datasets.begin();i!=datasets.end();++i){
    00282             std::string name2 = name + i->second->title + ext;
    00283             FILE* f=fopen(name2.data(),"w");
    00284             i->second->plot(f);
    00285             fflush(f);
    00286             fclose(f);
    00287         }
    00288     };
    00289 };
    00290
    00291 #endif
    00292