Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) GnuplotInterface

 

STLQt CreatorLubuntu

 

GnuplotInterface is a class that enables the user to easily plot values in Gnuplot. It handles both the connection to Gnuplot and performs the window management as well. It creates a text-file in which the location of the Gnuplot executable can be entered (without recompiling the program).

 

The tool TestGnuplotInterface tests the GnuplotInterface class.

 

I only got this interface to work under MacOS

 

The one function that this class is built around is the popen function. This is a non-standard function to open a pipe. If this function is unknown under your programming environment, try either std::popen, std::_popen, std::__popen, popen, _popen or __popen.

 

 

 

 

 

 

Known compile errors

 

Technical facts

 

 

 

 

 

 

./CppGnuplotInterface/CppGnuplotInterface.pri

 

INCLUDEPATH += \
    ../../Classes/CppCanvas

SOURCES += \
    ../../Classes/CppCanvas/canvas.cpp

HEADERS  += \
    ../../Classes/CppCanvas/canvas.h

OTHER_FILES += \
    ../../Classes/CppCanvas/Licence.txt

 

 

 

 

 

./CppGnuplotInterface/gnuplotinterface.h

 

//
//  Gnuplot - a C++ class interface with Gnuplot
//  V4.0
//
//  Created by Richel Bilderbeek on Fri Jun 10 2005.
//  Open source.
//
//  Richel Bilderbeek
//  Website: http://www.richelbilderbeek.nl
//
//  V4.0: 19th March 2008: Conformized code
//  V3.0: 23th September 2006: Implemented suggestion by Christoph Schmalz.
//                             According to Christoph it should work under Windows now.
//                             Made the code 100% Standard C++.
//  V2.0: 12th September 2005: Got program to compile under Windows environment.
//                             Program is found NOT to run under Windows.
//                             Somebody has an idea how to open Gnuplot.exe ???
//  V1.0: 10th June 2005: first version developed on Macintosh
//
//
//  This class functions well at a Macintosh. Under Windows, the pipe to the
//  Gnuplot executable (either MS-DOS or Windows executable) will not open.
//  If you have an idea to solve this, please E-mail me.
//
//
//  Feel free to contact me when:
//  - YOU can get the program to run under Windows (and normally it wouldn't)
//  - you encounter a compile error
//  - you have made additional functionality
//  - you have outsmarted me on this interface.
//

#ifndef __GNUPLOT_H
#define __GNUPLOT_H

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdio>
#include <ctime>
#include <cassert>

enum GnuplotStyle
{
  styleLines,
  stylePoints,
  styleLinespoints,
  styleImpulses,
  styleDots,
  styleSteps,
  styleErrorbars,
  styleBoxes,
  styleBoxerrorbars,
};

enum GnuplotTerminal
{
  terminalX11,
  terminalAqua
};

struct WindowData
{
  std::vector<std::string> tempFileName;
};

struct Gnuplot
{
  Gnuplot();
  ~Gnuplot();

  void Execute(const std::string&) const;

  void AddWindow(const int nWindows = 1);
  void ChangeWindow(const int);

  void SetTerminal(const GnuplotTerminal&);
  void SetStyle(const GnuplotStyle&);
  void SetYlabel(const std::string&);
  void SetXlabel(const std::string&);

  void Plot(const std::string &, const std::string& title = "y");
  void Plot(const std::vector<double>&, const std::string& title = "y");
  void Plot(const std::vector<double>&, const std::vector<double>&, const std::string& title = "data");
  void Plot(const std::vector<double>&, const std::vector<double>&, const std::vector<double>&, const std::string& title = "z");

  void EmptyPlot();

  //Helper functions
  void Sleep(const double) const;
  const std::string Itoa(const int) const;
  const std::string Ftoa(const double) const;
  const bool FileExists(const std::string& fileName) const;

  private:
  std::FILE * mGnuPipe;
  std::string mTerminal;
  std::string mStyle;
  std::vector<WindowData> mWindowData;
  int mCurrentWindowNumber;
  static int mTempFileNumber;

  void SetLineStyles();
  const std::string ReadFileName() const;
  const std::string CreateTempFileName();
  void CreateTempFile(const std::string&, const std::vector<double>&);
  void CreateTempFile(const std::string&, const std::vector<double>&, const std::vector<double>&);
  void CreateTempFile(const std::string&, const std::vector<double>&, const std::vector<double>&, const std::vector<double>&);
  void PlotTempFile2D(const std::string&, const std::string&);
  void PlotTempFile3D(const std::string&, const std::string&);
  void Dot(const std::string& debugString = ".") const;
};

#endif

 

 

 

 

 

./CppGnuplotInterface/gnuplotinterface.cpp

 

