3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
gnuplotinterface.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
28#ifndef DUMUX_GNUPLOT_INTERFACE_HH
29#define DUMUX_GNUPLOT_INTERFACE_HH
30
31#if !HAVE_GNUPLOT
32// Gnuplot has not been found by CMake, no output possible.
33#define GNUPLOT_EXECUTABLE "/usr/bin/gnuplot"
34#endif
35
36#include <cassert>
37#include <cmath>
38#include <fstream>
39#include <iostream>
40#include <iomanip>
41#include <sstream>
42#include <string>
43#include <vector>
44
45#include <dune/common/exceptions.hh>
46#include <dune/common/stdstreams.hh>
47
48namespace Dumux {
49
55template<class Scalar>
57{
58public:
59 using StringVector = std::vector<std::string>;
60 enum class CurveType
61 { function, file, data };
62 using CurveTypeVector = std::vector<CurveType>;
63
65 explicit GnuplotInterface(bool persist = true) :
66 pipeInteractive_(0), pipeImage_(0),
67 openPlotWindow_(true), persist_(persist), createImage_(true),
68 terminalType_("x11"), outputDirectory_("./"),
69 datafileSeparator_(' '), linetype_("solid"),
70 xRangeIsSet_(false), yRangeIsSet_(false),
71 xLabel_(""), yLabel_(""),
72 gnuplotPath_(GNUPLOT_EXECUTABLE)
73 {
74 open(persist_);
75 resetPlot();
76 }
77
80 {
81 close();
82 }
83
89 void plot(const std::string &filename = "")
90 {
91 // set correct terminal and general options
92 std::string plot = "set datafile separator \'" + std::string(1, datafileSeparator_) + "\'\n";
93
94 // set the labels and axes ranges
95 plot += "set xlabel \"" + xLabel_ + "\"\n";
96 plot += "set ylabel \"" + yLabel_ + "\"\n";
97 if (xRangeIsSet_)
98 plot += "set xrange [" + toStringWithPrecision(xRangeMin_) + ":" + toStringWithPrecision(xRangeMax_) + "]" + "\n";
99 if (yRangeIsSet_)
100 plot += "set yrange [" + toStringWithPrecision(yRangeMin_) + ":" + toStringWithPrecision(yRangeMax_) + "]" + "\n";
101
102 // set user defined options
103 plot += plotOptions_ + "\n";
104
105 // plot curves
106 plot += "plot";
107 std::string plotCommandForFile(plot);
108 for (unsigned int i = 0; i < curve_.size(); ++i)
109 {
110 if (curveType_[i] == CurveType::function)
111 {
112 plot += + " " + curve_[i] + " " + curveOptions_[i];
113 plotCommandForFile += + " " + curve_[i] + " " + curveOptions_[i];
114 }
115 else
116 {
117 plot += + " '" + outputDirectory_ + curve_[i] + "' " + curveOptions_[i];
118 plotCommandForFile += + " '" + curve_[i] + "' " + curveOptions_[i];
119 }
120
121 if (i < curve_.size()-1)
122 {
123 plot += ",\\";
124 plotCommandForFile += ",\\";
125 }
126 plot += "\n";
127 plotCommandForFile += "\n";
128 }
129
130 // initialize the interactive plot
131 std::string interactivePlot = "reset\n";
132
133 // set the terminal if the defaults were overwritten
134 if (terminalType_.compare("x11") != 0 || linetype_.compare("solid") != 0)
135 interactivePlot += "set term " + terminalType_ + " " + linetype_ + " " + " \n";
136
137 // add the plot command and plot
138 interactivePlot += plot;
139 if (openPlotWindow_)
140 executeGnuplot(interactivePlot, pipeInteractive_);
141
142 // create a gnuplot file if a filename is specified
143 if (filename.compare("") != 0)
144 {
145 std::string filePlot = "reset\n";
146 filePlot += "set term pngcairo size 800,600 " + linetype_ + " \n";
147 filePlot += "set output \"" + filename + ".png\"\n";
148 filePlot += plot;
149 std::string gnuplotFileName = outputDirectory_ + filename + ".gp";
150 std::ofstream file;
151 file.open(gnuplotFileName);
152 file << filePlot;
153 file.close();
154
155 // create the image if desired
156 if (createImage_)
157 executeGnuplot(filePlot, pipeImage_);
158 }
159 }
160
164 void resetAll(const bool persist = true)
165 {
166 close();
167 open(persist);
168 resetPlot();
169 }
170
175 {
176 curve_.clear();
177 curveOptions_.clear();
178 plotOptions_ = "";
179 }
180
184 void open(const bool persist = true)
185 {
186 if (persist)
187 pipeInteractive_ = popen((gnuplotPath_ + " -persist").c_str(), "w"); // "w" - writing
188 else
189 pipeInteractive_ = popen((gnuplotPath_).c_str(), "w");
190
191 // the image pipe should not persist
192 pipeImage_ = popen((gnuplotPath_).c_str(), "w");
193 }
194
198 void close()
199 {
200 if (pclose(pipeInteractive_) == -1 || pclose(pipeImage_) == -1)
201 assert("Could not close pipe to Gnuplot!");
202 }
203
210 void addFunctionToPlot(const std::string& function,
211 const std::string& options = "with lines")
212 {
213 curve_.push_back(function);
214 curveOptions_.push_back(options);
215 curveType_.push_back(CurveType::function);
216 }
217
224 void addFileToPlot(const std::string& fileName,
225 const std::string& options = "with lines")
226 {
227 curve_.push_back(fileName);
228 curveOptions_.push_back(options);
229 curveType_.push_back(CurveType::file);
230 }
231
242 void addDataSetToPlot(const std::vector<Scalar>& x,
243 const std::vector<Scalar>& y,
244 const std::string& fileName,
245 const std::string& options = "with lines")
246 {
247 if (x.empty() || y.empty())
248 DUNE_THROW(Dune::InvalidStateException, "Data vectors have to contain data!");
249
250 if (x.size() > y.size())
251 DUNE_THROW(Dune::InvalidStateException, "Non-matching data field sizes!");
252
253 if (x.size() != y.size())
254 std::cout << "GnuplotInterface warning: Added data fields of different size! "
255 << "Only plotting the first " << x.size() << " elements.\n";
256
257 // write data to file
258 std::ofstream file;
259 file.open(outputDirectory_ + fileName);
260 for (unsigned int i = 0; i < x.size(); i++)
261 {
262 checkNumber(x[i], "x[i] i=" + std::to_string(i) + " in " + fileName);
263 checkNumber(y[i], "y[i] i=" + std::to_string(i) + " in " + fileName);
264 file << x[i] << datafileSeparator_ << y[i] << std::endl;
265 }
266 file.close();
267
268 // adding file to list of plotted lines
269 curve_.push_back(fileName);
270 curveOptions_.push_back(options);
271 curveType_.push_back(CurveType::data);
272 }
273
279 void setXlabel(const std::string& label)
280 {
281 xLabel_ = label;
282 }
283
289 void setYlabel(const std::string& label)
290 {
291 yLabel_ = label;
292 }
293
300 void setXRange(Scalar min, Scalar max)
301 {
302 xRangeMin_ = min;
303 xRangeMax_ = max;
304 xRangeIsSet_ = true;
305 }
306
313 void setYRange(Scalar min, Scalar max)
314 {
315 yRangeMin_ = min;
316 yRangeMax_ = max;
317 yRangeIsSet_ = true;
318 }
319
325 void setOption(const std::string& option)
326 {
327 plotOptions_ += option + "\n";
328 }
329
335 void setOpenPlotWindow(bool openPlotWindow)
336 {
337 openPlotWindow_ = openPlotWindow;
338 }
339
345 void setCreateImage(bool createImage)
346 {
347 createImage_ = createImage;
348 }
349
355 void setDatafileSeparator(char separator)
356 {
357 datafileSeparator_ = separator;
358 }
359
365 void setTerminalType(std::string terminal)
366 {
367 terminalType_ = terminal;
368 }
369
375 void setOutputDirectory(const std::string& outputDirectory)
376 {
377 outputDirectory_ = outputDirectory + "/";
378 }
379
385 void useDashedLines(bool dashed)
386 {
387 linetype_ = dashed ? "dashed" : "solid";
388 }
389
390private:
391 // Give plot command to gnuplot
392 void executeGnuplot(const std::string& plotCommand, std::FILE * pipe) const
393 {
394#ifdef HAVE_GNUPLOT
395 fputs((plotCommand + "\n").c_str(), pipe);
396 fflush(pipe);
397#else
398 std::cerr << "Warning: Gnuplot has not been found by CMake, no image generation or interactive display possible." << std::endl;
399 std::cerr << "Note: The data and the gnuplot instruction file will still be created." << std::endl;
400#endif
401 }
402
403 // Check validity of number
404 void checkNumber(Scalar number, const std::string& text = "") const
405 {
406 using std::isnan;
407 using std::isinf;
408 if (isnan(number))
409 Dune::dwarn << "warning: " << text << " is not a number, adjust your data range" << std::endl;
410 if (isinf(number))
411 Dune::dwarn << "warning: " << text << " is infinity, adjust your data range" << std::endl;
412 }
413
414 // Convert string with higher precision
415 template <typename T>
416 std::string toStringWithPrecision(const T value, const int n = 8)
417 {
418 std::ostringstream out;
419 out << std::setprecision(n) << value;
420 return out.str();
421 }
422
423 std::FILE * pipeInteractive_;
424 std::FILE * pipeImage_;
425 bool openPlotWindow_;
426 bool persist_;
427 bool createImage_;
428 std::string terminalType_;
429 std::string outputDirectory_;
430 char datafileSeparator_;
431 std::string linetype_;
432 StringVector curve_;
433 StringVector curveOptions_;
434 CurveTypeVector curveType_;
435 Scalar xRangeMin_;
436 Scalar xRangeMax_;
437 Scalar xRangeIsSet_;
438 Scalar yRangeMin_;
439 Scalar yRangeMax_;
440 Scalar yRangeIsSet_;
441 std::string xLabel_;
442 std::string yLabel_;
443 std::string plotOptions_;
444 std::string gnuplotPath_;
445};
446} // end namespace Dumux
447#endif
#define GNUPLOT_EXECUTABLE
Definition: gnuplotinterface.hh:33
Definition: adapt.hh:29
Interface for passing data sets to a file and plotting them, if gnuplot is installed.
Definition: gnuplotinterface.hh:57
void setXlabel(const std::string &label)
Sets the label for the x-axis.
Definition: gnuplotinterface.hh:279
std::vector< CurveType > CurveTypeVector
Definition: gnuplotinterface.hh:62
void resetPlot()
Deletes all plots from a plotting window and resets user-defined options.
Definition: gnuplotinterface.hh:174
void addFileToPlot(const std::string &fileName, const std::string &options="with lines")
Adds a file to list of plots.
Definition: gnuplotinterface.hh:224
void addDataSetToPlot(const std::vector< Scalar > &x, const std::vector< Scalar > &y, const std::string &fileName, const std::string &options="with lines")
Adds a data set and writes a data file.
Definition: gnuplotinterface.hh:242
void plot(const std::string &filename="")
Plots the files for a specific window number, writes a gnuplot and png file.
Definition: gnuplotinterface.hh:89
void resetAll(const bool persist=true)
Resets all gnuplot parameters.
Definition: gnuplotinterface.hh:164
~GnuplotInterface()
The destructor.
Definition: gnuplotinterface.hh:79
void setTerminalType(std::string terminal)
Sets the terminal used for interactive outpu.
Definition: gnuplotinterface.hh:365
void setOption(const std::string &option)
Sets additional user-defined options.
Definition: gnuplotinterface.hh:325
void setOpenPlotWindow(bool openPlotWindow)
Define whether the gnuplot window should be opened.
Definition: gnuplotinterface.hh:335
void setCreateImage(bool createImage)
Define whether gnuplot should create .png files.
Definition: gnuplotinterface.hh:345
void addFunctionToPlot(const std::string &function, const std::string &options="with lines")
Adds a function to list of plots.
Definition: gnuplotinterface.hh:210
void setXRange(Scalar min, Scalar max)
Sets the range for the x-axis.
Definition: gnuplotinterface.hh:300
GnuplotInterface(bool persist=true)
The constructor.
Definition: gnuplotinterface.hh:65
void close()
Closes gnuplot.
Definition: gnuplotinterface.hh:198
void setDatafileSeparator(char separator)
Sets the datafile separator.
Definition: gnuplotinterface.hh:355
void setOutputDirectory(const std::string &outputDirectory)
Sets the output directory for data and gnuplot files.
Definition: gnuplotinterface.hh:375
void useDashedLines(bool dashed)
Use dashed (true) or solid (false) lines.
Definition: gnuplotinterface.hh:385
void open(const bool persist=true)
Opens gnuplot.
Definition: gnuplotinterface.hh:184
std::vector< std::string > StringVector
Definition: gnuplotinterface.hh:59
void setYRange(Scalar min, Scalar max)
Sets the range for the y-axis.
Definition: gnuplotinterface.hh:313
void setYlabel(const std::string &label)
Sets the label for the y-axis.
Definition: gnuplotinterface.hh:289
CurveType
Definition: gnuplotinterface.hh:61