cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
GnuplotDrawer.cpp
Go to the documentation of this file.
1/*
2 * CepGen: a central exclusive processes event generator
3 * Copyright (C) 2022-2024 Laurent Forthomme
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <fstream>
20
23#include "CepGen/Utils/Drawer.h"
24#include "CepGen/Utils/Graph.h"
26#include "CepGen/Utils/Piper.h"
27#include "CepGen/Utils/String.h"
28#include "CepGen/Version.h"
29
30#ifndef GNUPLOT_BIN
31#error "Gnuplot executable must be specified using GNUPLOT_BIN!"
32#else
33#define STRINGIFY(x) #x
34#define TOSTRING(x) STRINGIFY(x)
35#define GNUPLOT TOSTRING(GNUPLOT_BIN)
36#endif
37
38using namespace std::string_literals;
39
40namespace cepgen {
41 namespace utils {
43 class GnuplotDrawer final : public Drawer {
44 public:
46 explicit GnuplotDrawer(const ParametersList& params)
47 : Drawer(params),
48 extension_(steer<std::string>("extension")),
49 persist_(steer<bool>("persist")),
50 size_(steer<std::vector<std::string> >("size")),
51 font_(steer<std::string>("font")),
52 plot_style_(steer<std::string>("plotStyle")) {
53 if (size_.size() != 2)
54 throw CG_FATAL("GnuplotDrawer") << "Invalid canvas size specified: " << size_ << ".";
55 }
56
58 auto desc = Drawer::description();
59 desc.setDescription("Gnuplot drawing utility");
60 desc.add<std::string>("extension", "png");
61 desc.add<bool>("persist", false);
62 desc.add<std::vector<std::string> >("size", {"30cm", "20cm"});
63 desc.add<std::string>("font", "");
64 desc.add<std::string>("plotStyle", "lp");
65 return desc;
66 }
67
68 const GnuplotDrawer& draw(const Graph1D&, const Mode&) const override;
69 const GnuplotDrawer& draw(const Graph2D&, const Mode&) const override;
70 const GnuplotDrawer& draw(const Hist1D&, const Mode&) const override;
71 const GnuplotDrawer& draw(const Hist2D&, const Mode&) const override;
72
73 const GnuplotDrawer& draw(const DrawableColl&,
74 const std::string& name = "",
75 const std::string& title = "",
76 const Mode& mode = Mode::none) const override;
77
78 private:
79 void execute(const Piper::Commands& cmds, const std::string& name) const {
80 std::string term;
81 if (extension_ == "pdf")
82 term = "pdfcairo enhanced";
83 else if (extension_ == "png")
84 term = "pngcairo transparent enhanced";
85 else if (extension_ == "tex")
86 term = "epslatex";
87 else if (extension_ == "ps")
88 term = "postscript nobackground enhanced";
89 else if (extension_ == "fig")
90 term = "fig";
91 else
92 throw CG_FATAL("GnuplotDrawer:execute") << "Invalid extension set: '" + extension_ + "'";
93 if (!font_.empty())
94 term += " font '" + font_ + "'";
95 term += " size " + merge(size_, ",");
96 Piper::Commands full_cmds{"set term " + term, "set output '" + name + "." + extension_ + "'"};
97 full_cmds += cmds;
98 full_cmds += Piper::Commands{//"set key left bottom",
99 //"set key right top",
100 "exit"};
101 Piper(std::string(GNUPLOT) + (persist_ ? " -persist" : "")).execute(full_cmds);
102 CG_DEBUG("GnuplotDrawer:execute") << "Gnuplot just plotted:\n" << full_cmds;
103 }
104
105 static Piper::Commands preDraw(const Drawable& dr, const Mode& mode) {
106 Piper::Commands cmds;
107 //if (filling_)
108 if (mode & Mode::grid)
109 cmds += "set grid x y mx my";
110 if (mode & Mode::logx)
111 cmds += "set logscale x";
112 if (mode & Mode::logy)
113 cmds += "set logscale y";
114 if (mode & Mode::logz)
115 cmds += "set logscale z";
116 if (!dr.title().empty())
117 cmds += "set title " + delatexify(dr.title());
118 for (const auto& ai : std::unordered_map<std::string, const Drawable::AxisInfo&>{
119 {"x", dr.xAxis()}, {"y", dr.yAxis()}, {"z", dr.zAxis()}}) {
120 if (!ai.second.label().empty())
121 cmds += "set " + ai.first + "label " + delatexify(ai.second.label());
122 const auto& rng = ai.second.range();
123 if (rng.valid())
124 cmds += "set " + ai.first + "range [" + std::to_string(rng.min()) + ":" + std::to_string(rng.max()) + "]";
125 }
126 cmds += "set label 'CepGen v" + version::tag + "' at graph 1,1.025 right";
127 return cmds;
128 }
129 static Piper::Commands drawGraph1D(const Graph1D&, const Mode&, const std::string&);
130 static Piper::Commands drawHist1D(const Hist1D&, const Mode&);
131 static std::string delatexify(const std::string& tok) {
132 //return "\""s + utils::replaceAll(tok, {{"\\", "\\\\"}}) + "\"";
133 return "'"s + utils::replaceAll(tok, {{"'", "\\'"}}) + "'";
134 }
135
136 const std::string extension_;
137 const bool persist_;
138 const std::vector<std::string> size_;
139 const std::string font_, plot_style_;
140 };
141
142 const GnuplotDrawer& GnuplotDrawer::draw(const Graph1D& graph, const Mode& mode) const {
143 auto cmds = preDraw(graph, mode);
144 cmds += drawGraph1D(graph, mode, plot_style_);
145 execute(cmds, graph.name());
146 return *this;
147 }
148
149 const GnuplotDrawer& GnuplotDrawer::draw(const Graph2D& graph, const Mode& mode) const {
150 auto cmds = preDraw(graph, mode);
151 cmds += "$DATA << EOD";
152 const auto xs = graph.xCoords(), ys = graph.yCoords();
153 const std::vector<double> xvec(xs.begin(), xs.end()), yvec(ys.begin(), ys.end());
154 cmds += std::to_string(yvec.size()) + "\t" + merge(xvec, "\t");
155 for (const auto& y : yvec) {
156 std::ostringstream os;
157 os << y;
158 for (const auto& x : xvec)
159 os << "\t" << (double)graph.valueAt(x, y);
160 cmds += os.str();
161 }
162 cmds += "EOD";
163 cmds += "set autoscale xfix";
164 cmds += "set autoscale yfix";
165 cmds += "set autoscale cbfix";
166 if (mode & Mode::col) {
167 cmds += "set hidden3d";
168 cmds += "plot '$DATA' matrix nonuniform with image notitle";
169 } else if (mode & Mode::cont) {
170 cmds += "set view map";
171 cmds += "set contour";
172 cmds += "unset surface";
173 cmds += "set isosamples 500,100";
174 cmds += "set cntrlabel start 25 interval -1 font \",7\"";
175 cmds += "splot '$DATA' matrix nonuniform with lines notitle";
176 } else {
177 cmds += "set hidden3d";
178 cmds += "set style data lines";
179 cmds += "unset contour";
180 cmds += "splot '$DATA' matrix nonuniform notitle";
181 }
182 execute(cmds, graph.name());
183 return *this;
184 }
185
186 const GnuplotDrawer& GnuplotDrawer::draw(const Hist1D& hist, const Mode& mode) const {
187 auto cmds = preDraw(hist, mode);
188 cmds += drawHist1D(hist, mode);
189 execute(cmds, hist.name());
190 return *this;
191 }
192
193 const GnuplotDrawer& GnuplotDrawer::draw(const Hist2D& hist, const Mode& mode) const {
194 auto cmds = preDraw(hist, mode);
195 cmds += "$DATA << EOD";
196 {
197 std::ostringstream os;
198 os << hist.nbinsX();
199 for (size_t ix = 0; ix < hist.nbinsX(); ++ix)
200 os << "\t" << hist.binRangeX(ix).x(0.5);
201 cmds += os.str();
202 }
203 for (size_t iy = 0; iy < hist.nbinsY(); ++iy) {
204 std::ostringstream os;
205 os << hist.binRangeY(iy).x(0.5);
206 for (size_t ix = 0; ix < hist.nbinsX(); ++ix)
207 os << "\t" << (double)hist.value(ix, iy);
208 cmds += os.str();
209 }
210 cmds += "EOD";
211 if (mode & Mode::col) {
212 cmds += "set hidden3d";
213 cmds += "plot '$DATA' matrix nonuniform with image notitle";
214 } else if (mode & Mode::cont) {
215 cmds += "set view map";
216 cmds += "set contour";
217 cmds += "unset surface";
218 cmds += "set isosamples 500,100";
219 cmds += "splot '$DATA' matrix nonuniform with lines notitle";
220 } else {
221 cmds += "set hidden3d";
222 cmds += "set style data lines";
223 cmds += "unset contour";
224 cmds += "splot '$DATA' matrix nonuniform notitle";
225 }
226 execute(cmds, hist.name());
227 return *this;
228 }
229
231 const std::string& name,
232 const std::string& title,
233 const Mode& mode) const {
234 if (objs.empty())
235 return *this;
236 auto cmds = preDraw(*objs.at(0), mode);
237 cmds += "set title " + delatexify(title);
238 std::vector<std::string> plot_cmds, splot_cmds;
239 for (const auto* obj : objs) {
240 if (obj->isGraph1D()) {
241 if (const auto* gr = dynamic_cast<const Graph1D*>(obj); gr) {
242 auto gr_cmds = drawGraph1D(*gr, mode, plot_style_);
243 auto it = gr_cmds.begin();
244 while (it != gr_cmds.end())
245 if (startsWith(*it, "plot")) {
246 plot_cmds.emplace_back(replaceAll(it->substr(5), " notitle", " title " + delatexify(obj->title())));
247 it = gr_cmds.erase(it);
248 } else if (startsWith(*it, "splot")) {
249 splot_cmds.emplace_back(replaceAll(it->substr(6), " notitle", " title " + delatexify(obj->title())));
250 it = gr_cmds.erase(it);
251 } else
252 ++it;
253 if (plot_cmds.empty() && splot_cmds.empty())
254 throw CG_FATAL("GnuplotDrawer:draw")
255 << "No drawing command found for graph with name \"" << obj->name() << "\"!";
256 cmds += gr_cmds;
257 }
258 } else if (obj->isHist1D()) {
259 if (const auto* hist = dynamic_cast<const Hist1D*>(obj); hist) {
260 auto h_cmds = drawHist1D(*hist, mode);
261 auto it = h_cmds.begin();
262 while (it != h_cmds.end())
263 if (startsWith(*it, "plot")) {
264 plot_cmds.emplace_back(replaceAll(it->substr(5), " notitle", " title " + delatexify(obj->title())));
265 it = h_cmds.erase(it);
266 } else if (startsWith(*it, "splot")) {
267 splot_cmds.emplace_back(replaceAll(it->substr(6), " notitle", " title " + delatexify(obj->title())));
268 it = h_cmds.erase(it);
269 } else
270 ++it;
271 if (plot_cmds.empty() && splot_cmds.empty())
272 throw CG_FATAL("GnuplotDrawer:draw")
273 << "No drawing command found for histogram with name \"" << obj->name() << "\"!";
274 cmds += h_cmds;
275 }
276 }
277 }
278 if (plot_cmds.empty() && splot_cmds.empty())
279 throw CG_FATAL("GnuplotDrawer:draw") << "No drawing command found!";
280 else if (!plot_cmds.empty() && !splot_cmds.empty())
281 throw CG_FATAL("GnuplotDrawer:draw") << "Cannot combine 'flat', and surface-like drawing commands!";
282 else if (!plot_cmds.empty())
283 cmds += "plot " + merge(plot_cmds, ", ");
284 else if (!splot_cmds.empty())
285 cmds += "splot " + merge(splot_cmds, ", ");
286 execute(cmds, name);
287 return *this;
288 }
289
290 Piper::Commands GnuplotDrawer::drawGraph1D(const Graph1D& graph, const Mode&, const std::string& style) {
291 Piper::Commands cmds;
292 auto rnd = randomString(5);
293 cmds += "$DATA_" + rnd + " << EOD";
294 for (const auto& pt : graph.points())
295 cmds +=
296 merge(std::vector<double>{pt.first.value, pt.first.value_unc, pt.second, pt.second.uncertainty()}, "\t");
297 cmds += "EOD";
298 cmds += "plot '$DATA_" + rnd + "' u 1:3 w " + style + " notitle";
299 return cmds;
300 }
301
302 Piper::Commands GnuplotDrawer::drawHist1D(const Hist1D& hist, const Mode&) {
303 Piper::Commands cmds;
304 auto rnd = randomString(5);
305 cmds += "set style data histograms";
306 cmds += "set style histogram gap 0.";
307 //cmds += "set style fill solid 1.0 border -1";
308 cmds += "set style fill transparent pattern 2 bo";
309
310 cmds += "$DATA_" + rnd + " << EOH";
311 for (size_t ibin = 0; ibin < hist.nbins(); ++ibin)
312 cmds += merge(std::vector<double>{hist.binRange(ibin).x(0.5), (double)hist.value(ibin)}, "\t");
313 cmds += "EOH";
314 cmds += "set style data lines";
315 cmds += "set yrange [" + std::to_string(hist.minimum()) + ":" + std::to_string(hist.maximum()) + "]";
316 cmds += "set xtics 1 norangelimit nomirror";
317 cmds += "set style fill solid 0.5 noborder";
318 cmds += "set jitter spread 0.5";
319 cmds += "plot '$DATA_" + rnd + "' using 1:2 bins=" + std::to_string(hist.nbins()) + " with boxes notitle";
320 return cmds;
321 }
322 } // namespace utils
323} // namespace cepgen
#define REGISTER_DRAWER(name, obj)
Add a drawing utilitary.
#define CG_FATAL(mod)
Definition Exception.h:61
#define CG_DEBUG(mod)
Definition Message.h:220
double x(double v) const
Find the [0,1] value scaled between minimum and maximum.
Definition Limits.cpp:97
const std::string & name() const
Module unique indexing name.
Definition NamedModule.h:42
A description object for parameters collection.
static ParametersDescription description()
Description of all object parameters.
Definition Steerable.cpp:42
T steer(const std::string &key) const
Retrieve a parameters as previously steered.
Definition Steerable.h:39
const std::string & name() const
Drawable name.
Definition Drawable.h:37
A generic drawing utility.
Definition Drawer.h:36
friend class Hist1D
Definition Drawer.h:90
friend class Graph1D
Definition Drawer.h:88
friend class Drawable
Definition Drawer.h:87
Gnuplot drawable objects drawing utility.
const GnuplotDrawer & draw(const Graph1D &, const Mode &) const override
Draw a one-dimensional graph.
GnuplotDrawer(const ParametersList &params)
Class constructor.
static ParametersDescription description()
A one-dimensional graph object.
Definition Graph.h:29
A two-dimensional graph object.
Definition Graph.h:58
std::set< double > yCoords() const
List of vertical axis coordinates.
Definition Graph.cpp:107
std::set< double > xCoords() const
List of horizontal axis coordinates.
Definition Graph.cpp:100
const Value valueAt(double, double) const
Retrieve the value of the graph at the given coordinates.
Definition Graph.cpp:115
1D histogram container
Definition Histogram.h:72
2D histogram container
Definition Histogram.h:146
Limits binRangeX(size_t bin) const
Range for a single x-axis bin.
Definition Hist2D.cpp:183
size_t nbinsX() const
Number of x-axis bins.
Definition Hist2D.cpp:173
Value value(size_t bin_x, size_t bin_y) const
Retrieve the value + uncertainty for one bin.
Definition Hist2D.cpp:227
size_t nbinsY() const
Number of y-axis bins.
Definition Hist2D.cpp:196
Limits binRangeY(size_t bin) const
Range for a single y-axis bin.
Definition Hist2D.cpp:206
std::string s(const std::string &word, float num, bool show_number)
Add a trailing "s" when needed.
Definition String.cpp:228
bool startsWith(const std::string &str, const std::string &beg)
Check if a string starts with a given token.
Definition String.cpp:365
std::vector< const Drawable * > DrawableColl
A collection of drawable objects.
Definition Drawer.h:34
std::string randomString(size_t size)
Generate a random string of a given size.
Definition String.cpp:221
size_t replaceAll(std::string &str, const std::string &from, const std::string &to)
Replace all occurrences of a text by another.
Definition String.cpp:118
std::string merge(const std::vector< T > &vec, const std::string &delim)
Merge a collection of a printable type in a single string.
Definition String.cpp:248
Common namespace for this Monte Carlo generator.
A collection of commands to pipe to the session.
Definition Piper.h:36
static const std::string tag
CepGen version.
Definition Version.h:28