REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestAnalysisPlot.cxx
1 
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 
23 using namespace std;
24 
25 ClassImp(TRestAnalysisPlot);
26 
27 TRestAnalysisPlot::TRestAnalysisPlot() { Initialize(); }
28 
29 TRestAnalysisPlot::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 
47 TRestAnalysisPlot::~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 
330 TRestAnalysisPlot::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 
493 void 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 
500 void 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
507 void 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"
518 void 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 
530 Int_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 
538 TRestAnalysisTree* 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 
556 TRestRun* 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 
572 bool TRestAnalysisPlot::IsDynamicRange(const TString& rangeString) {
573  return (string(rangeString)).find(", ") != string::npos;
574 }
575 
576 Int_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 
587 Int_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 
598 Int_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 
609 void 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 
951 void TRestAnalysisPlot::SaveCanvasToPDF(const TString& fileName) { fCombinedCanvas->Print(fileName); }
952 
953 void 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 
978 void 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.