Analysis-Utilities 26.10.19
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#include <TAttLine.h>
3#include <TAttMarker.h>
4#include <TAxis.h>
5#include <TList.h>
6#include <TText.h>
7
8PlotSaveFormat PlottingUtils::save_format_ = PlotSaveFormat::kPNG;
9Bool_t PlottingUtils::preferences_set_ = kFALSE;
10Width_t PlottingUtils::line_width_ = 2;
11TString PlottingUtils::plots_base_dir_ = "plots";
12
13void PlottingUtils::SetPlotsBaseDir(const TString &dir) {
14 TString d = dir;
15 while (d.Length() > 0 && d[d.Length() - 1] == '/')
16 d.Chop();
17 plots_base_dir_ = d;
18}
19
20TString PlottingUtils::GetPlotsBaseDir() { return plots_base_dir_; }
21
22void PlottingUtils::WarnIfNotConfigured(const TString method_name) {
23 if (!preferences_set_)
24 std::cout << "WARNING: " << method_name
25 << " called before SetStylePreferences()." << std::endl;
26}
27
29 save_format_ = save_format;
30 preferences_set_ = kTRUE;
31 line_width_ = save_format_ == PlotSaveFormat::kPNG ? 2 : 1;
32
33 gStyle->SetOptStat(0);
34 gStyle->SetOptFit(0);
35 gStyle->SetPadLeftMargin(0.15);
36 gStyle->SetPadRightMargin(0.1);
37 gStyle->SetPadTopMargin(0.12);
38 gStyle->SetPadBottomMargin(0.15);
39 gStyle->SetTitleSize(0.06, "XY");
40 gStyle->SetLabelSize(0.06, "XY");
41 gStyle->SetLegendFont(132);
42 gStyle->SetTitleOffset(1.2, "X");
43 gStyle->SetTitleOffset(1.2, "Y");
44 gStyle->SetTextFont(42);
45 gStyle->SetHistLineWidth(line_width_);
46 gStyle->SetLineWidth(line_width_);
47 gStyle->SetPadGridX(1);
48 gStyle->SetPadGridY(1);
49 gStyle->SetGridStyle(3);
50 gStyle->SetGridWidth(line_width_);
51 gStyle->SetGridColor(kGray);
52 gStyle->SetPadTickX(1);
53 gStyle->SetPadTickY(1);
54
55 SetTurboPalette();
56}
57
58void PlottingUtils::ConfigureGraph(TGraph *graph, Int_t color,
59 const TString title) {
60 WarnIfNotConfigured("ConfigureGraph");
61 graph->SetLineColor(color);
62 graph->SetTitle(title);
63 graph->GetXaxis()->SetTitleSize(0.06);
64 graph->GetYaxis()->SetTitleSize(0.06);
65 graph->GetXaxis()->SetLabelSize(0.06);
66 graph->GetYaxis()->SetLabelSize(0.06);
67 graph->GetXaxis()->SetTitleOffset(1.2);
68 graph->GetYaxis()->SetTitleOffset(1.2);
69 graph->GetXaxis()->SetNdivisions(506);
70 graph->SetLineWidth(line_width_);
71}
72
73void PlottingUtils::ConfigureGraph(TGraphErrors *graph, Int_t color,
74 const TString title) {
75 WarnIfNotConfigured("ConfigureGraph");
76 graph->SetLineColor(color);
77 graph->SetTitle(title);
78 graph->GetXaxis()->SetTitleSize(0.06);
79 graph->GetYaxis()->SetTitleSize(0.06);
80 graph->GetXaxis()->SetLabelSize(0.06);
81 graph->GetYaxis()->SetLabelSize(0.06);
82 graph->GetXaxis()->SetTitleOffset(1.2);
83 graph->GetYaxis()->SetTitleOffset(1.2);
84 graph->GetXaxis()->SetNdivisions(506);
85 graph->SetMarkerStyle(20);
86 graph->SetMarkerSize(1.2);
87 graph->SetMarkerColor(color);
88 graph->SetLineWidth(line_width_);
89}
90
91void PlottingUtils::ConfigureHistogram(TH1 *hist, Int_t color,
92 const TString title) {
93 if (!hist)
94 return;
95 WarnIfNotConfigured("ConfigureHistogram");
96
97 hist->SetLineColor(color);
98 hist->SetTitle(title);
99 hist->SetLineWidth(line_width_);
100 hist->SetFillStyle(0);
101 hist->GetYaxis()->SetMoreLogLabels(kFALSE);
102 hist->GetYaxis()->SetNoExponent(kFALSE);
103 hist->GetXaxis()->SetNoExponent(kTRUE);
104 hist->GetYaxis()->SetNdivisions(50109);
105 hist->GetXaxis()->SetNdivisions(505);
106 hist->GetXaxis()->SetTitleSize(0.06);
107 hist->GetYaxis()->SetTitleSize(0.06);
108 hist->GetXaxis()->SetLabelSize(0.06);
109 hist->GetYaxis()->SetLabelSize(0.06);
110 hist->GetXaxis()->SetTitleOffset(1.2);
111 hist->GetYaxis()->SetTitleOffset(1.2);
112}
113
114void PlottingUtils::Configure2DHistogram(TH2 *hist, TCanvas *canvas,
115 const TString title) {
116 if (!hist)
117 return;
118 if (!canvas)
119 return;
120 WarnIfNotConfigured("Configure2DHistogram");
121
122 hist->SetTitle(title);
123 hist->GetYaxis()->SetMoreLogLabels(kFALSE);
124 hist->GetYaxis()->SetNoExponent(kFALSE);
125 hist->GetXaxis()->SetTitleSize(0.06);
126 hist->GetYaxis()->SetTitleSize(0.06);
127 hist->GetXaxis()->SetLabelSize(0.06);
128 hist->GetYaxis()->SetLabelSize(0.06);
129 hist->GetXaxis()->SetTitleOffset(1.2);
130 hist->GetYaxis()->SetTitleOffset(1);
131 hist->GetXaxis()->SetNdivisions(506);
132 hist->GetYaxis()->SetNdivisions(506);
133
134 canvas->SetLogz(kTRUE);
135 canvas->SetRightMargin(0.15);
136}
137
138void PlottingUtils::ConfigureAndDrawGraph(TGraph *graph, Int_t color,
139 const TString title) {
140 if (!graph)
141 return;
142
143 ConfigureGraph(graph, color, title);
144 graph->Draw();
145}
146
148 const TString title) {
149 if (!hist)
150 return;
151
152 ConfigureHistogram(hist, color, title);
153 hist->Draw("HIST");
154}
155
156void PlottingUtils::ConfigureAndDraw2DHistogram(TH2 *hist, TCanvas *canvas,
157 const TString title) {
158 if (!hist)
159 return;
160 if (!canvas)
161 return;
162
163 Configure2DHistogram(hist, canvas, title);
164 hist->Draw("COLZ");
165}
166
168 WarnIfNotConfigured("GetConfiguredCanvas");
169 TCanvas *canvas = new TCanvas(GetRandomName(), "", 1200, 800);
170
171 canvas->SetGridx(1);
172 canvas->SetGridy(1);
173 canvas->SetLogy(logy);
174
175 canvas->SetTicks(1, 1);
176 gPad->SetTicks(1, 1);
177
178 return canvas;
179}
180
182 TPad *&legend_pad,
183 Int_t legend_width_px,
184 Int_t plot_height_px,
185 Bool_t logy) {
186 WarnIfNotConfigured("GetConfiguredCanvasWithSideLegend");
187 const Int_t plot_width_px = 1200;
188 const Int_t canvas_width_px = plot_width_px + TMath::Max(0, legend_width_px);
189 TCanvas *canvas =
190 new TCanvas(GetRandomName(), "", canvas_width_px, plot_height_px);
191 canvas->SetTicks(1, 1);
192 const Double_t split = Double_t(plot_width_px) / Double_t(canvas_width_px);
193 plot = new TPad(GetRandomName(), "", 0.0, 0.0, split, 1.0);
194 plot->SetGridx(1);
195 plot->SetGridy(1);
196 plot->SetTicks(1, 1);
197 plot->SetLogy(logy);
198 const Double_t frame_right = split * (1.0 - plot->GetRightMargin());
199 legend_pad = new TPad(GetRandomName(), "", frame_right, 0.0, 1.0, 1.0);
200 legend_pad->SetFillStyle(4000);
201 legend_pad->SetMargin(0.0, 0.0, 0.0, 0.0);
202 plot->Draw();
203 legend_pad->Draw();
204 plot->cd();
205 return canvas;
206}
207
208void PlottingUtils::SplitPadForPanel(TVirtualPad *pad, Int_t panel_height_px,
209 TPad *&upper, TPad *&lower) {
210 upper = nullptr;
211 lower = nullptr;
212 if (!pad || !pad->GetCanvas())
213 return;
214 const Double_t pad_height_px = pad->GetCanvas()->GetWh() * pad->GetAbsHNDC();
215 if (!(pad_height_px > 0.0) || panel_height_px <= 0 ||
216 panel_height_px >= pad_height_px)
217 return;
218 const Double_t upper_height_px = pad_height_px - panel_height_px;
219 const Double_t split = Double_t(panel_height_px) / pad_height_px;
220 const Double_t lower_top =
221 (panel_height_px + pad->GetBottomMargin() * upper_height_px) /
222 pad_height_px;
223 TVirtualPad *previous = gPad;
224 pad->cd();
225 upper = new TPad(GetRandomName(), "", 0.0, split, 1.0, 1.0);
226 upper->SetLeftMargin(pad->GetLeftMargin());
227 upper->SetRightMargin(pad->GetRightMargin());
228 upper->SetTopMargin(pad->GetTopMargin());
229 upper->SetBottomMargin(pad->GetBottomMargin());
230 upper->SetGridx(pad->GetGridx());
231 upper->SetGridy(pad->GetGridy());
232 upper->SetTicks(pad->GetTickx(), pad->GetTicky());
233 upper->SetLogy(pad->GetLogy());
234 lower = new TPad(GetRandomName(), "", 0.0, 0.0, 1.0, lower_top);
235 lower->SetFillStyle(4000);
236 lower->SetLeftMargin(pad->GetLeftMargin());
237 lower->SetRightMargin(pad->GetRightMargin());
238 lower->SetTopMargin(0.03);
239 lower->SetBottomMargin(pad->GetBottomMargin());
240 lower->SetGridx(pad->GetGridx());
241 lower->SetGridy(pad->GetGridy());
242 lower->SetTicks(pad->GetTickx(), pad->GetTicky());
243 upper->Draw();
244 lower->Draw();
245 if (previous)
246 previous->cd();
247}
248
249void PlottingUtils::SaveFigure(TCanvas *canvas, TString output_name,
250 TString output_subdirectory,
251 PlotSaveOptions save_options) {
252 WarnIfNotConfigured("SaveFigure");
253 canvas->SetLogy(kFALSE);
254 canvas->Modified();
255 canvas->Update();
256
257 TString extension = (save_format_ == PlotSaveFormat::kPNG) ? ".png" : ".pdf";
258 TString output_filename = output_name + extension;
259
260 TString base = GetPlotsBaseDir();
261 TString full_dir =
262 output_subdirectory == "" ? base : base + "/" + output_subdirectory;
263
264 if (gSystem->AccessPathName(full_dir)) {
265 gSystem->mkdir(full_dir, kTRUE);
266 }
267
268 TString prefix = full_dir + "/";
269
270 // Left to itself, ROOT prints a canvas at least as wide as it is tall onto
271 // a portrait page turned by 90 degrees, which LaTeX then places sideways or
272 // shrunk. "Portrait" gives an unrotated page with the canvas's own shape.
273 TString print_option =
274 (save_format_ == PlotSaveFormat::kPDF) ? "pdf Portrait" : "";
275
276 if (save_options != PlotSaveOptions::kLOG)
277 canvas->Print(prefix + output_filename, print_option);
278
279 if (save_options != PlotSaveOptions::kLINEAR) {
280 TList *primitives = canvas->GetListOfPrimitives();
281 Int_t size = primitives->GetSize();
282
283 for (Int_t i = 0; i < size; i++) {
284 TObject *object = primitives->At(i);
285 if (object->InheritsFrom(TH2::Class())) {
286 std::cout << std::endl;
287 std::cerr << "ERROR: Used PlotSaveOptions::kLOG for 2D histogram."
288 << std::endl;
289 std::cout
290 << "This option is exclusive to 1D histograms/graphs because it refers to the y axis."
291 << std::endl;
292 std::cout << "Use PlotSaveOptions::kLINEAR." << std::endl;
293 std::cout
294 << "The z axis is already log by default if you used PlottingUtils::Configure2DHistogram()."
295 << std::endl;
296 std::cout << "Plot " << prefix + "log_" + output_filename
297 << " was not saved." << std::endl;
298 std::exit(1);
299 };
300 };
301
302 canvas->SetLogy(kTRUE);
303 canvas->Modified();
304 canvas->Update();
305 canvas->Print(prefix + "log_" + output_filename, print_option);
306
307 canvas->SetLogy(kFALSE);
308 canvas->Modified();
309 canvas->Update();
310 }
311}
312
314 return {kRed + 1, kBlue + 1, kGreen + 2, kOrange + 1, kMagenta + 1,
315 kCyan + 2, kViolet + 1, kSpring - 1, kPink + 1, kTeal + 2,
316 kAzure + 2, kYellow + 1, kOrange - 3, kMagenta - 3, kCyan - 6,
317 kRed - 4, kBlue - 4, kGreen - 6, kViolet - 4, kSpring + 5,
318 kPink - 3, kTeal - 5, kAzure - 3, kOrange + 7};
319}
320
321TLegend *PlottingUtils::AddLegend(Double_t x1, Double_t x2, Double_t y1,
322 Double_t y2) {
323 TLegend *leg = new TLegend(x1, y1, x2, y2);
324 leg->SetBorderSize(1);
325 leg->SetFillColor(kWhite);
326 leg->SetTextSize(30);
327 leg->SetTextFont(43);
328 leg->Draw();
329
330 return leg;
331}
332
333Double_t PlottingUtils::TextWidthPx(const TString &text, Double_t size_px,
334 Int_t font) {
335 if (text.Length() == 0)
336 return 0.0;
337 TVirtualPad *previous = gPad;
338 const Int_t scratch_px = 1000;
339 TCanvas *scratch = new TCanvas(GetRandomName(), "", scratch_px, scratch_px);
340 TLatex latex(0.1, 0.5, text);
341 latex.SetNDC();
342 latex.SetTextFont(font);
343 latex.SetTextSize(size_px);
344 const Double_t width_px = latex.GetXsize() * scratch_px;
345 delete scratch;
346 if (previous)
347 previous->cd();
348 return width_px;
349}
350
351Double_t PlottingUtils::LegendWidthPx(const std::vector<TString> &labels,
352 const TString &header, Double_t size_px,
353 Double_t margin, Double_t padding_px) {
354 Double_t width_px = TextWidthPx(header, size_px);
355 for (std::size_t i = 0; i < labels.size(); i++)
356 width_px = TMath::Max(width_px, TextWidthPx(labels[i], size_px) /
357 TMath::Max(0.05, 1.0 - margin));
358 return width_px + 2.0 * padding_px;
359}
360
361Double_t PlottingUtils::FigureScale(TVirtualPad *pad,
362 Int_t reference_width_px) {
363 if (!pad || !pad->GetCanvas() || reference_width_px <= 0)
364 return 1.0;
365 const Double_t pad_width_px = pad->GetCanvas()->GetWw() * pad->GetAbsWNDC();
366 return pad_width_px / Double_t(reference_width_px);
367}
368
369void PlottingUtils::ScaleFigure(TVirtualPad *pad, Int_t reference_width_px,
370 Int_t reference_height_px) {
371 WarnIfNotConfigured("ScaleFigure");
372 if (!pad)
373 return;
374 ScalePad(pad, FigureScale(pad, reference_width_px), reference_width_px,
375 reference_height_px);
376}
377
378void PlottingUtils::ScalePad(TVirtualPad *pad, Double_t scale,
379 Int_t reference_width_px,
380 Int_t reference_height_px) {
381 if (!pad || !pad->GetCanvas())
382 return;
383 const Double_t pad_width_px = pad->GetCanvas()->GetWw() * pad->GetAbsWNDC();
384 const Double_t pad_height_px = pad->GetCanvas()->GetWh() * pad->GetAbsHNDC();
385 if (!(pad_width_px > 0.0) || !(pad_height_px > 0.0))
386 return;
387 const Double_t x_factor = reference_width_px * scale / pad_width_px;
388 const Double_t y_factor = reference_height_px * scale / pad_height_px;
389 pad->SetLeftMargin(TMath::Min(0.9, pad->GetLeftMargin() * x_factor));
390 pad->SetRightMargin(TMath::Min(0.9, pad->GetRightMargin() * x_factor));
391 pad->SetTopMargin(TMath::Min(0.9, pad->GetTopMargin() * y_factor));
392 pad->SetBottomMargin(TMath::Min(0.9, pad->GetBottomMargin() * y_factor));
393
394 TList *primitives = pad->GetListOfPrimitives();
395 if (!primitives)
396 return;
397 TIter next(primitives);
398 for (TObject *object = next(); object; object = next()) {
399 if (object->InheritsFrom(TVirtualPad::Class())) {
400 ScalePad(static_cast<TVirtualPad *>(object), scale, reference_width_px,
401 reference_height_px);
402 continue;
403 }
404 if (object->InheritsFrom(TLegend::Class())) {
405 ScaleLegend(static_cast<TLegend *>(object), scale);
406 continue;
407 }
408 if (object->InheritsFrom(TText::Class())) {
409 ScaleText(static_cast<TText *>(object), pad, scale, reference_height_px);
410 continue;
411 }
412 if (object->InheritsFrom(TH1::Class()))
413 ScaleAxisFontsToPad(static_cast<TH1 *>(object), pad, scale,
414 reference_width_px, reference_height_px);
415 ScaleLine(dynamic_cast<TAttLine *>(object), scale);
416 ScaleMarker(dynamic_cast<TAttMarker *>(object), scale);
417 }
418}
419
420void PlottingUtils::ScaleAxisFontsToPad(TH1 *frame, TVirtualPad *pad,
421 Double_t scale,
422 Int_t reference_width_px,
423 Int_t reference_height_px) {
424 WarnIfNotConfigured("ScaleAxisFontsToPad");
425 if (!frame || !pad || !pad->GetCanvas() || reference_width_px <= 0 ||
426 reference_height_px <= 0)
427 return;
428 const Double_t pad_width_px = pad->GetCanvas()->GetWw() * pad->GetAbsWNDC();
429 const Double_t pad_height_px = pad->GetCanvas()->GetWh() * pad->GetAbsHNDC();
430 const Double_t pad_px = TMath::Min(pad_width_px, pad_height_px);
431 if (!(pad_px > 0.0))
432 return;
433 const Double_t size = 0.06 * reference_height_px * scale / pad_px;
434 const Double_t reference_aspect =
435 Double_t(TMath::Min(reference_width_px, reference_height_px)) /
436 Double_t(reference_width_px);
437 TAxis *axes[2] = {frame->GetXaxis(), frame->GetYaxis()};
438 for (Int_t i = 0; i < 2; i++) {
439 if (axes[i]->GetTitleSize() > 0.0)
440 axes[i]->SetTitleSize(size);
441 if (axes[i]->GetLabelSize() > 0.0)
442 axes[i]->SetLabelSize(size);
443 }
444 frame->GetXaxis()->SetTitleOffset(1.2 * pad_px / pad_height_px);
445 frame->GetYaxis()->SetTitleOffset(1.2 * (pad_px / pad_width_px) /
446 reference_aspect);
447}
448
449void PlottingUtils::ScaleLegend(TLegend *legend, Double_t scale) {
450 if (!legend)
451 return;
452 legend->SetTextSize(30.0 * scale);
453}
454
455void PlottingUtils::ScaleText(TText *text, TVirtualPad *pad, Double_t scale,
456 Int_t reference_height_px) {
457 if (!text || !pad || !pad->GetCanvas())
458 return;
459 const Int_t precision = text->GetTextFont() % 10;
460 if (precision == 3) {
461 text->SetTextSize(text->GetTextSize() * scale);
462 return;
463 }
464 const Double_t pad_width_px = pad->GetCanvas()->GetWw() * pad->GetAbsWNDC();
465 const Double_t pad_height_px = pad->GetCanvas()->GetWh() * pad->GetAbsHNDC();
466 const Double_t pad_px = TMath::Min(pad_width_px, pad_height_px);
467 if (!(pad_px > 0.0))
468 return;
469 text->SetTextSize(text->GetTextSize() * reference_height_px * scale / pad_px);
470}
471
472TLatex *PlottingUtils::DrawTitle(TVirtualPad *pad, const TString &title,
473 Double_t scale) {
474 if (!pad || title.Length() == 0)
475 return nullptr;
476 TVirtualPad *previous = gPad;
477 pad->cd();
478 TLatex *text = new TLatex(0.5, 1.0 - 0.5 * pad->GetTopMargin(), title);
479 text->SetNDC();
480 text->SetTextFont(43);
481 text->SetTextSize(36.0 * scale);
482 text->SetTextAlign(22);
483 text->Draw();
484 if (previous)
485 previous->cd();
486 return text;
487}
488
489void PlottingUtils::ScaleLine(TAttLine *line, Double_t scale) {
490 if (!line || line->GetLineWidth() == 0)
491 return;
492 line->SetLineWidth(
493 Width_t(TMath::Max(1, TMath::Nint(line->GetLineWidth() * scale))));
494}
495
496void PlottingUtils::ScaleMarker(TAttMarker *marker, Double_t scale) {
497 if (!marker)
498 return;
499 marker->SetMarkerSize(marker->GetMarkerSize() * scale);
500}
501
502TLatex *PlottingUtils::AddText(const TString label, Double_t x, Double_t y,
503 Double_t angle) {
504 TLatex *text = new TLatex(x, y, label);
505 text->SetNDC();
506 text->SetTextSize(30);
507 text->SetTextAlign(33);
508 text->SetTextFont(43);
509 text->SetTextAngle(angle);
510 text->Draw();
511
512 return text;
513}
514
516 static TRandom3 generator(0);
517 Double_t number = generator.Rndm();
518 TString name = Form("name%.7f", number);
519 return name;
520}
521
523 TH1 *hist, TGraph *total_graph,
524 const std::vector<TGraph *> &component_graphs, Float_t fit_range_low,
525 Float_t fit_range_high, const TString &output_name,
526 const TString &output_subdirectory, const TString &label, Bool_t logy) {
527 TCanvas *canvas = GetConfiguredCanvas(kFALSE);
528
529 TPad *pad1 = new TPad("pad1", "pad1", 0, 0.3, 1, 1.0);
530 TPad *pad2 = new TPad("pad2", "pad2", 0, 0, 1, 0.3);
531 pad1->SetBottomMargin(0.04);
532 pad1->SetGridx(1);
533 pad1->SetGridy(1);
534 pad1->SetTopMargin(0.12);
535 pad2->SetTopMargin(0.04);
536 pad2->SetBottomMargin(0.35);
537 pad2->SetGridx(1);
538 pad2->SetGridy(1);
539 pad1->Draw();
540 pad2->Draw();
541 pad1->cd();
542
543 Float_t min_hist_value = 0.9 * fit_range_low;
544 Float_t max_hist_value = 1.1 * fit_range_high;
545
546 hist->GetXaxis()->SetRangeUser(min_hist_value, max_hist_value);
547 hist->GetXaxis()->SetLabelSize(0);
548 hist->GetXaxis()->SetTitleSize(0);
549 hist->SetLineColor(kViolet);
550 hist->GetYaxis()->SetTitleOffset(1);
551 hist->SetLineWidth(line_width_);
552 hist->Draw();
553
554 pad1->SetTickx(0);
555 if (total_graph)
556 total_graph->Draw("L same");
557 for (std::size_t i = 0; i < component_graphs.size(); i++) {
558 if (component_graphs[i])
559 component_graphs[i]->Draw("L same");
560 }
561
562 pad2->cd();
563
564 Int_t nbins = hist->GetNbinsX();
565 TGraph *residuals = new TGraph();
566 Int_t point_counter = 0;
567 for (Int_t i = 1; i <= nbins; i++) {
568 Double_t x = hist->GetBinCenter(i);
569 if (x < fit_range_low || x > fit_range_high)
570 continue;
571 Double_t data = hist->GetBinContent(i);
572 Double_t fit_val = total_graph ? total_graph->Eval(x) : 0.0;
573 Double_t error = hist->GetBinError(i);
574
575 if (error > 0 && data > 0) {
576 Double_t pull = (data - fit_val) / error;
577 residuals->SetPoint(point_counter, x, pull);
578 point_counter++;
579 }
580 }
581
582 residuals->SetMarkerStyle(20);
583 residuals->SetMarkerSize(0.8);
584 residuals->SetMarkerColor(kAzure);
585 residuals->SetLineColor(kAzure);
586 residuals->SetTitle("");
587 Double_t actual_min =
588 hist->GetXaxis()->GetBinLowEdge(hist->GetXaxis()->GetFirst());
589 Double_t actual_max =
590 hist->GetXaxis()->GetBinUpEdge(hist->GetXaxis()->GetLast());
591 residuals->GetXaxis()->SetLimits(actual_min, actual_max);
592 residuals->GetYaxis()->SetTitle("#delta/#sigma");
593 residuals->GetXaxis()->SetTitle(hist->GetXaxis()->GetTitle());
594 residuals->GetXaxis()->SetTitleSize(0.13);
595 residuals->GetYaxis()->SetTitleSize(0.13);
596 residuals->GetXaxis()->SetLabelSize(0.12);
597 residuals->GetYaxis()->SetLabelSize(0.12);
598 residuals->GetXaxis()->SetTitleOffset(1.0);
599 residuals->GetYaxis()->SetTitleOffset(0.3);
600 residuals->GetYaxis()->SetNdivisions(505);
601 residuals->GetXaxis()->SetNdivisions(510);
602 residuals->GetYaxis()->CenterTitle(kTRUE);
603 residuals->GetYaxis()->SetRangeUser(-5.5, 5.5);
604 residuals->Draw("AP");
605
606 TF1 *zero_line = new TF1("zero_line", "0", actual_min, actual_max);
607 zero_line->SetLineColor(kBlack);
608 zero_line->SetLineStyle(2);
609 zero_line->SetLineWidth(line_width_);
610 zero_line->Draw("same");
611
612 TF1 *plus3_line = new TF1("plus3_line", "3", actual_min, actual_max);
613 plus3_line->SetLineColor(kGray + 2);
614 plus3_line->SetLineStyle(3);
615 plus3_line->SetLineWidth(line_width_);
616 plus3_line->Draw("same");
617
618 TF1 *minus3_line = new TF1("minus3_line", "-3", actual_min, actual_max);
619 minus3_line->SetLineColor(kGray + 2);
620 minus3_line->SetLineStyle(3);
621 minus3_line->SetLineWidth(line_width_);
622 minus3_line->Draw("same");
623
624 pad1->cd();
625 pad1->SetLogy(logy);
626 if (label.Length() > 0) {
627 AddText(label, 0.85, 0.85);
628 }
629
630 PlotSaveOptions save_opts =
632 SaveFigure(canvas, output_name, output_subdirectory, save_opts);
633
634 PlotPullHistogram(residuals, output_name, output_subdirectory);
635
636 gROOT->GetListOfCanvases()->Remove(canvas);
637 canvas->SetBatch(kTRUE);
638 delete canvas;
639 delete residuals;
640 delete zero_line;
641 delete plus3_line;
642 delete minus3_line;
643}
644
645void PlottingUtils::PlotPullHistogram(TGraph *residuals,
646 const TString &output_name,
647 const TString &output_subdirectory) {
648 Int_t npoints = residuals->GetN();
649 if (npoints == 0)
650 return;
651
652 TH1D *pull_hist =
653 new TH1D("pull_hist", ";#delta/#sigma;Counts", 82, -5.5, 5.5);
654
655 Double_t *y = residuals->GetY();
656 for (Int_t i = 0; i < npoints; i++) {
657 pull_hist->Fill(y[i]);
658 }
659
660 TH1D *gauss_ref = new TH1D("gauss_ref", "", 82, -5.5, 5.5);
661 for (Int_t i = 1; i <= gauss_ref->GetNbinsX(); i++) {
662 Double_t lo = gauss_ref->GetBinLowEdge(i);
663 Double_t hi = lo + gauss_ref->GetBinWidth(i);
664 gauss_ref->SetBinContent(i, npoints * (TMath::Freq(hi) - TMath::Freq(lo)));
665 }
666
667 Double_t ks_pvalue = pull_hist->KolmogorovTest(gauss_ref);
668
669 TCanvas *hist_canvas = GetConfiguredCanvas(kFALSE);
670 ConfigureAndDrawHistogram(pull_hist, kAzure);
671 AddText(TString::Format("KS p = %.3f", ks_pvalue), 0.85, 0.85);
672
673 SaveFigure(hist_canvas, "residuals_" + output_name,
674 output_subdirectory + "/residual_hists", PlotSaveOptions::kLINEAR);
675
676 delete hist_canvas;
677 delete gauss_ref;
678 delete pull_hist;
679}
680
681void PlottingUtils::SetTurboPalette() {
682 Int_t N_COLORS = 255;
683
684 std::vector<Double_t> stops(N_COLORS);
685 std::vector<Double_t> reds(N_COLORS);
686 std::vector<Double_t> greens(N_COLORS);
687 std::vector<Double_t> blues(N_COLORS);
688
689 for (Int_t i = 0; i < N_COLORS; ++i) {
690 Double_t x = Double_t(i) / Double_t(N_COLORS - 1);
691
692 Double_t r = 0.13572138 + 4.61539260 * x - 42.66032258 * x * x +
693 132.13108234 * x * x * x - 152.94239396 * x * x * x * x +
694 59.28637943 * x * x * x * x * x;
695
696 Double_t g = 0.09140261 + 2.19418839 * x + 4.84296658 * x * x -
697 14.18503333 * x * x * x + 4.27729857 * x * x * x * x +
698 2.82956604 * x * x * x * x * x;
699
700 Double_t b = 0.10667330 + 12.64194608 * x - 60.58204836 * x * x +
701 110.36276771 * x * x * x - 89.90310912 * x * x * x * x +
702 27.34824973 * x * x * x * x * x;
703
704 stops[i] = x;
705 reds[i] = std::max(0.0, std::min(1.0, r));
706 greens[i] = std::max(0.0, std::min(1.0, g));
707 blues[i] = std::max(0.0, std::min(1.0, b));
708 }
709
710 Int_t firstColor =
711 TColor::CreateGradientColorTable(N_COLORS, stops.data(), reds.data(),
712 greens.data(), blues.data(), N_COLORS);
713
714 std::vector<Int_t> palette(N_COLORS);
715 for (Int_t i = 0; i < N_COLORS; ++i) {
716 palette[i] = firstColor + i;
717 }
718
719 gStyle->SetNumberContours(N_COLORS);
720 gStyle->SetPalette(N_COLORS, palette.data());
721}
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.
@ kPDF
PDF vector output; line width 1.
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 TLatex * DrawTitle(TVirtualPad *pad, const TString &title, Double_t scale=1.0)
Draw a figure title centred in a pad's top margin, at the size ROOT's own pad title has on the standa...
static void ConfigureGraph(TGraph *graph, Int_t color, const TString title="")
Apply the preferred style to a graph without drawing it.
static void ScaleLegend(TLegend *legend, Double_t scale)
Set a legend's text to AddLegend()'s 30 px times a scale.
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 preferred 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 preferred style to a 1-D histogram without drawing it.
static TCanvas * GetConfiguredCanvasWithSideLegend(TPad *&plot, TPad *&legend_pad, Int_t legend_width_px=600, Int_t plot_height_px=800, Bool_t logy=kFALSE)
A canvas with the standard plot area and a legend pad to its right.
static Double_t LegendWidthPx(const std::vector< TString > &labels, const TString &header="", Double_t size_px=30.0, Double_t margin=0.25, Double_t padding_px=15.0)
Width a legend box needs for its labels at AddLegend()'s font.
static TCanvas * GetConfiguredCanvas(Bool_t logy=kFALSE)
Create a 1200x800 canvas with grid and ticks already set up.
static Double_t FigureScale(TVirtualPad *pad, Int_t reference_width_px=1200)
How much larger a pad is than the standard plot area, by width.
static void ScaleLine(TAttLine *line, Double_t scale)
Multiply a line width by a scale, rounded to a whole pixel.
static void ScaleText(TText *text, TVirtualPad *pad, Double_t scale, Int_t reference_height_px=800)
Scale a text object with its pad.
static void SplitPadForPanel(TVirtualPad *pad, Int_t panel_height_px, TPad *&upper, TPad *&lower)
Split a pad into a main pad above and a panel below, leaving the main pad's frame exactly as it would...
static Double_t TextWidthPx(const TString &text, Double_t size_px=30.0, Int_t font=43)
Rendered width of a text in a pixel-sized font.
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 ScaleFigure(TVirtualPad *pad, Int_t reference_width_px=1200, Int_t reference_height_px=800)
Scale everything on a pad, and its sub-pads, to print like the standard figure.
static void ScaleAxisFontsToPad(TH1 *frame, TVirtualPad *pad, Double_t scale=1.0, Int_t reference_width_px=1200, Int_t reference_height_px=800)
Size a frame's axis text as on the standard canvas, times a scale.
static void ScalePad(TVirtualPad *pad, Double_t scale, Int_t reference_width_px=1200, Int_t reference_height_px=800)
Scale one pad and everything drawn on it, recursively.
static void ScaleMarker(TAttMarker *marker, Double_t scale)
Multiply a marker size by a scale.
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.