//---------------------------------------------------------------------------
//
//  Gnuplot - a C++ class interface with Gnuplot
//  V4.0
//
//  Created by Richel Bilderbeek on Fri Jun 10 2005.
//  Open source.
//
//  Richel Bilderbeek
//  Website: http://www.richelbilderbeek.nl
//
//  V4.0: 19th March 2008: Conformized code
//  V3.0: 23th September 2006: Implemented suggestion by Christoph Schmalz.
//                             According to Christoph it should work under Windows now.
//                             Made the code 100% Standard C++.
//  V2.0: 12th September 2005: Got program to compile under Windows environment.
//                             Program is found NOT to run under Windows.
//                             Somebody has an idea how to open Gnuplot.exe ???
//  V1.0: 10th June 2005: first version developed on Macintosh
//
//
//  This class functions well at a Macintosh. Under Windows, the pipe to the
//  Gnuplot executable (either MS-DOS or Windows executable) will not open.
//  If you have an idea to solve this, please E-mail me.
//
//
//  Feel free to contact me when:
//  - YOU can get the program to run under Windows (and normally it wouldn't)
//  - you encounter a compile error
//  - you have made additional functionality
//  - you have outsmarted me on this interface.
//
//----------------------------------------------------------------------------------
#include "UnitGnuplotInterface.h"
//----------------------------------------------------------------------------------
//#define EXTENSIVE_LOG
//----------------------------------------------------------------------------------
int Gnuplot::mTempFileNumber = 0;
//----------------------------------------------------------------------------------
Gnuplot::Gnuplot() :
mGnuPipe(0),
mTerminal("aqua"),
mStyle("lines"),
mCurrentWindowNumber(0)
{
  const std::string fileName = ReadFileName();
  if (FileExists(fileName)==false)
  {
    std::cout
      << "\nGnuplot file '" << fileName << "' does not exist."
      << "\nTherefore, change the line in 'GnuplotLocation.txt"
      << "\nto your Gnuplot location (e.g. 'c:/gnuplot/gnuplot')"
      << "\nThis error is generated in line " << __LINE__
      << "\nof file " << __FILE__ << std::endl
      << "\n\nPress key to terminate program." << std::endl;
    std::cin.get();
    std::exit(1);
  }
  std::cout
    << "Gnuplot executable found at '" << fileName << "'."
    << "\nOpening pipe to Gnuplot" << std::endl;
  mGnuPipe = std::_popen((fileName+" -persist").c_str(),"w"); //Changed 'rw' to 'w'
  if (mGnuPipe==0)
  {
    std::cout << "Couldn't open connection to gnuplot" << std::endl;
    std::cin.get();
    std::exit(1);
  }
  SetLineStyles();
  AddWindow();
  ChangeWindow(0);
}
//----------------------------------------------------------------------------------
///This reads the location of Gnuplot from the config file called GnuplotLocation.txt
///If it cannot find this file, it is created with a default value
const std::string Gnuplot::ReadFileName() const
{
  const std::string fileName = "GnuplotLocation.txt";
  std::string returnFileName;
  if (FileExists(fileName)==true)
  {
    std::ifstream file(fileName.c_str());
    assert(file.is_open()==true);
    file >> returnFileName;
    file.close();
  }
  else
  {
    std::ofstream file(fileName.c_str());
    assert(file.is_open()==true);
    returnFileName ="/sw/bin/gnuplot";
    file << returnFileName << '\n';
    file.close();
  }
  return returnFileName;
}
//----------------------------------------------------------------------------------
Gnuplot::~Gnuplot()
{
  const int nWindows = mWindowData.size();
  for(int i=0; i!=nWindows; ++i)
  {
    mCurrentWindowNumber = i;
    EmptyPlot();
  }
  if (_pclose(mGnuPipe) == -1) assert(!"Problem closing communication to Gnuplot");
}
//----------------------------------------------------------------------------------
void Gnuplot::EmptyPlot()
{
  const int nPlots = mWindowData[mCurrentWindowNumber].tempFileName.size();
  for (int i=0; i!=nPlots; ++i)
  {
    Dot("Removing file: " + mWindowData[mCurrentWindowNumber].tempFileName[i]);
    std::remove(mWindowData[mCurrentWindowNumber].tempFileName[i].c_str());
  }
}
//----------------------------------------------------------------------------------
void Gnuplot::SetTerminal(const GnuplotTerminal& terminal)
{
  switch(terminal)
  {
    case terminalAqua : mTerminal = "aqua"; break;
    case terminalX11  : mTerminal = "x11" ; break;
    default: assert(!"Unknown GnuplotTerminal");
  }
}
//----------------------------------------------------------------------------------
void Gnuplot::SetStyle(const GnuplotStyle& style)
{
  switch(style)
  {
    case styleLines        : mStyle = "lines"; break;
    case stylePoints       : mStyle = "points"; break;
    case styleLinespoints  : mStyle = "linespoints"; break;
    case styleImpulses     : mStyle = "impulses"; break;
    case styleDots         : mStyle = "dots"; break;
    case styleSteps        : mStyle = "steps"; break;
    case styleErrorbars    : mStyle = "errorbars"; break;
    case styleBoxes        : mStyle = "boxes"; break;
    case styleBoxerrorbars : mStyle = "boxerrorbars"; break;
    default: assert(!"Unknown GnuplotStyle");
  }
}
//----------------------------------------------------------------------------------
void Gnuplot::Execute(const std::string& cmdstr) const
{
  Dot("Command sent to Gnuplot: " + static_cast<std::string>(cmdstr));
  fputs((cmdstr+"\n").c_str(),mGnuPipe);
  fflush(mGnuPipe);

  Sleep(1.0); //Setting this sleep time too low results in errors
}
//----------------------------------------------------------------------------------
void Gnuplot::SetYlabel(const std::string& label)
{
  const std::string command = "set ylabel \""+label+"\"";
  Execute(command.c_str());
}
//----------------------------------------------------------------------------------
void Gnuplot::SetXlabel(const std::string& label)
{
  const std::string command = "set xlabel \""+label+"\"";
  Execute(command.c_str());
}
//----------------------------------------------------------------------------------
///Change to plotting windows to 'windowNumber'. If this window number is beyond
///the amount of windows created, a new window will be created and that window
///will be set as the plotting window
void Gnuplot::ChangeWindow(const int windowNumber)
{
  if (windowNumber==mCurrentWindowNumber) return;
  if (windowNumber>= static_cast<int>(mWindowData.size()))
  {
    AddWindow();
    mCurrentWindowNumber = mWindowData.size()-1;
  }
  else
  {
    mCurrentWindowNumber=windowNumber;
  }
  const std::string myCommand = "set terminal "+mTerminal+" "+Itoa(mCurrentWindowNumber+1);
  Execute(myCommand.c_str());
}
//----------------------------------------------------------------------------------
///Creates an extra 'nWindows' display windows.
void Gnuplot::AddWindow(const int nWindows)
{
  for (int i=0; i!=nWindows; ++i)
  {
    WindowData temp;
    mWindowData.push_back(temp);
  }
}
//----------------------------------------------------------------------------------
void Gnuplot::Plot(const std::string &equation, const std::string &title)
{
  std::string myCommand;
  if (mWindowData[mCurrentWindowNumber].tempFileName.size() > 0)
    myCommand = "replot " + equation + " title \"" + title + "\" with " + mStyle;
  else
    myCommand = "plot " + equation + " title \"" + title + "\" with " + mStyle;

  Execute(myCommand.c_str());
}
//----------------------------------------------------------------------------------
void Gnuplot::Plot(const std::vector<double>& x, const std::string &title)
{
  const std::string tempFileName = CreateTempFileName();
  CreateTempFile(tempFileName,x);
  PlotTempFile2D(tempFileName,title);
}
//----------------------------------------------------------------------------------
void Gnuplot::Plot(const std::vector<double>& x, const std::vector<double>& y, const std::string &title)
{
  const std::string tempFileName = CreateTempFileName();
  CreateTempFile(tempFileName,x,y);
  PlotTempFile2D(tempFileName,title);
}
//----------------------------------------------------------------------------------
void Gnuplot::Plot(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& z, const std::string &title)
{
  const std::string tempFileName = CreateTempFileName();
  CreateTempFile(tempFileName,x,y,z);
  PlotTempFile3D(tempFileName,title);
}
//----------------------------------------------------------------------------------
void Gnuplot::PlotTempFile2D(const std::string& tempFileName, const std::string& title)
{
  std::string myCommand;
  const int nSeries = mWindowData[mCurrentWindowNumber].tempFileName.size();
  //Linestyles are nice, but don't work on my terminal...
  ///if (nSeries>12) std::cout << "MAKE MORE LINESTYLES!!!" << std::endl;
  //if ( nSeries == 0)
  // myCommand = "plot \"" + tempFileName + "\" ls "+Itoa(nSerie)+" title \"" + title + "\" with " + mStyle;
  //else
  // myCommand = "replot \"" + tempFileName + "\" ls "+Itoa(nSerie)+" title \"" + title + "\" with " + mStyle;

  if ( nSeries == 0)
    myCommand = "plot \"" + tempFileName + "\" title \"" + title + "\" with " + mStyle;
  else
    myCommand = "replot \"" + tempFileName + "\" title \"" + title + "\" with " + mStyle;

  Execute(myCommand.c_str());
  Sleep(1.0); //Setting this sleep time too low results in errors
  mWindowData[mCurrentWindowNumber].tempFileName.push_back(tempFileName);

}
//----------------------------------------------------------------------------------
void Gnuplot::PlotTempFile3D(const std::string& tempFileName, const std::string& title)
{
  //Does not work on my computer. Should be something like this...
  Execute("set pm3d");
  std::string myCommand;
  if (mWindowData[mCurrentWindowNumber].tempFileName.size() == 0)
    myCommand = "splot \"" + tempFileName + "\" title \"" + title + "\" with pm3d palette";
  else
    myCommand = "replot \"" + tempFileName + "\" title \"" + title + "\" with pm3d palette";

  Execute(myCommand.c_str());

  Sleep(1.0); //Setting this sleep time too low results in errors
  mWindowData[mCurrentWindowNumber].tempFileName.push_back(tempFileName);
}
//----------------------------------------------------------------------------------
const std::string Gnuplot::CreateTempFileName()
{
  ++mTempFileNumber;
  const std::string tempFileName = "GnuplotTemp"+Itoa(mTempFileNumber);
  Dot("Created temp file '" + tempFileName);
  return(tempFileName);
}
//----------------------------------------------------------------------------------
void Gnuplot::CreateTempFile(const std::string& tempFileName, const std::vector<double>& x)
{
  std::ofstream file(tempFileName.c_str());
  assert(file.is_open()==true);
  const int size = x.size();
  for (int i = 0; i != size; i++) file << x[i] << std::endl;
  file.close();
}
//----------------------------------------------------------------------------------
void Gnuplot::CreateTempFile(const std::string& tempFileName, const std::vector<double>& x, const std::vector<double>& y)
{
  assert(x.size()==y.size());

  std::ofstream file(tempFileName.c_str());
  assert(file.is_open()==true);
  const int size = x.size();
  for (int i = 0; i != size; i++) file << x[i] << " " << y[i] << std::endl;
  file.close();
}
//----------------------------------------------------------------------------------
void Gnuplot::CreateTempFile(const std::string& tempFileName, const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& z)
{
  assert(x.size()==y.size());
  assert(y.size()==z.size());

  std::ofstream file(tempFileName.c_str());
  assert(file.is_open()==true);
  const int size = x.size();
  for (int i = 0; i != size; i++) file << x[i] << " " << y[i] << " " << z[i] << std::endl;
  file.close();
}
//----------------------------------------------------------------------------------
void Gnuplot::SetLineStyles()
{
  //Does not work on all terminals. Like mine... :-(
  //Execute("set style line  1 lt pal frac 0.0 lw 2");
  //Execute("set style line  2 lt pal frac 0.0 lw 4");
  //Execute("set style line  3 lt pal frac 0.2 lw 2");
  //Execute("set style line  4 lt pal frac 0.2 lw 4");
  //Execute("set style line  5 lt pal frac 0.4 lw 2");
  //Execute("set style line  6 lt pal frac 0.4 lw 4");
  //Execute("set style line  7 lt pal frac 0.6 lw 2");
  //Execute("set style line  8 lt pal frac 0.6 lw 4");
  //Execute("set style line  9 lt pal frac 0.8 lw 2");
  //Execute("set style line 10 lt pal frac 0.8 lw 4");
  //Execute("set style line 11 lt pal frac 1.0 lw 2");
  //Execute("set style line 12 lt pal frac 1.0 lw 4");
}
//----------------------------------------------------------------------------------
///Logging when in developmental phase
void Gnuplot::Dot(const std::string& debugString) const
{
  #ifdef EXTENSIVE_LOG
  std::cout << "DOT: " << debugString << std::endl;
  #endif
}
//----------------------------------------------------------------------------------
///Wait for myTime seconds
void Gnuplot::Sleep(const double myTime) const
{
  std::clock_t timeStart = std::clock();
  std::clock_t timeEnd   = std::clock();
  while ((std::difftime(timeEnd,timeStart) / CLK_TCK) < myTime)
  {
    //Wait...
  }
}
//----------------------------------------------------------------------------------

///Converts an integer to a string
const std::string Gnuplot::Itoa(const int number) const
{
  std::ostringstream o;
  if (!(o << number)) return "ERROR";
  return o.str();
}
//----------------------------------------------------------------------------------
///Converts a double to a string
const std::string Gnuplot::Ftoa(const double number) const
{
  std::ostringstream o;
  if (!(o << number)) return "ERROR";
  return o.str();
}
//----------------------------------------------------------------------------------
///Checks if a file exists
const bool Gnuplot::FileExists(const std::string& fileName) const
{
  std::fstream fin;
  fin.open(fileName.c_str(),std::ios::in);
  if( fin.is_open() )
  {
    fin.close();
    return true;
  }
  fin.close();
  return false;
}
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml