cepgen is hosted by Hepforge, IPPP Durham
CepGen 1.2.5
Central exclusive processes event generator
Loading...
Searching...
No Matches
Drawer.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 <TGraph2DErrors.h>
20#include <TH2D.h>
21#include <TMultiGraph.h>
22
24#include "CepGen/Utils/Drawer.h"
25#include "CepGen/Utils/Graph.h"
28#include "CepGen/Utils/String.h"
30
31using namespace std::string_literals;
32
33namespace cepgen {
34 namespace root {
36 public:
37 explicit Drawer(const ParametersList& params)
38 : cepgen::utils::Drawer(params),
39 def_filename_(steer<std::string>("filename")),
40 def_extension_(steer<std::string>("format")) {
41 gStyle->SetPalette(steer<int>("palette"));
42 }
43
46 desc.add("filename", "canvas"s).setDescription("default filename for the output");
47 desc.add("format", "pdf"s).setDescription("default extension for the output");
48 desc.add<int>("palette", kLightTemperature).setDescription("ROOT colour palette to use");
49 return desc;
50 }
51
52 inline const Drawer& draw(const utils::Graph1D& graph, const Mode& mode) const override {
53 auto gr = convert(graph);
54 ROOTCanvas canv(graph.name().empty() ? def_filename_ : graph.name(), gr.GetTitle(), mode & Mode::ratio);
55 setMode(canv, mode);
56 gr.Draw("al");
57 gr.GetHistogram()->SetTitle(delatexify(";" + graph.xAxis().label() + ";" + graph.yAxis().label()));
58 canv.Prettify(gr.GetHistogram());
59 postDraw(gr.GetHistogram(), graph);
60 canv.Save(def_extension_);
61 return *this;
62 }
63 inline const Drawer& draw(const utils::Graph2D& graph, const Mode& mode) const override {
64 auto gr = convert(graph);
65 ROOTCanvas canv(graph.name().empty() ? def_filename_ : graph.name(), gr.GetTitle(), mode & Mode::ratio);
66 setMode(canv, mode);
67 if (mode & Mode::col)
68 gr.Draw("colz");
69 else if (mode & Mode::cont)
70 gr.Draw("cont");
71 else
72 gr.Draw("surf3");
73 gr.GetHistogram()->SetTitle(
74 delatexify(";" + graph.xAxis().label() + ";" + graph.yAxis().label() + ";" + graph.zAxis().label()));
75 canv.Prettify(gr.GetHistogram());
76 postDraw(gr.GetHistogram(), graph);
77 canv.Save(def_extension_);
78 return *this;
79 }
80 inline const Drawer& draw(const utils::Hist1D& hist, const Mode& mode) const override {
81 auto h = convert(hist);
82 ROOTCanvas canv(hist.name().empty() ? def_filename_ : hist.name(), h.GetTitle(), mode & Mode::ratio);
83 setMode(canv, mode);
84 h.Draw();
85 canv.Prettify(&h);
86 postDraw(&h, hist);
87 canv.Save(def_extension_);
88 return *this;
89 }
90 inline const Drawer& draw(const utils::Hist2D& hist, const Mode& mode) const override {
91 auto h = convert(hist);
92 ROOTCanvas canv(hist.name().empty() ? def_filename_ : hist.name(), h.GetTitle(), mode & Mode::ratio);
93 setMode(canv, mode);
94 h.Draw("colz");
95 canv.Prettify(&h);
96 postDraw(&h, hist);
97 canv.Save(def_extension_);
98 return *this;
99 }
100
101 const Drawer& draw(const utils::DrawableColl&,
102 const std::string& name = "",
103 const std::string& title = "",
104 const Mode& mode = Mode::none) const override;
105
106 private:
107 inline static void setMode(ROOTCanvas& canv, const Mode& mode) {
108 canv.SetLegendX1(0.175);
109 if (mode & Mode::logx)
110 canv.SetLogx();
111 if (mode & Mode::logy)
112 canv.SetLogy();
113 if (mode & Mode::logz)
114 canv.SetLogz();
115 if (mode & Mode::grid)
116 canv.SetGrid();
117 }
118
119 inline static void postDraw(TH1* obj, const utils::Drawable& dr) {
120 const auto &xrng = dr.xAxis().range(), &yrng = dr.yAxis().range();
121 obj->GetXaxis()->SetTitle(delatexify(dr.xAxis().label()));
122 obj->GetYaxis()->SetTitle(delatexify(dr.yAxis().label()));
123 obj->SetLineWidth(std::max((short)3, obj->GetLineWidth()));
124 if (xrng.valid())
125 obj->GetXaxis()->SetLimits(xrng.min(), xrng.max());
126 if (yrng.valid()) {
127 if (yrng.hasMin())
128 obj->SetMinimum(yrng.min());
129 if (yrng.hasMax())
130 obj->SetMaximum(yrng.max());
131 }
132 }
133 inline static TString delatexify(const std::string& tok) {
134 auto out = utils::replaceAll(tok, {{"$", ""}, {"\\", "#"}});
135 return TString(out);
136 }
137 static TGraphErrors convert(const utils::Graph1D&);
138 static TGraph2DErrors convert(const utils::Graph2D&);
139 static TH1D convert(const utils::Hist1D&);
140 static TH2D convert(const utils::Hist2D&);
141
142 const std::string def_filename_;
143 const std::string def_extension_;
144 };
145
147 const std::string& name,
148 const std::string& title,
149 const Mode& mode) const {
150 ROOTCanvas canv(name.empty() ? def_filename_ : name, delatexify(title).Data(), mode & Mode::ratio);
151 auto* mg = canv.Make<TMultiGraph>();
152 auto* hs = canv.Make<THStack>();
153 setMode(canv, mode);
154 utils::Drawable* first = nullptr;
155 utils::DrawableColl plots_2d;
156 for (size_t i = 0; i < objs.size(); ++i) {
157 const auto* obj = objs.at(i);
158 auto colour = ROOTCanvas::colours.at(i % ROOTCanvas::colours.size());
159 auto style = i + 1;
160 if (obj->isHist1D()) {
161 if (auto* hist = new TH1D(convert(*dynamic_cast<const utils::Hist1D*>(obj))); hist) {
162 hist->SetLineColor(colour);
163 hist->SetLineStyle(style);
164 hs->Add(hist);
165 canv.AddLegendEntry(hist, hist->GetTitle(), "l");
166 }
167 } else if (obj->isGraph1D()) {
168 if (auto* gr = new TGraphErrors(convert(*dynamic_cast<const utils::Graph1D*>(obj))); gr) {
169 gr->SetLineColor(colour);
170 gr->SetLineStyle(style);
171 mg->Add(gr);
172 canv.AddLegendEntry(gr, gr->GetTitle(), "l");
173 }
174 } else {
175 plots_2d.emplace_back(obj);
176 CG_DEBUG("root:Drawer:draw") << "Adding a 2-dimensional drawable '" << obj->name() << "' to the stack.";
177 continue;
178 }
179 if (!first)
180 first = const_cast<utils::Drawable*>(obj);
181 }
182 const bool has_hists = hs->GetHists() && !hs->GetHists()->IsEmpty();
183 const bool has_graphs = mg->GetListOfGraphs() && !mg->GetListOfGraphs()->IsEmpty();
184 if (has_hists || has_graphs) {
185 if (has_hists)
186 hs->Draw(((mode & Mode::bar ? "hist"s : ""s) + (mode & Mode::nostack ? "nostack"s : ""s)).data());
187 if (has_graphs)
188 mg->Draw(("l"s + (!has_hists ? "a" : "")).c_str());
189 if (has_hists) {
190 postDraw(hs->GetHistogram(), *first);
191 canv.Prettify(hs);
192 } else if (has_graphs) {
193 postDraw(mg->GetHistogram(), *first);
194 canv.Prettify(mg);
195 }
196 canv.Save(def_extension_);
197 }
198 for (size_t i = 0; i < plots_2d.size(); ++i) {
199 const auto* obj = plots_2d.at(i);
200 const std::string postfix = i == 0 ? "(" : i == plots_2d.size() - 1 ? ")" : "";
201 if (obj->isHist2D()) {
202 if (const auto* hist = dynamic_cast<const utils::Hist2D*>(obj); hist) {
203 auto* h = new TH2D(convert(*hist));
204 setMode(canv, mode);
205 h->Draw("colz");
206 canv.Prettify(h);
207 postDraw(h, *hist);
208 }
209 } else if (obj->isGraph2D()) {
210 if (const auto* graph = dynamic_cast<const utils::Graph2D*>(obj); graph) {
211 auto* gr = new TGraph2D(convert(*graph));
212 setMode(canv, mode);
213 if (mode & Mode::col)
214 gr->Draw("colz");
215 else if (mode & Mode::cont)
216 gr->Draw("cont");
217 else
218 gr->Draw("surf3");
219 gr->GetHistogram()->SetTitle(
220 delatexify(";" + graph->xAxis().label() + ";" + graph->yAxis().label() + ";" + graph->zAxis().label()));
221 canv.Prettify(gr->GetHistogram());
222 postDraw(gr->GetHistogram(), *graph);
223 }
224 }
225 canv.Print(utils::format("%s_multi.%s%s", canv.GetName(), def_extension_.data(), postfix.data()).data());
226 }
227 return *this;
228 }
229
230 TGraphErrors Drawer::convert(const utils::Graph1D& graph) {
231 TGraphErrors gr;
232 gr.SetTitle(delatexify(graph.title()));
233 int i = 0;
234 for (const auto& it : graph.points()) {
235 const auto& val = it.second;
236 gr.SetPoint(i, it.first.value, val);
237 gr.SetPointError(i, it.first.value_unc, val.uncertainty());
238 ++i;
239 }
240 gr.SetLineWidth(3);
241 return gr;
242 }
243
244 TGraph2DErrors Drawer::convert(const utils::Graph2D& graph) {
245 TGraph2DErrors gr;
246 gr.SetTitle(delatexify(graph.title()));
247 int i = 0;
248 for (const auto& it_x : graph.points()) {
249 const auto& ax_x = it_x.first.value;
250 for (const auto& it_y : it_x.second) {
251 const auto& ax_y = it_y.first.value;
252 const auto& val = it_y.second;
253 gr.SetPoint(i, ax_x, ax_y, val);
254 gr.SetPointError(i, 0., 0., val.uncertainty());
255 ++i;
256 }
257 }
258 return gr;
259 }
260
261 TH1D Drawer::convert(const utils::Hist1D& hist) {
262 const auto bins = hist.bins(utils::Histogram::BinMode::both);
263 TH1D h(hist.name().c_str(), delatexify(hist.title()), bins.size() - 1, bins.data());
264 h.SetBinContent(0, hist.underflow());
265 for (size_t i = 0; i < hist.nbins(); ++i) {
266 const auto val = hist.value(i);
267 h.SetBinContent(i + 1, val);
268 h.SetBinError(i + 1, val.uncertainty());
269 }
270 h.SetBinContent(hist.nbins() + 1, hist.overflow());
271 h.GetXaxis()->SetTitle(delatexify(hist.xAxis().label()));
272 h.GetYaxis()->SetTitle(delatexify(hist.yAxis().label()));
273 h.SetLineWidth(3);
274 return h;
275 }
276
277 TH2D Drawer::convert(const utils::Hist2D& hist) {
278 const auto bins_x = hist.binsX(utils::Histogram::BinMode::both),
279 bins_y = hist.binsY(utils::Histogram::BinMode::both);
280 TH2D h(hist.name().c_str(),
281 delatexify(hist.title()),
282 bins_x.size() - 1,
283 bins_x.data(),
284 bins_y.size() - 1,
285 bins_y.data());
286 for (size_t ix = 0; ix < hist.nbinsX(); ++ix)
287 for (size_t iy = 0; iy < hist.nbinsY(); ++iy) {
288 const auto val = hist.value(ix, iy);
289 h.SetBinContent(ix + 1, iy + 1, val);
290 h.SetBinError(ix + 1, iy + 1, val.uncertainty());
291 }
292 h.SetBinContent(0, 0, hist.outOfRange().at(utils::Hist2D::contents_t::LT_LT));
293 h.SetBinContent(0, 1, hist.outOfRange().at(utils::Hist2D::contents_t::LT_IN));
294 h.SetBinContent(0, hist.nbinsY() + 1, hist.outOfRange().at(utils::Hist2D::contents_t::LT_GT));
295 h.SetBinContent(1, 0, hist.outOfRange().at(utils::Hist2D::contents_t::IN_LT));
296 h.SetBinContent(1, hist.nbinsY() + 1, hist.outOfRange().at(utils::Hist2D::contents_t::IN_GT));
297 h.SetBinContent(hist.nbinsX() + 1, 0, hist.outOfRange().at(utils::Hist2D::contents_t::GT_LT));
298 h.SetBinContent(hist.nbinsX() + 1, 1, hist.outOfRange().at(utils::Hist2D::contents_t::GT_IN));
299 h.SetBinContent(hist.nbinsX() + 1, hist.nbinsY() + 1, hist.outOfRange().at(utils::Hist2D::contents_t::GT_GT));
300 h.GetXaxis()->SetTitle(delatexify(hist.xAxis().label()));
301 h.GetYaxis()->SetTitle(delatexify(hist.yAxis().label()));
302 h.GetZaxis()->SetTitle(delatexify(hist.zAxis().label()));
303 return h;
304 }
305 } // namespace root
306} // namespace cepgen
#define REGISTER_DRAWER(name, obj)
Add a drawing utilitary.
#define CG_DEBUG(mod)
Definition Message.h:220
const std::string & name() const
Module unique indexing name.
Definition NamedModule.h:42
A description object for parameters collection.
A "prettified" generic figure canvas.
Definition ROOTCanvas.h:89
void SetLegendX1(double x)
Set the horizontal coordinate of the low-left part of the legend object.
Definition ROOTCanvas.h:407
void SetLogz(int log=1)
Definition ROOTCanvas.h:396
T * Make(Args &&... args)
Garbage collector-like TObjects producer.
Definition ROOTCanvas.h:487
void Save(const std::string &ext, const std::string &out_dir=".")
Save the canvas in an external file.
Definition ROOTCanvas.h:434
static const std::vector< int > colours
Definition ROOTCanvas.h:91
void SetGrid(int x=1, int y=1)
Definition ROOTCanvas.h:377
void AddLegendEntry(const TObject *obj, const std::string &title, Option_t *option="lpf")
Add one new entry to the legend object.
Definition ROOTCanvas.h:420
void Prettify(TH1 *obj)
Draw main plot attributes in a pretty manner.
Definition ROOTCanvas.h:109
void SetLogx(int log=1)
Definition ROOTCanvas.h:383
void SetLogy(int log=1)
Definition ROOTCanvas.h:390
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 Drawer & draw(const utils::Hist2D &hist, const Mode &mode) const override
Draw a two-dimensional histogram.
Definition Drawer.cpp:90
const Drawer & draw(const utils::Graph2D &graph, const Mode &mode) const override
Draw a two-dimensional graph.
Definition Drawer.cpp:63
Drawer(const ParametersList &params)
Definition Drawer.cpp:37
static ParametersDescription description()
Definition Drawer.cpp:44
const Drawer & draw(const utils::Hist1D &hist, const Mode &mode) const override
Draw a one-dimensional histogram.
Definition Drawer.cpp:80
const Drawer & draw(const utils::Graph1D &graph, const Mode &mode) const override
Draw a one-dimensional graph.
Definition Drawer.cpp:52
const std::string & label() const
Axis title.
Definition Drawable.h:55
const Limits & range() const
Axis range.
Definition Drawable.h:72
A generic object which can be drawn in the standard output.
Definition Drawable.h:31
const std::string & name() const
Drawable name.
Definition Drawable.h:37
AxisInfo & yAxis()
Definition Drawable.h:81
AxisInfo & zAxis()
Definition Drawable.h:83
const std::string & title() const
Drawable name.
Definition Drawable.h:42
AxisInfo & xAxis()
Definition Drawable.h:79
A generic drawing utility.
Definition Drawer.h:36
A one-dimensional graph object.
Definition Graph.h:29
A two-dimensional graph object.
Definition Graph.h:58
1D histogram container
Definition Histogram.h:72
2D histogram container
Definition Histogram.h:146
std::string format(const std::string &fmt, Args... args)
Format a string using a printf style format descriptor.
Definition String.h:61
std::vector< const Drawable * > DrawableColl
A collection of drawable objects.
Definition Drawer.h:34
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
Common namespace for this Monte Carlo generator.