version 3.10-dev
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// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
16#ifndef DUMUX_GNUPLOT_INTERFACE_HH
17#define DUMUX_GNUPLOT_INTERFACE_HH
18
19#if !DUMUX_HAVE_GNUPLOT
20// Gnuplot has not been found by CMake, no output possible.
21#define GNUPLOT_EXECUTABLE "/usr/bin/gnuplot"
22#endif
23
24#include <cassert>
25#include <cmath>
26#include <fstream>
27#include <iostream>
28#include <iomanip>
29#include <sstream>
30#include <string>
31#include <vector>
32
33#include <dune/common/exceptions.hh>
34#include <dune/common/stdstreams.hh>
35
36namespace Dumux {
37
43template<class Scalar>
45{
46public:
47 using StringVector = std::vector<std::string>;
48 enum class CurveType
49 { function, file, data };
50 using CurveTypeVector = std::vector<CurveType>;
51
53 explicit GnuplotInterface(bool persist = true) :
54 pipeInteractive_(0), pipeImage_(0),
55 openPlotWindow_(true), persist_(persist), createImage_(true),
56 terminalType_("x11"), outputDirectory_("./"),
57 datafileSeparator_(' '), linetype_("solid"),
58 xRangeIsSet_(false), yRangeIsSet_(false),
59 xLabel_(""), yLabel_(""),
60 gnuplotPath_(GNUPLOT_EXECUTABLE)
61 {
62 open(persist_);
63 resetPlot();
64 }
65
68 {
69 close();
70 }
71
77 void plot(const std::string &filename = "")
78 {
79 // set correct terminal and general options
80 std::string plot = "set datafile separator \'" + std::string(1, datafileSeparator_) + "\'\n";
81
82 // set the labels and axes ranges
83 plot += "set xlabel \"" + xLabel_ + "\"\n";
84 plot += "set ylabel \"" + yLabel_ + "\"\n";
85 if (xRangeIsSet_)
86 plot += "set xrange [" + toStringWithPrecision(xRangeMin_) + ":" + toStringWithPrecision(xRangeMax_) + "]" + "\n";
87 if (yRangeIsSet_)
88 plot += "set yrange [" + toStringWithPrecision(yRangeMin_) + ":" + toStringWithPrecision(yRangeMax_) + "]" + "\n";
89
90 // set user defined options
91 plot += plotOptions_ + "\n";
92
93 // plot curves
94 plot += "plot";
95 std::string plotCommandForFile(plot);
96 for (unsigned int i = 0; i < curve_.size(); ++i)
97 {
98 if (curveType_[i] == CurveType::function)
99 {
100 plot += + " " + curve_[i] + " " + curveOptions_[i];
101 plotCommandForFile += + " " + curve_[i] + " " + curveOptions_[i];
102 }
103 else
104 {
105 plot += + " '" + outputDirectory_ + curve_[i] + "' " + curveOptions_[i];
106 plotCommandForFile += + " '" + curve_[i] + "' " + curveOptions_[i];
107 }
108
109 if (i < curve_.size()-1)
110 {
111 plot += ",\\";
112 plotCommandForFile += ",\\";
113 }
114 plot += "\n";
115 plotCommandForFile += "\n";
116 }
117
118 // initialize the interactive plot
119 std::string interactivePlot = "reset\n";
120
121 // set the terminal if the defaults were overwritten
122 if (terminalType_.compare("x11") != 0 || linetype_.compare("solid") != 0)
123 interactivePlot += "set term " + terminalType_ + " " + linetype_ + " " + " \n";
124
125 // add the plot command and plot
126 interactivePlot += plot;
127 if (openPlotWindow_)
128 executeGnuplot(interactivePlot, pipeInteractive_);
129
130 // create a gnuplot file if a filename is specified
131 if (filename.compare("") != 0)
132 {
133 std::string filePlot = "reset\n";
134 filePlot += "set term pngcairo size 800,600 " + linetype_ + " \n";
135 filePlot += "set output \"" + filename + ".png\"\n";
136 filePlot += plot;
137 std::string gnuplotFileName = outputDirectory_ + filename + ".gp";
138 std::ofstream file;
139 file.open(gnuplotFileName);
140 file << filePlot;
141 file.close();
142
143 // create the image if desired
144 if (createImage_)
145 executeGnuplot(filePlot, pipeImage_);
146 }
147 }
148
152 void resetAll(const bool persist = true)
153 {
154 close();
155 open(persist);
156 resetPlot();
157 }
158
163 {
164 curve_.clear();
165 curveOptions_.clear();
166 plotOptions_ = "";
167 }
168
172 void open(const bool persist = true)
173 {
174 if (persist)
175 pipeInteractive_ = popen((gnuplotPath_ + " -persist").c_str(), "w"); // "w" - writing
176 else
177 pipeInteractive_ = popen((gnuplotPath_).c_str(), "w");
178
179 // the image pipe should not persist
180 pipeImage_ = popen((gnuplotPath_).c_str(), "w");
181 }
182
186 void close()
187 {
188 if (pclose(pipeInteractive_) == -1 || pclose(pipeImage_) == -1)
189 assert("Could not close pipe to Gnuplot!");
190 }
191
198 void addFunctionToPlot(const std::string& function,
199 const std::string& options = "with lines")
200 {
201 curve_.push_back(function);
202 curveOptions_.push_back(options);
203 curveType_.push_back(CurveType::function);
204 }
205
212 void addFileToPlot(const std::string& fileName,
213 const std::string& options = "with lines")
214 {
215 curve_.push_back(fileName);
216 curveOptions_.push_back(options);
217 curveType_.push_back(CurveType::file);
218 }
219
230 template<class DataX, class DataY>
231 void addDataSetToPlot(const DataX& x, const DataY& y,
232 const std::string& fileName,
233 const std::string& options = "with lines")
234 {
235 if (x.size() == 0 || y.size() == 0)
236 DUNE_THROW(Dune::InvalidStateException, "Data vectors have to contain data!");
237
238 if (x.size() > y.size())
239 DUNE_THROW(Dune::InvalidStateException, "Non-matching data field sizes!");
240
241 if (x.size() != y.size())
242 std::cout << "GnuplotInterface warning: Added data fields of different size! "
243 << "Only plotting the first " << x.size() << " elements.\n";
244
245 // write data to file
246 std::ofstream file;
247 file.open(outputDirectory_ + fileName);
248 for (unsigned int i = 0; i < x.size(); i++)
249 {
250 checkNumber(x[i], "x[i] i=" + std::to_string(i) + " in " + fileName);
251 checkNumber(y[i], "y[i] i=" + std::to_string(i) + " in " + fileName);
252 file << x[i] << datafileSeparator_ << y[i] << std::endl;
253 }
254 file.close();
255
256 // adding file to list of plotted lines
257 curve_.push_back(fileName);
258 curveOptions_.push_back(options);
259 curveType_.push_back(CurveType::data);
260 }
261
267 void setXlabel(const std::string& label)
268 {
269 xLabel_ = label;
270 }
271
277 void setYlabel(const std::string& label)
278 {
279 yLabel_ = label;
280 }
281
288 void setXRange(Scalar min, Scalar max)
289 {
290 xRangeMin_ = min;
291 xRangeMax_ = max;
292 xRangeIsSet_ = true;
293 }
294
301 void setYRange(Scalar min, Scalar max)
302 {
303 yRangeMin_ = min;
304 yRangeMax_ = max;
305 yRangeIsSet_ = true;
306 }
307
313 void setOption(const std::string& option)
314 {
315 plotOptions_ += option + "\n";
316 }
317
323 void setOpenPlotWindow(bool openPlotWindow)
324 {
325 openPlotWindow_ = openPlotWindow;
326 }
327
333 void setCreateImage(bool createImage)
334 {
335 createImage_ = createImage;
336 }
337
343 void setDatafileSeparator(char separator)
344 {
345 datafileSeparator_ = separator;
346 }
347
353 void setTerminalType(std::string terminal)
354 {
355 terminalType_ = terminal;
356 }
357
363 void setOutputDirectory(const std::string& outputDirectory)
364 {
365 outputDirectory_ = outputDirectory + "/";
366 }
367
373 void useDashedLines(bool dashed)
374 {
375 linetype_ = dashed ? "dashed" : "solid";
376 }
377
378private:
379 // Give plot command to gnuplot
380 void executeGnuplot(const std::string& plotCommand, std::FILE * pipe) const
381 {
382#ifdef DUMUX_HAVE_GNUPLOT
383 fputs((plotCommand + "\n").c_str(), pipe);
384 fflush(pipe);
385#else
386 std::cerr << "Warning: Gnuplot has not been found by CMake, no image generation or interactive display possible." << std::endl;
387 std::cerr << "Note: The data and the gnuplot instruction file will still be created." << std::endl;
388#endif
389 }
390
391 // Check validity of number
392 void checkNumber(Scalar number, const std::string& text = "") const
393 {
394 using std::isnan;
395 using std::isinf;
396 if (isnan(number))
397 Dune::dwarn << "warning: " << text << " is not a number, adjust your data range" << std::endl;
398 if (isinf(number))
399 Dune::dwarn << "warning: " << text << " is infinity, adjust your data range" << std::endl;
400 }
401
402 // Convert string with higher precision
403 template <typename T>
404 std::string toStringWithPrecision(const T value, const int n = 8)
405 {
406 std::ostringstream out;
407 out << std::setprecision(n) << value;
408 return out.str();
409 }
410
411 std::FILE * pipeInteractive_;
412 std::FILE * pipeImage_;
413 bool openPlotWindow_;
414 bool persist_;
415 bool createImage_;
416 std::string terminalType_;
417 std::string outputDirectory_;
418 char datafileSeparator_;
419 std::string linetype_;
420 StringVector curve_;
421 StringVector curveOptions_;
422 CurveTypeVector curveType_;
423 Scalar xRangeMin_;
424 Scalar xRangeMax_;
425 bool xRangeIsSet_;
426 Scalar yRangeMin_;
427 Scalar yRangeMax_;
428 bool yRangeIsSet_;
429 std::string xLabel_;
430 std::string yLabel_;
431 std::string plotOptions_;
432 std::string gnuplotPath_;
433};
434} // end namespace Dumux
435#endif
Interface for passing data sets to a file and plotting them, if gnuplot is installed.
Definition: gnuplotinterface.hh:45
void setXlabel(const std::string &label)
Sets the label for the x-axis.
Definition: gnuplotinterface.hh:267
std::vector< CurveType > CurveTypeVector
Definition: gnuplotinterface.hh:50
void resetPlot()
Deletes all plots from a plotting window and resets user-defined options.
Definition: gnuplotinterface.hh:162
void addFileToPlot(const std::string &fileName, const std::string &options="with lines")
Adds a file to list of plots.
Definition: gnuplotinterface.hh:212
void addDataSetToPlot(const DataX &x, const DataY &y, const std::string &fileName, const std::string &options="with lines")
Adds a data set and writes a data file.
Definition: gnuplotinterface.hh:231
void plot(const std::string &filename="")
Plots the files for a specific window number, writes a gnuplot and png file.
Definition: gnuplotinterface.hh:77
void resetAll(const bool persist=true)
Resets all gnuplot parameters.
Definition: gnuplotinterface.hh:152
~GnuplotInterface()
The destructor.
Definition: gnuplotinterface.hh:67
void setTerminalType(std::string terminal)
Sets the terminal used for interactive output.
Definition: gnuplotinterface.hh:353
void setOption(const std::string &option)
Sets additional user-defined options.
Definition: gnuplotinterface.hh:313
void setOpenPlotWindow(bool openPlotWindow)
Define whether the gnuplot window should be opened.
Definition: gnuplotinterface.hh:323
void setCreateImage(bool createImage)
Define whether gnuplot should create .png files.
Definition: gnuplotinterface.hh:333
void addFunctionToPlot(const std::string &function, const std::string &options="with lines")
Adds a function to list of plots.
Definition: gnuplotinterface.hh:198
void setXRange(Scalar min, Scalar max)
Sets the range for the x-axis.
Definition: gnuplotinterface.hh:288
GnuplotInterface(bool persist=true)
The constructor.
Definition: gnuplotinterface.hh:53
void close()
Closes gnuplot.
Definition: gnuplotinterface.hh:186
void setDatafileSeparator(char separator)
Sets the datafile separator.
Definition: gnuplotinterface.hh:343
void setOutputDirectory(const std::string &outputDirectory)
Sets the output directory for data and gnuplot files.
Definition: gnuplotinterface.hh:363
void useDashedLines(bool dashed)
Use dashed (true) or solid (false) lines.
Definition: gnuplotinterface.hh:373
void open(const bool persist=true)
Opens gnuplot.
Definition: gnuplotinterface.hh:172
std::vector< std::string > StringVector
Definition: gnuplotinterface.hh:47
void setYRange(Scalar min, Scalar max)
Sets the range for the y-axis.
Definition: gnuplotinterface.hh:301
void setYlabel(const std::string &label)
Sets the label for the y-axis.
Definition: gnuplotinterface.hh:277
CurveType
Definition: gnuplotinterface.hh:49
#define GNUPLOT_EXECUTABLE
Definition: gnuplotinterface.hh:21
Definition: adapt.hh:17