529 std::vector<std::string> obsList;
532 if (
fCut !=
nullptr) {
533 const auto paramCut =
fCut->GetParamCut();
534 for (
const auto& [param, condition] : paramCut) {
535 obsList.push_back(param);
540 for (
const auto& plots :
fPlots) {
541 for (
const auto& hist : plots.histos) {
542 for (
const auto& var : hist.variable) {
543 obsList.push_back(var);
545 if (hist.histoCut ==
nullptr)
continue;
546 const auto paramCut = hist.histoCut->GetParamCut();
547 for (
const auto& [param, condition] : paramCut) {
548 obsList.push_back(param);
553 std::map<std::string, TRestDataSet::RelevantQuantity> quantity;
557 for (
auto& [key, posLabel] : panel.expPos) {
559 auto&& [exp, label,
units, precision] = key;
560 std::string text = exp;
561 while (text.find_last_of(
'[') != std::string::npos) {
562 int squareBracketCorrector = 0;
563 size_t posOpen = text.find_last_of(
'[');
564 size_t posClose = text.find_first_of(
']', posOpen);
566 if (text[posOpen - 1] ==
'[') {
567 squareBracketCorrector = 1;
570 std::string varOrMeta = text.substr(posOpen - squareBracketCorrector,
571 posClose + 1 - posOpen + 2 * squareBracketCorrector);
572 if (squareBracketCorrector == 0) {
578 quantity[label] = quant;
580 text =
Replace(text, varOrMeta,
"1");
584 while (text.find(
"_") != std::string::npos) {
585 size_t pos_ = text.find(
"_");
586 size_t beginning = text.find_last_of(
" -+*/)(^%", pos_) + 1;
587 size_t end = text.find_first_of(
" -+*/)(^%", pos_);
588 std::string obs = text.substr(beginning, end - beginning);
589 text =
Replace(text, obs,
"1");
590 obsList.push_back(obs);
594 RESTWarning <<
"The expression " << exp
595 <<
" has not been correctly parsed into variables, metadata and observables"
600 for (
auto& [key, posLabel] : panel.obsPos) {
601 auto&& [obs, label,
units] = key;
602 obsList.push_back(obs);
605 for (
auto& [key, posLabel] : panel.metadataPos) {
606 auto&& [metadata, label,
units] = key;
610 quantity[label] = quant;
615 std::sort(obsList.begin(), obsList.end());
616 obsList.erase(std::unique(obsList.begin(), obsList.end()), obsList.end());
618 dataSet.SetObservablesList(obsList);
619 dataSet.SetQuantity(quantity);
629 dataSet.EnableMultiThreading(
true);
635 if (dataSet.
GetTree() ==
nullptr) {
636 RESTWarning <<
"Cannot import dataSet, trying to generate it with pattern " <<
fDataSetName
638 RESTWarning <<
"Note that the generation of a dataSet inside TRestDataSetPlot is deplecated. Check "
639 "TRestDataSet documentation to generate a dataSet"
642 if (dataSet.
GetTree() ==
nullptr) {
643 RESTError <<
"Cannot generate dataSet " <<
RESTendl;
652 combinedCanvas.Divide((Int_t)fCanvasDivisions.X(), (Int_t)fCanvasDivisions.Y(),
653 fCanvasDivisionMargins.X(), fCanvasDivisionMargins.Y());
658 const double startTime = dataSet.GetStartTime();
659 const double endTime = dataSet.GetEndTime();
662 std::map<std::string, std::string> paramMap;
667 const auto quantity = dataSet.GetQuantity();
672 combinedCanvas.cd(canvasIndex);
674 auto dataFrame = dataSet.
MakeCut(panel.panelCut);
675 const int entries = *dataFrame.Count();
676 const double meanRate = entries / duration;
677 const double runLength = duration / 3600.;
682 paramMap[
"[[cutNames]]"] =
"";
683 paramMap[
"[[cuts]]"] =
"";
685 for (
const auto& cut :
fCut->GetCuts()) {
686 if (paramMap[
"[[cutNames]]"].empty())
687 paramMap[
"[[cutNames]]"] += cut.GetName();
689 paramMap[
"[[cutNames]]"] +=
"," + (std::string)cut.GetName();
690 if (paramMap[
"[[cuts]]"].empty())
691 paramMap[
"[[cuts]]"] += cut.GetTitle();
693 paramMap[
"[[cuts]]"] +=
" && " + (std::string)cut.GetTitle();
697 paramMap[
"[[panelCutNames]]"] =
"";
698 paramMap[
"[[panelCuts]]"] =
"";
699 if (panel.panelCut) {
700 for (
const auto& cut : panel.panelCut->GetCuts()) {
701 if (paramMap[
"[[panelCutNames]]"].empty())
702 paramMap[
"[[panelCutNames]]"] += cut.GetName();
704 paramMap[
"[[panelCutNames]]"] +=
"," + (std::string)cut.GetName();
705 if (paramMap[
"[[panelCuts]]"].empty())
706 paramMap[
"[[panelCuts]]"] += cut.GetTitle();
708 paramMap[
"[[panelCuts]]"] +=
" && " + (std::string)cut.GetTitle();
712 RESTInfo <<
"Global cuts: " << paramMap[
"[[cuts]]"] <<
RESTendl;
713 if (!paramMap[
"[[panelCuts]]"].empty())
714 RESTInfo <<
"Additional panel cuts: " << paramMap[
"[[panelCuts]]"] <<
RESTendl;
717 for (
const auto& [key, posLabel] : panel.variablePos) {
718 auto&& [variable, label,
units] = key;
720 std::string var = variable;
722 for (
const auto& [param, val] : paramMap) {
725 var =
Replace(var, param, val, pos);
730 if (!found) RESTWarning <<
"Variable " << variable <<
" not found" <<
RESTendl;
733 if (var.find(
'.') == std::string::npos) {
735 var = StringWithPrecision(dblVar, panel.precision);
738 var = StringWithPrecision(dblVar, panel.precision);
742 label + panel.delimiter.Data() + StringWithPrecision(var, panel.precision) +
" " +
units;
743 panel.text.emplace_back(
new TLatex(posLabel.X(), posLabel.Y(), lab.c_str()));
747 for (
const auto& [key, posLabel] : panel.metadataPos) {
748 auto&& [metadata, label,
units] = key;
749 std::string value =
"";
751 for (
const auto& [name, quant] : quantity) {
752 if (quant.metadata == metadata) value = quant.value;
756 RESTWarning <<
"Metadata quantity " << metadata <<
" not found in dataSet" <<
RESTendl;
761 label + panel.delimiter.Data() + StringWithPrecision(value, panel.precision) +
" " +
units;
762 panel.text.emplace_back(
new TLatex(posLabel.X(), posLabel.Y(), lab.c_str()));
766 for (
const auto& [key, posLabel] : panel.obsPos) {
767 auto&& [obs, label,
units] = key;
768 auto value = *dataFrame.Mean(obs);
771 label + panel.delimiter.Data() + StringWithPrecision(value, panel.precision) +
" " +
units;
772 panel.text.emplace_back(
new TLatex(posLabel.X(), posLabel.Y(), lab.c_str()));
776 for (
const auto& [key, posLabel] : panel.expPos) {
777 auto&& [text, label,
units, precision] = key;
778 std::string var = text;
781 std::vector<std::string> subtexts;
782 while (var.find_last_of(
'{') != std::string::npos) {
783 size_t posOpen = var.find_last_of(
'{');
784 size_t posClose = var.find_first_of(
'}', posOpen);
785 if (posClose == std::string::npos) {
786 RESTWarning <<
"Unmatched { in expression: " << var <<
RESTendl;
789 std::string subtext = var.substr(posOpen + 1, posClose - posOpen - 1);
790 subtexts.push_back(subtext);
792 var.erase(posOpen, posClose - posOpen + 1);
797 std::vector<std::string> precisionParts;
798 for (
const auto& part :
Split(precision,
",",
false,
true)) {
799 precisionParts.push_back(part);
801 if (precisionParts.size() != subtexts.size()) {
802 RESTDebug <<
"Not enough precision values provided for the expression: `" << text
803 <<
"`. Using " << precisionParts.back() <<
" for last subtexts." <<
RESTendl;
804 precisionParts.resize(subtexts.size(), precisionParts.back());
807 size_t precisionIndex = precisionParts.size() - 1;
808 for (
const auto& subtext : subtexts) {
809 std::string subVar = subtext;
811 for (
const auto& [param, val] : paramMap) {
812 subVar =
Replace(subVar, param, val);
815 for (
const auto& [name, quant] : quantity) {
816 subVar =
Replace(subVar,
"[" + name +
"]", quant.value);
817 subVar =
Replace(subVar, name, quant.value);
820 for (
const auto& obs : dataFrame.GetColumnNames()) {
821 if (var.find(obs) == std::string::npos)
continue;
824 double value = *dataFrame.Mean(obs);
827 subVar =
Replace(subVar,
"[",
"(");
828 subVar =
Replace(subVar,
"]",
")");
832 std::string prec = precisionParts[precisionIndex--];
833 if (prec.find(
'%') != std::string::npos) {
838 RESTWarning <<
"Unknown precision format: " << prec
839 <<
". Using panels precision: " << panel.precision <<
RESTendl;
840 subVar = StringWithPrecision(value, panel.precision);
843 var =
Replace(var,
"{" + subtext +
"}", subVar);
846 std::string lab = label + panel.delimiter.Data() + var +
" " +
units;
847 panel.text.emplace_back(
new TLatex(posLabel.X(), posLabel.Y(), lab.c_str()));
851 for (
const auto& text : panel.text) {
852 text->SetTextColor(1);
853 text->SetTextSize(panel.font_size);
859 for (
auto& plots :
fPlots) {
861 combinedCanvas.cd(canvasIndex);
862 plots.hs =
new THStack(plots.name.c_str(), plots.title.c_str());
863 if (plots.legendOn) plots.legend =
new TLegend(
fLegendX1, fLegendY1, fLegendX2, fLegendY2);
865 for (
auto& hist : plots.histos) {
866 auto dataFrame = dataSet.
MakeCut(hist.histoCut);
867 if (hist.variable.front() ==
"timeStamp") {
868 hist.range.front().SetX(startTime);
869 hist.range.front().SetY(endTime);
872 if (hist.variable.size() == 1) {
873 auto histo = dataFrame.Histo1D({hist.name.c_str(), hist.name.c_str(), hist.nBins.front(),
874 hist.range.front().X(), hist.range.front().Y()},
875 hist.variable.front());
876 hist.histo =
static_cast<TH1*
>(histo->DrawClone());
878 }
else if (hist.variable.size() == 2) {
879 auto histo = dataFrame.Histo2D(
880 {hist.name.c_str(), hist.name.c_str(), hist.nBins.front(), hist.range.front().X(),
881 hist.range.front().Y(), hist.nBins.back(), hist.range.back().X(), hist.range.back().Y()},
882 hist.variable.front(), hist.variable.back());
883 hist.histo =
static_cast<TH1*
>(histo->DrawClone());
885 RESTError <<
"Only 1D or 2D histograms are supported " <<
RESTendl;
888 hist.histo->SetLineColor(hist.lineColor);
889 hist.histo->SetLineWidth(hist.lineWidth);
890 hist.histo->SetLineStyle(hist.lineStyle);
891 hist.histo->SetFillColor(hist.fillColor);
892 hist.histo->SetFillStyle(hist.fillStyle);
894 if (hist.statistics) {
895 hist.histo->SetStats(
true);
897 combinedCanvas.Update();
899 hist.histo->SetStats(
false);
902 if (plots.normalize > 0) {
903 const double integral = hist.histo->Integral();
904 if (integral > 0) hist.histo->Scale(plots.normalize / integral);
907 if (plots.scale !=
"") {
908 std::string inputScale = plots.scale;
909 double binSize = hist.histo->GetXaxis()->GetBinWidth(1);
910 double entries = hist.histo->GetEntries();
912 double integral = hist.histo->Integral(
"width");
919 std::string scale =
"1./(" + inputScale +
")";
924 plots.hs->Add(hist.histo, hist.drawOption.c_str());
926 if (plots.legend !=
nullptr) plots.legend->AddEntry(hist.histo, hist.histo->GetName(),
"lf");
931 for (
auto& plots :
fPlots) {
932 if (plots.hs ==
nullptr)
continue;
934 TPad* targetPad = (TPad*)combinedCanvas.cd(canvasIndex);
935 targetPad->SetLogx(plots.logX);
936 targetPad->SetLogy(plots.logY);
937 targetPad->SetLogz(plots.logZ);
938 targetPad->SetGridx(plots.gridX);
939 targetPad->SetGridy(plots.gridY);
940 targetPad->SetLeftMargin(plots.marginLeft);
941 targetPad->SetRightMargin(plots.marginRight);
942 targetPad->SetBottomMargin(plots.marginBottom);
943 targetPad->SetTopMargin(plots.marginTop);
946 plots.hs->Draw(plots.stackDrawOption.c_str());
947 plots.hs->GetXaxis()->SetTitle(plots.labelX.c_str());
948 plots.hs->GetYaxis()->SetTitle(plots.labelY.c_str());
949 plots.hs->GetXaxis()->SetLabelSize(1.1 * plots.hs->GetXaxis()->GetLabelSize());
950 plots.hs->GetYaxis()->SetLabelSize(1.1 * plots.hs->GetYaxis()->GetLabelSize());
951 plots.hs->GetXaxis()->SetTitleSize(1.1 * plots.hs->GetXaxis()->GetTitleSize());
952 plots.hs->GetYaxis()->SetTitleSize(1.1 * plots.hs->GetYaxis()->GetTitleSize());
954 if (plots.timeDisplay) plots.hs->GetXaxis()->SetTimeDisplay(1);
955 if (plots.legend !=
nullptr) plots.legend->Draw();
958 combinedCanvas.Update();
964 combinedCanvas.Resize();
969 for (
auto& plots :
fPlots) {
970 if (plots.save.empty())
continue;
971 std::unique_ptr<TCanvas> canvas(
new TCanvas());
972 canvas->SetLogx(plots.logX);
973 canvas->SetLogy(plots.logY);
974 canvas->SetLogz(plots.logZ);
975 canvas->SetGridx(plots.gridX);
976 canvas->SetGridy(plots.gridY);
977 canvas->SetLeftMargin(plots.marginLeft);
978 canvas->SetRightMargin(plots.marginRight);
979 canvas->SetBottomMargin(plots.marginBottom);
980 canvas->SetTopMargin(plots.marginTop);
981 plots.hs->Draw(plots.stackDrawOption.c_str());
982 canvas->Print(plots.save.c_str());
987 for (
const auto& [name, quant] : quantity) {
994 std::unique_ptr<TFile> f(TFile::Open(
fOutputFileName.c_str(),
"UPDATE"));
995 for (
auto& plots :
fPlots) {
996 for (
auto& hist : plots.histos) {