Analysis-Utilities 26.9.9
C++/ROOT utilities for nuclear measurement data analysis
Loading...
Searching...
No Matches
PlottingUtils.cpp
Go to the documentation of this file.
1#include "PlottingUtils.hpp"
2
3PlotSaveFormat PlottingUtils::save_format_ = PlotSaveFormat::kPNG;
4Bool_t PlottingUtils::preferences_set_ = kFALSE;
5Width_t PlottingUtils::line_width_ = 2;
6TString PlottingUtils::plots_base_dir_ = "plots";
7
8void PlottingUtils::SetPlotsBaseDir(const TString &dir) {
9 TString d = dir;
10 while (d.Length() > 0 && d[d.Length() - 1] == '/')
11 d.Chop();
12 plots_base_dir_ = d;
13}
14
15TString PlottingUtils::GetPlotsBaseDir() { return plots_base_dir_; }
16
17void PlottingUtils::WarnIfNotConfigured(const TString method_name) {
18 if (!preferences_set_)
19 std::cout << "WARNING: " << method_name
20 << " called before SetStylePreferences()." << std::endl;
21}
22
24 save_format_ = save_format;
25 preferences_set_ = kTRUE;
26 line_width_ = save_format_ == PlotSaveFormat::kPNG ? 2 : 1;
27
28 gStyle->SetOptStat(0);
29 gStyle->SetOptFit(0);
30 gStyle->SetPadLeftMargin(0.15);
31 gStyle->SetPadRightMargin(0.1);
32 gStyle->SetPadTopMargin(0.12);
33 gStyle->SetPadBottomMargin(0.15);
34 gStyle->SetTitleSize(0.06, "XY");
35 gStyle->SetLabelSize(0.06, "XY");
36 gStyle->SetLegendFont(132);
37 gStyle->SetTitleOffset(1.2, "X");
38 gStyle->SetTitleOffset(1.2, "Y");
39 gStyle->SetTextFont(42);
40 gStyle->SetHistLineWidth(line_width_);
41 gStyle->SetLineWidth(line_width_);
42 gStyle->SetPadGridX(1);
43 gStyle->SetPadGridY(1);
44 gStyle->SetGridStyle(3);
45 gStyle->SetGridWidth(line_width_);
46 gStyle->SetGridColor(kGray);
47 gStyle->SetPadTickX(1);
48 gStyle->SetPadTickY(1);
49
50 SetTurboPalette();
51}
52
53void PlottingUtils::ConfigureGraph(TGraph *graph, Int_t color,
54 const TString title) {
55 WarnIfNotConfigured("ConfigureGraph");
56 graph->SetLineColor(color);
57 graph->SetTitle(title);
58 graph->GetXaxis()->SetTitleSize(0.06);
59 graph->GetYaxis()->SetTitleSize(0.06);
60 graph->GetXaxis()->SetLabelSize(0.06);
61 graph->GetYaxis()->SetLabelSize(0.06);
62 graph->GetXaxis()->SetTitleOffset(1.2);
63 graph->GetYaxis()->SetTitleOffset(1.2);
64 graph->GetXaxis()->SetNdivisions(506);
65 graph->SetLineWidth(line_width_);
66}
67
68void PlottingUtils::ConfigureGraph(TGraphErrors *graph, Int_t color,
69 const TString title) {
70 WarnIfNotConfigured("ConfigureGraph");
71 graph->SetLineColor(color);
72 graph->SetTitle(title);
73 graph->GetXaxis()->SetTitleSize(0.06);
74 graph->GetYaxis()->SetTitleSize(0.06);
75 graph->GetXaxis()->SetLabelSize(0.06);
76 graph->GetYaxis()->SetLabelSize(0.06);
77 graph->GetXaxis()->SetTitleOffset(1.2);
78 graph->GetYaxis()->SetTitleOffset(1.2);
79 graph->GetXaxis()->SetNdivisions(506);
80 graph->SetMarkerStyle(20);
81 graph->SetMarkerSize(1.2);
82 graph->SetMarkerColor(color);
83 graph->SetLineWidth(line_width_);
84}
85
86void PlottingUtils::ConfigureHistogram(TH1 *hist, Int_t color,
87 const TString title) {
88 if (!hist)
89 return;
90 WarnIfNotConfigured("ConfigureHistogram");
91
92 hist->SetLineColor(color);
93 hist->SetTitle(title);
94 hist->SetLineWidth(line_width_);
95 hist->SetFillStyle(0);
96 hist->GetYaxis()->SetMoreLogLabels(kFALSE);
97 hist->GetYaxis()->SetNoExponent(kFALSE);
98 hist->GetXaxis()->SetNoExponent(kTRUE);
99 hist->GetYaxis()->SetNdivisions(50109);
100 hist->GetXaxis()->SetNdivisions(505);
101 hist->GetXaxis()->SetTitleSize(0.06);
102 hist->GetYaxis()->SetTitleSize(0.06);
103 hist->GetXaxis()->SetLabelSize(0.06);
104 hist->GetYaxis()->SetLabelSize(0.06);
105 hist->GetXaxis()->SetTitleOffset(1.2);
106 hist->GetYaxis()->SetTitleOffset(1.2);
107}
108
109void PlottingUtils::Configure2DHistogram(TH2 *hist, TCanvas *canvas,
110 const TString title) {
111 if (!hist)
112 return;
113 if (!canvas)
114 return;
115 WarnIfNotConfigured("Configure2DHistogram");
116
117 hist->SetTitle(title);
118 hist->GetYaxis()->SetMoreLogLabels(kFALSE);
119 hist->GetYaxis()->SetNoExponent(kFALSE);
120 hist->GetXaxis()->SetTitleSize(0.06);
121 hist->GetYaxis()->SetTitleSize(0.06);
122 hist->GetXaxis()->SetLabelSize(0.06);
123 hist->GetYaxis()->SetLabelSize(0.06);
124 hist->GetXaxis()->SetTitleOffset(1.2);
125 hist->GetYaxis()->SetTitleOffset(1);
126 hist->GetXaxis()->SetNdivisions(506);
127 hist->GetYaxis()->SetNdivisions(506);
128
129 canvas->SetLogz(kTRUE);
130 canvas->SetRightMargin(0.15);
131}
132
133void PlottingUtils::ConfigureAndDrawGraph(TGraph *graph, Int_t color,
134 const TString title) {
135 if (!graph)
136 return;
137
138 ConfigureGraph(graph, color, title);
139 graph->Draw();
140}
141
143 const TString title) {
144 if (!hist)
145 return;
146
147 ConfigureHistogram(hist, color, title);
148 hist->Draw("HIST");
149}
150
151void PlottingUtils::ConfigureAndDraw2DHistogram(TH2 *hist, TCanvas *canvas,
152 const TString title) {
153 if (!hist)
154 return;
155 if (!canvas)
156 return;
157
158 Configure2DHistogram(hist, canvas, title);
159 hist->Draw("COLZ");
160}
161
163 WarnIfNotConfigured("GetConfiguredCanvas");
164 TCanvas *canvas = new TCanvas(GetRandomName(), "", 1200, 800);
165
166 canvas->SetGridx(1);
167 canvas->SetGridy(1);
168 canvas->SetLogy(logy);
169
170 canvas->SetTicks(1, 1);
171 gPad->SetTicks(1, 1);
172
173 return canvas;
174}
175
176void PlottingUtils::SaveFigure(TCanvas *canvas, TString output_name,
177 TString output_subdirectory,
178 PlotSaveOptions save_options) {
179 WarnIfNotConfigured("SaveFigure");
180 canvas->SetLogy(kFALSE);
181 canvas->Modified();
182 canvas->Update();
183
184 TString extension = (save_format_ == PlotSaveFormat::kPNG) ? ".png" : ".pdf";
185 TString output_filename = output_name + extension;
186
187 TString base = GetPlotsBaseDir();
188 TString full_dir =
189 output_subdirectory == "" ? base : base + "/" + output_subdirectory;
190
191 if (gSystem->AccessPathName(full_dir)) {
192 gSystem->mkdir(full_dir, kTRUE);
193 }
194
195 TString prefix = full_dir + "/";
196
197 if (save_options != PlotSaveOptions::kLOG)
198 canvas->Print(prefix + output_filename);
199
200 if (save_options != PlotSaveOptions::kLINEAR) {
201 TList *primitives = canvas->GetListOfPrimitives();
202 Int_t size = primitives->GetSize();
203
204 for (Int_t i = 0; i < size; i++) {
205 TObject *object = primitives->At(i);
206 if (object->InheritsFrom(TH2::Class())) {
207 std::cout << std::endl;
208 std::cerr << "ERROR: Used PlotSaveOptions::kLOG for 2D histogram."
209 << std::endl;
210 std::cout
211 << "This option is exclusive to 1D histograms/graphs because it refers to the y axis."
212 << std::endl;
213 std::cout << "Use PlotSaveOptions::kLINEAR." << std::endl;
214 std::cout
215 << "The z axis is already log by default if you used PlottingUtils::Configure2DHistogram()."
216 << std::endl;
217 std::cout << "Plot " << prefix + "log_" + output_filename
218 << " was not saved." << std::endl;
219 std::exit(1);
220 };
221 };
222
223 canvas->SetLogy(kTRUE);
224 canvas->Modified();
225 canvas->Update();
226 canvas->Print(prefix + "log_" + output_filename);
227
228 canvas->SetLogy(kFALSE);
229 canvas->Modified();
230 canvas->Update();
231 }
232}
233
235 return {kRed + 1, kBlue + 1, kGreen + 2, kOrange + 1, kMagenta + 1,
236 kCyan + 2, kViolet + 1, kSpring - 1, kPink + 1, kTeal + 2,
237 kAzure + 2, kYellow + 1, kOrange - 3, kMagenta - 3, kCyan - 6,
238 kRed - 4, kBlue - 4, kGreen - 6, kViolet - 4, kSpring + 5,
239 kPink - 3, kTeal - 5, kAzure - 3, kOrange + 7};
240}
241
242TLegend *PlottingUtils::AddLegend(Double_t x1, Double_t x2, Double_t y1,
243 Double_t y2) {
244 TLegend *leg = new TLegend(x1, y1, x2, y2);
245 leg->SetBorderSize(1);
246 leg->SetFillColor(kWhite);
247 leg->SetTextSize(30);
248 leg->SetTextFont(43);
249 leg->Draw();
250
251 return leg;
252}
253
254TLatex *PlottingUtils::AddText(const TString label, Double_t x, Double_t y,
255 Double_t angle) {
256 TLatex *text = new TLatex(x, y, label);
257 text->SetNDC();
258 text->SetTextSize(30);
259 text->SetTextAlign(33);
260 text->SetTextFont(43);
261 text->SetTextAngle(angle);
262 text->Draw();
263
264 return text;
265}
266
268 static TRandom3 generator(0);
269 Double_t number = generator.Rndm();
270 TString name = Form("name%.7f", number);
271 return name;
272}
273
275 TH1 *hist, TGraph *total_graph,
276 const std::vector<TGraph *> &component_graphs, Float_t fit_range_low,
277 Float_t fit_range_high, const TString &output_name,
278 const TString &output_subdirectory, const TString &label, Bool_t logy) {
279 TCanvas *canvas = GetConfiguredCanvas(kFALSE);
280
281 TPad *pad1 = new TPad("pad1", "pad1", 0, 0.3, 1, 1.0);
282 TPad *pad2 = new TPad("pad2", "pad2", 0, 0, 1, 0.3);
283 pad1->SetBottomMargin(0.04);
284 pad1->SetGridx(1);
285 pad1->SetGridy(1);
286 pad1->SetTopMargin(0.12);
287 pad2->SetTopMargin(0.04);
288 pad2->SetBottomMargin(0.35);
289 pad2->SetGridx(1);
290 pad2->SetGridy(1);
291 pad1->Draw();
292 pad2->Draw();
293 pad1->cd();
294
295 Float_t min_hist_value = 0.9 * fit_range_low;
296 Float_t max_hist_value = 1.1 * fit_range_high;
297
298 hist->GetXaxis()->SetRangeUser(min_hist_value, max_hist_value);
299 hist->GetXaxis()->SetLabelSize(0);
300 hist->GetXaxis()->SetTitleSize(0);
301 hist->SetLineColor(kViolet);
302 hist->GetYaxis()->SetTitleOffset(1);
303 hist->SetLineWidth(line_width_);
304 hist->Draw();
305
306 pad1->SetTickx(0);
307 if (total_graph)
308 total_graph->Draw("L same");
309 for (std::size_t i = 0; i < component_graphs.size(); i++) {
310 if (component_graphs[i])
311 component_graphs[i]->Draw("L same");
312 }
313
314 pad2->cd();
315
316 Int_t nbins = hist->GetNbinsX();
317 TGraph *residuals = new TGraph();
318 Int_t point_counter = 0;
319 for (Int_t i = 1; i <= nbins; i++) {
320 Double_t x = hist->GetBinCenter(i);
321 if (x < fit_range_low || x > fit_range_high)
322 continue;
323 Double_t data = hist->GetBinContent(i);
324 Double_t fit_val = total_graph ? total_graph->Eval(x) : 0.0;
325 Double_t error = hist->GetBinError(i);
326
327 if (error > 0 && data > 0) {
328 Double_t pull = (data - fit_val) / error;
329 residuals->SetPoint(point_counter, x, pull);
330 point_counter++;
331 }
332 }
333
334 residuals->SetMarkerStyle(20);
335 residuals->SetMarkerSize(0.8);
336 residuals->SetMarkerColor(kAzure);
337 residuals->SetLineColor(kAzure);
338 residuals->SetTitle("");
339 Double_t actual_min =
340 hist->GetXaxis()->GetBinLowEdge(hist->GetXaxis()->GetFirst());
341 Double_t actual_max =
342 hist->GetXaxis()->GetBinUpEdge(hist->GetXaxis()->GetLast());
343 residuals->GetXaxis()->SetLimits(actual_min, actual_max);
344 residuals->GetYaxis()->SetTitle("#delta/#sigma");
345 residuals->GetXaxis()->SetTitle(hist->GetXaxis()->GetTitle());
346 residuals->GetXaxis()->SetTitleSize(0.13);
347 residuals->GetYaxis()->SetTitleSize(0.13);
348 residuals->GetXaxis()->SetLabelSize(0.12);
349 residuals->GetYaxis()->SetLabelSize(0.12);
350 residuals->GetXaxis()->SetTitleOffset(1.0);
351 residuals->GetYaxis()->SetTitleOffset(0.3);
352 residuals->GetYaxis()->SetNdivisions(505);
353 residuals->GetXaxis()->SetNdivisions(510);
354 residuals->GetYaxis()->CenterTitle(kTRUE);
355 residuals->GetYaxis()->SetRangeUser(-5.5, 5.5);
356 residuals->Draw("AP");
357
358 TF1 *zero_line = new TF1("zero_line", "0", actual_min, actual_max);
359 zero_line->SetLineColor(kBlack);
360 zero_line->SetLineStyle(2);
361 zero_line->SetLineWidth(line_width_);
362 zero_line->Draw("same");
363
364 TF1 *plus3_line = new TF1("plus3_line", "3", actual_min, actual_max);
365 plus3_line->SetLineColor(kGray + 2);
366 plus3_line->SetLineStyle(3);
367 plus3_line->SetLineWidth(line_width_);
368 plus3_line->Draw("same");
369
370 TF1 *minus3_line = new TF1("minus3_line", "-3", actual_min, actual_max);
371 minus3_line->SetLineColor(kGray + 2);
372 minus3_line->SetLineStyle(3);
373 minus3_line->SetLineWidth(line_width_);
374 minus3_line->Draw("same");
375
376 pad1->cd();
377 pad1->SetLogy(logy);
378 if (label.Length() > 0) {
379 AddText(label, 0.85, 0.85);
380 }
381
382 PlotSaveOptions save_opts =
384 SaveFigure(canvas, output_name, output_subdirectory, save_opts);
385
386 PlotPullHistogram(residuals, output_name, output_subdirectory);
387
388 gROOT->GetListOfCanvases()->Remove(canvas);
389 canvas->SetBatch(kTRUE);
390 delete canvas;
391 delete residuals;
392 delete zero_line;
393 delete plus3_line;
394 delete minus3_line;
395}
396
397void PlottingUtils::PlotPullHistogram(TGraph *residuals,
398 const TString &output_name,
399 const TString &output_subdirectory) {
400 Int_t npoints = residuals->GetN();
401 if (npoints == 0)
402 return;
403
404 TH1D *pull_hist =
405 new TH1D("pull_hist", ";#delta/#sigma;Counts", 82, -5.5, 5.5);
406
407 Double_t *y = residuals->GetY();
408 for (Int_t i = 0; i < npoints; i++) {
409 pull_hist->Fill(y[i]);
410 }
411
412 TH1D *gauss_ref = new TH1D("gauss_ref", "", 82, -5.5, 5.5);
413 for (Int_t i = 1; i <= gauss_ref->GetNbinsX(); i++) {
414 Double_t lo = gauss_ref->GetBinLowEdge(i);
415 Double_t hi = lo + gauss_ref->GetBinWidth(i);
416 gauss_ref->SetBinContent(i, npoints * (TMath::Freq(hi) - TMath::Freq(lo)));
417 }
418
419 Double_t ks_pvalue = pull_hist->KolmogorovTest(gauss_ref);
420
421 TCanvas *hist_canvas = GetConfiguredCanvas(kFALSE);
422 ConfigureAndDrawHistogram(pull_hist, kAzure);
423 AddText(TString::Format("KS p = %.3f", ks_pvalue), 0.85, 0.85);
424
425 SaveFigure(hist_canvas, "residuals_" + output_name,
426 output_subdirectory + "/residual_hists", PlotSaveOptions::kLINEAR);
427
428 delete hist_canvas;
429 delete gauss_ref;
430 delete pull_hist;
431}
432
433void PlottingUtils::SetTurboPalette() {
434 Int_t N_COLORS = 255;
435
436 std::vector<Double_t> stops(N_COLORS);
437 std::vector<Double_t> reds(N_COLORS);
438 std::vector<Double_t> greens(N_COLORS);
439 std::vector<Double_t> blues(N_COLORS);
440
441 for (Int_t i = 0; i < N_COLORS; ++i) {
442 Double_t x = Double_t(i) / Double_t(N_COLORS - 1);
443
444 Double_t r = 0.13572138 + 4.61539260 * x - 42.66032258 * x * x +
445 132.13108234 * x * x * x - 152.94239396 * x * x * x * x +
446 59.28637943 * x * x * x * x * x;
447
448 Double_t g = 0.09140261 + 2.19418839 * x + 4.84296658 * x * x -
449 14.18503333 * x * x * x + 4.27729857 * x * x * x * x +
450 2.82956604 * x * x * x * x * x;
451
452 Double_t b = 0.10667330 + 12.64194608 * x - 60.58204836 * x * x +
453 110.36276771 * x * x * x - 89.90310912 * x * x * x * x +
454 27.34824973 * x * x * x * x * x;
455
456 stops[i] = x;
457 reds[i] = std::max(0.0, std::min(1.0, r));
458 greens[i] = std::max(0.0, std::min(1.0, g));
459 blues[i] = std::max(0.0, std::min(1.0, b));
460 }
461
462 Int_t firstColor =
463 TColor::CreateGradientColorTable(N_COLORS, stops.data(), reds.data(),
464 greens.data(), blues.data(), N_COLORS);
465
466 std::vector<Int_t> palette(N_COLORS);
467 for (Int_t i = 0; i < N_COLORS; ++i) {
468 palette[i] = firstColor + i;
469 }
470
471 gStyle->SetNumberContours(N_COLORS);
472 gStyle->SetPalette(N_COLORS, palette.data());
473}
PlotSaveOptions
Which axis scalings SaveFigure() should write out.
@ kLOG
Logarithmic y only, written with a log_ filename prefix.
@ kLINEAR
Linear y only.
PlotSaveFormat
Output file format for saved figures.
@ kPNG
PNG raster output; line width 2.
static TLatex * AddText(const TString label, Double_t x=0.9, Double_t y=0.85, Double_t angle=0)
Create and draw a text annotation on the current pad.
static void ConfigureAndDrawGraph(TGraph *graph, Int_t color, const TString title="")
ConfigureGraph() followed by Draw().
static TLegend * AddLegend(Double_t x1=0.7, Double_t x2=0.9, Double_t y1=0.7, Double_t y2=0.9)
Create, style and draw a legend on the current pad.
static void SaveFigure(TCanvas *canvas, TString output_filename, TString output_subdirectory="", PlotSaveOptions save_options=PlotSaveOptions::kBOTH)
Write a canvas to disk under the configured plots base directory.
static void SetPlotsBaseDir(const TString &dir)
Set the base directory that saved figures are written under.
static TString GetRandomName()
Generate a name unlikely to collide with existing ROOT objects.
static void ConfigureGraph(TGraph *graph, Int_t color, const TString title="")
Apply the house style to a graph without drawing it.
static void SetStylePreferences(PlotSaveFormat save_format=PlotSaveFormat::kPNG)
Install the global ROOT style and choose the output format.
static void Configure2DHistogram(TH2 *hist, TCanvas *canvas, const TString title="")
Apply the house style to a 2-D histogram and its canvas.
static void ConfigureAndDrawHistogram(TH1 *hist, Int_t color, const TString title="")
ConfigureHistogram() followed by Draw("HIST").
static void ConfigureHistogram(TH1 *hist, Int_t color, const TString title="")
Apply the house style to a 1-D histogram without drawing it.
static TCanvas * GetConfiguredCanvas(Bool_t logy=kFALSE)
Create a 1200x800 canvas with grid and ticks already set up.
static void PlotFitWithResiduals(TH1 *hist, TGraph *total_graph, const std::vector< TGraph * > &component_graphs, Float_t fit_range_low, Float_t fit_range_high, const TString &output_name, const TString &output_subdirectory="fits", const TString &label="", Bool_t logy=kTRUE)
Draw a fit over its data with a residual panel and save it.
static std::vector< Int_t > GetDefaultColors()
A palette of visually distinct ROOT colour indices.
static void ConfigureAndDraw2DHistogram(TH2 *hist, TCanvas *canvas, const TString title="")
Configure2DHistogram() followed by Draw("COLZ").
static TString GetPlotsBaseDir()
Current base directory for saved figures, without trailing slash.