ATLAS Offline Software
Loading...
Searching...
No Matches
HanOutputFile.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
5// **********************************************************************
6// $Id: HanOutputFile.cxx,v 1.59 2009-05-18 15:37:12 ponyisi Exp $
7// **********************************************************************
8
10
11#include <TBufferJSON.h>
12#include <TCanvas.h>
13#include <TDirectory.h>
14#include <TEfficiency.h>
15#include <TF1.h>
16#include <TFile.h>
17#include <TGraph.h>
18#include <TGraphAsymmErrors.h>
19#include <TH1.h>
20#include <TH2.h>
21#include <THStack.h>
22#include <TImage.h>
23#include <TIterator.h>
24#include <TKey.h>
25#include <TLatex.h>
26#include <TLegend.h>
27#include <TLine.h>
28#include <TMath.h>
29#include <TProfile.h>
30#include <TROOT.h>
31#include <TStyle.h>
32#include <TText.h>
33#include <TImageDump.h>
34#include <TFrame.h>
35
36#include <charconv>
37#include <cstdlib>
38#include <fstream>
39#include <sstream>
40#include <iostream>
41#include <algorithm>
42#include <ranges>
43#include <tuple> //for std::ignore
44
46#include "TPluginManager.h"
47
48#define BINLOEDGE(h, n) h->GetXaxis()->GetBinLowEdge(n)
49#define BINWIDTH(h, n) h->GetXaxis()->GetBinWidth(n)
50
52
53namespace
54{
55 // class DisableMustClean {
56 // public:
57 // inline DisableMustClean() : useRecursiveDelete(gROOT->MustClean()) { gROOT->SetMustClean(false); }
58 // inline ~DisableMustClean() { gROOT->SetMustClean(useRecursiveDelete); }
59 // private:
60 // bool useRecursiveDelete;
61 // };
62
63 Double_t getScaleVal(std::string& display) {
64 std::size_t found = display.find("ScaleRef");
65 std::size_t found2 = display.find_first_of(',', found + 1);
66 // has multiple entries? Do this later.
67 std::string valueStr = display.substr(found + 9, found2 - found - 9);
68 double resultVal = 0.0;
69 auto [ptr, ec] = std::from_chars(valueStr.data(), valueStr.data() + valueStr.size(), resultVal);
70 if (ec != std::errc()) {
71 std::cerr << "Unable to cast scaling value " << valueStr << " to double" << std::endl;
72 return 1.;
73 }
74 return resultVal;
75 }
76} // end unnamed namespace
77
78namespace dqutils
79{
80 // *********************************************************************
81 // Public Methods
82 // *********************************************************************
83
84 std::vector<int> root_color_choices = {
85 kBlue, kRed, kGray, kOrange, kViolet, kGreen + 1
86 };
87
90 TPluginHandler* h;
91 if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "image"))) {
92 if (h->LoadPlugin() == -1) return;
93
94 h->ExecPlugin(0);
95 }
96 }
97
98 HanOutputFile::HanOutputFile(const std::string& fileName) : m_file(0), m_style(0) {
100 HanOutputFile::setFile(fileName);
101 TPluginHandler* h;
102 if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualPS", "image"))) {
103 if (h->LoadPlugin() == -1) return;
104
105 h->ExecPlugin(0);
106 }
107 }
108
110 // bool useRecursiveDelete = gROOT->MustClean();
111 // gROOT->SetMustClean(false);
112
114
115 // gROOT->SetMustClean(useRecursiveDelete);
116 }
117
118 void HanOutputFile::getAllGroupDirs(DirMap_t& dirmap, TDirectory* dir, const std::string& dirName) {
119 if (dir == 0) return;
120
121 if (dirName != "") { // Not a file
122 std::string name(dir->GetName());
123 if (name == "Config" || name == "Results") {
124 delete dir;
125 return;
126 }
127
128 std::string::size_type i = name.find_last_of('_');
129 if (i == (name.size() - 1)) {
130 delete dir;
131 return;
132 }
133
134 DirMap_t::value_type dirmapVal(dirName, dir);
135 dirmap.insert(std::move(dirmapVal));
136 } else {
137 DirMap_t::value_type dirmapVal("<top_level>", dir);
138 dirmap.insert(std::move(dirmapVal));
139 }
140
141 dir->cd();
142
143 TIter next(dir->GetListOfKeys());
144 TKey* key;
145 while ((key = dynamic_cast<TKey*>(next())) != 0) {
146 // don't delete TDirectories
147 TObject* obj = key->ReadObj();
148 TDirectory* subdir = dynamic_cast<TDirectory*>(obj);
149 if (subdir != 0) {
150 std::string subdirName(subdir->GetName());
151 std::string fName("");
152 if (dirName != "") {
153 fName += dirName;
154 fName += "/";
155 }
156 fName += subdirName;
157 getAllGroupDirs(dirmap, subdir, fName);
158 } else {
159 delete obj;
160 }
161 }
162 }
163
164 void HanOutputFile::getAllGroupDirs_V2(DirStrMap_t& dirstrmap, TObject* obj, const std::string& objName) {
165 if (obj == nullptr) return;
166
167 TDirectory* dir {};
168 std::string obj_type = obj->ClassName();
169
170 if (objName != "") { // Not a file
171 if (obj_type == "TDirectoryFile" || obj_type == "TDirectory" || obj_type == "TFile") {
172 dir = static_cast<TDirectory*> (obj);
173 std::string name(dir->GetName());
174 if (name == "Config" || name == "Results") {
175 delete dir;
176 return;
177 }
178
179 std::string::size_type i = name.find_last_of('_'); // If this dir is a histgram info
180 if (i == (name.size() - 1)) {
181 delete dir;
182 return;
183 }
184 DirStrMap_t::value_type dirstrmapVal(objName, obj);
185 dirstrmap.insert(std::move(dirstrmapVal));
186 } else {
187 DirStrMap_t::value_type dirstrmapVal(objName, obj);
188 dirstrmap.insert(std::move(dirstrmapVal));
189 }
190 } else { // If the object is a file
191 DirStrMap_t::value_type dirstrmapVal("<top_level>", obj);
192 dirstrmap.insert(std::move(dirstrmapVal));
193 }
194
195 if (obj_type == "TDirectoryFile" || obj_type == "TDirectory" || obj_type == "TFile") {
196 dir = static_cast<TDirectory*> (obj);
197 dir->cd();
198 TIter next(dir->GetListOfKeys());
199 TKey* key;
200 while ((key = dynamic_cast<TKey*>(next())) != 0) {
201 // don't delete TDirectories
202 std::string fName("");
203 TObject* obj_in_dir = key->ReadObj();
204 std::string obj_in_dir_type = obj_in_dir->ClassName();
205 // Check if this is node (not a histogram)
206 if (obj_in_dir_type == "TDirectoryFile" || obj_in_dir_type == "TDirectory" || obj_in_dir_type == "TFile" ||
207 obj_in_dir_type == "TObjString") {
208 std::string obj_in_dirName;
209 obj_in_dirName = key->GetName(); // If we will read name of the string, it will actually be a content of
210 // the string, so that's why we read name of the key
211 if (objName != "") {
212 fName += objName;
213 fName += "/";
214 }
215 fName += obj_in_dirName; //?
216 if (obj_in_dirName != "Config" && obj_in_dirName != "Results" && obj_in_dirName != "Version_name") { // We
217 // don't
218 // save
219 // 'Config'
220 // and
221 // 'Results'
222 // in
223 // dirstrmap
224 // structure.
225 // And we
226 // don't
227 // store
228 // version
229 // flag
230 // in
231 // dirstrmap
232 // object
233 std::string::size_type i =
234 obj_in_dirName.find_last_of('_'); // if it's an object, that stores info about histogram
235 if (i != (obj_in_dirName.size() - 1)) { // We don't store it in a dirstrmap object
236 getAllGroupDirs_V2(dirstrmap, obj_in_dir,
237 fName); // Everything else we store in dirstrmap as it is for getAllGroupDirs method
238 }
239 }
240 } else { // in case if it isn't a node but a histogram
241 delete obj_in_dir;
242 }
243 }
244 }
245 }
246
247 void HanOutputFile::getAllAssessments(AssMap_t& dirmap, TDirectory* dir) {
248 dqi::DisableMustClean disabled;
249
250 dir->cd();
251 TIter next(dir->GetListOfKeys());
252 TKey* key;
253 while ((key = dynamic_cast<TKey*>(next())) != 0) {
254 TObject* obj = key->ReadObj();
255 if (dynamic_cast<TH1*>(obj) || dynamic_cast<TGraph*>(obj) || dynamic_cast<TEfficiency*>(obj)) {
256 const char* path(dir->GetPath());
257 std::string assName(obj->GetName());
258 AssMap_t::value_type AssmapVal(assName, path);
259 dirmap.insert(std::move(AssmapVal));
260 }
261 delete obj;
262 }
263 }
264
265 void HanOutputFile::printDQGroupJSON(const nlohmann::json& j, const std::string& location, const char* path_to_file) {
266 // Parse our JSON and get all nested Assessments
267 nlohmann::json valuestring;
268 for (nlohmann::json::const_iterator it = j.begin(); it != j.end(); ++it) {
269 std::string sName = location;
270 std::string keyname = it.key();
271 if (keyname != "Config" && keyname != "Results") { // We are now at subAssessments (not at Results and Config
272 // nodes)
273 std::string::size_type i = keyname.find_last_of('_'); // if it's an object, that stores info about histogram
274 if (i != (keyname.size() - 1)) { // We don't store it in a dirstrmap object
275 if (location != "") { // Path to the TObjString
276 sName += "/"; // increment the path for the nested assesment
277 }
278 sName += keyname;
279 std::cout << "name: " << sName << ", path: " << path_to_file << sName << "\n";
280 valuestring = it.value(); // JSON content inside the subAssessment
281 printDQGroupJSON(valuestring, sName, path_to_file); // Recursively print Results/Status, Config/name of this
282 // subAssessment and looking for subsubAssessment
283 }
284 }
285 }
286 }
287
288 std::string HanOutputFile::getStringName(const std::string& location, int file_version) {
289 std::string stringName("Undefined");
290 if (file_version == 1) {
291 // bool success = gROOT->cd(location.c_str() );
292 // if( !success ) {
293 if (gROOT->cd(location.c_str()) == 0) {
294 // std::cout << "Directory \"" << location << "\" is not in han output file\n";
295 return "Undefined";
296 }
297 TIter mylist(gDirectory->GetListOfKeys());
298 TKey* key;
299 while ((key = dynamic_cast<TKey*>(mylist.Next())) != 0) {
300 TObject* obj = key->ReadObj();
301 stringName = (obj->GetName());
302 delete obj;
303 }
304 return stringName;
305 } else if (file_version == 2) {
306 // Split path to TDirectories part and JSON part
307 // All JSON strings are Results or Config
308 std::size_t split_point = 0;
309 std::string JSON_name(""); // Results or Config
310 std::string path_inTDir(""); // Path befor Results
311 std::string path_inJSON(""); // Path after Results
312 if ((split_point = location.find("/Results/")) != std::string::npos) {
313 JSON_name = "Results";
314 path_inTDir = location.substr(0, split_point);
315 path_inJSON = location.substr(split_point + 8); // 8 - is the length of "/Results"
316 } else if ((split_point = location.find("/Config/")) != std::string::npos) {
317 JSON_name = "Config";
318 path_inTDir = location.substr(0, split_point);
319 path_inJSON = location.substr(split_point + 7); // 7 - is the length of "/Config"
320 }
321 // Go to TDirectory path
322 if (gROOT->cd(path_inTDir.c_str()) == 0) {
323 return "Undefined";
324 }
325 // Extract JSON object
326 TObjString* JSON_obj = dynamic_cast<TObjString*>(gDirectory->GetKey(JSON_name.c_str())->ReadObj());
327 if (not JSON_obj) {
328 std::cerr << "HanOutputFile::getStringName : dynamic cast failed\n";
329 return "Null";
330 }
331 std::string JSON_str = (JSON_obj->GetName());
332 nlohmann::json j = nlohmann::json::parse(JSON_str);
333 nlohmann::json::json_pointer JSON_ptr(path_inJSON);
334 delete JSON_obj; // Maybe should not be used
335 try
336 {
337 auto val = j.at(JSON_ptr);
338 if (!(val.is_null())) stringName = val.get<std::string>();
339 else return "Null";
340 }
341 catch (...)
342 {
343 // Exception. In case if json_pointer (used above) doesn't exist
344 return "Null";
345 }
346 }
347 return stringName;
348 }
349
350 bool HanOutputFile::containsDir(std::string dirname, std::string maindir) {
351 while (dirname.size() > 0 && dirname[dirname.size() - 1] == '/') {
352 dirname.erase(dirname.size() - 2, dirname.size());
353 }
354 while (dirname.size() > 0 && dirname[0] == '/') {
355 dirname = dirname.substr(1, dirname.size());
356 }
357 std::size_t found = dirname.find_first_of("/", 1);
358 std::string str = dirname.substr(0, found);
359 gROOT->cd(maindir.c_str());
360 TKey* key = gDirectory->FindKey(str.c_str());
361 bool status = false;
362 TObject* obj(0);
363 TDirectory* dirobj(0);
364 if (key != 0) {
365 obj = key->ReadObj();
366 dirobj = dynamic_cast<TDirectory*>(obj);
367 }
368 if (dirobj != 0) {
369 if (found != std::string::npos) {
370 maindir = maindir + "/" + str;
371 dirname = dirname.substr(found + 1, dirname.size());
372 status = containsDir(std::move(dirname), std::move(maindir));
373 } else {
374 status = true;
375 }
376 }
377 delete obj;
378 return status;
379 }
380
381 std::optional<std::string> HanOutputFile::containsKeyInJSON(
382 const std::string& pathInJSON, const std::string& jsonName, const std::string& path_to_JSON) {
383 gROOT->cd(path_to_JSON.c_str());
384 TKey* key = gDirectory->FindKey(jsonName.c_str());
385 TObject* obj(0);
386 if (key == 0) {
387 return {}; // the JSON with this name is absent
388 } else {
389 obj = key->ReadObj();
390 }
391 std::string content = obj->GetName(); // In ATLAS DQM root files GetName() actually returns the content rather
392 // than the name of a string
393 if (pathInJSON == "") { // If we should check just the existense of the JSON string
394 delete obj;
395 return "JSON exists";
396 }
397 if (pathInJSON == "/") { // When we need the whole JSON string
398 delete obj;
399 return content;
400 }
401 nlohmann::ordered_json j = nlohmann::ordered_json::parse(content);
402 nlohmann::ordered_json::json_pointer p1(pathInJSON);
403 std::string return_string;
404 try
405 {
406 auto val1 = j.at(p1);
407 if (val1.type() == nlohmann::json::value_t::string) {
408 val1.get_to(return_string);
409 } else if (val1.type() == nlohmann::json::value_t::object) {
410 return_string = val1.dump();
411 } else {
412 std::cout << "Warning: Strange part of JSON" << std::endl;
413 delete obj;
414 return {};
415 }
416 }
417 catch (...)
418 {
419 // std::cout<<" the path not exists\n";
420 // std::cout<<"J\n";
421 delete obj;
422 return {};
423 }
424 delete obj;
425 return return_string;
426 }
427
428 double HanOutputFile::getNEntries(std::string location, std::string histname) {
429 if (m_file == 0) {
430 std::cerr << "HanOutputFile::getNEntries(): "
431 << "No input file is open\n";
432 return 0.0;
433 }
434
435 double Nentries = 0.0;
436 m_file->cd(location.c_str());
437 // gdirectory->cd(location.c_str() );
438 TH1* h(0);
439 gDirectory->GetObject(histname.c_str(), h);
440 if (h != 0) {
441 Nentries = h->GetEntries();
442 delete h;
443 }
444 TGraph* g(0);
445 gDirectory->GetObject(histname.c_str(), g);
446 if (g != 0) {
447 Nentries = g->GetN();
448 delete g;
449 }
450 TEfficiency* e(0);
451 gDirectory->GetObject(histname.c_str(), e);
452 if (e != 0) {
453 Nentries = e->GetCopyTotalHisto()->GetEntries();
454 delete e;
455 }
456
457 return Nentries;
458 }
459
460 double HanOutputFile::getNEntries(const TObject* obj) {
461 if (const TH1* h = dynamic_cast<const TH1*>(obj)) {
462 return h->GetEntries();
463 } else if (const TGraph* g = dynamic_cast<const TGraph*>(obj)) {
464 return g->GetN();
465 } else if (const TEfficiency* e = dynamic_cast<const TEfficiency*>(obj)) {
466 return e->GetCopyTotalHisto()->GetEntries();
467 } else {
468 std::cerr << "HanOutputFile::getNEntries(): "
469 << "provided object is not a histogram or graph\n";
470 return 0.0;
471 }
472 }
473
474 std::string HanOutputFile::getInfo(const std::string& location, int file_version) {
475 dqi::DisableMustClean disabled;
476 std::string value("");
477 if (file_version == 1) {
478 gROOT->cd(location.c_str());
479 TIter mylist(gDirectory->GetListOfKeys());
480 TKey* key;
481 while ((key = dynamic_cast<TKey*>(mylist.Next())) != 0) {
482 TObject* obj = key->ReadObj();
483 TDirectory* subdir = dynamic_cast<TDirectory*>(obj);
484 if (subdir != 0) {
485 std::string name_subdir = subdir->GetName();
486 gROOT->cd((location + "/" + name_subdir).c_str());
487 TIter mylist1(gDirectory->GetListOfKeys());
488 TKey* key1;
489 while ((key1 = dynamic_cast<TKey*>(mylist1.Next())) != 0) {
490 TObject* obj1 = key1->ReadObj();
491 TDirectory* subsubdir = dynamic_cast<TDirectory*>(obj1);
492 if (subsubdir != 0) {
493 std::string name_subsubdir = obj1->GetName();
494 gROOT->cd((location + "/" + name_subdir + "/" + name_subsubdir).c_str());
495 TIter mylist2(gDirectory->GetListOfKeys());
496 TKey* key2;
497 while ((key2 = dynamic_cast<TKey*>(mylist2.Next())) != 0) {
498 TObject* obj2 = key2->ReadObj();
499 TDirectory* finaldir = dynamic_cast<TDirectory*>(obj2);
500 if (finaldir != 0) {
501 std::string name_finaldir = obj2->GetName();
502 gROOT->cd((location + "/" + name_subdir + "/" + name_subsubdir + "/" + name_finaldir).c_str());
503 TIter mylist3(gDirectory->GetListOfKeys());
504 TKey* key3;
505 while ((key3 = dynamic_cast<TKey*>(mylist3.Next())) != 0) {
506 TObject* obj3 = key3->ReadObj();
507 std::string value_info = obj3->GetName();
508 value += (name_subsubdir + name_finaldir + ": " + value_info + " ");
509 delete obj3;
510 }
511 gROOT->cd((location + "/" + name_subdir + "/" + name_subsubdir).c_str());
512 } else if (name_subsubdir != "name" && name_subsubdir != "Status" && name_subsubdir != "display") {
513 // else if(name_subsubdir!="name" && name_subsubdir!="Status"){
514 std::string value_info = obj2->GetName();
515 value += (name_subsubdir + ": " + value_info + " ");
516 }
517 delete obj2;
518 }
519 gROOT->cd((location + "/" + name_subdir).c_str());
520 } else if (name_subdir != "name" && name_subdir != "Status") {
521 std::string value_info = obj1->GetName();
522 value += (name_subdir + ": " + value_info + " ");
523 }
524 delete obj1;
525 }
526 gROOT->cd((location).c_str());
527 }
528 delete obj;
529 }
530 } else if (file_version == 2) {
531 // Separate Tdirectory from the JSON file. JSON File starts with Results or Config Node
532 std::string JSON_name(""); // Results or Config
533 std::string TDir_path(""); // Path befor Results
534 std::string path_inJSON(""); // Path after Results
535 std::size_t split_point = 0;
536 if ((split_point = location.rfind("/Results")) != std::string::npos) {
537 JSON_name = "Results";
538 TDir_path = location.substr(0, split_point);
539 path_inJSON = location.substr(split_point + 8); // 8 - is the length of "/Results"
540 } else if ((split_point = location.rfind("/Config")) != std::string::npos) {
541 JSON_name = "Config";
542 TDir_path = location.substr(0, split_point);
543 path_inJSON = location.substr(split_point + 7); // 7 - is the length of "/Config"
544 }
545 // Go to TDirectory path
546 if (gROOT->cd(TDir_path.c_str()) == 0) { // Go to Tdirectory, that contains JSON
547 return "Undefined";
548 }
549 // Extract JSON object
550 std::unique_ptr<TObjString> JSON_obj(dynamic_cast<TObjString*>(gDirectory->GetKey(JSON_name.c_str())->ReadObj()));
551 if (not JSON_obj) {
552 std::cerr << "HanOutputFile::getInfo : dynamic cast failed\n";
553 return "Null";
554 }
555 std::string JSON_str = (JSON_obj->GetName());
556 nlohmann::ordered_json j = nlohmann::ordered_json::parse(JSON_str);
557 nlohmann::ordered_json json_in_j;
558 if (path_inJSON != "") {
559 nlohmann::ordered_json::json_pointer JSON_ptr(path_inJSON);
560 try
561 {
562 json_in_j = j.at(JSON_ptr);
563 }
564 catch (...)
565 {
566 // Exception. In case if json_pointer (used above) doesn't exist
567 std::cout << "Wrong path: " << location << "\n";
568 return "Null";
569 }
570 } else {
571 json_in_j = std::move(j);
572 }
573 value = processJSON_ingetInfo(json_in_j);
574 }
575 return value;
576 }
577
578 std::string HanOutputFile::getInfo(const std::string& JSON_str) {
579 dqi::DisableMustClean disabled;
580 std::string value("");
581 nlohmann::ordered_json j = nlohmann::ordered_json::parse(JSON_str);
582 value = processJSON_ingetInfo(j);
583 return value;
584 }
585
586 std::string HanOutputFile::processJSON_ingetInfo(const nlohmann::ordered_json& j) {
587 std::string value("");
588 for (nlohmann::ordered_json::const_iterator it = j.begin(); it != j.end(); ++it) { // Search in Results/Config node
589 const auto& key = it.key(); // subdir name analog
590 auto val = it.value();
591 if (strcmp(val.type_name(), "object") == 0) { // subsubdir analog
592 for (nlohmann::ordered_json::const_iterator it1 = val.begin(); it1 != val.end(); ++it1) {
593 const auto& key1 = it1.key(); // subsubdir name analog
594 auto val1 = it1.value();
595 if (strcmp(val1.type_name(), "object") == 0) { // finaldir analog
596 for (nlohmann::ordered_json::const_iterator it2 = val1.begin(); it2 != val1.end(); ++it2) {
597 const auto& key2 = it2.key(); // finaldir name analog
598 auto val2 = it2.value(); // leaf
599 value += (key1 + key2 + ": " + val2.get<std::string>() +
600 " "); //.get<std::string is needed to get rid of quotes in cout
601 }
602 } else if (key1 != "name" && key1 != "Status" && key1 != "display") {
603 value += (key1 + ": " + val1.get<std::string>() +
604 " "); //.get<std::string is needed to get rid of quotes in cout
605 }
606 }
607 } else if (key != "name" && key != "Status") {
608 if (val.is_null()) {
609 value += (key + ": null ");
610 } else {
611 value +=
612 (key + ": " + val.get<std::string>() + " "); //.get<std::string is needed to get rid of quotes in cout
613 }
614 }
615 }
616 return value;
617 }
618
619 std::string HanOutputFile::getIndentation(const std::string& pathName, const std::string& leadingSpace) {
620 std::string space = leadingSpace;
621 std::string::size_type i = pathName.find_first_of('/');
622 if (i != std::string::npos) {
623 std::string subPath(pathName, i + 1, std::string::npos);
624 space += " ";
625 return getIndentation(subPath, space);
626 }
627 return space;
628 }
629
630 bool HanOutputFile::setFile(const std::string& fileName) {
631 clearData();
632 if (fileName == "") return false;
633
634 m_file = TFile::Open(fileName.c_str());
635 if (m_file != 0) return true;
636
637 return false;
638 }
639
641 if (m_file == 0) {
642 std::cerr << "HanOutputFile::getFileVersion(): "
643 << "No input file is open\n";
644 return 0;
645 }
646
647 m_file->cd("HanMetadata_");
648
649 if (gDirectory->FindKey("File")) {
650 gDirectory->cd("File");
651 gDirectory->cd("Version_name");
652 TIter next(gDirectory->GetListOfKeys());
653 TKey* key;
654 while ((key = (TKey*) next())) {
655 std::string key_name = key->GetName();
656 if (key_name == "V.2.3") {
657 return 2;
658 } else {
659 return 1;
660 }
661 }
662 } else {
663 return 1;
664 }
665 return 0;
666 }
667
669 if (m_file == 0) {
670 std::cerr << "HanOutputFile::printAllGroupDirs(): "
671 << "No input file is open\n";
672 return;
673 }
674 int file_version = getFileVersion();
675 if (file_version == 1) {
676 if (m_indirMap.size() == 0) {
678 }
679
680 DirMap_t::const_iterator idirend = m_indirMap.end();
681 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
682 std::string idirName = idir->first;
683 const char* path(idir->second->GetPath());
684 std::cout << "name: " << idirName << ", path: " << path << "\n";
685 }
686 } else if (file_version == 2) {
687 if (m_indirstrMap.size() == 0) {
689 }
690 const char* path_to_file = m_file->GetPath();
691 DirStrMap_t::const_iterator idirend = m_indirstrMap.end();
692 for (DirStrMap_t::const_iterator idir = m_indirstrMap.begin(); idir != idirend; ++idir) {
693 std::string idirName = idir->first; // Actually it's a path
694 TDirectory* dirobj = dynamic_cast<TDirectory*>(idir->second);
695 if (dirobj != 0) { // If the object is a TDirectory type
696 std::string pathname(dirobj->GetPath());
697 std::cout << "name: " << idirName << ", path: " << pathname << "\n";
698 } else {
699 std::cout << "name: " << idirName << ", path: " << path_to_file << idirName << "\n";
700 TObjString* strobj = dynamic_cast<TObjString*>(idir->second);
701 if (not strobj) {
702 std::cerr << "HanOutputFile::printAllGroupDirs(): dynamic cast failed\n";
703 continue;
704 }
705 std::string content = strobj->GetName(); // In ATLAS DQM root files GetName() actually returns the
706 // content rather than the name of a string
707 nlohmann::json j = nlohmann::json::parse(content); // Get JSON object from TObjString
708 printDQGroupJSON(j, idirName, path_to_file); // Recursive parsing and print of the nested Assessment in
709 // the form of TOBJString
710 }
711 }
712 }
713 }
714
716
718
719 std::string HanOutputFile::stringListSystemPaths(std::string location) {
720 if (m_file == 0) {
721 std::cerr << "HanOutputFile::stringListSystemPaths(): "
722 << "No input file is open\n";
723 return "";
724 }
725
726 if (m_indirMap.size() == 0) {
728 }
729
730 std::string result("");
731
732 DirMap_t::const_iterator idirend = m_indirMap.end();
733 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
734 DirToAssMap_t::const_iterator aMapIter = m_assessMap.find(idir->first);
735 if (aMapIter == m_assessMap.end()) {
736 AssMap_t* aMap = new AssMap_t();
737 DirToAssMap_t::value_type aMapVal(idir->first, aMap);
738 aMapIter = m_assessMap.insert(std::move(aMapVal)).first;
739 getAllAssessments(*aMap, idir->second);
740 }
741
742 AssMap_t::const_iterator ias = aMapIter->second->begin();
743 if (ias != aMapIter->second->end()) {
744 std::string hisPath = ias->second;
745 std::string::size_type sepi = hisPath.find(':');
746 if (sepi != std::string::npos) {
747 hisPath = std::string(hisPath, sepi + 1, std::string::npos);
748 }
749 std::string completeDir(location);
750 completeDir += hisPath;
751 result += completeDir;
752 result += " ";
753 }
754 }
755 return result;
756 }
757
759 std::ostringstream result;
761 return result.str();
762 }
763
765 std::ostringstream result;
767 return result.str();
768 }
769
771 std::ostringstream result;
773 return result.str();
774 }
775
776 void HanOutputFile::streamAllDQAssessments(std::ostream& o, bool streamAll) {
777 if (m_file == 0) {
778 std::cerr << "HanOutputFile::streamAllDQAssessments(): "
779 << "No input file is open\n";
780 return;
781 }
782
783 int file_version = getFileVersion();
784
785 if ((file_version == 1) || (file_version == 2)) {
786 if (m_indirMap.size() == 0) {
788 }
789
790 DirMap_t::const_iterator idirend = m_indirMap.end();
791 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
792 std::string idirName = idir->first;
793 std::string pathname(idir->second->GetPath());
794 std::string::size_type i = pathname.find_last_of('/');
795 if (i != (pathname.size() - 1)) {
796 pathname += "/";
797 }
798 std::string pathnameS = pathname + "Results/Status";
799 std::string pathnameA = pathname + "Config/name";
800 std::string idirStatus = getStringName(pathnameS, file_version);
801 std::string idirAlg = getStringName(pathnameA, file_version);
802 std::string indent = (idirName == "<top_level>") ? "" : getIndentation(idirName, " ");
803 if (!streamAll) {
804 std::string::size_type idirNamei = idirName.find_last_of('/');
805 if (idirNamei != std::string::npos) {
806 idirName = std::string(idirName, idirNamei + 1, std::string::npos);
807 }
808 }
809 std::string formattedName(indent);
810 formattedName += idirName;
811
812 // left-align this text
813 const std::ios_base::fmtflags savedFlags = o.setf(std::ios_base::left, std::ios_base::adjustfield);
814 // set the width of the next item to be printed
815
816 o.width(40);
817 o << formattedName << " ";
818 // return to normal right-alignment
819 o.setf(std::ios_base::right, std::ios_base::adjustfield);
820 o.width(9);
821 o << idirStatus << " ";
822 o.width(30);
823 o << idirAlg;
824 if (streamAll) {
825 o << " dir\n";
826 } else {
827 o << "\n";
828 }
829 o.flags(savedFlags);
830
831 DirToAssMap_t::const_iterator aMapIter = m_assessMap.find(idir->first);
832 if (aMapIter == m_assessMap.end()) {
833 AssMap_t* aMap = new AssMap_t();
834 DirToAssMap_t::value_type aMapVal(idir->first, aMap);
835 aMapIter = m_assessMap.insert(std::move(aMapVal)).first;
836 getAllAssessments(*aMap, idir->second);
837 }
838
839 AssMap_t::const_iterator aend = aMapIter->second->end();
840 std::string info1("");
841 std::string info2("");
842 for (AssMap_t::const_iterator ias = aMapIter->second->begin(); ias != aend; ++ias) {
843 std::string hisName = ias->first;
844 std::string hisPath = ias->second;
845 std::string Path1 = hisPath + "/" + hisName + "_/Results";
846 std::string Path2 = hisPath + "/" + hisName + "_/Config";
847 if (streamAll) {
848 info1 = getInfo(Path1, file_version);
849
850 info2 = getInfo(Path2, file_version);
851 }
852 std::string formattedHistName(indent);
853 std::string status = getStringName(Path1 + "/Status", file_version);
854 std::string algo = getStringName(Path2 + "/name", file_version);
855 formattedHistName += " ";
856 formattedHistName += hisName;
857 // left-align this text
858 const std::ios_base::fmtflags savedFlags = o.setf(std::ios_base::left, std::ios_base::adjustfield);
859 // set the width of the next item to be printed
860
861 o.width(40);
862 o << formattedHistName << " ";
863 // return to normal right-alignment
864 o.setf(std::ios_base::right, std::ios_base::adjustfield);
865 o.width(9);
866 o << status << " ";
867 o.width(30);
868 o << algo;
869 if (streamAll) {
870 // Get information about hsitogram
871 gDirectory->cd(pathname.c_str());
872 TObject* h;
873 // TH1 *h;
874 gDirectory->GetObject(hisName.c_str(), h);
875 std::string hisTitle = h->GetTitle();
876 // Print information about histograms
877 o << " ass entries: " << getNEntries(h) << " ";
878 TH1* h1;
879 if ((h1 = dynamic_cast<TH1*>(h)) && h1->GetDimension() == 1) {
880 o << " Underflow: " << h1->GetBinContent(0) << " Overflow: " << h1->GetBinContent(h1->GetNbinsX() + 1)
881 << " ";
882 }
883 if (info1 != "" && info2 != "") {
884 o << "Config "
885 << "Config " << info2 << " Results "
886 << "Results " << info1 << " title " << hisTitle << "\n";
887 } else if (info1 != "") {
888 o << "Results Results " << info1 << " title " << hisTitle << "\n";
889 } else if (info2 != "") {
890 o << "Config Config " << info2 << " title " << hisTitle << "\n";
891 } else {
892 o << " title " << hisTitle << "\n";
893 }
894 delete h;
895 } else {
896 o << "\n";
897 }
898 o.flags(savedFlags);
899 }
900 }
901 }
902 }
903
904 void HanOutputFile::streamHistoAssessments(std::ostream& o, bool streamAll) {
905 if (m_file == 0) {
906 std::cerr << "HanOutputFile::streamHistoAssessments(): "
907 << "No input file is open\n";
908 return;
909 }
910
911 if (m_indirMap.size() == 0) {
913 }
914
915 DirMap_t::const_iterator idirend = m_indirMap.end();
916 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
917 std::string idirName = idir->first;
918 std::string pathname(idir->second->GetPath());
919 std::string::size_type i = pathname.find_last_of('/');
920 if (i != (pathname.size() - 1)) {
921 pathname += "/";
922 }
923 std::string idirStatus = "Undefined";
924 std::string idirAlg = "Undefined";
925 std::string indent = (idirName == "<top_level>") ? "" : getIndentation(idirName, " ");
926 if (!streamAll) {
927 std::string::size_type idirNamei = idirName.find_last_of('/');
928 if (idirNamei != std::string::npos) {
929 idirName = std::string(idirName, idirNamei + 1, std::string::npos);
930 }
931 }
932 std::string formattedName;
933 formattedName += idirName;
934
935 DirToAssMap_t::const_iterator aMapIter = m_assessMap.find(idir->first);
936 if (aMapIter == m_assessMap.end()) {
937 AssMap_t* aMap = new AssMap_t();
938 DirToAssMap_t::value_type aMapVal(idir->first, aMap);
939 aMapIter = m_assessMap.insert(std::move(aMapVal)).first;
940 getAllAssessments(*aMap, idir->second);
941 }
942
943 AssMap_t::const_iterator aend = aMapIter->second->end();
944 for (AssMap_t::const_iterator ias = aMapIter->second->begin(); ias != aend; ++ias) {
945 std::string hisName = ias->first;
946 std::string hisPath = ias->second;
947 std::string formattedHistName;
948 gDirectory->cd(pathname.c_str());
949 // TH1 *h;
950 TObject* h;
951 gDirectory->GetObject(hisName.c_str(), h);
952 std::string hisTitle(h->GetTitle());
953 formattedHistName += "";
954 formattedHistName += hisName;
955 // left-align this text
956 const std::ios_base::fmtflags savedFlags = o.setf(std::ios_base::left, std::ios_base::adjustfield);
957 o.width(40);
958
959 if (streamAll) {
960 o << hisPath << "/" << formattedHistName << " "
961 << "\n";
962 } else {
963 o << "\n";
964 }
965 o.flags(savedFlags);
966 }
967 }
968 }
969
970 void HanOutputFile::streamAllHistograms(std::ostream& o, bool streamAll) {
971 if (m_file == 0) {
972 std::cerr << "HanOutputFile::streamAllDQAssessments(): "
973 << "No input file is open\n";
974 return;
975 }
976
977 if (m_indirMap.size() == 0) {
979 }
980
981 DirMap_t::const_iterator idirend = m_indirMap.end();
982 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
983 std::string idirName = idir->first;
984 std::string pathname(idir->second->GetPath());
985 std::string::size_type i = pathname.find_last_of('/');
986 if (i != (pathname.size() - 1)) {
987 pathname += "/";
988 }
989 std::string idirStatus = "Undefined";
990 std::string idirAlg = "Undefined";
991 std::string indent = (idirName == "<top_level>") ? "" : getIndentation(idirName, " ");
992 if (!streamAll) {
993 std::string::size_type idirNamei = idirName.find_last_of('/');
994 if (idirNamei != std::string::npos) {
995 idirName = std::string(idirName, idirNamei + 1, std::string::npos);
996 }
997 }
998 std::string formattedName(indent);
999 formattedName += idirName;
1000
1001 // left-align this text
1002 const std::ios_base::fmtflags savedFlags = o.setf(std::ios_base::left, std::ios_base::adjustfield);
1003 // set the width of the next item to be printed
1004 o.width(40);
1005 o << formattedName << " ";
1006 // return to normal right-alignment
1007 o.setf(std::ios_base::right, std::ios_base::adjustfield);
1008 o.width(9);
1009 o << idirStatus << " ";
1010 o.width(30);
1011 o << idirAlg;
1012 if (streamAll) {
1013 o << " dir\n";
1014 } else {
1015 o << "\n";
1016 }
1017 o.flags(savedFlags);
1018
1019 DirToAssMap_t::const_iterator aMapIter = m_assessMap.find(idir->first);
1020 if (aMapIter == m_assessMap.end()) {
1021 AssMap_t* aMap = new AssMap_t();
1022 DirToAssMap_t::value_type aMapVal(idir->first, aMap);
1023 aMapIter = m_assessMap.insert(std::move(aMapVal)).first;
1024 getAllAssessments(*aMap, idir->second);
1025 }
1026
1027 AssMap_t::const_iterator aend = aMapIter->second->end();
1028 for (AssMap_t::const_iterator ias = aMapIter->second->begin(); ias != aend; ++ias) {
1029 std::string hisName = ias->first;
1030 std::string hisPath = ias->second;
1031 // std::string Path1 = hisPath + "/"+ hisName + "_/Results";
1032 // std::string info1 = getInfo(Path1);
1033 std::string info1, info2;
1034 // std::string Path2 = hisPath + "/"+ hisName + "_/Config";
1035 // std::string info2 = getInfo(Path2);
1036 std::string formattedHistName(indent);
1037 std::string status = "Undefined";
1038 std::string algo = "Undefined";
1039 gDirectory->cd(pathname.c_str());
1040 // TH1 *h;
1041 TObject* h;
1042 gDirectory->GetObject(hisName.c_str(), h);
1043 std::string hisTitle(h->GetTitle());
1044 formattedHistName += " ";
1045 formattedHistName += hisName;
1046 // left-align this text
1047 const std::ios_base::fmtflags savedFlags = o.setf(std::ios_base::left, std::ios_base::adjustfield);
1048 // set the width of the next item to be printed
1049 o.width(40);
1050 o << formattedHistName << " ";
1051 // return to normal right-alignment
1052 o.setf(std::ios_base::right, std::ios_base::adjustfield);
1053 o.width(9);
1054 o << status << " ";
1055 o.width(30);
1056 o << algo;
1057 if (streamAll) {
1058 o << " ass entries: " << getNEntries(h) << " ";
1059 if (info1 != "" && info2 != "") {
1060 o << "Config "
1061 << "Config " << info2 << " Results "
1062 << "Results " << info1 << " title " << hisTitle << "\n";
1063 } else if (info1 != "") {
1064 o << "Results Results " << info1 << " title " << hisTitle << "\n";
1065 } else if (info2 != "") {
1066 o << "Config Config " << info2 << " title " << hisTitle << "\n";
1067 } else {
1068 o << " title " << hisTitle << "\n";
1069 }
1070 } else {
1071 o << "\n";
1072 }
1073 o.flags(savedFlags);
1074 }
1075 }
1076 }
1077
1078 int HanOutputFile::saveAllHistograms(const std::string& location, bool drawRefs, const std::string& run_min_LB,
1079 int cnvsType) {
1080 if (m_file == 0) {
1081 std::cerr << "HanOutputFile::saveAllHistograms(): "
1082 << "No input file is open\n";
1083 return 0;
1084 }
1085
1086 if (m_indirMap.size() == 0) {
1088 }
1089
1090 int nSaved = 0;
1091
1092 DirMap_t::const_iterator idirend = m_indirMap.end();
1093 for (DirMap_t::const_iterator idir = m_indirMap.begin(); idir != idirend; ++idir) {
1094 DirToAssMap_t::const_iterator aMapIter = m_assessMap.find(idir->first);
1095 if (aMapIter == m_assessMap.end()) {
1096 AssMap_t* aMap = new AssMap_t();
1097 DirToAssMap_t::value_type aMapVal(idir->first, aMap);
1098 aMapIter = m_assessMap.insert(std::move(aMapVal)).first;
1099 getAllAssessments(*aMap, idir->second);
1100 }
1101 AssMap_t::const_iterator aend = aMapIter->second->end();
1102 for (AssMap_t::const_iterator ias = aMapIter->second->begin(); ias != aend; ++ias) {
1103 std::string hisName = ias->first;
1104 std::string hisPath = ias->second;
1105 std::string::size_type sepi = hisPath.find(':');
1106 if (sepi != std::string::npos) {
1107 hisPath = std::string(hisPath, sepi + 1, std::string::npos);
1108 }
1109 std::string completeDir(location);
1110 completeDir += hisPath;
1111 completeDir += "/";
1112 std::cout << "Saving " << completeDir << " " << hisName << std::endl;
1113 try
1114 {
1115 bool isSaved = saveHistogramToFile(
1116 hisName, std::move(completeDir), idir->second, drawRefs, run_min_LB, (hisPath + "/" + hisName), cnvsType);
1117 if (isSaved) ++nSaved;
1118 }
1119 catch (std::exception& e)
1120 {
1121 std::cerr << "Exception caught: " << e.what() << std::endl;
1122 }
1123 }
1124 }
1125 return nSaved;
1126 }
1127
1128 void getImageBuffer ATLAS_NOT_THREAD_SAFE(TImage** img, TCanvas* myC, char** x, int* y) {
1129 gVirtualPS->Open(myC->GetName(), 114);
1130 myC->Paint();
1131 auto pImgDump = dynamic_cast<TImageDump*>(gVirtualPS);
1132 if (pImgDump) {
1133 (*img) = pImgDump->GetImage();
1134 if (*img) {
1135 (*img)->GetImageBuffer(x, y, TImage::kPng);
1136 }
1137 }
1138 }
1139
1140 bool HanOutputFile::saveHistogramToFile(const std::string& nameHis, std::string location, TDirectory* groupDir,
1141 bool drawRefs, const std::string& run_min_LB, const std::string& pathName,
1142 int cnvsType) {
1143 std::pair<std::string, std::string> pngAndJson =
1144 getHistogram(nameHis, groupDir, drawRefs, run_min_LB, pathName, cnvsType);
1145 // std::string tosave = getHistogramPNG(nameHis, groupDir, drawRefs, run_min_LB, pathName);
1146 if (pngAndJson.first == "" && pngAndJson.second == "") {
1147 return false;
1148 }
1149 std::string namePNG = nameHis;
1150 std::string nameJSON = nameHis;
1151
1152 namePNG += ".png";
1153 nameJSON += ".json";
1154
1155 std::string::size_type i = location.find_last_of('/');
1156 if (i != (location.size() - 1)) {
1157 location += '/';
1158 }
1159
1160 namePNG = location + namePNG;
1161 nameJSON = location + nameJSON;
1162 return saveFile(cnvsType, namePNG, pngAndJson.first, nameJSON, pngAndJson.second);
1163 }
1164
1166 const std::string& nameHis, TDirectory* groupDir, bool drawRefs, const std::string& run_min_LB,
1167 const std::string& pathName) {
1168 int cnvsType = 1;
1169
1170 return getHistogram(nameHis, groupDir, drawRefs, run_min_LB, pathName, cnvsType).first;
1171 }
1172
1173 std::pair<std::string, std::string> HanOutputFile::getHistogramJSON(
1174 const std::string& nameHis, TDirectory* groupDir, bool drawRefs, const std::string& run_min_LB,
1175 const std::string& pathName) {
1176 int cnvsType = 2;
1177
1178 return getHistogram(nameHis, groupDir, drawRefs, run_min_LB, pathName, cnvsType);
1179 }
1180
1181 std::pair<std::string, std::string> HanOutputFile::getHistogram(const std::string& nameHis, TDirectory* groupDir,
1182 bool drawRefs, const std::string& run_min_LB,
1183 const std::string& pathName, int cnvsType) {
1184 dqi::DisableMustClean disabled;
1185 groupDir->cd();
1186
1187 int iMarkerStyle = 20;
1188 gStyle->SetFrameBorderMode(0);
1189 gStyle->SetFrameFillColor(0);
1190 gStyle->SetCanvasBorderMode(0);
1191 gStyle->SetPadBorderMode(0);
1192 gStyle->SetPadColor(0);
1193 gStyle->SetCanvasColor(0);
1194 gStyle->SetTitleColor(0);
1195 gStyle->SetStatColor(0);
1196 gStyle->SetFillColor(1);
1197 gStyle->SetPalette(1, 0);
1198 gStyle->SetTitleFontSize(0.06);
1199 gStyle->SetTitleH(0.06);
1200 gStyle->SetMarkerStyle(iMarkerStyle);
1201 gStyle->SetOptStat(111100);
1202 gStyle->SetStatBorderSize(0);
1203 gStyle->SetStatX(0.99);
1204 gStyle->SetStatY(0.99);
1205 gStyle->SetStatW(0.2);
1206 gStyle->SetStatH(0.1);
1207
1208 //Used in TASImage::GetImageBuffer, Buffer must be deallocated after usage with free(buffer) call
1209 char* x = nullptr;
1210 int y {};
1211 std::string json;
1212 TImage* img = nullptr;
1213
1214 gROOT->SetBatch();
1215 TImageDump tid;
1216 std::string pathname(groupDir->GetPath());
1217 std::string display = "";
1218 bool WasCollectionReference = false;
1219 int file_version = getFileVersion();
1220 bool LookForDisplay;
1221 if (file_version == 1) {
1222 LookForDisplay = containsDir("Config/annotations/display", (pathname + "/" + nameHis + "_"));
1223 if (LookForDisplay) {
1224 display = getStringName(pathname + "/" + nameHis + "_/Config/annotations/display", file_version);
1225 }
1226 } else if (file_version == 2) {
1227 std::optional<std::string> JSON_content;
1228 LookForDisplay = containsDir((nameHis + "_"), pathname);
1229 if (LookForDisplay) {
1230 JSON_content = containsKeyInJSON("/annotations/display", "Config", (pathname + "/" + nameHis + "_"));
1231 if (JSON_content) {
1232 LookForDisplay = true;
1233 } else {
1234 LookForDisplay = false;
1235 }
1236 }
1237 if (LookForDisplay) {
1238 display = JSON_content.value();
1239 }
1240 }
1241 // Plot overflows?
1242 bool PlotOverflows = (display.find("PlotUnderOverflow") != std::string::npos);
1243 // Look for Draw Options
1244 std::size_t found = display.find("Draw=");
1245 std::string drawopt = "";
1246 while (found != std::string::npos) {
1247 std::size_t found1 = display.find_first_of(',', found + 1);
1248 auto temp = display.substr(found + 5, found1 != std::string::npos ? found1 - found - 5 : display.size());
1249 std::ranges::transform(temp, temp.begin(), [](unsigned char c) { return std::tolower(c); });
1250 drawopt += temp;
1251 found = display.find("Draw=", found + 1);
1252 }
1253 // Look for DrawRef Options
1254 found = display.find("DrawRef=");
1255 std::string drawrefopt = "";
1256 while (found != std::string::npos) {
1257 std::size_t found1 = display.find_first_of(',', found + 1);
1258 auto temp = display.substr(found + 8, found1 != std::string::npos ? found1 - found - 8 : display.size());
1259 std::ranges::transform(temp, temp.begin(), [](unsigned char c) { return std::tolower(c); });
1260 drawrefopt += temp;
1261 found = display.find("DrawRef=", found + 1);
1262 }
1263 if (drawrefopt == "") {
1264 drawrefopt = drawopt;
1265 }
1266 // Look for DrawRef2D Options
1267 found = display.find("DrawRef2D=");
1268 std::string drawrefopt2D = "";
1269 while (found != std::string::npos) {
1270 std::size_t found1 = display.find_first_of(',', found + 1);
1271 auto temp = display.substr(found + 10, found1 != std::string::npos ? found1 - found - 10 : display.size());
1272 std::ranges::transform(temp, temp.begin(), [](unsigned char c) { return std::tolower(c); });
1273 drawrefopt2D += temp;
1274 found = display.find("DrawRef2D=", found + 1);
1275 }
1276
1277 // should we rename "Data" ?
1278 found = display.find("DataName");
1279 std::string datatitle;
1280 if (found == std::string::npos) {
1281 datatitle = "Data";
1282 }
1283 while (found != std::string::npos) {
1284 std::size_t found1 = display.find_first_of(',', found + 1);
1285 if (found1 != std::string::npos) {
1286 datatitle += display.substr(found + 9, found1 - found - 9);
1287 } else {
1288 datatitle += display.substr(found + 9, display.size());
1289 }
1290 found = display.find("DataName", found + 1);
1291 }
1292 groupDir->cd();
1293 TKey* hkey = groupDir->FindKey(nameHis.c_str());
1294 if (hkey == 0) {
1295 std::cerr << "Did not find TKey for \"" << nameHis << "\", will not save this histogram.\n";
1296 return std::pair<std::string, std::string>{
1297 "", ""
1298 };
1299 }
1300 TLegend* legend(0);
1301 TObject* hobj = hkey->ReadObj();
1302 TObject* ref(0);
1303 TH1* hRef(0);
1304 TEfficiency* eRef(0);
1305 TH2* h2Ref(0);
1306 std::vector<TH1*> hRefs;
1307 std::vector<TEfficiency*> eRefs;
1308 bool hasPlotted(false);
1309 TH1* h = dynamic_cast<TH1*>(hobj);
1310 TH2* h2 = dynamic_cast<TH2*>(h);
1311 TGraph* g = dynamic_cast<TGraph*>(hobj);
1312 TEfficiency* e = dynamic_cast<TEfficiency*>(hobj);
1313
1314 std::string name = nameHis;
1315 /* name+=".png";
1316 std::string::size_type i = location.find_last_of( '/' );
1317 if( i != (location.size()-1) ) {
1318 location+="/";
1319 }
1320 name=location + name; */
1321 std::string AlgoName("");
1322 AlgoName = getStringName(pathname + "/" + nameHis + "_/Config/name", file_version);
1323 int ww = 550;
1324 int wh = 490;
1325 found = display.find("TCanvas", found + 1);
1326 if (found != std::string::npos) {
1327 std::size_t found1 = display.find_first_of(',', found + 1);
1328 ww = std::atoi((display.substr(found + 8, found1 - found - 8)).c_str());
1329 found = display.find_first_of(')', found1 + 1);
1330 wh = std::atoi((display.substr(found1 + 1, found - found1 - 1)).c_str());
1331 }
1332 if (h != 0) {
1333 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
1334
1335 // if( h->GetMinimum() >= 0) {
1336 // gPad->SetLogy(display.find("LogY")!=std::string::npos );
1337 // }
1338 // if( BINLOEDGE(h, 1) > 0) {
1339 // gPad->SetLogx(display.find("LogX")!=std::string::npos );
1340 // }
1341 gPad->SetGridx(display.find("SetGridx") != std::string::npos);
1342 gPad->SetGridy(display.find("SetGridy") != std::string::npos);
1343 std::size_t found = display.find("SetPalette");
1344 if (found != std::string::npos) {
1345 std::size_t found1 = display.find_first_of('(', found + 1);
1346 std::size_t found2 = display.find_first_of(",)", found + 1);
1347 std::string cn = display.substr(found1 + 1, found2 - found1 - 1);
1348 int n1 = std::strtol(cn.c_str(), NULL, 0);
1349 gStyle->SetPalette((Int_t) n1);
1350 }
1351 found = display.find("SetGridStyle");
1352 if (found != std::string::npos) {
1353 std::size_t found1 = display.find_first_of('(', found + 1);
1354 std::size_t found2 = display.find_first_of(",)", found + 1);
1355 std::string cn = display.substr(found1 + 1, found2 - found1 - 1);
1356 int n1 = std::strtol(cn.c_str(), NULL, 0);
1357 gStyle->SetGridStyle((Style_t) n1);
1358 }
1359
1360 /******************* for plotting fit function on top of histogram ******************/
1361 found = display.find("gaus");
1362 if (found != std::string::npos) {
1363 Double_t minstat = 0.;
1364 std::size_t fpos1, fpos2, fpos;
1365 fpos = display.find("MinStat");
1366 if (fpos != std::string::npos) {
1367 fpos1 = display.find('(', fpos + 1);
1368 if (fpos1 != std::string::npos) {
1369 fpos2 = display.find(')', fpos1 + 1);
1370 if (fpos2 != std::string::npos) {
1371 std::string s_minstat = display.substr(fpos1 + 1, fpos2 - fpos1 - 1);
1372 minstat = std::strtod(s_minstat.c_str(), NULL);
1373 }
1374 }
1375 }
1376 std::string fitopt("");
1377 fpos = display.find("FitOption");
1378 if (fpos != std::string::npos) {
1379 fpos1 = display.find('(', fpos + 1);
1380 if (fpos1 != std::string::npos) {
1381 fpos2 = display.find(')', fpos1 + 1);
1382 if (fpos2 != std::string::npos) {
1383 fitopt = display.substr(fpos1 + 1, fpos2 - fpos1 - 1);
1384 }
1385 }
1386 }
1387 // plot double gaus
1388 std::size_t found1 = display.find("doublegaus");
1389 if (found1 != std::string::npos) {
1390 std::size_t found2 = display.find('(', found1 + 1);
1391 if (found2 != std::string::npos) {
1392 std::size_t found3 = display.find(')', found2 + 1);
1393 if (found3 != std::string::npos) {
1394 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
1395 Double_t xmin = std::strtod(range.c_str(), NULL);
1396 std::size_t found4 = display.find(',', found2 + 1);
1397 if (found4 != std::string::npos) {
1398 range = display.substr(found4 + 1, found3 - found4 - 1);
1399 Double_t xmax = std::strtod(range.c_str(), NULL);
1400 TF1* f1 = new TF1("f1", "gaus", xmin, xmax);
1401 h->Fit(f1, "q");
1402 Double_t par[6];
1403 f1->GetParameters(par);
1404 TF1* func = new TF1("func", "gaus(0)+gaus(3)", xmin, xmax);
1405 func->SetParameters(par);
1406 func->SetParameter(3, h->GetBinContent(h->GetMaximumBin()));
1407 func->SetParameter(4, h->GetMean());
1408 func->SetParameter(5, par[2]);
1409 func->SetLineColor(kRed);
1410 func->SetLineWidth(2);
1411 if (h->GetEffectiveEntries() > minstat) {
1412 h->Fit(func, ("rq" + fitopt).c_str());
1413 }
1414 delete f1;
1415 delete func;
1416 }
1417 }
1418 }
1419 } else {
1420 // draw gaus+pol1
1421 std::size_t found1 = display.find("gauspluspol1");
1422 if (found1 != std::string::npos) {
1423 std::size_t found2 = display.find('(', found1 + 1);
1424 if (found2 != std::string::npos) {
1425 std::size_t found3 = display.find(')', found2 + 1);
1426 if (found3 != std::string::npos) {
1427 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
1428 Double_t xmin = std::strtod(range.c_str(), NULL);
1429 std::size_t found4 = display.find(',', found2 + 1);
1430 if (found4 != std::string::npos) {
1431 range = display.substr(found4 + 1, found3 - found4 - 1);
1432 Double_t xmax = std::strtod(range.c_str(), NULL);
1433 TF1* func = new TF1("func", "gaus(0)+pol1(3)", xmin, xmax);
1434 func->SetLineColor(kRed);
1435 func->SetLineWidth(2);
1436 func->SetParameters(h->GetBinContent(h->GetMaximumBin()), h->GetMean(), h->GetRMS());
1437 if (h->GetEffectiveEntries() > minstat) {
1438 h->Fit(func, ("rq" + fitopt).c_str());
1439 }
1440 delete func;
1441 }
1442 }
1443 }
1444 } else {
1445 // draw gaus+expo
1446 found1 = display.find("gausplusexpo");
1447 if (found1 != std::string::npos) {
1448 std::size_t found2 = display.find('(', found1 + 1);
1449 if (found2 != std::string::npos) {
1450 std::size_t found3 = display.find(')', found2 + 1);
1451 if (found3 != std::string::npos) {
1452 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
1453 Double_t xmin = std::strtod(range.c_str(), NULL);
1454 std::size_t found4 = display.find(',', found2 + 1);
1455 if (found4 != std::string::npos) {
1456 range = display.substr(found4 + 1, found3 - found4 - 1);
1457 Double_t xmax = std::strtod(range.c_str(), NULL);
1458
1459 TF1* func = new TF1("func", "gaus(0)+expo(3)", xmin, xmax);
1460 func->SetLineColor(kRed);
1461 func->SetLineWidth(2);
1462 func->SetParameters(h->GetBinContent(h->GetMaximumBin()), h->GetMean(), h->GetRMS());
1463 if (h->GetEffectiveEntries() > minstat) {
1464 h->Fit(func, ("rq" + fitopt).c_str());
1465 }
1466 delete func;
1467 }
1468 }
1469 }
1470 } else {
1471 // the last case: single gaus
1472 std::size_t found2 = display.find('(', found + 1);
1473 if (found2 != std::string::npos) {
1474 std::size_t found3 = display.find(')', found2 + 1);
1475 if (found3 != std::string::npos) {
1476 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
1477 Double_t xmin = std::strtod(range.c_str(), NULL);
1478 std::size_t found4 = display.find(',', found2 + 1);
1479 if (found4 != std::string::npos) {
1480 range = display.substr(found4 + 1, found3 - found4 - 1);
1481 Double_t xmax = std::strtod(range.c_str(), NULL);
1482 TF1* func = new TF1("func", "gaus", xmin, xmax);
1483 func->SetLineColor(kRed);
1484 func->SetLineWidth(2);
1485 if (h->GetEffectiveEntries() > minstat) {
1486 h->Fit(func, ("rq" + fitopt).c_str());
1487 }
1488 delete func;
1489 }
1490 }
1491 }
1492 }
1493 }
1494 }
1495 }
1496 if (h2 != 0) {
1497 formatTH2(myC.get(), h2);
1498 myC->cd();
1499 if (h2->GetMinimum() >= 0 && h2->GetMaximum() > 0.) {
1500 gPad->SetLogy(display.find("LogY") != std::string::npos);
1501 gPad->SetLogz(display.find("LogZ") != std::string::npos);
1502 }
1503 if (BINLOEDGE(h2, 1) > 0) {
1504 gPad->SetLogx(display.find("LogX") != std::string::npos);
1505 }
1506 if (h->GetXaxis()->GetXmin() >= h->GetXaxis()->GetXmax()) {
1507 std::cerr << "HanOutputFile::saveHistogramToFile(): "
1508 << "Inconsistent x-axis settings: min=" << h->GetXaxis()->GetXmin() << ", "
1509 << "max=" << h->GetXaxis()->GetXmax() << ", "
1510 << "Will not save this histogram.\n";
1511 return std::pair<std::string, std::string>{
1512 "", ""
1513 };
1514 }
1515 if (h->GetYaxis()->GetXmin() >= h->GetYaxis()->GetXmax()) {
1516 std::cerr << "HanOutputFile::saveHistogramToFile(): "
1517 << "Inconsistent y-axis settings: min=" << h->GetYaxis()->GetXmin() << ", "
1518 << "max=" << h->GetYaxis()->GetXmax() << ", "
1519 << "Will not save this histogram.\n";
1520 return std::pair<std::string, std::string>{
1521 "", ""
1522 };
1523 }
1524 axisOption(display, h2);
1525 if (drawopt == "") {
1526 drawopt = "COLZ";
1527 }
1528 if (drawRefs) {
1529 if (file_version == 1) {
1530 groupDir->cd((nameHis + "_/Results").c_str());
1531 gDirectory->GetObject("Reference;1", ref);
1532 } else if (file_version == 2) {
1533 if (groupDir->GetDirectory((nameHis + "_").c_str()) != 0) {
1534 groupDir->cd((nameHis + "_").c_str());
1535 gDirectory->GetObject("Reference;1", ref);
1536 }
1537 }
1538 h2Ref = dynamic_cast<TH2*>(ref);
1539 TCollection* colln = dynamic_cast<TCollection*>(ref);
1540 if (colln) {
1541 h2Ref = dynamic_cast<TH2*>(colln->MakeIterator()->Next());
1542 }
1543 if (h2Ref && (drawrefopt2D != "")) {
1544 formatTH2(myC.get(), h2Ref);
1545 h2Ref->Draw(drawrefopt2D.c_str());
1546 }
1547 }
1548 h2->Draw(("SAME" + drawopt).c_str());
1549 displayExtra(myC.get(), display);
1550 if (drawopt.find("lego") == std::string::npos) {
1551 myC->RedrawAxis();
1552 }
1553 if (h2Ref) ratioplot2D(myC.get(), h2, h2Ref, display);
1554
1555 polynomial(myC.get(), display, h2);
1556 TLatex t;
1557 t.SetNDC();
1558 t.SetTextSize(0.03);
1559 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
1560 TLatex tt;
1561 tt.SetNDC();
1562 tt.SetTextSize(0.03);
1563 tt.DrawLatex(0.02, 0.01, pathName.c_str());
1564 convertToGraphics(cnvsType, myC.get(), json, &img, &x, &y);
1565 } else if (h != 0) {
1566 formatTH1(myC.get(), h);
1567 if (display.find("StatBox") != std::string::npos) {
1568 h->SetStats(kTRUE);
1569 }
1570 if (h->GetXaxis()->GetXmin() >= h->GetXaxis()->GetXmax()) {
1571 std::cerr << "HanOutputFile::saveHistogramToFile(): "
1572 << "Inconsistent x-axis settings: min=" << h->GetXaxis()->GetXmin() << ", "
1573 << "max=" << h->GetXaxis()->GetXmax() << ", "
1574 << "Will not save this histogram.\n";
1575 return std::pair<std::string, std::string>{
1576 "", ""
1577 };
1578 }
1579 h->SetLineColor(kBlack);
1580 h->SetMarkerColor(1);
1581 // h->SetMarkerStyle(iMarkerStyle);
1582 // h->SetMarkerSize(0.8);
1583 h->SetFillStyle(0);
1584 h->SetLineWidth(2);
1585 myC->cd();
1586 if (drawRefs) {
1587 if (file_version == 1) {
1588 groupDir->cd((nameHis + "_/Results").c_str());
1589 gDirectory->GetObject("Reference;1", ref);
1590 } else if (file_version == 2) {
1591 if (groupDir->GetDirectory((nameHis + "_").c_str()) != 0) {
1592 groupDir->cd((nameHis + "_").c_str());
1593 gDirectory->GetObject("Reference;1", ref);
1594 }
1595 }
1596 hRef = dynamic_cast<TH1*>(ref);
1597 if (hRef) {
1598 hRefs.push_back(hRef);
1599 } else {
1600 TCollection* colln = dynamic_cast<TCollection*>(ref);
1601 if (colln) {
1602 WasCollectionReference = true;
1603 std::unique_ptr<TIterator> icolln(colln->MakeIterator());
1604 TObject* ref2;
1605 while ((ref2 = icolln->Next())) {
1606 hRef = dynamic_cast<TH1*>(ref2);
1607 if (hRef) {
1608 if (hRef->GetDimension() == h->GetDimension()) {
1609 hRefs.push_back(hRef);
1610 }
1611 } else std::cout << "hRef cast failed!!!" << std::endl;
1612 }
1613 }
1614 }
1615 groupDir->cd();
1616 }
1617
1618 if (hRefs.size() > 0) {
1619 legend = new TLegend(0.55, 0.77, 0.87, 0.87);
1620 legend->SetTextFont(62);
1621 legend->SetMargin(0.15);
1622 legend->SetFillStyle(0);
1623 legend->SetBorderSize(0);
1624 legend->AddEntry(h, datatitle.c_str());
1625 int itrcolor(0);
1626 for (auto hRef : hRefs) {
1627 int local_color = root_color_choices[itrcolor];
1628 itrcolor++;
1629 formatTH1(myC.get(), hRef);
1630 TProfile* pRef = dynamic_cast<TProfile*>(hRef);
1631 if (pRef != 0) {
1632 hRef->SetMarkerColor(local_color);
1633 // hRef->SetMarkerStyle(iMarkerStyle);
1634 // hRef->SetMarkerSize(0.8);
1635 hRef->SetLineColor(local_color);
1636 hRef->SetLineWidth(2);
1637 double ymin = (hRef->GetMinimum() < h->GetMinimum()) ? hRef->GetMinimum() : h->GetMinimum();
1638 double ymax = (hRef->GetMaximum() > h->GetMaximum()) ? hRef->GetMaximum() : h->GetMaximum();
1639 double xmin, xmax;
1640 if (PlotOverflows) {
1641 xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1) ? BINLOEDGE(hRef, 1) - BINWIDTH(hRef, 1)
1642 : BINLOEDGE(h, 1) - BINWIDTH(h, 1));
1643 xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
1644 BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()))
1645 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + 2.0 * BINWIDTH(hRef, hRef->GetNbinsX())
1646 : BINLOEDGE(h, h->GetNbinsX()) + 2.0 * BINWIDTH(h, h->GetNbinsX());
1647 } else {
1648 xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1) : BINLOEDGE(h, 1);
1649 xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) > BINLOEDGE(h, h->GetNbinsX())
1650 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX())
1651 : BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()));
1652 }
1653 // double y_av = (ymax + ymin)/2;
1654 // double y_halv = (ymax-ymin)*0.6;
1655 bool isLogY = (display.find("LogY") != std::string::npos);
1656 if (isLogY) {
1657 if (ymax <= 0.) ymax = 5.0;
1658 if (ymin > 0.) {
1659 double lymax = log(ymax);
1660 double lymin = log(ymin);
1661 h->SetAxisRange(exp(lymin - (lymax - lymin) * 0.05), exp(lymax + (lymax - lymin) * 0.05),
1662 "Y"); // leave 5% gap on above and below
1663 } else {
1664 std::cerr << "ymin is <0. and LogY requested for histogram \"" << pathname + "/" + nameHis
1665 << "\", ymin=" << ymin << std::endl;
1666 }
1667 } else {
1668 double yMargin = (ymax - ymin) * 0.05;
1669 h->SetAxisRange(ymin - yMargin, ymax + yMargin, "Y");
1670 }
1671 h->GetXaxis()->SetRangeUser(xmin, xmax);
1672 hRef->GetXaxis()->SetRangeUser(xmin, xmax);
1673 axisOption(display, h);
1674 if (h->GetMinimum() >= 0. && hRef->GetMinimum() >= 0. && h->GetMaximum() > 0. &&
1675 hRef->GetMaximum() > 0.) {
1676 gPad->SetLogy(display.find("LogY") != std::string::npos);
1677 }
1678 if (BINLOEDGE(h, 1) > 0 && BINLOEDGE(hRef, 1) > 0) {
1679 gPad->SetLogx(display.find("LogX") != std::string::npos);
1680 }
1681 if (!hasPlotted) {
1682 h->Draw(drawopt.c_str());
1683 hasPlotted = true;
1684 }
1685 hRef->Draw(("SAME" + drawrefopt).c_str());
1686 } else {
1687 double scale = 1.0;
1688 if (display.find("ScaleRef") != std::string::npos) {
1689 scale = getScaleVal(display);
1690 } else if (h->Integral("width") > 0.0 && hRef->Integral("width") > 0.0 &&
1691 (AlgoName.find("BinContentComp") == std::string::npos) &&
1692 (display.find("NoNorm") == std::string::npos)) {
1693 scale = h->Integral("width") / hRef->Integral("width");
1694 }
1695 hRef->Scale(scale);
1696 // hRef->SetMarkerStyle(iMarkerStyle);
1697 // hRef->SetMarkerSize(0.8);
1698 hRef->SetMarkerColor(local_color);
1699 // hRef->SetFillColor(local_color);
1700 hRef->SetLineColor(local_color);
1701 double ymin = (hRef->GetMinimum() < h->GetMinimum()) ? hRef->GetMinimum() : h->GetMinimum();
1702 double ymax = (hRef->GetMaximum() > h->GetMaximum()) ? hRef->GetMaximum() : h->GetMaximum();
1703 double xmin, xmax;
1704 if (PlotOverflows) {
1705 xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1) - BINWIDTH(hRef, 1)
1706 : BINLOEDGE(h, 1) - BINWIDTH(h, 1);
1707 xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
1708 BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()))
1709 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + 2.0 * BINWIDTH(hRef, hRef->GetNbinsX())
1710 : BINLOEDGE(h, h->GetNbinsX()) + 2.0 * BINWIDTH(h, h->GetNbinsX());
1711 } else {
1712 xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1) : BINLOEDGE(h, 1);
1713 xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
1714 BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()))
1715 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX())
1716 : BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX());
1717 }
1718
1719 // double y_av = (ymax + ymin)/2;
1720 // double y_halv = (ymax-ymin)*0.6;
1721 bool isLogY = (display.find("LogY") != std::string::npos);
1722 // if ( ymin == 0.0 && display.find("LogY")!=std::string::npos ){
1723
1724 if (isLogY) {
1725 if (ymax <= 0.) ymax = 5.0;
1726 if (ymin > 0.) {
1727 double lymax = log(ymax);
1728 double lymin = log(ymin);
1729 h->SetAxisRange(exp(lymin - (lymax - lymin) * 0.05), exp(lymax + (lymax - lymin) * 0.05), "Y");
1730 // leave 5% gap on above and below
1731 } else {
1732 std::cerr << "ymin is <=0. and LogY requested for histogram \"" << pathname + "/" + nameHis
1733 << "\", ymin=" << ymin << std::endl;
1734 }
1735 } else {
1736 double yDiff = ymax - ymin;
1737 h->SetAxisRange(ymin - yDiff * 0.05, ymax + yDiff * 0.05, "Y"); // leave 5% gap above and below
1738 }
1739
1740 h->GetXaxis()->SetRangeUser(xmin, xmax);
1741 hRef->GetXaxis()->SetRangeUser(xmin, xmax);
1742 myC->cd();
1743 if (h->GetMinimum() >= 0 && hRef->GetMinimum() >= 0 && h->GetMaximum() > 0. && hRef->GetMaximum() > 0.) {
1744 gPad->SetLogy(display.find("LogY") != std::string::npos);
1745 }
1746 if (BINLOEDGE(h, 1) > 0 && BINLOEDGE(hRef, 1) > 0) {
1747 gPad->SetLogx(display.find("LogX") != std::string::npos);
1748 }
1749 axisOption(display, h);
1750 if (!hasPlotted) {
1751 h->Draw(drawopt.c_str());
1752 hasPlotted = true;
1753 }
1754 hRef->Draw(("SAME" + drawrefopt).c_str());
1755 }
1756 if (WasCollectionReference) {
1757 legend->AddEntry(hRef, hRef->GetName());
1758 } else {
1759 std::string refInfo("");
1760 refInfo = getStringName(pathname + "/" + nameHis + "_/Config/annotations/refInfo", file_version);
1761 legend->AddEntry(hRef, refInfo != "Undefined" ? refInfo.c_str() : "Reference");
1762 }
1763 }
1764 h->Draw(("SAME" + drawopt).c_str());
1765 legend->Draw();
1766 } else {
1767 myC->cd();
1768 if (h->GetMinimum() >= 0) {
1769 gPad->SetLogy(display.find("LogY") != std::string::npos);
1770 }
1771 if (BINLOEDGE(h, 1) > 0) {
1772 gPad->SetLogx(display.find("LogX") != std::string::npos);
1773 }
1774 axisOption(display, h);
1775 h->Draw(drawopt.c_str());
1776 }
1777 myC->cd();
1778 displayExtra(myC.get(), display);
1779 myC->RedrawAxis();
1780
1781 if (hRef) {
1782 ratioplot(myC.get(), h, hRef, display); // RatioPad
1783 }
1784 myC->cd(); // might be unnecessary
1785 polynomial(myC.get(), display, h); // draw polynome for TH1
1786
1787 TLatex t;
1788 t.SetNDC();
1789 t.SetTextSize(0.03);
1790 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
1791 TLatex tt;
1792 tt.SetNDC();
1793 tt.SetTextSize(0.03);
1794 tt.DrawLatex(0.02, 0.01, pathName.c_str());
1795
1796 convertToGraphics(cnvsType, myC.get(), json, &img, &x, &y);
1797 }
1798 // delete myC;
1799 gStyle->Reset();
1800 }
1801 if (g) {
1802 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
1803 myC->cd();
1804 if (g->GetMinimum() >= 0. && g->GetMaximum() > 0.) {
1805 gPad->SetLogy(display.find("LogY") != std::string::npos);
1806 }
1807 // if( BINLOEDGE(h2, 1) > 0) {
1808 // gPad->SetLogx(display.find("LogX")!=std::string::npos );
1809 // }
1810 // gPad->SetLogz(display.find("LogZ")!=std::string::npos );
1811 formatTGraph(myC.get(), g);
1812 // axisOption(display,g);
1813 g->Draw((std::string("AP") + drawopt).c_str());
1814 displayExtra(myC.get(), display);
1815 TLatex t;
1816 t.SetNDC();
1817 t.SetTextSize(0.03);
1818 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
1819 TLatex tt;
1820 tt.SetNDC();
1821 tt.SetTextSize(0.03);
1822 tt.DrawLatex(0.02, 0.01, pathName.c_str());
1823 // myC->SaveAs( name.c_str() );
1824
1825 convertToGraphics(cnvsType, myC.get(), json, &img, &x, &y);
1826
1827 gStyle->Reset();
1828 }
1829 if (e != 0) {
1830 hasPlotted = false;
1831 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
1832 formatTEfficiency(myC.get(), e);
1833 if (drawopt == "") {
1834 if (e->GetDimension() == 1) {
1835 drawopt = "AP";
1836 } else {
1837 drawopt = "COLZ";
1838 }
1839 }
1840 if (drawRefs) {
1841 if (file_version == 1) {
1842 groupDir->cd((nameHis + "_/Results").c_str());
1843 gDirectory->GetObject("Reference;1", ref);
1844 } else if (file_version == 2) {
1845 if (groupDir->cd((nameHis + "_").c_str())) {
1846 gDirectory->GetObject("Reference;1", ref);
1847 }
1848 }
1849 eRef = dynamic_cast<TEfficiency*>(ref);
1850 if (eRef) {
1851 eRefs.push_back(eRef);
1852 } else {
1853 TCollection* colln = dynamic_cast<TCollection*>(ref);
1854 if (colln) {
1855 WasCollectionReference = true;
1856 TIterator* icolln = colln->MakeIterator();
1857 TObject* ref2;
1858 while ((ref2 = icolln->Next())) {
1859 eRef = dynamic_cast<TEfficiency*>(ref2);
1860 if (eRef) {
1861 if (eRef->GetDimension() == e->GetDimension()) {
1862 eRefs.push_back(eRef);
1863 }
1864 } else std::cout << "eRef cast failed!!!" << std::endl;
1865 }
1866 }
1867 }
1868 groupDir->cd();
1869 }
1870 if (eRefs.size() > 0) {
1871 legend = new TLegend(0.55, 0.77, 0.87, 0.87);
1872 legend->SetTextFont(62);
1873 legend->SetMargin(0.15);
1874 legend->SetFillStyle(0);
1875 legend->SetBorderSize(0);
1876 legend->AddEntry(e, datatitle.c_str());
1877 int itrcolor(0);
1878 for (auto eRef : eRefs) {
1879 myC->cd();
1880 e->Draw("");
1881 eRef->Draw("");
1882 gPad->Update();
1883
1884 int local_color = root_color_choices[itrcolor];
1885 itrcolor++;
1886
1887 formatTEfficiency(myC.get(), eRef);
1888 eRef->SetMarkerColor(local_color);
1889 eRef->SetLineColor(local_color);
1890
1891 if (!hasPlotted) {
1892 e->Draw(drawopt.c_str());
1893 hasPlotted = true;
1894 }
1895 eRef->Draw("SAME");
1896 myC->Update();
1897
1898 if (WasCollectionReference) {
1899 legend->AddEntry(eRef, eRef->GetName());
1900 } else {
1901 std::string refInfo("");
1902 refInfo = getStringName(pathname + "/" + nameHis + "_/Config/annotations/refInfo", file_version);
1903 legend->AddEntry(eRef, refInfo != "Undefined" ? refInfo.c_str() : "Reference");
1904 }
1905 }
1906 legend->Draw();
1907 } else {
1908 myC->cd();
1909 e->Draw(drawopt.c_str());
1910 }
1911
1912 // Fix to display x axis title
1913 myC->Update();
1914 e->GetPaintedGraph()->GetXaxis()->SetTitleColor();
1915
1916 myC->cd();
1917 displayExtra(myC.get(), display);
1918 TLatex t;
1919 t.SetNDC();
1920 t.SetTextSize(0.03);
1921 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
1922 TLatex tt;
1923 tt.SetNDC();
1924 tt.SetTextSize(0.03);
1925 tt.DrawLatex(0.02, 0.01, pathName.c_str());
1926 convertToGraphics(cnvsType, myC.get(), json, &img, &x, &y);
1927 gStyle->Reset();
1928 }
1929 std::string rv;
1930 if (cnvsType & GENERATE_PNG) {
1931 if (x) rv.assign(x, y);
1932 }
1933 ;
1934 std::pair<std::string, std::string> rvPair {
1935 rv, json
1936 };
1937 //deallocate image buffer with free(x), see https://root.cern.ch/doc/master/classTASImage.html
1938 free(x);
1939 delete hobj;
1940 delete ref;
1941 delete legend;
1942 return rvPair;
1943 }
1944
1945 bool HanOutputFile::saveHistogramToFileSuperimposed(const std::string& nameHis, std::string location,
1946 TDirectory* groupDir1,
1947 TDirectory* groupDir2, bool drawRefs,
1948 const std::string& run_min_LB, const std::string& pathName,
1949 int cnvsType) {
1950 dqi::DisableMustClean disabled;
1951 groupDir1->cd();
1952 gStyle->SetFrameBorderMode(0);
1953 gStyle->SetFrameFillColor(0);
1954 gStyle->SetCanvasBorderMode(0);
1955 gStyle->SetPadBorderMode(0);
1956 gStyle->SetPadColor(0);
1957 gStyle->SetCanvasColor(0);
1958 gStyle->SetTitleColor(0);
1959 gStyle->SetStatColor(0);
1960 gStyle->SetFillColor(1);
1961 gStyle->SetPalette(1, 0);
1962 gStyle->SetTitleFontSize(0.06);
1963 gStyle->SetTitleH(0.06);
1964 gStyle->SetMarkerStyle(20);
1965 gStyle->SetOptStat(111100);
1966 gStyle->SetStatBorderSize(0);
1967 gStyle->SetStatX(0.99);
1968 gStyle->SetStatY(0.99);
1969 gStyle->SetStatW(0.2);
1970 gStyle->SetStatH(0.1);
1971
1972 gROOT->SetBatch();
1973 std::string pathname(groupDir1->GetPath());
1974 std::string display = "";
1975 int file_version = getFileVersion();
1976 bool LookForDisplay;
1977 if (file_version == 1) {
1978 LookForDisplay = containsDir("Config/annotations/display", (pathname + "/" + nameHis + "_"));
1979 if (LookForDisplay) {
1980 display = getStringName(pathname + "/" + nameHis + "_/Config/annotations/display", file_version);
1981 }
1982 } else if (file_version == 2) {
1983 std::optional<std::string> JSON_content;
1984 LookForDisplay = containsDir((nameHis + "_"), pathname);
1985 if (LookForDisplay) {
1986 JSON_content = containsKeyInJSON("/annotations/display", "Config", (pathname + "/" + nameHis + "_"));
1987 if (JSON_content) {
1988 LookForDisplay = true;
1989 } else {
1990 LookForDisplay = false;
1991 }
1992 }
1993 if (LookForDisplay) {
1994 display = JSON_content.value();
1995 }
1996 }
1997
1998 // Look for Draw Options
1999 std::size_t found = display.find("Draw");
2000 std::string drawopt = "";
2001 while (found != std::string::npos) {
2002 std::size_t found1 = display.find_first_of(',', found + 1);
2003 auto temp = display.substr(found + 5, found1 != std::string::npos ? found1 - found - 5 : display.size() );
2004 std::ranges::transform(temp, temp.begin(), [](unsigned char c) { return std::tolower(c); });
2005 drawopt += temp;
2006 found = display.find("Draw", found + 1);
2007 }
2008
2009 groupDir1->cd();
2010 TKey* hkey = groupDir1->FindKey(nameHis.c_str());
2011 groupDir2->cd();
2012 TKey* hkey2 = groupDir2->FindKey(nameHis.c_str());
2013 if (hkey == 0 || hkey2 == 0) {
2014 std::cerr << "Did not find TKey for \"" << nameHis << "\", will not save this histogram.\n";
2015 return false;
2016 }
2017 groupDir1->cd();
2018 TLegend* legend(0);
2019 TObject* hobj = hkey->ReadObj();
2020 TObject* hobj2 = hkey2->ReadObj();
2021 TH1* hRef(0);
2022 TH1* h(0), *hist2(0);
2023 TH2* h2(0), *h2_2(0), *h2Diff(0);
2024 TGraph* g(0), *g2(0);
2025 TEfficiency* e(0), *e2(0);
2026
2027 std::string json;
2028 std::string nameJSON = nameHis;
2029 std::string namePNG = nameHis;
2030 namePNG += ".png";
2031 nameJSON += ".json";
2032 std::string::size_type i = location.find_last_of('/');
2033 if (i != (location.size() - 1)) {
2034 location += "/";
2035 }
2036 namePNG = location + namePNG;
2037 nameJSON = location + nameJSON;
2038 std::string AlgoName = getStringName(pathname + "/" + nameHis + "_/Config/name", file_version);
2039 int ww = 550;
2040 int wh = 490;
2041 found = display.find("TCanvas");
2042 if (found != std::string::npos) {
2043 std::size_t found1 = display.find_first_of(',', found + 1);
2044 ww = std::atoi((display.substr(found + 8, found1 - found - 8)).c_str());
2045 found = display.find_first_of(')', found1 + 1);
2046 wh = std::atoi((display.substr(found1 + 1, found - found1 - 1)).c_str());
2047 }
2048
2049 if ((h = dynamic_cast<TH1*>(hobj)) != 0 && (hist2 = dynamic_cast<TH1*>(hobj2)) != 0) {
2050 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
2051 setupCanvas(drawopt, display);
2052 attachFits(h, drawopt, display);
2053 /******************* for plotting fit function on top of histogram ******************/
2054
2055 /*************************************************************************************************************/
2056 std::string tmpdraw(drawopt);
2057 if ((h2 = dynamic_cast<TH2*>(h)) != 0 && ((h2_2 = dynamic_cast<TH2*>(hist2)) != 0)) {
2058 // if(tmpdraw=="")
2059 h2Diff = (TH2*) h2->Clone("difference");
2060 // tmpdraw="box";//we don't want colz for overlaid histos
2061 // h2->SetLineColor(2);
2062 // h2->SetMarkerColor(2);
2063 // if(!drawH2(myC,h2,tmpdraw,display))return false;
2064 // h2_2->SetMarkerColor(4);
2065 // //h2_2->SetFillColor(4);
2066 // h2_2->SetLineWidth(2);
2067 // h2_2->SetLineColor(4);
2068 // tmpdraw=" box same";
2069 // if(!drawH2(myC,h2_2,tmpdraw,display))return false;
2070 h2Diff->Add(h2, h2_2, 1.0, -1.0);
2071 h2Diff->SetLineColor(2);
2072 h2Diff->SetMarkerColor(2);
2073 if (!drawH2(myC.get(), h2Diff, tmpdraw, display)) return false;
2074
2075 TLatex t;
2076 t.SetNDC();
2077 t.SetTextSize(0.03);
2078 t.DrawLatex(0.02, 0.04, (run_min_LB + " difference").c_str());
2079 TLatex tt;
2080 tt.SetNDC();
2081 tt.SetTextSize(0.03);
2082 tt.DrawLatex(0.02, 0.01, pathName.c_str());
2083
2084 convertToGraphics(cnvsType, myC.get(), namePNG, nameJSON);
2085 } else if (h != 0 && hist2 != 0) {
2086 // Petronel
2087 double scale = 1.0;
2088 if (display.find("ScaleRef") != std::string::npos) {
2089 scale = getScaleVal(display);
2090 } else if (h->Integral("width") > 0.0 && hist2->Integral("width") > 0.0 &&
2091 (AlgoName.find("BinContentComp") == std::string::npos) &&
2092 (display.find("NoNorm") == std::string::npos)) {
2093 scale = h->Integral("width") / hist2->Integral("width");
2094 }
2095 hist2->Scale(scale);
2096 double ymin = (hist2->GetMinimum() < h->GetMinimum()) ? hist2->GetMinimum() : h->GetMinimum();
2097 double ymax = (hist2->GetMaximum() > h->GetMaximum()) ? hist2->GetMaximum() : h->GetMaximum();
2098 double yMargin = (ymax - ymin) * 0.05;
2099 h->SetAxisRange(ymin - yMargin, ymax + yMargin, "Y");
2100
2101 h->SetMarkerColor(1);
2102 h->SetFillStyle(0);
2103 h->SetLineWidth(2);
2104 hist2->SetMarkerColor(4);
2105 hist2->SetLineColor(4);
2106 hist2->SetFillStyle(0);
2107 hist2->SetLineWidth(2);
2108 if (drawRefs) {
2109 if (file_version == 1) {
2110 groupDir1->cd((nameHis + "_/Results").c_str());
2111 } else {
2112 groupDir1->cd((nameHis + "_").c_str());
2113 }
2114 gDirectory->GetObject("Reference;1", hRef);
2115 groupDir1->cd();
2116 }
2117 if (!drawH1(myC.get(), h, hRef, tmpdraw, display, AlgoName)) return false;
2118
2119 tmpdraw += "same";
2120 if (!drawH1(myC.get(), hist2, 0, tmpdraw, display, AlgoName)) return false;
2121
2122 legend = new TLegend(0.55, 0.77, 0.87, 0.87);
2123 legend->SetTextFont(62);
2124 legend->SetMargin(0.15);
2125 legend->SetFillStyle(0);
2126 legend->SetBorderSize(0);
2127
2128 std::size_t foundN1 = run_min_LB.find_first_of("-");
2129 std::size_t foundN2 = run_min_LB.find_first_of(',');
2130
2131 legend->AddEntry(h, ("Run " + run_min_LB.substr(5, foundN1 - 5)).c_str());
2132 legend->AddEntry(hist2, ("Run " + run_min_LB.substr(foundN1 + 1, foundN2 - foundN1 - 1)).c_str());
2133 if (hRef) {
2134 legend->AddEntry(hRef, "Reference");
2135 }
2136 legend->Draw();
2137
2138 TLatex t;
2139 t.SetNDC();
2140 t.SetTextSize(0.03);
2141 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
2142 TLatex tt;
2143 tt.SetNDC();
2144 tt.SetTextSize(0.03);
2145 tt.DrawLatex(0.02, 0.01, pathName.c_str());
2146
2147 convertToGraphics(cnvsType, myC.get(), namePNG, nameJSON);
2148 } // end histogram drawing
2149 delete h2Diff;
2150 gStyle->Reset();
2151 }
2152
2153 /*************************************************************************************************************/
2154 if (((g = dynamic_cast<TGraph*>(hobj)) != 0) && ((g2 = dynamic_cast<TGraph*>(hobj2)) != 0)) {
2155 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
2156 myC->cd();
2157 if (g->GetMinimum() >= 0. && g2->GetMinimum() >= 0. && g->GetMaximum() > 0. && g2->GetMaximum() > 0.) {
2158 gPad->SetLogy(display.find("LogY") != std::string::npos);
2159 }
2160 formatTGraph(myC.get(), g);
2161 formatTGraph(myC.get(), g2);
2162 g->Draw((std::string("AP") + drawopt).c_str());
2163 displayExtra(myC.get(), display);
2164 g2->SetMarkerColor(2);
2165 g2->SetLineColor(2);
2166 g2->Draw((std::string("P") + drawopt + " same").c_str());
2167 TLatex t;
2168 t.SetNDC();
2169 t.SetTextSize(0.03);
2170 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
2171 TLatex tt;
2172 tt.SetNDC();
2173 tt.SetTextSize(0.03);
2174 tt.DrawLatex(0.02, 0.01, pathName.c_str());
2175
2176 convertToGraphics(cnvsType, myC.get(), namePNG, nameJSON);
2177
2178 gStyle->Reset();
2179 }
2180
2181 if (((e = dynamic_cast<TEfficiency*>(hobj)) != 0) && ((e2 = dynamic_cast<TEfficiency*>(hobj2)) != 0)) {
2182 auto myC = std::make_unique<TCanvas>(nameHis.c_str(), "myC", ww, wh);
2183 myC->cd();
2184
2185 formatTEfficiency(myC.get(), e);
2186 formatTEfficiency(myC.get(), e2);
2187 e->Draw((std::string("AP") + drawopt).c_str());
2188
2189 // Fix to display x axis title
2190 myC->Update();
2191 e->GetPaintedGraph()->GetXaxis()->SetTitleColor();
2192
2193 displayExtra(myC.get(), display);
2194 e2->SetMarkerColor(2);
2195 e2->SetLineColor(2);
2196 e2->Draw((std::string("P") + drawopt + " same").c_str());
2197 TLatex t;
2198 t.SetNDC();
2199 t.SetTextSize(0.03);
2200 t.DrawLatex(0.02, 0.04, run_min_LB.c_str());
2201 TLatex tt;
2202 tt.SetNDC();
2203 tt.SetTextSize(0.03);
2204 tt.DrawLatex(0.02, 0.01, pathName.c_str());
2205
2206 convertToGraphics(cnvsType, myC.get(), namePNG, std::move(nameJSON));
2207
2208 gStyle->Reset();
2209 }
2210
2211 delete hobj;
2212 delete hobj2;
2213 delete hRef;
2214 delete legend;
2215 return true;
2216 }
2217
2218 bool HanOutputFile::drawH2(TCanvas* myC, TH2* h2, std::string& drawop, std::string& display) {
2219 std::string drawopt(drawop);
2220 myC->cd();
2221 if (h2->GetMinimum() >= 0 && h2->GetMaximum() > 0) {
2222 gPad->SetLogy(display.find("LogY") != std::string::npos);
2223 gPad->SetLogz(display.find("LogZ") != std::string::npos);
2224 } else {
2225 gPad->SetLogy(false);
2226 }
2227 if (BINLOEDGE(h2, 1) > 0) {
2228 gPad->SetLogx(display.find("LogX") != std::string::npos);
2229 } else {
2230 gPad->SetLogx(false);
2231 }
2232 formatTH2(myC, h2);
2233 if (h2->GetXaxis()->GetXmin() >= h2->GetXaxis()->GetXmax()) {
2234 std::cerr << "HanOutputFile::saveHistogramToFile(): "
2235 << "Inconsistent x-axis settings: min=" << h2->GetXaxis()->GetXmin() << ", "
2236 << "max=" << h2->GetXaxis()->GetXmax() << ", "
2237 << "Will not save this histogram.\n";
2238 return false;
2239 }
2240 if (h2->GetYaxis()->GetXmin() >= h2->GetYaxis()->GetXmax()) {
2241 std::cerr << "HanOutputFile::saveHistogramToFile(): "
2242 << "Inconsistent y-axis settings: min=" << h2->GetYaxis()->GetXmin() << ", "
2243 << "max=" << h2->GetYaxis()->GetXmax() << ", "
2244 << "Will not save this histogram.\n";
2245 return false;
2246 }
2247 axisOption(display, h2);
2248 if (drawopt == "") {
2249 drawopt = "COLZ";
2250 }
2251 h2->Draw(drawopt.c_str());
2252 displayExtra(myC, display);
2253 // std::cout<<"drawh2 drawopt="<<drawopt<<",display="<<display<<std::endl;
2254 // if (drawopt.find("lego") == std::string::npos) {
2255 myC->RedrawAxis();
2256 //}
2257 return true;
2258 }
2259
2260 void HanOutputFile::setupCanvas(std::string& drawopt, std::string& display) {
2261 gPad->SetGridx(display.find("SetGridx") != std::string::npos);
2262 gPad->SetGridy(display.find("SetGridy") != std::string::npos);
2263 std::size_t found = display.find("SetPalette");
2264 if (found != std::string::npos) {
2265 std::size_t found1 = display.find_first_of('(', found + 1);
2266 std::size_t found2 = display.find_first_of(",)", found + 1);
2267 std::string cn = display.substr(found1 + 1, found2 - found1 - 1);
2268 int n1 = std::strtol(cn.c_str(), NULL, 0);
2269 gStyle->SetPalette((Int_t) n1);
2270 }
2271 found = display.find("SetGridStyle");
2272 if (found != std::string::npos) {
2273 std::size_t found1 = display.find_first_of('(', found + 1);
2274 std::size_t found2 = display.find_first_of(",)", found + 1);
2275 std::string cn = display.substr(found1 + 1, found2 - found1 - 1);
2276 int n1 = std::strtol(cn.c_str(), NULL, 0);
2277 gStyle->SetGridStyle((Style_t) n1);
2278 }
2279 if (!drawopt.empty()) {
2280 // do any modifications coming from drawopt
2281 }
2282 }
2283
2284 void HanOutputFile::attachFits(TH1* h, std::string& drawopt, std::string& display) {
2285 size_t found = display.find("gaus");
2286
2287 if (found != std::string::npos) {
2288 Double_t minstat = 0.;
2289 std::size_t fpos1, fpos2, fpos;
2290 fpos = display.find("MinStat");
2291 if (fpos != std::string::npos) {
2292 fpos1 = display.find('(', fpos + 1);
2293 if (fpos1 != std::string::npos) {
2294 fpos2 = display.find(')', fpos1 + 1);
2295 if (fpos2 != std::string::npos) {
2296 std::string s_minstat = display.substr(fpos1 + 1, fpos2 - fpos1 - 1);
2297 minstat = std::strtod(s_minstat.c_str(), NULL);
2298 }
2299 }
2300 }
2301 std::string fitopt("");
2302 fpos = display.find("FitOption");
2303 if (fpos != std::string::npos) {
2304 fpos1 = display.find('(', fpos + 1);
2305 if (fpos1 != std::string::npos) {
2306 fpos2 = display.find(')', fpos1 + 1);
2307 if (fpos2 != std::string::npos) {
2308 fitopt = display.substr(fpos1 + 1, fpos2 - fpos1 - 1);
2309 }
2310 }
2311 }
2312 // plot double gaus
2313 std::size_t found1 = display.find("doublegaus");
2314 if (found1 != std::string::npos) {
2315 std::size_t found2 = display.find('(', found1 + 1);
2316 if (found2 != std::string::npos) {
2317 std::size_t found3 = display.find(')', found2 + 1);
2318 if (found3 != std::string::npos) {
2319 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
2320 Double_t xmin = std::strtod(range.c_str(), NULL);
2321 std::size_t found4 = display.find(',', found2 + 1);
2322 if (found4 != std::string::npos) {
2323 range = display.substr(found4 + 1, found3 - found4 - 1);
2324 Double_t xmax = std::strtod(range.c_str(), NULL);
2325 TF1* f1 = new TF1("f1", "gaus", xmin, xmax);
2326 h->Fit(f1, "q");
2327 Double_t par[6];
2328 f1->GetParameters(par);
2329 TF1* func = new TF1("func", "gaus(0)+gaus(3)", xmin, xmax);
2330 func->SetParameters(par);
2331 func->SetParameter(3, h->GetBinContent(h->GetMaximumBin()));
2332 func->SetParameter(4, h->GetMean());
2333 func->SetParameter(5, par[2]);
2334 func->SetLineColor(kRed);
2335 func->SetLineWidth(2);
2336 if (h->GetEffectiveEntries() > minstat) {
2337 h->Fit(func, ("rq" + fitopt).c_str());
2338 }
2339 delete f1;
2340 delete func;
2341 }
2342 }
2343 }
2344 } else {
2345 // draw gaus+pol1
2346 std::size_t found1 = display.find("gauspluspol1");
2347 if (found1 != std::string::npos) {
2348 std::size_t found2 = display.find('(', found1 + 1);
2349 if (found2 != std::string::npos) {
2350 std::size_t found3 = display.find(')', found2 + 1);
2351 if (found3 != std::string::npos) {
2352 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
2353 Double_t xmin = std::strtod(range.c_str(), NULL);
2354 std::size_t found4 = display.find(',', found2 + 1);
2355 if (found4 != std::string::npos) {
2356 range = display.substr(found4 + 1, found3 - found4 - 1);
2357 Double_t xmax = std::strtod(range.c_str(), NULL);
2358 TF1* func = new TF1("func", "gaus(0)+pol1(3)", xmin, xmax);
2359 func->SetLineColor(kRed);
2360 func->SetLineWidth(2);
2361 func->SetParameters(h->GetBinContent(h->GetMaximumBin()), h->GetMean(), h->GetRMS());
2362 if (h->GetEffectiveEntries() > minstat) {
2363 h->Fit(func, ("rq" + fitopt).c_str());
2364 }
2365 delete func;
2366 }
2367 }
2368 }
2369 } else {
2370 // draw gaus+expo
2371 found1 = display.find("gausplusexpo");
2372 if (found1 != std::string::npos) {
2373 std::size_t found2 = display.find('(', found1 + 1);
2374 if (found2 != std::string::npos) {
2375 std::size_t found3 = display.find(')', found2 + 1);
2376 if (found3 != std::string::npos) {
2377 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
2378 Double_t xmin = std::strtod(range.c_str(), NULL);
2379 std::size_t found4 = display.find(',', found2 + 1);
2380 if (found4 != std::string::npos) {
2381 range = display.substr(found4 + 1, found3 - found4 - 1);
2382 Double_t xmax = std::strtod(range.c_str(), NULL);
2383
2384 TF1* func = new TF1("func", "gaus(0)+expo(3)", xmin, xmax);
2385 func->SetLineColor(kRed);
2386 func->SetLineWidth(2);
2387 func->SetParameters(h->GetBinContent(h->GetMaximumBin()), h->GetMean(), h->GetRMS());
2388 if (h->GetEffectiveEntries() > minstat) {
2389 h->Fit(func, ("rq" + fitopt).c_str());
2390 }
2391 delete func;
2392 }
2393 }
2394 }
2395 } else {
2396 // the last case: single gaus
2397 std::size_t found2 = display.find('(', found + 1);
2398 if (found2 != std::string::npos) {
2399 std::size_t found3 = display.find(')', found2 + 1);
2400 if (found3 != std::string::npos) {
2401 std::string range = display.substr(found2 + 1, found3 - found2 - 1);
2402 Double_t xmin = std::strtod(range.c_str(), NULL);
2403 std::size_t found4 = display.find(',', found2 + 1);
2404 if (found4 != std::string::npos) {
2405 range = display.substr(found4 + 1, found3 - found4 - 1);
2406 Double_t xmax = std::strtod(range.c_str(), NULL);
2407 TF1* func = new TF1("func", "gaus", xmin, xmax);
2408 func->SetLineColor(kRed);
2409 func->SetLineWidth(2);
2410 if (h->GetEffectiveEntries() > minstat) {
2411 h->Fit(func, ("rq" + fitopt).c_str());
2412 }
2413 delete func;
2414 }
2415 }
2416 }
2417 }
2418 }
2419 }
2420 }
2421 if (!drawopt.empty()) {
2422 // do drawopt related stuff here
2423 }
2424 }
2425
2427 TCanvas* myC, TH1* h, TH1* hRef, std::string& drawopt, std::string& display, std::string& AlgoName) {
2428 formatTH1(myC, h);
2429 if (display.find("StatBox") != std::string::npos) {
2430 h->SetStats(kTRUE);
2431 }
2432 if (h->GetXaxis()->GetXmin() >= h->GetXaxis()->GetXmax()) {
2433 std::cerr << "HanOutputFile::saveHistogramToFile(): "
2434 << "Inconsistent x-axis settings: min=" << h->GetXaxis()->GetXmin() << ", "
2435 << "max=" << h->GetXaxis()->GetXmax() << ", "
2436 << "Will not save this histogram.\n";
2437 return false;
2438 }
2439 myC->cd();
2440 if (hRef != 0) {
2441 drawReference(myC, hRef, h, drawopt, display, AlgoName);
2442 } else {
2443 myC->cd();
2444 if (h->GetMinimum() >= 0 && h->GetMaximum() > 0.) {
2445 gPad->SetLogy(display.find("LogY") != std::string::npos);
2446 } else {
2447 gPad->SetLogy(false);
2448 }
2449 if (BINLOEDGE(h, 1) > 0) {
2450 gPad->SetLogx(display.find("LogX") != std::string::npos);
2451 } else {
2452 gPad->SetLogx(false);
2453 }
2454 axisOption(display, h);
2455 h->Draw(drawopt.c_str());
2456 }
2457 myC->cd();
2458 displayExtra(myC, display);
2459 myC->RedrawAxis();
2460 return true;
2461 }
2462
2464 TCanvas* myC, TH1* hRef, TH1* h, std::string& drawopt, std::string& display, std::string& AlgoName) {
2465 formatTH1(myC, hRef);
2466 TProfile* pRef = dynamic_cast<TProfile*>(hRef);
2467 if (pRef != 0) { // profile reference
2468 hRef->SetMarkerColor(2);
2469 hRef->SetLineColor(2);
2470 hRef->SetLineWidth(2);
2471 double ymin = (hRef->GetMinimum() < h->GetMinimum()) ? hRef->GetMinimum() : h->GetMinimum();
2472 double ymax = (hRef->GetMaximum() > h->GetMaximum()) ? hRef->GetMaximum() : h->GetMaximum();
2473 // double xmin = ( BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1)-BINWIDTH(hRef, 1) : BINLOEDGE(h,
2474 // 1)-BINWIDTH(h, 1); double xmax = ( BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
2475 // BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()) ) ?
2476 // BINLOEDGE(hRef, hRef->GetNbinsX()) + 2.0*BINWIDTH(hRef, hRef->GetNbinsX()): BINLOEDGE(h, h->GetNbinsX())
2477 // + 2.0*BINWIDTH(h, h->GetNbinsX()) ;
2478 double xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1) : BINLOEDGE(h, 1);
2479 double xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
2480 BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()))
2481 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX())
2482 : BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX());
2483 // double y_av = (ymax + ymin)/2;
2484 // double y_halv = (ymax-ymin)*0.6;
2485 bool isLogY = (display.find("LogY") != std::string::npos);
2486 if (isLogY) {
2487 if (ymax <= 0.0) ymax = 5.0;
2488 if (ymin > 0.) {
2489 double lymax = log(ymax);
2490 double lymin = log(ymin);
2491 h->SetAxisRange(exp(lymin - (lymax - lymin) * 0.05), exp(lymax + (lymax - lymin) * 0.05), "Y");
2492 // leave 5% gap on above and below
2493 } else {
2494 std::cerr << "ymin is <0. and LogY requested for histogram \"" << h->GetName() << " "
2495 << h->GetDirectory()->GetPath() << "\", ymin=" << ymin << std::endl;
2496 }
2497 } else {
2498 double yMargin = (ymax - ymin) * 0.05;
2499 h->SetAxisRange(ymin - yMargin, ymax + yMargin, "Y");
2500 }
2501 // h->SetAxisRange(xmin,xmax,"X");
2502 h->GetXaxis()->SetRangeUser(xmin, xmax);
2503 axisOption(display, h);
2504 if (h->GetMinimum() >= 0 && hRef->GetMinimum() >= 0 && h->GetMaximum() > 0 && hRef->GetMaximum() > 0) {
2505 gPad->SetLogy(display.find("LogY") != std::string::npos);
2506 }
2507 if (BINLOEDGE(h, 1) > 0 && BINLOEDGE(hRef, 1) > 0) {
2508 gPad->SetLogx(display.find("LogX") != std::string::npos);
2509 }
2510 h->Draw(drawopt.c_str());
2511 hRef->Draw(("SAME" + drawopt).c_str());
2512 h->Draw(("SAME" + drawopt).c_str());
2513 } else { // ordinary reference
2514 double scale = 1.0;
2515 if (display.find("ScaleRef") != std::string::npos) {
2516 scale = getScaleVal(display);
2517 } else if (h->Integral("width") > 0.0 && hRef->Integral("width") > 0.0 &&
2518 (AlgoName.find("BinContentComp") == std::string::npos) &&
2519 (display.find("NoNorm") == std::string::npos)) {
2520 scale = h->Integral("width") / hRef->Integral("width");
2521 }
2522 hRef->Scale(scale);
2523 hRef->SetMarkerColor(15);
2524 hRef->SetFillColor(15);
2525 hRef->SetLineColor(15);
2526 double ymin = (hRef->GetMinimum() < h->GetMinimum()) ? hRef->GetMinimum() : h->GetMinimum();
2527 double ymax = (hRef->GetMaximum() > h->GetMaximum()) ? hRef->GetMaximum() : h->GetMaximum();
2528 // double xmin = ( BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1)-BINWIDTH(hRef, 1) : BINLOEDGE(h,
2529 // 1)-BINWIDTH(h, 1); double xmax = ( BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
2530 // BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()) ) ? BINLOEDGE(hRef, hRef->GetNbinsX())
2531 // + 2.0*BINWIDTH(hRef, hRef->GetNbinsX()): BINLOEDGE(h, h->GetNbinsX()) + 2.0*BINWIDTH(h, h->GetNbinsX()) ;
2532 double xmin = (BINLOEDGE(hRef, 1) < BINLOEDGE(h, 1)) ? BINLOEDGE(hRef, 1) : BINLOEDGE(h, 1);
2533 double xmax = (BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX()) >
2534 BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX()))
2535 ? BINLOEDGE(hRef, hRef->GetNbinsX()) + BINWIDTH(hRef, hRef->GetNbinsX())
2536 : BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX());
2537 // double y_av = (ymax + ymin)/2;
2538 // double y_halv = (ymax-ymin)*0.6;
2539 bool isLogY = (display.find("LogY") != std::string::npos);
2540 // if ( ymin == 0.0 && display.find("LogY")!=std::string::npos ){
2541
2542 if (isLogY) {
2543 if (ymax <= 0.0) ymax = 5.0;
2544 if (ymin > 0.) {
2545 double lymax = log(ymax);
2546 double lymin = log(ymin);
2547 h->SetAxisRange(exp(lymin - (lymax - lymin) * 0.05), exp(lymax + (lymax - lymin) * 0.05), "Y");
2548 // leave 5% gap on above and below
2549 } else {
2550 std::cerr << "ymin is <=0. and LogY requested for histogram \"" << h->GetName() << " "
2551 << h->GetDirectory()->GetPath() << "\", ymin=" << ymin << std::endl;
2552 }
2553 } else {
2554 double yDiff = ymax - ymin;
2555 h->SetAxisRange(ymin - yDiff * 0.05, ymax + yDiff * 0.05, "Y"); // leave 5% gap above and below
2556 }
2557
2558 // h->SetAxisRange(xmin,xmax,"X");
2559 h->GetXaxis()->SetRangeUser(xmin, xmax);
2560 myC->cd();
2561 if (h->GetMinimum() >= 0. && hRef->GetMinimum() >= 0. && h->GetMaximum() > 0. && hRef->GetMaximum() > 0.) {
2562 gPad->SetLogy(display.find("LogY") != std::string::npos);
2563 }
2564 if (BINLOEDGE(h, 1) > 0 && BINLOEDGE(hRef, 1) > 0) {
2565 gPad->SetLogx(display.find("LogX") != std::string::npos);
2566 }
2567 axisOption(display, h);
2568 h->Draw(drawopt.c_str());
2569 hRef->Draw(("SAME" + drawopt).c_str());
2570 h->Draw(("SAME" + drawopt).c_str());
2571 }
2572 return true;
2573 }
2574
2575 // bool HanOutputFile::drawGraph(TCanvas* canv,TGraph* hist,std::string &drawopt,std::string &display){
2576 // return false;
2577 // }
2578
2579 void HanOutputFile::axisOption(std::string str, TH1* h) {
2580 std::size_t found = str.find("AxisRange");
2581 while (found != std::string::npos) {
2582 // std::string coordinates, cx1,cy1 ="";
2583 // std::size_t found1 = str.find_first_of(')',found+1);
2584 // std::size_t found2 = str.find_first_of("\'",found+1);
2585 // if (found2!=std::string::npos){
2586 std::string coordinates, cx1, cy1 = "";
2587 std::size_t found1 = str.find_first_of(')', found + 1);
2588 std::size_t found2 = str.find_first_of("\'", found + 1);
2589 if (found2 != std::string::npos) {
2590 found2 = str.find_first_of("\'", found2 + 1);
2591 if (found1 < found2) {
2592 found1 = str.find_first_of(')', found2 + 1);
2593 }
2594 /* }
2595 if (found1!=std::string::npos){
2596 coordinates = str.substr(found+10,found1-found-10);
2597 found1 = coordinates.find_first_of(',');
2598 if (found1!=std::string::npos){
2599 cx1 = coordinates.substr(0,found1);
2600 double x1=std::strtod(cx1.c_str(),NULL);
2601 found2 = coordinates.find_first_of(',',found1+1);
2602 if (found2!=std::string::npos){
2603 cy1 = coordinates.substr(found1+1,found2-found1-1);
2604 double y1=std::strtod(cy1.c_str(),NULL);
2605 std::string txt = coordinates.substr(found2+2,coordinates.size() );
2606 txt = txt.substr(0,txt.size()-1 );
2607 if (txt == "X" && x1 < y1)
2608 {
2609 h->SetAxisRange(x1,y1,"X");
2610 }
2611 if (txt == "Y" && x1 < y1)
2612 {
2613 h->SetAxisRange(x1,y1,"Y");
2614 }
2615 if (txt == "Z" && x1 < y1)
2616 {
2617 h->SetAxisRange(x1,y1,"Z");
2618 }
2619 }
2620 }
2621 }
2622 found=str.find("AxisRange",found+1);
2623 }
2624 */
2625 }
2626 if (found1 != std::string::npos) {
2627 coordinates = str.substr(found + 10, found1 - found - 10);
2628 found1 = coordinates.find_first_of(',');
2629 if (found1 != std::string::npos) {
2630 cx1 = coordinates.substr(0, found1);
2631 double x1 = std::strtod(cx1.c_str(), NULL);
2632 found2 = coordinates.find_first_of(',', found1 + 1);
2633 if (found2 != std::string::npos) {
2634 cy1 = coordinates.substr(found1 + 1, found2 - found1 - 1);
2635 double y1 = std::strtod(cy1.c_str(), NULL);
2636 std::string txt = coordinates.substr(found2 + 2, coordinates.size());
2637 txt.pop_back();
2638 if (txt == "X" && x1 < y1) {
2639 h->GetXaxis()->SetRangeUser(x1, y1);
2640 }
2641 if (txt == "Y" && x1 < y1) {
2642 h->SetAxisRange(x1, y1, "Y");
2643 }
2644 if (txt == "Z" && x1 < y1) {
2645 h->SetAxisRange(x1, y1, "Z");
2646 }
2647 } else {
2648 std::string txt = coordinates.substr(found1 + 2, coordinates.size());
2649 txt.pop_back();
2650 if (txt[1] == 'M') {
2651 if (txt == "XMax") {
2652 double xmin = BINLOEDGE(h, 1);
2653 h->GetXaxis()->SetRangeUser(xmin, x1);
2654 }
2655 if (txt == "XMin") {
2656 double xmax = BINLOEDGE(h, h->GetNbinsX()) + BINWIDTH(h, h->GetNbinsX());
2657 h->GetXaxis()->SetRangeUser(x1, xmax);
2658 }
2659 if (txt == "YMax") {
2660 double ymin = h->GetMinimum();
2661 h->SetAxisRange(ymin, x1, "Y");
2662 }
2663 if (txt == "YMin") {
2664 double ymax = h->GetMaximum();
2665 h->SetAxisRange(x1, ymax, "Y");
2666 }
2667 }
2668 }
2669 }
2670 }
2671 found = str.find("AxisRange", found + 1);
2672 }
2673 }
2674
2675 //-----------------------------
2676 void HanOutputFile::ratioplot(TCanvas* myC_upperpad, TH1* h, TH1* hRef, std::string display) {
2677 // this method creates two pads under a main canvas, upperpad with input canvas displayed, lower with ratio plot
2678 // Then it clears the input canvas and draws this newly created in input
2679 // I dont know if it is the best aproach,I used this method to minimize the changes on the main code
2680 if (display.find("RatioPad") == std::string::npos) return;
2681
2682 unsigned int ww = myC_upperpad->GetWw();
2683 unsigned int wh = myC_upperpad->GetWh();
2684 std::string padname = "PAD";
2685 std::string padname_ratio = "PAD_main";
2686 auto myC_ratiopad = std::make_unique<TCanvas>(padname_ratio.c_str(), "myC_ratiopad", ww, wh);
2687 auto myC_main = std::make_unique<TCanvas>(padname.c_str(), "myC_main", ww, wh);
2688 myC_main->cd();
2689 // producing ratio histogram and plotting it on to myC_ratiopad
2690 myC_ratiopad->cd();
2691 myC_ratiopad->SetTopMargin(0);
2692 myC_ratiopad->SetLogx(display.find("LogX") != std::string::npos);
2693 // TH1F *clonehist=(TH1F*)h->Clone();
2694 // clonehist->Divide(hRef);
2695
2699 TProfile* phRef = dynamic_cast<TProfile*>(hRef);
2700 TProfile* ph = dynamic_cast<TProfile*>(h);
2701 std::unique_ptr<TH1F> clonehist; // we will release this later, but use a unique_ptr in case we return early
2702 std::unique_ptr<TH1F> clonehistref;
2703 // transform if profiles
2704 if (ph != 0) {
2705 clonehist.reset((TH1F*) ph->ProjectionX());
2706 } else {
2707 clonehist.reset((TH1F*) h->Clone());
2708 if (!clonehist->GetSumw2()) {
2709 clonehist->Sumw2();
2710 }
2711 }
2712 if (phRef != 0) {
2713 clonehistref.reset((TH1F*) phRef->ProjectionX());
2714 } else {
2715 clonehistref.reset((TH1F*) hRef->Clone());
2716 if (!clonehistref->GetSumw2()) {
2717 clonehistref->Sumw2();
2718 }
2719 }
2720 if (!clonehist or !clonehistref) {
2721 return;
2722 }
2723 clonehist->SetBit(kCanDelete);
2724 clonehist->Divide(clonehistref.get());
2727
2728 formatTH1(myC_ratiopad.get(), clonehist.get());
2729 clonehist->SetTitle("");
2730
2731 // extract delta value from string that holds the draw options
2732 double delta = 0.75;
2733 if (display.find("delta(") != std::string::npos) {
2734 delta = std::stod(display.substr(display.find("delta(") + 6));
2735 }
2736 clonehist->SetAxisRange(1. - delta, 1. + delta, "Y");
2737
2738 clonehist->GetYaxis()->SetNdivisions(3, true);
2739 clonehist->SetMarkerStyle(1);
2740 clonehist->Draw("E"); // plots into myC_ratiopad
2741 clonehist->GetXaxis()->SetTitleSize(0.11);
2742 clonehist->GetXaxis()->SetLabelSize(0.11);
2743 clonehist->GetYaxis()->SetTitleSize(0.11);
2744 clonehist->GetYaxis()->SetLabelSize(0.11);
2745 myC_main->cd(); // lowerPad and upperPad plotted into myC_main
2746 TPad* lowerPad = new TPad("lowerPad", "lowerPad", .005, .060, .995, .250); // deleted by myC_main
2747 lowerPad->SetTopMargin(0);
2748 lowerPad->SetFillStyle(0);
2749 lowerPad->Draw();
2750 TPad* upperPad = new TPad("upperPad", "upperPad", .005, .250, .995, .995); // deleted by myC_main
2751 upperPad->SetBottomMargin(0);
2752 upperPad->SetFillStyle(0);
2753 upperPad->Draw();
2754
2755 lowerPad->cd();
2756 myC_ratiopad->DrawClonePad(); // clone contents of myC_ratiopad to lowerPad (will fix ownership later)
2757 // Draw y=1 lineon ratio plot
2758 TLine line;
2759 line.SetLineColor(kRed);
2760 line.SetLineWidth(1);
2761 // method belove might be a problem when axis range changed
2762 double xmin = clonehist->GetXaxis()->GetXmin();
2763 double xmax = clonehist->GetXaxis()->GetXmax();
2764 // double xmin = BINLOEDGE(clonehist, 1)-BINWIDTH(clonehist, 1);
2765 // double xmax = BINLOEDGE(clonehist, clonehist->GetNbinsX() ) + 2.0*BINWIDTH(clonehist, clonehist->GetNbinsX() ) ;
2766 line.DrawLine(xmin, 1, xmax, 1);
2767 upperPad->cd();
2768 myC_upperpad->SetBottomMargin(0);
2769 myC_upperpad->SetFillStyle(0);
2770 h->GetXaxis()->SetLabelSize(0.);
2771 h->GetXaxis()->SetTitleSize(0.);
2772 myC_upperpad->DrawClonePad(); // clone original canvas (i.e. main plot) into upperPad (will fix ownership later)
2773 myC_upperpad->cd();
2774 myC_upperpad->Clear(); // reset original canvas
2775 myC_main->DrawClonePad(); // clone contents of myC_main back into original canvas (will fix ownership shortly)
2776
2777 std::ignore = clonehist.release(); // this will be deleted by lowerpad cleanup
2778 // At this point myC_main contains the original lowerPad and upperPad, which contain clones of the original canvas
2779 // and ownership of clonehist. Iterate one level down and mark contained objects as deleteable. This will delete
2780 // the pads, as well as clonehist.
2781 for (TObject* o : *(myC_main->GetListOfPrimitives())) {
2782 o->SetBit(kCanDelete);
2783 if (auto* o2 = dynamic_cast<TPad*>(o)) {
2784 for (auto* o3: *(o2->GetListOfPrimitives())) {
2785 if (!dynamic_cast<TFrame*>(o3)) {
2786 o3->SetBit(kCanDelete);
2787 }
2788 }
2789 }
2790 }
2791 // At this point myC_upperpad contains clones of all its objects, including the pads. None of them have pointers
2792 // outside of myC_upperpad and its contained cloned pads. Mark them all deleteable. The original plot will be
2793 // deleted
2794 // in the calling code.
2795 for (TObject* o : *(myC_upperpad->GetListOfPrimitives())) {
2796 o->SetBit(kCanDelete);
2797 if (auto* o2 = dynamic_cast<TPad*>(o)) {
2798 for (auto* o3: *(o2->GetListOfPrimitives())) {
2799 if (!dynamic_cast<TFrame*>(o3)) {
2800 o3->SetBit(kCanDelete);
2801 }
2802 }
2803 }
2804 }
2805 }
2806
2807 void HanOutputFile::ratioplot2D(TCanvas* canvas_top, TH2* h2, TH2* h2Ref, std::string display) {
2808 if (display.find("Ref2DRatio") == std::string::npos && display.find("Ref2DSignif") == std::string::npos) return;
2809
2810 auto canvas_bot =
2811 std::make_unique<TCanvas>("canvas_bottom", "canvas_bottom", canvas_top->GetWw(), canvas_top->GetWh());
2812 auto canvas_all = std::make_unique<TCanvas>("canvas_all", "canvas_all", canvas_top->GetWw(), canvas_top->GetWh());
2813
2814 canvas_bot->cd();
2815 canvas_bot->SetTopMargin(0);
2816
2817 h2Ref->Scale(h2->Integral() / h2Ref->Integral());
2818
2819 TH2* comparison = (TH2*) (h2->Clone());
2820 comparison->Divide(h2, h2Ref, 1.0, 1.0);
2821 comparison->SetTitle("");
2822 formatTH2(canvas_bot.get(), comparison);
2823
2824 if (display.find("Ref2DRatio") != std::string::npos) {
2825 comparison->GetZaxis()->SetTitle("ratio to ref.");
2826 comparison->SetAxisRange(0.0, 2.0, "Z");
2827 } else if (display.find("Ref2DSignif") != std::string::npos) {
2828 comparison->GetZaxis()->SetTitle("difference to ref. (#sigma)");
2829 comparison->SetAxisRange(-4.5, 4.5, "Z");
2830
2831 double value_a = 0;
2832 double value_b = 0;
2833 double sigma_a = 0;
2834 double sigma_b = 0;
2835 double signif = 0;
2836
2837 for (int binx = 0; binx <= comparison->GetNbinsX(); binx++) {
2838 for (int biny = 0; biny <= comparison->GetNbinsY(); biny++) {
2839 value_a = h2->GetBinContent(binx, biny);
2840 value_b = h2Ref->GetBinContent(binx, biny);
2841
2842 sigma_a = h2->GetBinError(binx, biny);
2843 sigma_b = h2Ref->GetBinError(binx, biny);
2844
2845 if (sigma_a == 0 && sigma_b == 0) signif = 0;
2846 else signif = (value_a - value_b) / sqrt((sigma_a * sigma_a + sigma_b * sigma_b));
2847
2848 comparison->SetBinContent(binx, biny, signif);
2849 }
2850 }
2851 }
2852
2853 comparison->Draw("colz");
2854
2855 canvas_all->cd();
2856 TPad* pad_bot = new TPad("pad_bot", "pad_bot", 0.005, 0.060, 0.995, 0.550);
2857 TPad* pad_top = new TPad("pad_top", "pad_top", 0.005, 0.550, 0.995, 0.995);
2858
2859 pad_bot->SetTopMargin(0);
2860 pad_top->SetBottomMargin(0);
2861
2862 pad_bot->SetFillStyle(0);
2863 pad_top->SetFillStyle(0);
2864
2865 pad_bot->Draw();
2866 pad_top->Draw();
2867
2868 pad_bot->cd();
2869 canvas_bot->DrawClonePad();
2870
2871 pad_top->cd();
2872 canvas_top->SetBottomMargin(0);
2873 canvas_top->SetFillStyle(0);
2874 h2->GetXaxis()->SetLabelSize(0.);
2875 h2->GetXaxis()->SetTitleSize(0.);
2876 canvas_top->DrawClonePad();
2877 canvas_top->cd();
2878 canvas_top->Clear();
2879
2880 canvas_all->DrawClonePad();
2881 }
2882
2883 //-----------------------------
2884 void HanOutputFile::polynomial(TCanvas* c, std::string str, TH1* h) {
2885 double xmin = h->GetXaxis()->GetXmin();
2886 double xmax = h->GetXaxis()->GetXmax();
2887
2888 std::size_t found = str.find("polynomial(");
2889 while (found != std::string::npos) {
2890 std::size_t endpos = str.find_first_of(')', found + 1);
2891 std::cout << "found;" << found << " endpos;" << endpos << "count "
2892 << " \n";
2893 std::string inp_str = str.substr(found + 11, endpos - found - 11);
2894 std::size_t found1 = 0;
2895 std::size_t found2 = inp_str.find_first_of(',', found1);
2896 TF1* func = new TF1("func", "pol9", xmin, xmax);
2897 for (int j = 0; j < 10; j++) {
2898 std::string value_str = inp_str.substr(found1, found2 - found1);
2899 double value_double = std::strtod(value_str.c_str(), NULL);
2900 func->SetParameter(j, value_double);
2901 if (found2 == std::string::npos) {
2902 break;
2903 }
2904 found1 = found2 + 1;
2905 found2 = inp_str.find_first_of(',', found1);
2906 }
2907 func->SetNpx(1000);
2908 c->cd();
2909 func->Draw("SAME");
2910 found = str.find("polynomial(", found + 1);
2911 }
2912 }
2913
2914 void HanOutputFile::displayExtra(TCanvas* c, const std::string& str) {
2915 std::size_t found = str.find("TLine");
2916 while (found != std::string::npos) {
2917 std::size_t found1 = str.find_first_of(')', found + 1);
2918 if (found1 != std::string::npos) {
2919 std::string coordinates = str.substr(found + 6, found1 - found - 6);
2920 bool NDC = false;
2921 if (found1 < str.size() - 3 && str.substr(found1 + 1, 3) == "NDC") {
2922 NDC = true;
2923 }
2924 found1 = coordinates.find_first_of(',');
2925 if (found1 != std::string::npos) {
2926 std::string cx1 = coordinates.substr(0, found1);
2927 double x1 = std::strtod(cx1.c_str(), NULL);
2928 std::size_t found2 = coordinates.find_first_of(',', found1 + 1);
2929 if (found2 != std::string::npos) {
2930 std::string cy1 = coordinates.substr(found1 + 1, found2 - found1 - 1);
2931 double y1 = std::strtod(cy1.c_str(), NULL);
2932 found1 = coordinates.find_first_of(',', found2 + 1);
2933 if (found1 != std::string::npos) {
2934 std::string cx2 = coordinates.substr(found2 + 1, found1 - found2 - 1);
2935 double x2 = std::strtod(cx2.c_str(), NULL);
2936 std::string cy2 = coordinates.substr(found1 + 1, coordinates.size());
2937 double y2 = std::strtod(cy2.c_str(), NULL);
2938 c->cd();
2939 TLine* L = new TLine;
2940 if (NDC) {
2941 if (x1 <= 1.0 && x1 >= 0.0 && x2 <= 1.0 && x2 >= 0.0 && y1 <= 1.0 && y1 >= 0.0 && y2 <= 1.0 &&
2942 y2 >= 0.0) {
2943 L->DrawLineNDC(x1, y1, x2, y2);
2944 }
2945 } else {
2946 L->DrawLine(x1, y1, x2, y2);
2947 }
2948 }
2949 }
2950 }
2951 }
2952 found = str.find("TLine", found + 1);
2953 }
2954
2955 found = str.find("TText");
2956 while (found != std::string::npos) {
2957 std::string coordinates, cx1, cy1 = "";
2958 std::size_t found1 = str.find_first_of(')', found + 1);
2959 std::size_t found2 = str.find_first_of('\'', found + 1);
2960 if (found2 != std::string::npos) {
2961 found2 = str.find_first_of('\"', found2 + 1);
2962 if (found2 != std::string::npos && found1 < found2) {
2963 found1 = str.find_first_of(')', found2 + 1);
2964 }
2965 }
2966 if (found1 != std::string::npos) {
2967 coordinates = str.substr(found + 6, found1 - found - 6);
2968 bool NDC = false;
2969 if (found1 < str.size() - 3 && str.substr(found1 + 1, 3) == "NDC") {
2970 NDC = true;
2971 }
2972 found1 = coordinates.find_first_of(',');
2973 if (found1 != std::string::npos) {
2974 cx1 = coordinates.substr(0, found1);
2975 double x1 = std::strtod(cx1.c_str(), NULL);
2976 found2 = coordinates.find_first_of(',', found1 + 1);
2977 if (found2 != std::string::npos) {
2978 cy1 = coordinates.substr(found1 + 1, found2 - found1 - 1);
2979 double y1 = std::strtod(cy1.c_str(), NULL);
2980 std::string txt = coordinates.substr(found2 + 2, coordinates.size());
2981 txt.pop_back();
2982 c->cd();
2983 TText* T = new TText;
2984 if (NDC) {
2985 if (x1 <= 1.0 && x1 >= 0.0 && y1 <= 1.0 && y1 >= 0.0) {
2986 T->DrawTextNDC(x1, y1, txt.c_str());
2987 }
2988 } else {
2989 T->DrawText(x1, y1, txt.c_str());
2990 }
2991 }
2992 }
2993 }
2994 found = str.find("TText", found + 1);
2995 }
2996
2997 found = str.find("TDota");
2998 while (found != std::string::npos) {
2999 std::size_t found1 = str.find_first_of(')', found + 1);
3000 if (found1 != std::string::npos) {
3001 std::string coordinates = str.substr(found + 6, found1 - found - 6);
3002 bool NDC = false;
3003 if (found1 < str.size() - 3 && str.substr(found1 + 1, 3) == "NDC") {
3004 NDC = true;
3005 }
3006 found1 = coordinates.find_first_of(',');
3007 if (found1 != std::string::npos) {
3008 std::string cx1 = coordinates.substr(0, found1);
3009 double x1 = std::strtod(cx1.c_str(), NULL);
3010 std::size_t found2 = coordinates.find_first_of(',', found1 + 1);
3011 if (found2 != std::string::npos) {
3012 std::string cy1 = coordinates.substr(found1 + 1, found2 - found1 - 1);
3013 double y1 = std::strtod(cy1.c_str(), NULL);
3014 found1 = coordinates.find_first_of(',', found2 + 1);
3015 if (found1 != std::string::npos) {
3016 std::string cx2 = coordinates.substr(found2 + 1, found1 - found2 - 1);
3017 double x2 = std::strtod(cx2.c_str(), NULL);
3018 std::string cy2 = coordinates.substr(found1 + 1, coordinates.size());
3019 double y2 = std::strtod(cy2.c_str(), NULL);
3020 c->cd();
3021 TLine* L = new TLine;
3022 L->SetLineStyle(2);
3023 if (NDC) {
3024 if (x1 <= 1.0 && x1 >= 0.0 && x2 <= 1.0 && x2 >= 0.0 && y1 <= 1.0 && y1 >= 0.0 && y2 <= 1.0 &&
3025 y2 >= 0.0) {
3026 L->DrawLineNDC(x1, y1, x2, y2);
3027 }
3028 } else {
3029 L->DrawLine(x1, y1, x2, y2);
3030 }
3031 }
3032 }
3033 }
3034 }
3035 found = str.find("TDota", found + 1);
3036 }
3037
3038 found = str.find("TSize");
3039 while (found != std::string::npos) {
3040 std::string coordinates, cx1, cy1, txtsize = "";
3041 std::size_t found1 = str.find_first_of(')', found + 1);
3042 std::size_t found2 = str.find_first_of('\'', found + 1);
3043 if (found2 != std::string::npos) {
3044 found2 = str.find_first_of('\"', found2 + 1);
3045 if (found2 != std::string::npos && found1 < found2) {
3046 found1 = str.find_first_of(')', found2 + 1);
3047 }
3048 }
3049 if (found1 != std::string::npos) {
3050 coordinates = str.substr(found + 6, found1 - found - 6);
3051 bool NDC = false;
3052 if (found1 < str.size() - 3 && str.substr(found1 + 1, 3) == "NDC") {
3053 NDC = true;
3054 }
3055 found1 = coordinates.find_first_of(',');
3056 if (found1 != std::string::npos) {
3057 cx1 = coordinates.substr(0, found1);
3058 double x1 = std::strtod(cx1.c_str(), NULL);
3059 found2 = coordinates.find_first_of(',', found1 + 1);
3060 if (found2 != std::string::npos) {
3061 cy1 = coordinates.substr(found1 + 1, found2 - found1 - 1);
3062 double y1 = std::strtod(cy1.c_str(), NULL);
3063 std::size_t found3 = coordinates.find_first_of(',', found2 + 1);
3064 if (found3 != std::string::npos) {
3065 txtsize = coordinates.substr(found2 + 1, found3 - found2 - 1);
3066 double size = std::strtod(txtsize.c_str(), NULL);
3067 std::string txt = coordinates.substr(found3 + 2, coordinates.size());
3068 txt.pop_back();
3069 c->cd();
3070 TText* T = new TText;
3071 T->SetTextSize(size / 100);
3072 if (NDC) {
3073 if (x1 <= 1.0 && x1 >= 0.0 && y1 <= 1.0 && y1 >= 0.0) {
3074 T->DrawTextNDC(x1, y1, txt.c_str());
3075 }
3076 } else {
3077 T->DrawText(x1, y1, txt.c_str());
3078 }
3079 }
3080 }
3081 }
3082 }
3083 found = str.find("TSize", found + 1);
3084 }
3085 }
3086
3087 void HanOutputFile::formatTH1(TCanvas* c, TH1* h) const {
3088 if (c == 0 || h == 0) return;
3089
3090 c->SetLeftMargin(0.15);
3091 c->SetRightMargin(0.13);
3092 c->SetBottomMargin(0.15);
3093 c->SetTopMargin(0.12);
3094
3095 h->SetStats(kFALSE);
3096 h->SetLabelSize(0.04, "X");
3097 h->SetLabelSize(0.04, "Y");
3098 h->SetLabelFont(62, "X");
3099 h->SetLabelFont(62, "Y");
3100 h->SetTitleSize(0.04, "X");
3101 h->SetTitleSize(0.04, "Y");
3102 h->GetXaxis()->SetTitleFont(62);
3103 h->GetXaxis()->SetTitleSize(0.04);
3104 h->GetYaxis()->SetTitleFont(62);
3105 h->GetYaxis()->SetTitleSize(0.04);
3106 h->SetMarkerStyle(20);
3107 h->SetMarkerSize(0.8);
3108
3109 h->SetTitleOffset(1.5, "y");
3110 h->SetTitleOffset(0.9, "x");
3111
3112 h->SetNdivisions(504, "X");
3113 h->SetNdivisions(504, "Y");
3114 }
3115
3116 void HanOutputFile::formatTH2(TCanvas* c, TH2* h) const {
3117 if (c == 0 || h == 0) return;
3118
3119 c->SetLeftMargin(0.15);
3120 c->SetRightMargin(0.13);
3121 c->SetBottomMargin(0.15);
3122 c->SetTopMargin(0.12);
3123
3124 h->SetStats(kFALSE);
3125
3126 h->SetLabelSize(0.04, "X");
3127 h->SetLabelSize(0.04, "Y");
3128 h->SetLabelSize(0.04, "Z");
3129 h->SetLabelFont(62, "X");
3130 h->SetLabelFont(62, "Y");
3131 h->SetLabelFont(62, "Z");
3132 h->SetTitleSize(0.04, "X");
3133 h->SetTitleSize(0.04, "Y");
3134 h->SetTitleSize(0.04, "Z");
3135 h->GetXaxis()->SetTitleFont(62);
3136 h->GetXaxis()->SetTitleSize(0.04);
3137 h->GetYaxis()->SetTitleFont(62);
3138 h->GetYaxis()->SetTitleSize(0.04);
3139
3140 h->SetTitleOffset(1.5, "y");
3141 h->SetTitleOffset(0.9, "x");
3142
3143 h->SetNdivisions(504, "X");
3144 h->SetNdivisions(504, "Y");
3145 }
3146
3147 void HanOutputFile::formatTGraph(TCanvas* c, TGraph* g) const {
3148 if (c == 0 || g == 0) return;
3149
3150 c->SetLeftMargin(0.15);
3151 c->SetRightMargin(0.13);
3152 c->SetBottomMargin(0.15);
3153 c->SetTopMargin(0.12);
3154
3155 g->SetMarkerStyle(20);
3156 }
3157
3158 void HanOutputFile::formatTEfficiency(TCanvas* c, TEfficiency* e) const {
3159 if (c == 0 || e == 0) return;
3160
3161 c->SetLeftMargin(0.15);
3162 c->SetRightMargin(0.13);
3163 c->SetBottomMargin(0.15);
3164 c->SetTopMargin(0.12);
3165 }
3166
3167 // *********************************************************************
3168 // Protected Methods
3169 // *********************************************************************
3170
3172 dqi::DisableMustClean disabled;
3173 // bool useRecursiveDelete = gROOT->MustClean();
3174 // gROOT->SetMustClean(false);
3175
3176 delete m_file;
3177 delete m_style;
3178 m_file = 0;
3179 m_style = 0;
3180 m_indirMap.clear();
3181
3182 DirToAssMap_t::const_iterator assessMapEnd = m_assessMap.end();
3183 for (DirToAssMap_t::const_iterator i = m_assessMap.begin(); i != assessMapEnd; ++i) {
3184 delete i->second;
3185 }
3186 m_assessMap.clear();
3187
3188 // gROOT->SetMustClean(useRecursiveDelete);
3189 }
3190
3191 bool HanOutputFile::writeToFile(const std::string& fname, const std::string& content) {
3192 std::ofstream outfile(fname);
3193 if (!outfile.is_open()) {
3194 std::cerr << "Error writing file to " << fname << std::endl;
3195 return false;
3196 }
3197 outfile << content;
3198 outfile.close();
3199 return true;
3200 }
3201
3202 void HanOutputFile::convertToGraphics(int cnvsType, TCanvas* myC, std::string& json, TImage** img, char** x, int* y) {
3203 if (cnvsType & GENERATE_PNG) {
3204 if (img) getImageBuffer(img, myC, x, y);
3205 }
3206 if (cnvsType & GENERATE_JSON) {
3207 json = TBufferJSON::ConvertToJSON(myC);
3208 }
3209 }
3210
3211 void HanOutputFile::convertToGraphics(int cnvsType, TCanvas* myC, const std::string& namePNG,
3212 const std::string& nameJSON) {
3213 if (cnvsType & GENERATE_PNG) {
3214 myC->SaveAs(namePNG.c_str());
3215 }
3216 if (cnvsType & GENERATE_JSON) {
3217 std::string json = std::string(TBufferJSON::ConvertToJSON(myC));
3218 writeToFile(nameJSON, json);
3219 }
3220 }
3221
3223 int cnvsType, const std::string& pngfName, const std::string& pngContent, const std::string& jsonfName,
3224 const std::string& jsonfContent) {
3225 bool png = false;
3226 bool json = false;
3227
3228 if (cnvsType & GENERATE_PNG) {
3229 png = writeToFile(pngfName, pngContent);
3230 }
3231 if (cnvsType & GENERATE_JSON) {
3232 json = writeToFile(jsonfName, jsonfContent);
3233 }
3234 return(png || json);
3235 }
3236} // namespace dqutils
const boost::regex ref(r_ef)
ClassImp(dqutils::HanOutputFile) namespace
#define BINLOEDGE(h, n)
#define BINWIDTH(h, n)
nlohmann::json json
#define y
#define x
#define ATLAS_NOT_THREAD_SAFE
getNoisyStrip() Find noisy strips from hitmaps and write out into xml/db formats
Header file for AthHistogramAlgorithm.
static void printDQGroupJSON(const nlohmann::json &j, const std::string &location, const char *path_to_file)
Print path - and name of Assessment, represented as JSON TObjString.
virtual void formatTEfficiency(TCanvas *c, TEfficiency *e) const
static std::optional< std::string > containsKeyInJSON(const std::string &pathInJSON, const std::string &jsonName, const std::string &path_to_JSON)
Checks JSON file for a key (by its path)
virtual bool writeToFile(const std::string &fName, const std::string &content)
virtual void printAllDQGroups()
virtual void polynomial(TCanvas *c, std::string str, TH1 *h)
virtual void streamHistoAssessments(std::ostream &o, bool streamAll)
virtual bool saveFile(int cnvsType, const std::string &pngfName, const std::string &pngContent, const std::string &jsonfName, const std::string &jsonfContent)
virtual bool setFile(const std::string &fileName)
Clears all previous data and opens the file with the given name for analysis, returning a boolean ind...
std::map< std::string, TObject * > DirStrMap_t
virtual void attachFits(TH1 *hist, std::string &drawopt, std::string &display)
virtual void ratioplot(TCanvas *myC_main, TH1 *h, TH1 *href, std::string str)
virtual double getNEntries(std::string location, std::string histname)
virtual void convertToGraphics(int cnvsType, TCanvas *myC, std::string &json, TImage **img=0, char **x=0, int *y=0)
virtual bool drawH2(TCanvas *canv, TH2 *hist, std::string &drawopt, std::string &display)
!!
static std::string processJSON_ingetInfo(const nlohmann::ordered_json &j)
virtual bool drawH1(TCanvas *canv, TH1 *hist, TH1 *reference, std::string &drawopt, std::string &display, std::string &AlgoName)
virtual std::string getHistogramPNG(const std::string &nameHis, TDirectory *groupDir, bool drawRefs, const std::string &run_min_LB, const std::string &pathName)
virtual void formatTH2(TCanvas *c, TH2 *h) const
virtual void displayExtra(TCanvas *c, const std::string &str)
virtual void streamAllDQAssessments(std::ostream &o, bool streamAll)
virtual void axisOption(std::string str, TH1 *h)
static std::string getIndentation(const std::string &pathName, const std::string &leadingSpace="")
static const int GENERATE_JSON
static std::string getStringName(const std::string &location, int file_version)
virtual void ratioplot2D(TCanvas *canvas, TH2 *h2, TH2 *h2Ref, std::string display)
virtual std::string stringAllHistograms()
virtual std::string stringListSystemPaths(std::string location)
virtual std::string stringHistoAssessments()
std::map< std::string, std::string > AssMap_t
DirMap_t but For Version 2 files.
virtual std::pair< std::string, std::string > getHistogramJSON(const std::string &nameHis, TDirectory *groupDir, bool drawRefs, const std::string &run_min_LB, const std::string &pathName)
static void getAllGroupDirs_V2(DirStrMap_t &dirstrmap, TObject *obj, const std::string &objName)
Same as getAllGroupDirs, but works with Version 2.3 files.
virtual std::pair< std::string, std::string > getHistogram(const std::string &nameHis, TDirectory *groupDir, bool drawRefs, const std::string &run_min_LB, const std::string &pathName, int cnvsType=1)
virtual void printHistoAssessments()
virtual std::string stringAllDQAssessments()
static void getAllAssessments(AssMap_t &dirmap, TDirectory *dir)
virtual void setupCanvas(std::string &drawopt, std::string &display)
static bool containsDir(std::string dirname, std::string maindir)
virtual bool saveHistogramToFile(const std::string &nameHis, std::string location, TDirectory *groupDir, bool drawRefs, const std::string &run_min_LB, const std::string &pathName, int cnvsType=1)
std::map< std::string, TDirectory * > DirMap_t
virtual void streamAllHistograms(std::ostream &o, bool streamAll)
static void getAllGroupDirs(DirMap_t &dirmap, TDirectory *dir, const std::string &dirName)
virtual bool saveHistogramToFileSuperimposed(const std::string &nameHis, std::string location, TDirectory *groupDir1, TDirectory *groupDir2, bool drawRefs, const std::string &run_min_LB, const std::string &pathName, int cnvsType=1)
virtual void formatTGraph(TCanvas *c, TGraph *g) const
virtual void printAllDQAssessments()
static std::string getInfo(const std::string &location, int file_version)
virtual bool drawReference(TCanvas *canv, TH1 *hRef, TH1 *h, std::string &drawopt, std::string &display, std::string &AlgoName)
virtual int saveAllHistograms(const std::string &location, bool drawRefs, const std::string &run_min_LB, int cnvsType=1)
virtual void formatTH1(TCanvas *c, TH1 *h) const
static const int GENERATE_PNG
cnvsType: 1=pngOnly;2=jsonOnly;3=pngAndJson
DirToAssMap_t m_assessMap
Same Dim_indirMaprMap, but for files of version 2.
double xmax
Definition listroot.cxx:61
double ymin
Definition listroot.cxx:63
double xmin
Definition listroot.cxx:60
double ymax
Definition listroot.cxx:64
std::vector< int > root_color_choices
std::string dirname(std::string name)
Definition utils.cxx:200