REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestAnalysisPlot.cxx
1
12
13#include "TRestAnalysisPlot.h"
14
15#include <TLegend.h>
16#include <TStyle.h>
17
18#include <ctime>
19
20#include "TRestManager.h"
21#include "TRestTools.h"
22
23using namespace std;
24
25ClassImp(TRestAnalysisPlot);
26
27TRestAnalysisPlot::TRestAnalysisPlot() { Initialize(); }
28
29TRestAnalysisPlot::TRestAnalysisPlot(const char* configFilename, const char* name)
30 : TRestMetadata(configFilename) {
31 Initialize();
32
33 LoadConfigFromFile(fConfigFileName, name);
34}
35
37 SetSectionName(this->ClassName());
38
39 fRun = nullptr;
40 fNFiles = 0;
41 fCombinedCanvas = nullptr;
42 fPlotNamesCheck.clear();
43 fDrawNEntries = TTree::kMaxEntries;
44 fDrawFirstEntry = 0;
45}
46
47TRestAnalysisPlot::~TRestAnalysisPlot() { delete fRun; }
48
50 if (fHostmgr->GetRunInfo() != nullptr) {
51 fRun = fHostmgr->GetRunInfo();
52 }
53 if (fRun == nullptr) {
54 fRun = new TRestRun();
55 fRun->SetHistoricMetadataSaving(false);
56 string defaultFileName = REST_TMP_PATH + "restplot_" + REST_USER + ".root";
57 string outputname = GetParameter("outputFile", defaultFileName);
58 if (outputname != "null" && outputname != "/dev/null") {
59 fRun->SetOutputFileName(outputname);
60 fRun->FormOutputFile();
61 }
62 }
63
64 TiXmlElement* ele = GetElement("addFile");
65 while (ele != nullptr) {
66 std::string inputfile = GetParameter("name", ele);
67 if (inputfile.find("http") == 0)
68 this->AddFile(inputfile);
69 else {
70 std::vector<std::string> infiles = TRestTools::GetFilesMatchingPattern(inputfile);
71 for (const auto& f : infiles) this->AddFile(f);
72 }
73 ele = GetNextElement(ele);
74 }
75 // try to add files from external TRestRun handler
76 if (fNFiles == 0) AddFileFromExternalRun();
77 // try to add files from env "inputFile", which is set by --i argument
78 if (fNFiles == 0) AddFileFromEnv();
79
80 if (fNFiles == 0) {
81 RESTWarning << "TRestAnalysisPlot: No input files are added!" << RESTendl;
82 // exit(1);
83 }
84
85 RESTDebug << "TRestAnalysisPlot: Reading canvas settings" << RESTendl;
86 TiXmlElement* formatDefinition = GetElement("labels");
87 if (formatDefinition != nullptr) {
89 cout << formatDefinition << endl;
90 cout << "Reading format definition : " << endl;
91 cout << "---------------------------" << endl;
92 }
93
94 fTicksScaleX = StringToDouble(GetFieldValue("ticksScaleX", formatDefinition));
95 fTicksScaleY = StringToDouble(GetFieldValue("ticksScaleY", formatDefinition));
96
97 fLabelScaleX = StringToDouble(GetFieldValue("labelScaleX", formatDefinition));
98 fLabelScaleY = StringToDouble(GetFieldValue("labelScaleY", formatDefinition));
99
100 fLabelOffsetX = StringToDouble(GetFieldValue("labelOffsetX", formatDefinition));
101 fLabelOffsetY = StringToDouble(GetFieldValue("labelOffsetY", formatDefinition));
102
103 if (fLabelOffsetX == -1) fLabelOffsetX = 1.1;
104 if (fLabelOffsetY == -1) fLabelOffsetY = 1.3;
105
106 if (fTicksScaleX == -1) fTicksScaleX = 1.5;
107 if (fTicksScaleY == -1) fTicksScaleY = 1.5;
108
109 if (fLabelScaleX == -1) fLabelScaleX = 1.3;
110 if (fLabelScaleY == -1) fLabelScaleY = 1.3;
111
113 cout << "ticks scale X : " << fTicksScaleX << endl;
114 cout << "ticks scale Y : " << fTicksScaleY << endl;
115 cout << "label scale X : " << fLabelScaleX << endl;
116 cout << "label scale Y : " << fLabelScaleY << endl;
117 cout << "label offset X : " << fLabelOffsetX << endl;
118 cout << "label offset Y : " << fLabelOffsetY << endl;
119
121 }
122 }
123
124 TiXmlElement* legendDefinition = GetElement("legendPosition");
125 if (legendDefinition != nullptr) {
127 cout << legendDefinition << endl;
128 cout << "Reading legend definition : " << endl;
129 cout << "---------------------------" << endl;
130 }
131
132 fLegendX1 = StringToDouble(GetFieldValue("x1", legendDefinition));
133 fLegendY1 = StringToDouble(GetFieldValue("y1", legendDefinition));
134
135 fLegendX2 = StringToDouble(GetFieldValue("x2", legendDefinition));
136 fLegendY2 = StringToDouble(GetFieldValue("y2", legendDefinition));
137
138 if (fLegendX1 == -1) fLegendX1 = 0.7;
139 if (fLegendY1 == -1) fLegendY1 = 0.75;
140
141 if (fLegendX2 == -1) fLegendX2 = 0.88;
142 if (fLegendY2 == -1) fLegendY2 = 0.88;
143
145 cout << "x1 : " << fLegendX1 << " y1 : " << fLegendY1 << endl;
146 cout << "x2 : " << fLegendX2 << " y2 : " << fLegendY2 << endl;
147
149 }
150 }
151
152 TiXmlElement* canvasdef = fElement->FirstChildElement("canvas");
153 if (canvasdef == nullptr) {
154 canvasdef = fElement;
155 }
156
157 fCanvasSize = StringTo2DVector(GetParameter("size", canvasdef, "(800,600)"));
158 fCanvasDivisions = StringTo2DVector(GetParameter("divide", canvasdef, "(1,1)"));
159 fCanvasDivisionMargins = StringTo2DVector(GetParameter("divideMargin", canvasdef, "(0.01, 0.01)"));
160
161 string save = (string)GetParameter("save", canvasdef, "rest_AnalysisPlot.pdf");
162 if (save.rfind("/", 0) == 0)
163 fCanvasSave = (TString)save;
164 else
165 fCanvasSave = GetDataPath() + save;
166
167 fPaletteStyle = StringToInteger(GetParameter("paletteStyle", canvasdef, "57"));
168
169 RESTDebug << "TRestAnalysisPlot: Reading global cuts" << RESTendl;
170 vector<string> globalCuts;
171 TiXmlElement* gCutele = GetElement("globalCut");
172 while (gCutele != nullptr) // general cuts
173 {
174 string cutActive = GetParameter("value", gCutele, "ON");
175
176 if (ToUpper(cutActive) == "ON") {
177 string obsName = GetParameter("variable", gCutele, "");
178 if (obsName == "") {
179 obsName = GetParameter("name", gCutele, "");
180 if (obsName != "") {
181 RESTWarning << "<globalCut name=\"var\" is now obsolete." << RESTendl;
182 RESTWarning << "Please, replace by : <globalCut variable=\"var\" " << RESTendl;
183 cout << endl;
184 }
185 }
186
187 if (obsName == "") continue;
188
189 string cutCondition = GetParameter("condition", gCutele);
190 string cutString = obsName + cutCondition;
191
192 globalCuts.push_back(cutString);
193 }
194
195 gCutele = GetNextElement(gCutele);
196 }
197
198 RESTDebug << "TRestAnalysisPlot: Reading global cut strings" << RESTendl;
199 TiXmlElement* gCutStrele = GetElement("globalCutString");
200 while (gCutStrele != nullptr) // general cuts
201 {
202 string cutActive = GetParameter("value", gCutStrele, "ON");
203
204 if (ToUpper(cutActive) == "ON") {
205 string cutString = GetParameter("string", gCutStrele, "");
206 cutString = "(" + cutString + ")";
207 if (cutString == "") continue;
208
209 globalCuts.push_back(cutString);
210 }
211
212 gCutStrele = GetNextElement(gCutStrele);
213 }
214
215 RESTDebug << "TRestAnalysisPlot: Reading plot sections" << RESTendl;
216 Int_t maxPlots = (Int_t)fCanvasDivisions.X() * (Int_t)fCanvasDivisions.Y();
217 TiXmlElement* plotele = GetElement("plot");
218 while (plotele != nullptr) {
219 string active = GetParameter("value", plotele, "ON");
220 if (ToUpper(active) == "ON") {
221 int N = fPlots.size();
222 if (N >= maxPlots) {
223 RESTError << "Your canvas divisions (" << fCanvasDivisions.X() << " , "
224 << fCanvasDivisions.Y() << ") are not enough to show " << N + 1 << " plots"
225 << RESTendl;
226 exit(1);
227 }
228 PlotInfoSet plot;
229 plot.name = RemoveWhiteSpaces(GetParameter("name", plotele, "plot_" + ToString(N)));
230 plot.title = GetParameter("title", plotele, plot.name);
231 plot.logY = StringToBool(GetParameter("logscale", plotele, "false"));
232 plot.logY = plot.logY ? plot.logY : StringToBool(GetParameter("logY", plotele, "false"));
233 plot.logX = StringToBool(GetParameter("logX", plotele, "false"));
234 plot.logZ = StringToBool(GetParameter("logZ", plotele, "false"));
235 plot.gridY = StringToBool(GetParameter("gridY", plotele, "false"));
236 plot.gridX = StringToBool(GetParameter("gridX", plotele, "false"));
237 plot.normalize = StringToDouble(GetParameter("norm", plotele, ""));
238 plot.scale = GetParameter("scale", plotele, "");
239 plot.labelX = GetParameter("xlabel", plotele, "");
240 plot.labelY = GetParameter("ylabel", plotele, "");
241 plot.ticksX = StringToInteger(GetParameter("xticks", plotele, "510"));
242 plot.ticksY = StringToInteger(GetParameter("yticks", plotele, "510"));
243 plot.marginBottom = StringToDouble(GetParameter("marginBottom", plotele, "0.15"));
244 plot.marginTop = StringToDouble(GetParameter("marginTop", plotele, "0.07"));
245 plot.marginLeft = StringToDouble(GetParameter("marginLeft", plotele, "0.25"));
246 plot.marginRight = StringToDouble(GetParameter("marginRight", plotele, "0.1"));
247 plot.legendOn = StringToBool(GetParameter("legend", plotele, "OFF"));
248 plot.staticsOn = StringToBool(GetParameter("stats", plotele, "OFF"));
249 plot.annotationOn = StringToBool(GetParameter("annotation", plotele, "OFF"));
250 plot.xOffset = StringToDouble(GetParameter("xOffset", plotele, "0"));
251 plot.yOffset = StringToDouble(GetParameter("yOffset", plotele, "0"));
252 plot.timeDisplay = StringToBool(GetParameter("timeDisplay", plotele, "OFF"));
253 plot.save = RemoveWhiteSpaces(GetParameter("save", plotele, ""));
254
255 TiXmlElement* histele = GetElement("histo", plotele);
256 if (histele == nullptr) {
257 // in case for single-hist plot, variables are added directly inside the <plot section
258 histele = plotele;
259 }
260 while (histele != nullptr) {
261 HistoInfoSet hist = SetupHistogramFromConfigFile(histele, plot);
262 // add global cut
263 for (unsigned int i = 0; i < globalCuts.size(); i++) {
264 if (i > 0 || hist.cutString != "") hist.cutString += " && ";
266 cout << "Adding global cut : " << globalCuts[i] << endl;
267 hist.cutString += globalCuts[i];
268 }
269 hist.weight = GetParameter("weight", histele, "");
270
271 if (hist.plotString == "") {
272 RESTWarning << "No variables or histograms defined in the plot, skipping!" << RESTendl;
273 } else {
274 plot.histos.push_back(hist);
275 }
276
277 if (histele == plotele) {
278 break;
279 }
280 histele = GetNextElement(histele);
281 }
282
283 fPlots.push_back(plot);
284 plotele = GetNextElement(plotele);
285 }
286 }
287
288 RESTDebug << "TRestAnalysisPlot: Reading panel sections" << RESTendl;
289 maxPlots -= fPlots.size(); // remaining spaces on canvas
290 TiXmlElement* panelele = GetElement("panel");
291 while (panelele != nullptr) {
292 string active = GetParameter("value", panelele, "ON");
293 if (ToUpper(active) == "ON") {
294 int N = fPanels.size();
295 if (N >= maxPlots) {
296 RESTError << "Your canvas divisions (" << fCanvasDivisions.X() << " , "
297 << fCanvasDivisions.Y() << ") are not enough to show " << fPlots.size()
298 << " plots, and " << N + 1 << " info panels" << RESTendl;
299 exit(1);
300 }
301
302 PanelInfo panel;
303 panel.font_size = StringToDouble(GetParameter("font_size", panelele, "0.1"));
304 panel.precision = StringToInteger(GetParameter("precision", panelele, "2"));
305
306 TiXmlElement* labelele = GetElement("label", panelele);
307 while (labelele != nullptr) {
308 panel.label.push_back(GetParameter("value", labelele, "Error. Label value not defined"));
309 panel.posX.push_back(StringToDouble(GetParameter("x", labelele, "0.1")));
310 panel.posY.push_back(StringToDouble(GetParameter("y", labelele, "0.1")));
311
312 labelele = GetNextElement(labelele);
313 }
314
315 fPanels.push_back(panel);
316 panelele = GetNextElement(panelele);
317 }
318 }
319
320 for (unsigned int n = 0; n < fPanels.size(); n++) {
321 RESTExtreme << "Panel " << n << " with font size : " << fPanels[n].font_size << RESTendl;
322 for (unsigned int m = 0; m < fPanels[n].posX.size(); m++) {
323 RESTExtreme << "Label : " << fPanels[n].label[m] << RESTendl;
324 RESTExtreme << "Pos X : " << fPanels[n].posX[m] << RESTendl;
325 RESTExtreme << "Pos Y : " << fPanels[n].posY[m] << RESTendl;
326 }
327 }
328}
329
330TRestAnalysisPlot::HistoInfoSet TRestAnalysisPlot::SetupHistogramFromConfigFile(TiXmlElement* histele,
331 PlotInfoSet plot) {
332 HistoInfoSet hist;
333 hist.name = RemoveWhiteSpaces(GetParameter("name", histele, plot.name));
334 hist.drawOption = GetParameter("option", histele, "colz");
335
336 for (const auto& n : fPlotNamesCheck)
337 if (hist.name == n) {
338 RESTError
339 << "Repeated plot/histo names were found! Please, use different names for different plots!"
340 << RESTendl;
341 RESTError << "<plot/histo name=\"" << hist.name << "\" already defined!" << RESTendl;
342 exit(1);
343 }
344
345 fPlotNamesCheck.push_back(hist.name);
346
347 // 1. construct plot variables for the hist
348 // read variables
349 vector<string> varNames;
350 vector<TVector2> ranges;
351 vector<Int_t> bins;
352 TiXmlElement* varele = GetElement("variable", histele);
353 while (varele != nullptr) {
354 varNames.push_back(GetParameter("name", varele));
355
356 string rangeStr = GetParameter("range", varele);
357 rangeStr = Replace(rangeStr, "unixTime", std::to_string(std::time(nullptr)));
358 rangeStr = Replace(rangeStr, "days", "24*3600");
359 ranges.push_back(StringTo2DVector(rangeStr));
360
361 bins.push_back(StringToInteger(GetParameter("nbins", varele)));
362 varele = GetNextElement(varele);
363 }
365 for (unsigned int n = 0; n < bins.size(); n++) {
366 cout << "Variable " << varNames[n] << endl;
367 cout << "------------------------------------------" << endl;
368 cout << "Plot range : ( " << ranges.back().X() << " , " << ranges.back().Y() << " ) " << endl;
369 cout << "bins : " << bins.back() << endl;
370 cout << endl;
371 }
372 }
373
374 string pltString = "";
375 for (int i = varNames.size() - 1; i >= 0; i--) {
376 // The draw branches are in reversed ordered in TTree::Draw()
377 pltString += varNames[i];
378 if (i > 0) pltString += ":";
379 }
380 hist.plotString = pltString;
381
382 // 2. construct plot name for the hist
383 string rangestr = "";
384 for (unsigned int i = 0; i < bins.size(); i++) {
385 string binsStr = ToString(bins[i]);
386 if (bins[i] == -1) binsStr = " ";
387
388 string rXStr = ToString(ranges[i].X());
389 if (ranges[i].X() == -1) {
390 rXStr = " ";
391 if (varNames[i] == "timeStamp" || plot.timeDisplay) rXStr = "MIN_TIME";
392 }
393
394 string rYStr = ToString(ranges[i].Y());
395 if (ranges[i].Y() == -1) {
396 rYStr = " ";
397 if (varNames[i] == "timeStamp" || plot.timeDisplay) rYStr = "MAX_TIME";
398 }
399
400 if (i == 0) rangestr += "(";
401 rangestr += binsStr + " , " + rXStr + " , " + rYStr;
402 if (i < bins.size() - 1) rangestr += ",";
403 if (i == bins.size() - 1) rangestr += ")";
404 }
405 hist.range = rangestr;
406
407 // 3. read cuts
408 string cutString = "";
409
410 TiXmlElement* cutele = GetElement("cut", histele);
411 while (cutele != nullptr) {
412 string cutActive = GetParameter("value", cutele, "ON");
413 if (ToUpper(cutActive) == "ON") {
414 string cutVariable = GetParameter("variable", cutele);
415 if (cutVariable == PARAMETER_NOT_FOUND_STR) {
416 RESTError << "Variable was not found! There is a problem inside <cut definition. Check it."
417 << RESTendl;
418 cout << "Contents of entire <histo definition : " << ElementToString(histele) << endl;
419 cout << endl;
420 }
421
422 string cutCondition = GetParameter("condition", cutele);
423 if (cutCondition == PARAMETER_NOT_FOUND_STR) {
424 RESTError << "Condition was not found! There is a problem inside <cut definition. Check it."
425 << RESTendl;
426 cout << "Contents of entire <histo definition : " << ElementToString(histele) << endl;
427 cout << endl;
428 }
429
430 if (cutString.length() > 0) cutString += " && ";
431 RESTDebug << "Adding local cut : " << cutVariable << cutCondition << RESTendl;
432
433 cutCondition = RemoveWhiteSpaces(cutCondition);
434 if (cutCondition.find("==") == 0) {
435 string condValue = cutCondition.substr(2);
436 if (!isANumber(condValue)) cutCondition = "==\"" + condValue + "\"";
437 }
438
439 cutString += cutVariable + cutCondition;
440 }
441 cutele = GetNextElement(cutele);
442 }
443
444 TiXmlElement* cutstrele = GetElement("cutString", histele);
445 while (cutstrele != nullptr) {
446 string cutActive = GetParameter("value", cutstrele, "ON");
447 if (ToUpper(cutActive) == "ON") {
448 string cutStr = GetParameter("string", cutstrele);
449 if (cutStr == PARAMETER_NOT_FOUND_STR) {
450 RESTError
451 << "Cut string was not found! There is a problem inside <cutString definition. Check it."
452 << RESTendl;
453 cout << "Contents of entire <histo definition : " << ElementToString(histele) << endl;
454 cout << endl;
455 }
456
457 if (cutString.length() > 0) cutString += " && ";
458 RESTDebug << "Adding local cut : " << cutStr << RESTendl;
459
460 cutString += "(" + cutStr + ")";
461 }
462 cutstrele = GetNextElement(cutstrele);
463 }
464 hist.cutString = cutString;
465
466 // 4. read classify condition
467 hist.classifyMap.clear();
468 TiXmlElement* classifyele = GetElement("classify", histele);
469 while (classifyele != nullptr) {
470 string Active = GetParameter("value", classifyele, "ON");
471 if (ToUpper(Active) == "ON") {
472 TiXmlAttribute* attr = classifyele->FirstAttribute();
473 while (attr != nullptr) {
474 if (attr->Value() != nullptr && !string(attr->Value()).empty()) {
475 hist.classifyMap[attr->Name()] = attr->Value();
476 }
477 attr = attr->Next();
478 }
479 }
480 classifyele = GetNextElement(classifyele);
481 }
482
483 // 5. read draw style(line color, width, fill style, etc.)
484 hist.lineColor = GetColorIDFromString(GetParameter("lineColor", histele, "602"));
485 hist.lineWidth = StringToInteger(GetParameter("lineWidth", histele, "1"));
486 hist.lineStyle = GetLineStyleIDFromString(GetParameter("lineStyle", histele, "1"));
487 hist.fillStyle = GetFillStyleIDFromString(GetParameter("fillStyle", histele, "1001"));
488 hist.fillColor = GetColorIDFromString(GetParameter("fillColor", histele, "0"));
489
490 return hist;
491}
492
493void TRestAnalysisPlot::AddFile(const TString& fileName) {
494 RESTInfo << "TRestAnalysisPlot::AddFile. Adding file. " << RESTendl;
495 RESTInfo << "File name: " << fileName << RESTendl;
496 fRunInputFileName.emplace_back(fileName.Data());
497 fNFiles++;
498}
499
500void TRestAnalysisPlot::SetFile(const TString& fileName) {
501 fRunInputFileName.clear();
502 fRunInputFileName = Vector_cast<string, TString>(TRestTools::GetFilesMatchingPattern((string)fileName));
503 fNFiles = fRunInputFileName.size();
504}
505
506// we can add input file from process's output file
507void TRestAnalysisPlot::AddFileFromExternalRun() {
508 if (fRun != nullptr && fNFiles == 0) {
509 if (fHostmgr->GetProcessRunner() != nullptr && fRun->GetOutputFileName() != "") {
510 // if we have a TRestProcessRunner before head, we use its output file
511 AddFile(fRun->GetOutputFileName());
512 return;
513 }
514 }
515}
516
517// we can add input file from parameter "inputFile"
518void TRestAnalysisPlot::AddFileFromEnv() {
519 if (fNFiles == 0) {
520 string filepattern = GetParameter("inputFileName", "");
521 auto files = TRestTools::GetFilesMatchingPattern(filepattern);
522
523 for (const auto& file : files) {
524 RESTEssential << "Adding file : " << file << RESTendl;
525 AddFile(file);
526 }
527 }
528}
529
530Int_t TRestAnalysisPlot::GetPlotIndex(const TString& plotName) {
531 for (unsigned int n = 0; n < fPlots.size(); n++)
532 if (fPlots[n].name == plotName) return n;
533
534 RESTWarning << "TRestAnalysisPlot::GetPlotIndex. Plot name " << plotName << " not found" << RESTendl;
535 return -1;
536}
537
538TRestAnalysisTree* TRestAnalysisPlot::GetTree(const TString& fileName) {
539 if (fRun->GetInputFile() != nullptr && fRun->GetInputFile()->GetName() == fileName) {
540 // this means the file is already opened by TRestRun
541 return fRun->GetAnalysisTree();
542 }
543 if (fileName == fRun->GetOutputFileName() && fRun->GetOutputFile() != nullptr) {
544 // this means the process is finished and the chain's output file is transferred to TRestRun
545 return (TRestAnalysisTree*)fRun->GetOutputFile()->Get("AnalysisTree");
546 }
547 if (fHostmgr != nullptr && fHostmgr->GetProcessRunner() != nullptr &&
548 fHostmgr->GetProcessRunner()->GetStatus() != kFinished) {
549 // this means the process is still ongoing
550 return fHostmgr->GetProcessRunner()->GetOutputAnalysisTree();
551 }
552 fRun->OpenInputFile(fileName);
553 return fRun->GetAnalysisTree();
554}
555
556TRestRun* TRestAnalysisPlot::GetRunInfo(const TString& fileName) {
557 // in any case we directly return fRun. No need to reopen the given file
558 if (fRun->GetInputFile() != nullptr && fRun->GetInputFile()->GetName() == fileName) {
559 return fRun;
560 }
561 if (fileName == fRun->GetOutputFileName() && fRun->GetOutputFile() != nullptr) {
562 return fRun;
563 }
564 if (fHostmgr != nullptr && fHostmgr->GetProcessRunner() != nullptr &&
565 fHostmgr->GetProcessRunner()->GetStatus() != kFinished) {
566 return fRun;
567 }
568 fRun->OpenInputFile(fileName);
569 return fRun;
570}
571
572bool TRestAnalysisPlot::IsDynamicRange(const TString& rangeString) {
573 return (string(rangeString)).find(", ") != string::npos;
574}
575
576Int_t TRestAnalysisPlot::GetColorIDFromString(const string& in) {
577 if (in.find_first_not_of("0123456789") == string::npos) {
578 return StringToInteger(in);
579 } else if (ColorIdMap.count(in) != 0) {
580 return ColorIdMap.at(in);
581 } else {
582 RESTWarning << "cannot find color with name \"" << in << "\"" << RESTendl;
583 }
584 return -1;
585}
586
587Int_t TRestAnalysisPlot::GetFillStyleIDFromString(const string& in) {
588 if (in.find_first_not_of("0123456789") == string::npos) {
589 return StringToInteger(in);
590 } else if (FillStyleMap.count(in) != 0) {
591 return FillStyleMap.at(in);
592 } else {
593 RESTWarning << "cannot find fill style with name \"" << in << "\"" << RESTendl;
594 }
595 return -1;
596}
597
598Int_t TRestAnalysisPlot::GetLineStyleIDFromString(const string& in) {
599 if (in.find_first_not_of("0123456789") == string::npos) {
600 return StringToInteger(in);
601 } else if (LineStyleMap.count(in) != 0) {
602 return LineStyleMap.at(in);
603 } else {
604 RESTWarning << "cannot find line style with name \"" << in << "\"" << RESTendl;
605 }
606 return -1;
607}
608
609void TRestAnalysisPlot::PlotCombinedCanvas() {
610 // Initializing canvas window
611 if (fCombinedCanvas != nullptr) {
612 delete fCombinedCanvas;
613 fCombinedCanvas = nullptr;
614 }
615 fCombinedCanvas = new TCanvas(this->GetName(), this->GetName(), 0, 0, fCanvasSize.X(), fCanvasSize.Y());
616 fCombinedCanvas->Divide((Int_t)fCanvasDivisions.X(), (Int_t)fCanvasDivisions.Y(),
617 fCanvasDivisionMargins.X(), fCanvasDivisionMargins.Y());
618
619 // Setting up TStyle
620 TStyle* st = new TStyle();
621 st->SetPalette(fPaletteStyle);
622
623 Double_t startTime = 0;
624 Double_t endTime = 0;
625 Double_t runLength = 0;
626 Int_t totalEntries = 0;
627 for (const auto& inputFilename : fRunInputFileName) {
628 auto run = GetRunInfo(inputFilename);
629
630 Double_t endTimeStamp = run->GetEndTimestamp();
631 Double_t startTimeStamp = run->GetStartTimestamp();
632
633 // We get the lowest/highest run time stamps.
634 if (!startTime || startTime > endTimeStamp) startTime = endTimeStamp;
635 if (!startTime || startTime > startTimeStamp) startTime = startTimeStamp;
636
637 if (!endTime || endTime < startTimeStamp) endTime = startTimeStamp;
638 if (!endTime || endTime < endTimeStamp) endTime = endTimeStamp;
639
640 if (endTimeStamp - startTimeStamp > 0) {
641 runLength += endTimeStamp - startTimeStamp;
642 totalEntries += run->GetEntries();
643 }
644 }
645
646 Double_t meanRate = totalEntries / runLength;
647
648 runLength /= 3600.;
649
650 for (unsigned int n = 0; n < fPanels.size(); n++) {
651 fCombinedCanvas->cd(n + 1);
652 for (unsigned int m = 0; m < fPanels[n].posX.size(); m++) {
653 string label = fPanels[n].label[m];
654
655 size_t pos = 0;
656 label = Replace(label, "[[startTime]]", ToDateTimeString(startTime), pos);
657 pos = 0;
658 label = Replace(label, "[[endTime]]", ToDateTimeString(endTime), pos);
659 pos = 0;
660 label = Replace(label, "[[entries]]", Form("%d", totalEntries), pos);
661 pos = 0;
662 label = Replace(label, "[[runLength]]", Form("%5.2lf", runLength), pos);
663 pos = 0;
664 label = Replace(label, "[[meanRate]]", Form("%5.2lf", meanRate), pos);
665
666 auto run = GetRunInfo(fRunInputFileName[0]);
667 label = run->ReplaceMetadataMembers(label, fPanels[n].precision);
668
669 TLatex* textLatex = new TLatex(fPanels[n].posX[m], fPanels[n].posY[m], label.c_str());
670 textLatex->SetTextColor(1);
671 textLatex->SetTextSize(fPanels[n].font_size);
672 textLatex->Draw("same");
673 }
674 }
675
676 // start drawing plots
677 vector<TH3F*> histCollectionAll;
678 for (unsigned int n = 0; n < fPlots.size(); n++) {
679 PlotInfoSet& plot = fPlots[n];
680
681 TPad* targetPad = (TPad*)fCombinedCanvas->cd(n + 1 + fPanels.size());
682 targetPad->SetLogx(plot.logX);
683 targetPad->SetLogy(plot.logY);
684 targetPad->SetLogz(plot.logZ);
685 targetPad->SetGridx(plot.gridX);
686 targetPad->SetGridy(plot.gridY);
687 targetPad->SetLeftMargin(plot.marginLeft);
688 targetPad->SetRightMargin(plot.marginRight);
689 targetPad->SetBottomMargin(plot.marginBottom);
690 targetPad->SetTopMargin(plot.marginTop);
691
692 // draw each histogram in the pad
693 for (unsigned int i = 0; i < plot.histos.size(); i++) {
694 HistoInfoSet& hist = plot.histos[i];
695
696 TString plotString = hist.plotString;
697 TString nameString = hist.name;
698 TString rangeString = hist.range;
699 TString cutString = hist.cutString;
700 TString optString = hist.drawOption;
701
702 size_t pos = 0;
703 rangeString = Replace((string)rangeString, "MIN_TIME", (string)Form("%9f", startTime), pos);
704 rangeString = Replace((string)rangeString, "MAX_TIME", (string)Form("%9f", endTime), pos);
705
706 if (cutString == "")
707 cutString = hist.weight;
708 else if (!hist.weight.empty())
709 cutString = "(" + cutString + ") * " + hist.weight;
710
712 cout << endl;
713 cout << "--------------------------------------" << endl;
714 cout << "Plot string : " << plotString << endl;
715 cout << "Plot name : " << nameString << endl;
716 cout << "Plot range : " << rangeString << endl;
717 cout << "Cut : " << cutString << endl;
718 cout << "Plot option : " << optString << endl;
719 cout << "++++++++++++++++++++++++++++++++++++++" << endl;
720 }
721
722 // draw single histo from different file
723 bool firstdraw = false;
724 TH3F* hTotal = hist.ptr;
725 for (unsigned int j = 0; j < fRunInputFileName.size(); j++) {
726 auto run = GetRunInfo(fRunInputFileName[j]);
727 // apply "classify" condition
728 bool flag = true;
729 for (const auto& [inputFile, info] : hist.classifyMap) {
730 if (run->GetRunInformation(inputFile).find(info) == string::npos) {
731 flag = false;
732 break;
733 }
734 }
735 if (!flag) continue;
736
737 TTree* tree = GetTree(fRunInputFileName[j]);
738
739 // call Draw() from analysis tree
740 int outVal;
741 TString reducedHistoName = nameString + "_" + std::to_string(j);
742 TString histoName = nameString + "_" + std::to_string(j) + rangeString;
743 RESTInfo << "AnalysisTree->Draw(\"" << plotString << ">>" << histoName << "\", \""
744 << cutString << "\", \"" << optString << "\", " << fDrawNEntries << ", "
745 << fDrawFirstEntry << ")" << RESTendl;
746 outVal = tree->Draw(plotString + ">>" + histoName, cutString, optString, fDrawNEntries,
747 fDrawFirstEntry);
748 TH3F* hh = (TH3F*)gPad->GetPrimitive(reducedHistoName);
749 if (outVal == 0) {
750 RESTInfo << "File: " << fRunInputFileName[j] << ": No entries are drawn" << RESTendl;
751 RESTInfo << "AnalysisTree is empty? cut is too hard?" << RESTendl;
752 } else if (outVal == -1) {
753 RESTError << RESTendl;
754 RESTError
755 << "TRestAnalysisPlot::PlotCombinedCanvas. Plot string not properly constructed. "
756 "Does the analysis observable exist inside the file?"
757 << RESTendl;
758 RESTError << "Use \" restManager PrintTrees FILE.ROOT\" to get a list of "
759 "existing observables."
760 << RESTendl;
761 RESTError << RESTendl;
762 exit(1);
763 }
764
765 // add to histogram
766 if (hTotal == nullptr) {
767 if (hh != nullptr) {
768 hTotal = (TH3F*)hh->Clone(nameString);
769 hist.ptr = hTotal;
770 firstdraw = true;
771 // This is important so that the histogram is not erased when we delete TRestRun!
772 hTotal->SetDirectory(0);
773 }
774 } else {
775 if (outVal > 0) {
776 if (IsDynamicRange(rangeString)) {
777 hTotal->SetDirectory(gDirectory);
778 hTotal->SetCanExtend(TH1::kAllAxes);
779 tree->Draw(plotString + ">>+" + hTotal->GetName(), cutString, optString,
780 fDrawNEntries, fDrawFirstEntry);
781 RESTInfo << "AnalysisTree->Draw(\"" << plotString << ">>+" << hTotal->GetName()
782 << "\", \"" << cutString << "\", \"" << optString << "\", "
783 << fDrawNEntries << ", " << fDrawFirstEntry << ")" << RESTendl;
784 hTotal->SetDirectory(0);
785 } else {
786 hTotal->Add(hh);
787 }
788 }
789 }
790 }
791
792 if (hTotal == nullptr) {
793 RESTWarning << "Histogram \"" << nameString << "\" is nullptr" << RESTendl;
794 } else if (firstdraw) {
795 // adjust the histogram
796 hTotal->SetTitle(plot.title.c_str());
797 hTotal->SetStats(plot.staticsOn);
798
799 hTotal->GetXaxis()->SetTitle(plot.labelX.c_str());
800 hTotal->GetYaxis()->SetTitle(plot.labelY.c_str());
801
802 hTotal->GetXaxis()->SetLabelSize(1.1 * hTotal->GetXaxis()->GetLabelSize());
803 hTotal->GetYaxis()->SetLabelSize(1.1 * hTotal->GetYaxis()->GetLabelSize());
804 hTotal->GetXaxis()->SetTitleSize(1.1 * hTotal->GetXaxis()->GetTitleSize());
805 hTotal->GetYaxis()->SetTitleSize(1.1 * hTotal->GetYaxis()->GetTitleSize());
806 hTotal->GetXaxis()->SetTitleOffset(1 * hTotal->GetXaxis()->GetTitleOffset());
807 hTotal->GetYaxis()->SetTitleOffset(1 * hTotal->GetYaxis()->GetTitleOffset());
808 hTotal->GetXaxis()->SetNdivisions(plot.ticksX);
809 hTotal->GetYaxis()->SetNdivisions(plot.ticksY);
810
811 hTotal->SetLineColor(hist.lineColor);
812 hTotal->SetLineWidth(hist.lineWidth);
813 hTotal->SetLineStyle(hist.lineStyle);
814 hTotal->SetFillColor(hist.fillColor);
815 hTotal->SetFillStyle(hist.fillStyle);
816
817 hTotal->SetDrawOption(hist.drawOption.c_str());
818
819 if (plot.timeDisplay) hTotal->GetXaxis()->SetTimeDisplay(1);
820
821 histCollectionAll.push_back(hTotal);
822 }
823 }
824
825 bool allEmpty = true;
826 for (unsigned int i = 0; i < plot.histos.size(); i++) {
827 if (plot.histos[i].ptr == nullptr)
828 continue;
829 else {
830 allEmpty = false;
831 break;
832 }
833 }
834 if (allEmpty) {
835 RESTWarning << "TRestAnalysisPlot: pad empty for the plot: " << plot.name << RESTendl;
836 continue;
837 }
838
839 // normalize the histograms
840 if (plot.normalize > 0) {
841 for (unsigned int i = 0; i < plot.histos.size(); i++) {
842 if (plot.histos[i].ptr == nullptr) continue;
843 Double_t scale = 1.;
844 if (plot.histos[i].ptr->Integral() > 0) {
845 scale = plot.normalize / plot.histos[i].ptr->Integral();
846 plot.histos[i].ptr->Scale(scale);
847 }
848 }
849 }
850
851 // scale the histograms
852 if (plot.scale != "") {
853 for (unsigned int i = 0; i < plot.histos.size(); i++) {
854 if (plot.histos[i].ptr == nullptr) continue;
855 Double_t scale = 1.;
856 if (plot.scale == "binSize")
857 scale = 1. / plot.histos[i].ptr->GetXaxis()->GetBinWidth(1);
858 else
859 scale = StringToDouble(plot.scale);
860
861 plot.histos[i].ptr->Scale(scale);
862 }
863 }
864
865 // draw to the pad
866 targetPad = (TPad*)fCombinedCanvas->cd(n + 1 + fPanels.size());
867 Double_t maxValue_Pad = 0;
868 unsigned int maxID = 0;
869 for (unsigned int i = 0; i < plot.histos.size(); i++) {
870 // need to draw the max histogram first, in order to prevent peak hidden problem
871 if (plot.histos[i].ptr == nullptr) continue;
872 Double_t value = plot.histos[i]->GetBinContent(plot.histos[i].ptr->GetMaximumBin());
873 if (i == 0) {
874 maxValue_Pad = value;
875 } else if (value > maxValue_Pad) {
876 maxValue_Pad = value;
877 maxID = i;
878 }
879 }
880 plot.histos[maxID]->Draw(plot.histos[maxID].drawOption.c_str());
881 // if (((string)plot.histos[maxID]->ClassName()).find("TH1") != -1) {
882 // plot.histos[maxID]->GetYaxis()->SetRangeUser(plot.logY, maxValue_Pad * 1.2);
883 //}
884
885 for (unsigned int i = 0; i < plot.histos.size(); i++) {
886 // draw the remaining histo
887 if (plot.histos[i].ptr == nullptr) continue;
888 if (i != maxID) {
889 plot.histos[i]->Draw((plot.histos[i].drawOption + "same").c_str());
890 }
891 }
892
893 // save histogram to root file
894 if (fRun->GetOutputFile() != nullptr) {
895 fRun->GetOutputFile()->cd();
896 for (auto& histo : plot.histos) {
897 if (histo.ptr == nullptr) continue;
898 histo->Write();
899 }
900 }
901
902 // draw legend
903 if (plot.legendOn) {
904 TLegend* legend = new TLegend(fLegendX1, fLegendY1, fLegendX2, fLegendY2);
905 for (auto& histo : plot.histos) {
906 if (histo.ptr == nullptr) continue;
907 legend->AddEntry(histo.ptr, histo->GetName(), "lf");
908 }
909 legend->Draw("same");
910 }
911
912 // save pad
913 targetPad->SetRightMargin(plot.marginRight);
914 targetPad->SetLeftMargin(plot.marginLeft);
915 targetPad->SetBottomMargin(plot.marginBottom);
916 targetPad->Update();
917 if (!plot.save.empty()) targetPad->Print(plot.save.c_str());
918
919 fCombinedCanvas->Update();
920 }
921
922 // Preview plot. User can make some changed before saving
923 if (!REST_Display_CompatibilityMode && StringToBool(GetParameter("previewPlot", "TRUE"))) {
924 GetChar();
925 }
926
927 // Save canvas to a PDF file
928 fCanvasSave = fRun->FormFormat(fCanvasSave);
929 if (fCanvasSave != "") fCombinedCanvas->Print(fCanvasSave);
930
931 // If the extension of the canvas save file is ROOT we store also the histograms
932 if (TRestTools::isRootFile((string)fCanvasSave)) {
933 TRestRun* run = new TRestRun();
934 run->SetOutputFileName((string)fCanvasSave);
935 run->FormOutputFile();
936 for (auto& h : histCollectionAll) {
937 h->Write();
938 }
939 delete run;
940 }
941
942 // Save this class to the root file
943 if (fRun->GetOutputFile() != nullptr) {
944 fRun->GetOutputFile()->cd();
945 this->Write();
946 }
947
948 delete st;
949}
950
951void TRestAnalysisPlot::SaveCanvasToPDF(const TString& fileName) { fCombinedCanvas->Print(fileName); }
952
953void TRestAnalysisPlot::SavePlotToPDF(const TString& fileName, Int_t n) {
954 // gErrorIgnoreLevel = 10;
955 fCombinedCanvas->SetBatch(kTRUE);
956
957 if (n == 0) {
958 fCombinedCanvas->Print(fileName);
959 fCombinedCanvas->SetBatch(kFALSE);
960 return;
961 }
962
963 TPad* pad = (TPad*)fCombinedCanvas->GetPad(n);
964 pad->SetRightMargin(fPlots[n - 1].marginRight);
965 pad->SetLeftMargin(fPlots[n - 1].marginLeft);
966 pad->SetBottomMargin(fPlots[n - 1].marginBottom);
967
968 TCanvas* c = new TCanvas(fPlots[n - 1].name.c_str(), fPlots[n - 1].name.c_str(), 800, 600);
969 pad->DrawClone();
970
971 c->Print(fileName);
972
973 delete c;
974
975 fCombinedCanvas->SetBatch(kFALSE);
976}
977
978void TRestAnalysisPlot::SaveHistoToPDF(const TString& fileName, Int_t nPlot, Int_t nHisto) {
979 string name = fPlots[nPlot].histos[nHisto].name;
980 TH3F* hist = (TH3F*)gPad->GetPrimitive(name.c_str());
981
982 TCanvas* c = new TCanvas(name.c_str(), name.c_str(), 800, 600);
983
984 hist->Draw();
985
986 c->Print(fileName);
987
988 delete c;
989}
void Initialize() override
Making default settings.
Long64_t fDrawNEntries
Output canvas.
std::vector< TString > fRunInputFileName
TRestRun to handle output file.
TCanvas * fCombinedCanvas
TRestRun to handle input file.
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
REST core data-saving helper based on TTree.
A base class for any REST metadata class.
Definition: TRestMetadata.h:74
endl_t RESTendl
Termination flag object for TRestStringOutput.
std::string ElementToString(TiXmlElement *ele)
Convert an TiXmlElement object to string.
TiXmlElement * GetElement(std::string eleDeclare, TiXmlElement *e=nullptr)
Get an xml element from a given parent element, according to its declaration.
TRestStringOutput::REST_Verbose_Level GetVerboseLevel()
returns the verboselevel in type of REST_Verbose_Level enumerator
std::string GetFieldValue(std::string parName, TiXmlElement *e)
Returns the field value of an xml element which has the specified name.
TString GetDataPath()
Returns a std::string with the path used for data storage.
void SetSectionName(std::string sName)
set the section name, clear the section content
TRestManager * fHostmgr
All metadata classes can be initialized and managed by TRestManager.
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
overwriting the write() method with fStore considered
TiXmlElement * GetNextElement(TiXmlElement *e)
Get the next sibling xml element of this element, with same eleDeclare.
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
TiXmlElement * fElement
Saving the sectional element together with global element.
Data provider and manager in REST.
Definition: TRestRun.h:18
void OpenInputFile(int i)
Open the i th file in the file list.
Definition: TRestRun.cxx:314
TFile * FormOutputFile()
Create a new TFile as REST output file. Writing metadata objects into it.
Definition: TRestRun.cxx:1036
TString FormFormat(const TString &filenameFormat)
Form output file name according to file info list, proc info list and run data.
Definition: TRestRun.cxx:940
@ REST_Debug
+show the defined debug messages
static std::vector< std::string > GetFilesMatchingPattern(std::string pattern, bool unlimited=false)
Returns a list of files whose name match the pattern string. Key word is "*". e.g....
Definition: TRestTools.cxx:976
static bool isRootFile(const std::string &filename)
Returns true if the filename has *.root* extension.
Definition: TRestTools.cxx:733
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
Double_t StringToDouble(std::string in)
Gets a double from a string.
std::string ToUpper(std::string in)
Convert string to its upper case. Alternative of TString::ToUpper.
Int_t StringToInteger(std::string in)
Gets an integer from a string.
TVector2 StringTo2DVector(std::string in)
Gets a 2D-vector from a string.
Int_t isANumber(std::string in)
Returns 1 only if a valid number is found in the string in. If not it returns 0.
std::string RemoveWhiteSpaces(std::string in)
Returns the input string removing all white spaces.
std::string ToDateTimeString(time_t time)
Format time_t into string.
std::string Replace(std::string in, std::string thisString, std::string byThisString, size_t fromPosition=0, Int_t N=0)
Replace any occurences of thisSring by byThisString inside string in.