157 std::map<
int, std::vector<int>> ranges, std::map<
int, std::vector<int>> rangesBase,
164 NLogTrace(
"NGnNavigator::Reshape: Reshaping navigator for level=%d levels=%zu", level, levels.size());
165 TH1::AddDirectory(kFALSE);
169 branch =
fGnTree->GetStorageTree()->GetBranch(
"outputPoint");
171 int outputPointStatus = 0;
181 if (current ==
nullptr) {
182 NLogDebug(
"NGnNavigator::Reshape: Creating root navigator %d/%zu...", level, levels.size());
183 current =
new NGnNavigator(TString::Format(
"%s_L%zu", GetName(), level).Data(),
184 TString::Format(
"%s_L%zu", GetTitle(), level).Data());
194 if (level < levels.size()) {
201 std::vector<int> minsBin;
202 std::vector<int> maxsBin;
203 for (
auto & idx : levels[level]) {
204 NLogTrace(
"NGnNavigator::Reshape: [B%d] Axis %d: %s", level, idx,
205 binningDef->
GetContent()->GetAxis(idx)->GetName());
209 minsBin.push_back(1);
210 maxsBin.push_back(binningDef->
GetContent()->GetAxis(idx)->GetNbins());
211 NLogTrace(
"NGnNavigator::Reshape: [B%d] Axis %d: %s bins=[%d,%d]", level, idx,
212 binningDef->
GetContent()->GetAxis(idx)->GetName(), minsBin.back(), maxsBin.back());
216 auto loop_task_bin = [
this, current, binningDef, levels, level, ranges,
217 rangesBase](
const std::vector<int> & coords) {
218 NLogTrace(
"NGnNavigator::Reshape: [B%d] Processing coordinates: coords=%s levels=%s", level,
220 NLogTrace(
"NGnNavigator::Reshape: [L%d] Generating %zuD histogram %s with ranges: %s", level,
223 std::vector<int> axesIds = levels[level];
226 Int_t nDims = axesIds.size();
227 auto dims = std::make_unique<Int_t[]>(nDims);
229 for (
int i = 0; i < nDims; i++) {
230 dims[i] = axesIds[i];
232 THnSparse * hnsIn = binningDef->GetContent();
244 std::string name =
"";
245 std::string title =
"";
246 for (
auto & axisId : axesIds) {
247 TAxis * a = hnsIn->GetAxis(axisId);
248 title += std::string(a->GetName()) +
" vs ";
249 name += TString::Format(
"%s-", a->GetName()).Data();
251 name = name.substr(0, name.size() - 1);
252 if (name.empty()) name =
"hns_proj";
253 title = title.substr(0, title.size() - 4);
254 if (ranges.size() > 0) title +=
" for ranges: ";
255 for (
const auto & [axisId, range] : rangesBase) {
257 TAxis * a = hnsIn->GetAxis(axisId);
258 if (a->IsAlphanumeric()) {
259 title += TString::Format(
"%s[%s]", a->GetName(), a->GetBinLabel(range[0]));
263 TString::Format(
"%s[%.2f,%.2f]", a->GetName(), a->GetBinLowEdge(range[0]), a->GetBinUpEdge(range[1]));
279 int indexInProj = -1;
280 TH1 * hProj =
nullptr;
283 hProj = hnsIn->Projection(axesIds[0]);
284 hProj->SetDirectory(
nullptr);
286 TAxis * axisIn0 = hnsIn->GetAxis(axesIds[0]);
287 TAxis * axisProjX = hProj->GetXaxis();
288 axisProjX->SetName(axisIn0->GetName());
290 if (axisIn0->IsAlphanumeric()) {
291 for (
int b = 1; b <= hProj->GetNbinsX(); b++) {
292 axisProjX->SetBinLabel(b, axisIn0->GetBinLabel(b));
295 indexInProj = hProj->FindFixBin(axisProjX->GetBinCenter(coords[0]));
297 else if (nDims == 2) {
299 hProj = hnsIn->Projection(axesIds[1], axesIds[0]);
300 hProj->SetDirectory(
nullptr);
301 TAxis * axisIn1 = hnsIn->GetAxis(axesIds[0]);
302 TAxis * axisIn0 = hnsIn->GetAxis(axesIds[1]);
303 TAxis * axisProjX = hProj->GetXaxis();
304 TAxis * axisProjY = hProj->GetYaxis();
305 axisProjX->SetName(axisIn1->GetName());
306 axisProjY->SetName(axisIn0->GetName());
308 if (axisIn1->IsAlphanumeric()) {
309 for (
int b = 1; b <= hProj->GetNbinsX(); b++) {
310 axisProjX->SetBinLabel(b, axisIn1->GetBinLabel(b));
314 if (axisIn0->IsAlphanumeric()) {
315 for (
int b = 1; b <= hProj->GetNbinsY(); b++) {
316 axisProjY->SetBinLabel(b, axisIn0->GetBinLabel(b));
319 indexInProj = hProj->FindFixBin(axisProjX->GetBinCenter(coords[0]), axisProjY->GetBinCenter(coords[1]));
321 else if (nDims == 3) {
322 hProj = hnsIn->Projection(axesIds[0], axesIds[1], axesIds[2]);
323 hProj->SetDirectory(
nullptr);
324 TAxis * axisIn0 = hnsIn->GetAxis(axesIds[0]);
325 TAxis * axisIn1 = hnsIn->GetAxis(axesIds[1]);
326 TAxis * axisIn2 = hnsIn->GetAxis(axesIds[2]);
327 TAxis * axisProjX = hProj->GetXaxis();
328 TAxis * axisProjY = hProj->GetYaxis();
329 TAxis * axisProjZ = hProj->GetZaxis();
330 axisProjX->SetName(axisIn0->GetName());
331 axisProjY->SetName(axisIn1->GetName());
332 axisProjZ->SetName(axisIn2->GetName());
334 if (axisIn0->IsAlphanumeric()) {
335 for (
int b = 1; b <= hProj->GetNbinsX(); b++) {
336 axisProjX->SetBinLabel(b, axisIn0->GetBinLabel(b));
340 if (axisIn1->IsAlphanumeric()) {
341 for (
int b = 1; b <= hProj->GetNbinsY(); b++) {
342 axisProjY->SetBinLabel(b, axisIn1->GetBinLabel(b));
345 if (axisIn2->IsAlphanumeric()) {
346 for (
int b = 1; b <= hProj->GetNbinsZ(); b++) {
347 axisProjZ->SetBinLabel(b, axisIn2->GetBinLabel(b));
350 indexInProj = hProj->FindFixBin(axisProjX->GetBinCenter(coords[0]), axisProjY->GetBinCenter(coords[1]),
351 axisProjZ->GetBinCenter(coords[2]));
354 NLogError(
"NGnNavigator::Reshape: Cannot project THnSparse with %d dimensions", nDims);
358 NLogError(
"NGnNavigator::Reshape: Projection failed for level %d !!!", level);
362 hProj->SetName(name.c_str());
363 hProj->SetTitle(title.c_str());
366 int dim = hProj->GetDimension();
368 for (
int x = 1; x <= hProj->GetNbinsX(); ++x) {
369 content = hProj->GetBinContent(x);
371 hProj->SetBinContent(x, content + 1.0);
376 for (
int x = 1; x <= hProj->GetNbinsX(); ++x) {
377 for (
int y = 1; y <= hProj->GetNbinsY(); ++y) {
378 content = hProj->GetBinContent(x, y);
380 hProj->SetBinContent(x, y, content + 1.0);
386 for (
int x = 1; x <= hProj->GetNbinsX(); ++x) {
387 for (
int y = 1; y <= hProj->GetNbinsY(); ++y) {
388 for (
int z = 1; z <= hProj->GetNbinsZ(); ++z) {
389 content = hProj->GetBinContent(x, y, z);
391 hProj->SetBinContent(x, y, z, content + 1.0);
401 Int_t nd = hnsIn->GetNdimensions();
402 Int_t * firstCoord =
new Int_t[nd];
404 content = hnsIn->GetBinContent(0, firstCoord);
409 int bx = firstCoord[axesIds[0]];
410 if (content < 0.5 && bx >= 1 && bx <= hProj->GetNbinsX())
411 hProj->SetBinContent(bx, hProj->GetBinContent(bx) + 1.0);
413 else if (nDims == 2) {
414 int bx = firstCoord[axesIds[0]];
415 int by = firstCoord[axesIds[1]];
416 if (content < 0.5 && bx >= 1 && bx <= hProj->GetNbinsX() && by >= 1 && by <= hProj->GetNbinsY())
417 hProj->SetBinContent(bx, by, hProj->GetBinContent(bx, by) + 1.0);
419 else if (nDims == 3) {
420 int bx = firstCoord[axesIds[0]];
421 int by = firstCoord[axesIds[1]];
422 int bz = firstCoord[axesIds[2]];
423 if (content < 0.5 && bx >= 1 && bx <= hProj->GetNbinsX() && by >= 1 && by <= hProj->GetNbinsY() &&
424 bz >= 1 && bz <= hProj->GetNbinsZ())
425 hProj->SetBinContent(bx, by, bz, hProj->GetBinContent(bx, by, bz) + 1.0);
431 NLogTrace(
"NGnNavigator::Reshape: [L%d] Projection histogram '%s' for coords=%s index=%d", level,
455 std::map<int, std::vector<int>> rangesTmp = ranges;
456 std::map<int, std::vector<int>> rangesBaseTmp = rangesBase;
457 for (
auto & kv : rangesBaseTmp) {
458 std::vector<int> range = rangesTmp[kv.first];
459 NLogTrace(
"NGnNavigator::Reshape: [L%d] Axis %d[%s]: rangeBase=%s range=%s", level, kv.first,
463 int minBase = 0, maxBase = 0;
465 for (
auto & c : coords) {
469 NLogTrace(
"NGnNavigator::Reshape: Axis %d: minBase=%d maxBase=%d", axesIds[i], minBase, maxBase);
470 rangesTmp[axesIds[i]] = {c, c};
471 rangesBaseTmp[axesIds[i]] = {minBase, maxBase};
475 if (hProj ==
nullptr) {
476 NLogError(
"NGnNavigator::Reshape: Projection histogram is null for level %d !!!", level);
480 size_t nCells = hProj->GetNcells();
484 if (currentChild ==
nullptr) {
485 NLogTrace(
"NGnNavigator::Reshape: [L%d] Creating new child for index %d nCells=%d ...", level, indexInProj,
487 std::string childName = TString::Format(
"%s_L%zu_C%d", GetName(), level + 1, indexInProj).Data();
488 currentChild =
new NGnNavigator(childName.c_str(), childName.c_str());
503 NLogError(
"NGnNavigator::Reshape: [L%d] Using existing child for index %d [NOT OK] ...", level, indexInProj);
509 if (level == levels.size() - 1) {
510 NLogTrace(
"NGnNavigator::Reshape: [L%d] Filling projections from all branches %s for ranges:", level,
512 for (
auto & kv : rangesBaseTmp) {
513 std::vector<int> range = rangesTmp[kv.first];
514 NLogTrace(
"NGnNavigator::Reshape: [L%d] Axis %d ['%s']: rangeBase=%s range=%s", level, kv.first,
526 std::unique_ptr<ROOT::Internal::THnBaseBinIter> iter{hnsIn->CreateIter(
true )};
527 std::vector<int> linBins;
531 while ((linBin = iter->Next()) >= 0) {
532 NLogTrace(
"NGnNavigator::Reshape: [L%d] Found bin %lld [%lld]", level, linBin, binningDef->GetId(linBin));
533 linBins.push_back(binningDef->GetId(linBin));
535 if (linBins.empty()) {
536 NLogTrace(
"NGnNavigator::Reshape: [L%d] No bins found for the given ranges, skipping ...", level);
541 NLogTrace(
"NGnNavigator::Reshape: Branch object Point coordinates: %s",
545 for (
int lb : linBins) {
547 for (
auto & [key, val] :
fGnTree->GetStorageTree()->GetBranchesMap()) {
548 if (val.GetBranchStatus() == 0) {
549 NLogTrace(
"NGnNavigator::Reshape: [L%d] Branch '%s' is disabled, skipping ...", level, key.c_str());
552 NLogTrace(
"NGnNavigator::Reshape: [L%d] Processing branch '%s' with %zu objects to loop ...", level,
553 key.c_str(), linBins.size());
565 TString className = val.GetObjectClassName();
566 if (className.BeginsWith(
"THnSparse")) {
614 else if (className.BeginsWith(
"TList")) {
615 NLogTrace(
"[L%d] Branch '%s' is a TList, getting object at index %d ...", level, key.c_str(),
617 TList * list =
dynamic_cast<TList *
>(val.GetObject());
620 std::vector<std::string> objNames;
621 for (
int i = 0; i < list->GetEntries(); i++) {
622 TObject * o = list->At(i);
623 objNames.push_back(o->GetName());
628 NLogTrace(
"[L%d] Branch '%s' TList contains %d objects: %s", level, key.c_str(), list->GetEntries(),
635 for (
auto & name : objNames) {
636 TH1 * hProjTmp =
dynamic_cast<TH1 *
>(list->FindObject(name.c_str()));
637 if (hProjTmp ==
nullptr) {
638 NLogTrace(
"NGnNavigator::Reshape::Warning Branch '%s' TList does not contain '%s' as TH1 !!!",
639 key.c_str(), name.c_str());
644 if (TMath::IsNaN(hProjTmp->GetEntries()) || TMath::IsNaN(hProjTmp->GetSumOfWeights())) {
645 NLogWarning(
"NGnNavigator::Reshape: Branch '%s' '%s' histogram is nan !!!", key.c_str(),
652 "[L%d] Histogram name='%s' title='%s' for branch '%s' storing with indexInProj=%d, entries=%.0f",
653 level, name.c_str(), hProjTmp->GetTitle(), key.c_str(), indexInProj, hProjTmp->GetEntries());
665 TH1 * hClone = (TH1 *)hProjTmp->Clone();
666 hClone->SetDirectory(
nullptr);
667 current->
SetObject(name, hClone, indexInProj);
669 if (isValid ==
false) {
670 NLogTrace(
"NGnNavigator::Reshape::Warning: Branch '%s' TList does not contain any valid histograms !!!",
675 else if (className.BeginsWith(
"Ndmspc::NParameters")) {
679 TH1 * hParams = parameters->
GetHisto();
682 NLogTrace(
"[L%d] Branch '%s' Point contains '_params' histogram with %.0f entries ...", level,
683 key.c_str(), hParams->GetEntries());
685 for (
int b = 1; b <= hParams->GetNbinsX(); b++) {
687 std::string binLabel = hParams->GetXaxis()->GetBinLabel(b);
688 double binValue = hParams->GetBinContent(b);
689 double binError = hParams->GetBinError(b);
690 NLogTrace(
"[L%d] Bin %d[%s] = %e indexInProj=%d", level, b, binLabel.c_str(), binValue,
704 NLogTrace(
"[L%d] Stored parameter '%s' = %e +/- %e at indexInProj=%d", level, binLabel.c_str(),
705 binValue, binError, indexInProj);
710 NLogWarning(
"NGnNavigator::Reshape: Branch '%s' Point parameters object is null !!!", key.c_str());
714 NLogWarning(
"NGnNavigator::Reshape: Branch '%s' has unsupported class '%s' !!! Skipping ...", key.c_str(),
724 current->
SetChild(currentChild, indexInProj);
726 Reshape(binningDef, levels, level + 1, rangesTmp, rangesBaseTmp, currentChild);
728 executorBin.
Execute(loop_task_bin);
731 NLogTrace(
"NGnNavigator::Reshape: Reached the end of levels, level=%d", level);
732 std::vector<std::vector<int>> rangesEmpty;
738 NLogTrace(
"NGnNavigator::Reshape: =========== Reshaping navigator for level %d DONE ================", level);
741 NLogInfo(
"NGnNavigator::Reshape: Reshaping navigator DONE.");
743 for (
size_t l = 0; l < levels.size(); l++) {
744 std::string axesStr =
"";
745 for (
auto & a : levels[l]) {
746 TAxis * axis = binningDef->
GetContent()->GetAxis(a);
747 axesStr += TString::Format(
"%d('%s') ", a, axis->GetName()).Data();
749 NLogInfo(
" Level %zu axes: %s", l, axesStr.c_str());
843 if (obj ==
nullptr) {
844 NLogError(
"NGnNavigator::ExportJson: Object is nullptr !!!");
854 NLogError(
"NGnNavigator::ExportJson: Projection is nullptr !!!");
865 TString hJsonStr = TBufferJSON::ConvertToJSON(h);
866 j = json::parse(hJsonStr.Data());
868 double entries = 0.0;
870 if (objectNames.empty()) {
873 bool isValid =
false;
876 for (
size_t i = 0; i < val.size(); i++) {
877 TObject * objContent = val[i];
881 std::string className = objContent ? objContent->ClassName() :
"";
882 if (className.empty()) {
883 NLogWarning(
"NGnNavigator::ExportJson: Object %s has empty class name", key.c_str());
887 className = className.substr(0, 3);
899 if (isValid) objectNames.push_back(key);
903 NLogDebug(
"NGnNavigator::ExportJson: Exporting selected objects: %s",
NUtils::GetCoordsString(objectNames).c_str());
907 for (
const auto & name : objectNames) {
908 NLogTrace(
"NGnNavigator::ExportJson: Included object name: '%s'", name.c_str());
913 NLogTrace(
"NGnNavigator::ExportJson: Processing object '%s' with %zu entries ...", key.c_str(), val.size());
915 if (std::find(objectNames.begin(), objectNames.end(), key) == objectNames.end()) {
916 NLogDebug(
"NGnNavigator::ExportJson: Skipping object '%s' ...", key.c_str());
920 double min = std::numeric_limits<double>::max();
921 double max = -std::numeric_limits<double>::max();
924 for (
size_t i = 0; i < val.size(); i++) {
925 TObject * objContent = val[i];
929 TH1 * hist =
dynamic_cast<TH1 *
>(objContent);
932 TString histJsonStr = TBufferJSON::ConvertToJSON(hist);
933 json objJson = json::parse(histJsonStr.Data());
934 double objMin, objMax;
936 min = TMath::Min(min, objMin);
937 max = TMath::Max(max, objMax);
938 entries = hist->GetEntries();
939 j[
"fArray"][i] = entries;
941 j[
"children"][key].push_back(objJson);
944 j[
"children"][key].push_back(
nullptr);
948 NLogWarning(
"NGnNavigator::ExportJson: Object %s at index %zu is not a TH1, skipping.", key.c_str(), i);
950 j[
"children"][key].push_back(
nullptr);
955 j[
"children"][key].push_back(
nullptr);
961 double min = std::numeric_limits<double>::max();
962 double max = -std::numeric_limits<double>::max();
965 for (
size_t i = 0; i < val.size(); i++) {
966 double param = val[i];
967 double paramError = 0.0;
969 if (i < val.size()) {
974 NLogWarning(
"NGnNavigator::ExportJson: Exception in GetParameterError for key %s index %zu", key.c_str(), i);
978 if (!std::isnan(param) && std::fabs(param) > 1e-12) {
979 min = TMath::Min(min, param);
980 max = TMath::Max(max, param);
981 j[
"fArrays"][key][
"values"][i] = param;
982 j[
"fArrays"][key][
"errors"][i] = TMath::Power(paramError, 2);
985 j[
"fArrays"][key][
"values"][i] = 0.0;
986 j[
"fArrays"][key][
"errors"][i] = 0.0;
990 if (key.compare(
"mass") == 0) {
998 double margin = 0.05 * (max - min);
1001 j[
"fArrays"][key][
"min"] = min;
1002 j[
"fArrays"][key][
"max"] = max;
1008 double min = std::numeric_limits<double>::max();
1009 double max = -std::numeric_limits<double>::max();
1010 std::vector<double> tmpContent;
1012 std::map<std::string, double> paramMinGlobal;
1013 std::map<std::string, double> paramMaxGlobal;
1014 bool firstChild =
true;
1017 if (child !=
nullptr) {
1022 NLogWarning(
"NGnNavigator::ExportJson: Exception in recursive ExportToJson for child.");
1026 if (childJson.contains(
"fArrays")) {
1027 for (
auto & [param, arr] : childJson[
"fArrays"].items()) {
1028 if (arr.contains(
"min") && arr.contains(
"max")) {
1029 double cmin = arr[
"min"].get<
double>();
1030 double cmax = arr[
"max"].get<
double>();
1031 if (firstChild || paramMinGlobal.find(param) == paramMinGlobal.end()) {
1032 paramMinGlobal[param] = cmin;
1033 paramMaxGlobal[param] = cmax;
1036 paramMinGlobal[param] = std::min(paramMinGlobal[param], cmin);
1037 paramMaxGlobal[param] = std::max(paramMaxGlobal[param], cmax);
1044 j[
"children"][
"content"].push_back(childJson);
1048 if (!paramMinGlobal.empty()) {
1049 for (
const auto & [param, minVal] : paramMinGlobal) {
1050 j[
"fArrays"][param][
"min"] = minVal;
1051 j[
"fArrays"][param][
"max"] = paramMaxGlobal[param];
1055 bool hasContent =
false;
1056 for (
auto & c : j[
"children"][
"content"]) {
1064 j[
"children"].erase(
"content");
1072 j[
"ndmspc"][
"content"][
"fMinimum"] = min;
1073 j[
"ndmspc"][
"content"][
"fMaximum"] = max;
1079 for (
const auto & child : j[
"children"][
"content"]) {
1081 if (child ==
nullptr || child.is_null()) {
1087 if (child.contains(
"ndmspc")) {
1090 double max = -std::numeric_limits<double>::max();
1092 for (
auto & [key, value] : child[
"ndmspc"].items()) {
1093 if (value.is_object()) {
1096 max = TMath::Max(max, value[
"fMaximum"].get<double>());
1099 j[
"fArray"][i] = max;
1105 if (j[
"children"][
"content"].is_null()) j[
"children"].erase(
"content");
1322 Double_t x_pad = gPad->AbsPixeltoX(px);
1323 Double_t y_pad = gPad->AbsPixeltoY(py);
1326 Double_t x_user = gPad->PadtoX(x_pad);
1327 Double_t y_user = gPad->PadtoY(y_pad);
1329 size_t bin =
fProjection->FindBin(x_user, y_user);
1331 TVirtualPad * originalPad = gPad;
1334 bool isActionTriggered = (
event ==
fTrigger);
1337 isActionTriggered = isActionTriggered && (isBinChanged ||
event == kButton1Down);
1339 if (isActionTriggered) {
1340 Int_t binx, biny, binz;
1342 Double_t content =
fProjection->GetBinContent(bin);
1343 NLogDebug(
"NGnNavigator::ExecuteEvent: [%s] Mouse trigger on bin=[%d, %d] at px=[%f, %f] with content: %f "
1344 "level=%d nLevels=%d",
1345 gPad->GetName(), binx, biny, x_user, y_user, content,
fLevel,
fNLevels);
1347 int nDimensions =
fGnTree->GetBinning()->GetDefinition()->GetContent()->GetNdimensions();
1351 if (nDimensions == 1) {
1355 NLogTrace(
"NGnNavigator::ExecuteEvent: Index in histogram: %d level=%d", index,
fLevel);
1357 TCanvas * cObject = (TCanvas *)gROOT->GetListOfCanvases()->FindObject(
"cObject");
1359 NLogTrace(
"NGnNavigator::ExecuteEvent: [%s]Child object '%p' found at index %d", gPad->GetName(),
1362 gPad = originalPad->GetMother();
1363 TVirtualPad * pad = gPad->cd(
fLevel + 1 + 1);
1368 hProj->SetStats(kFALSE);
1369 hProj->SetMinimum(0);
1370 hProj->Draw(
"text colz");
1380 latex.SetTextAlign(22);
1381 latex.SetTextSize(0.05);
1382 latex.DrawLatex(0.5, 0.5,
"Select bottom pad to see projection");
1390 NLogTrace(
"NGnNavigator::ExecuteEvent: No child object found at index %d", index);
1392 TH1 * hProj = (TH1 *)
GetObject(objName, index);
1393 if (hProj ==
nullptr) {
1394 NLogError(
"NGnNavigator::ExecuteEvent: No histogram found for index %d", index);
1398 if (cObject ==
nullptr) {
1399 cObject =
new TCanvas(
"cObject",
"cObject", 800, 600);
1404 if (hProj->GetXaxis()->IsAlphanumeric()) {
1405 TPaveText * pt =
new TPaveText(0.15, 0.15, 0.85, 0.85);
1406 for (Int_t binx = 1; binx <= hProj->GetNbinsX(); ++binx) {
1407 std::string name = hProj->GetXaxis()->GetBinLabel(binx);
1408 std::string value = TString::Format(
"%.3f", hProj->GetBinContent(binx)).Data();
1409 std::string t = TString::Format(
"%s: %s", name.c_str(), value.c_str()).Data();
1411 pt->AddText(t.c_str());
1421 gPad->ModifiedUpdate();
1424 if (event == kMouseMotion) {
1428 Int_t binx, biny, binz;
1430 NLogTrace(
"[%s] Mouse hover on bin[%d, %d] at px[%f, %f] level=%d nLevels=%d", gPad->GetName(), binx, biny,
1434 NLogTrace(
"[%s] Setting point for level %d %s", gPad->GetName(),
fLevel,
fProjection->GetTitle());
1733 const std::string & minmaxMode, Option_t * option)
const
1739 if (parameterName.empty()) {
1740 NLogError(
"NGnNavigator::DrawSpectra: Parameter name is empty");
1746 NLogError(
"NGnNavigator::DrawSpectra: Parameter name '%s' not found in fParameterContentMap",
1747 parameterName.c_str());
1750 Int_t screenWidth = gClient->GetDisplayWidth();
1751 Int_t screenHeight = gClient->GetDisplayHeight();
1754 TCanvas * c =
nullptr;
1756 constexpr double canvasScale = 0.2;
1757 Int_t canvasWidth =
static_cast<Int_t
>(screenWidth * canvasScale);
1758 Int_t canvasHeight =
static_cast<Int_t
>(screenHeight * canvasScale);
1760 if (canvasWidth < 800) canvasWidth = 800;
1761 if (canvasHeight < 600) canvasHeight = 600;
1763 NLogTrace(
"Screen size: %dx%d", screenWidth, screenHeight);
1766 THnSparse * hnsObjContent = binningDef->
GetContent();
1767 hnsObjContent->Print(
"all");
1768 std::vector<std::vector<int>> projections;
1769 if (projIds.empty()) {
1771 std::iota(projIds.begin(), projIds.end(), 0);
1775 projections.push_back(projIds);
1778 if (projections.empty()) {
1779 NLogError(
"NGnNavigator::DrawSpectra: No projections found");
1782 if (projections[0].size() > 3) {
1783 NLogError(
"NGnNavigator::DrawSpectra: Too many projection dimensions: %zu (max 3)", projections[0].size());
1787 TList * outputList =
new TList();
1788 for (
const auto & proj : projections) {
1793 TH1 * hParameterProjection = (TH1 *)
fProjection->Clone(
"hParameterProjection");
1795 hParameterProjection->SetDirectory(
nullptr);
1799 hParameterProjection->SetContent(
GetParameters(parameterName).data());
1809 THnSparse * hsParam = THnSparse::CreateSparse(parameterName.c_str(), parameterName.c_str(), hParameterProjection);
1812 int nDimensions = hParameterProjection->GetDimension();
1813 for (
int i = 0; i < nDimensions; i++) {
1814 TAxis * axis =
nullptr;
1816 axis = hParameterProjection->GetXaxis();
1818 axis = hParameterProjection->GetYaxis();
1820 axis = hParameterProjection->GetZaxis();
1822 hsParam->GetAxis(i)->SetName(axis->GetName());
1823 hsParam->GetAxis(i)->SetTitle(axis->GetTitle());
1824 if (axis->IsVariableBinSize()) {
1825 hsParam->GetAxis(i)->Set(axis->GetNbins(), axis->GetXbins()->GetArray());
1827 if (axis->IsAlphanumeric()) {
1828 for (
int j = 1; j <= axis->GetNbins(); j++) {
1829 const char * label = axis->GetBinLabel(j);
1830 hsParam->GetAxis(i)->SetBinLabel(j, label);
1835 delete hParameterProjection;
1837 std::vector<int> dims;
1841 for (
auto &
id : proj) {
1842 dims.push_back(currentLevels[
id]);
1845 if (dims.size() > 3) {
1846 NLogError(
"NGnNavigator::DrawSpectra: Too many projection dimensions: %zu (max 3)", dims.size());
1857 std::vector<std::set<int>> dimsResults(3);
1859 std::vector<std::vector<int>> ranges;
1861 Int_t * p =
new Int_t[hsParam->GetNdimensions()];
1862 Long64_t linBin = 0;
1863 std::unique_ptr<ROOT::Internal::THnBaseBinIter> iter{hsParam->CreateIter(
true )};
1864 while ((linBin = iter->Next()) >= 0) {
1867 hsParam->GetBinContent(linBin, p);
1877 dimsResults[0].insert(p[proj[0]]);
1878 if (dims.size() > 1) dimsResults[1].insert(p[proj[1]]);
1879 if (dims.size() > 2) dimsResults[2].insert(p[proj[2]]);
1890 if (!gROOT->IsBatch()) {
1901 int nPads = dims.size() > 2 ? dimsResults[2].size() : 1;
1903 std::vector<std::string> projNames;
1905 NLogTrace(
"Projection dims: %d %d %d", dims[0], dims.size() > 1 ? dims[1] : -1, dims.size() > 2 ? dims[2] : -1);
1906 projNames.push_back(hnsObjContent->GetAxis(dims[0])->GetName());
1907 if (dims.size() > 1) projNames.push_back(hnsObjContent->GetAxis(dims[1])->GetName());
1908 if (dims.size() > 2) projNames.push_back(hnsObjContent->GetAxis(dims[2])->GetName());
1914 std::string canvasName = Form(
"c_%s", posfix.c_str());
1915 NLogTrace(
"Creating canvas '%s' with size %dx%d", canvasName.c_str(), canvasWidth, canvasHeight);
1918 TCanvas * existingCanvas = (TCanvas *)gROOT->GetListOfCanvases()->FindObject(canvasName.c_str());
1919 if (existingCanvas) {
1920 NLogTrace(
"Deleting existing canvas '%s'", canvasName.c_str());
1921 delete existingCanvas;
1924 c =
new TCanvas(canvasName.c_str(), canvasName.c_str(), canvasWidth, canvasHeight);
1925 c->SetBit(kMustCleanup, kFALSE);
1929 TList * stackList =
new TList();
1931 for (
int iPad = 0; iPad < nPads; iPad++) {
1934 std::string stackName = Form(
"hStack_%s_%d", posfix.c_str(), iPad);
1935 std::string stackTitle = parameterName +
" : ";
1936 stackTitle += projNames[0];
1937 stackTitle += projNames.size() > 1 ?
" vs " + projNames[1] :
"";
1938 if (proj.size() > 2) {
1942 auto it = std::next(dimsResults[2].begin(), iPad);
1943 if (it != dimsResults[2].end()) {
1952 TAxis * aPad = hsParam->GetAxis(proj[2]);
1953 if (aPad->IsAlphanumeric()) {
1954 stackTitle += projNames.size() > 2 ?
" for " + projNames[2] +
" [" + aPad->GetBinLabel(p[proj[2]]) +
"]" :
"";
1957 double binLowEdge = aPad->GetBinLowEdge(p[proj[2]]);
1958 double binUpEdge = aPad->GetBinUpEdge(p[proj[2]]);
1960 projNames.size() > 2 ?
" for " + projNames[2] +
" " + Form(
" [%.3f,%.3f]", binLowEdge, binUpEdge) :
"";
1963 NLogTrace(
"Creating stack '%s' with title '%s'", stackName.c_str(), stackTitle.c_str());
1971 THStack * hStack =
new THStack(stackName.c_str(), stackTitle.c_str());
1972 hStack->SetBit(kMustCleanup, kFALSE);
1974 int nStacks = proj.size() > 1 ? dimsResults[1].size() : 1;
1975 double stackMin = std::numeric_limits<double>::max();
1976 double stackMax = std::numeric_limits<double>::lowest();
1978 std::string mode = (minmaxMode ==
"VE" || minmaxMode ==
"V" || minmaxMode ==
"D") ? minmaxMode :
"V";
1979 for (
int iStack = 0; iStack < nStacks; iStack++) {
1981 if (proj.size() > 1) {
1982 auto it = std::next(dimsResults[1].begin(), iStack);
1983 if (it != dimsResults[1].end()) {
1989 std::vector<std::vector<int>> rangesTmp;
1990 if (proj.size() > 2) rangesTmp.push_back({proj[2], p[proj[2]], p[proj[2]]});
1991 if (proj.size() > 1) rangesTmp.push_back({proj[1], p[proj[1]], p[proj[1]]});
1994 if (!hProj || hProj->GetEntries() == 0) {
1995 NLogError(
"Failed to project THnSparse for stack %d with projection IDs: %s", iStack,
2000 if (proj.size() > 1) {
2001 TAxis * aStack = hsParam->GetAxis(proj[1]);
2002 if (aStack->IsAlphanumeric()) {
2003 std::string label = aStack->GetBinLabel(p[proj[1]]);
2004 hProj->SetName(Form(
"%s_%s", aStack->GetName(), label.c_str()));
2005 hProj->SetTitle(Form(
"%s [%s]", aStack->GetName(), label.c_str()));
2008 double binLowEdge = aStack->GetBinLowEdge(p[proj[1]]);
2009 double binUpEdge = aStack->GetBinUpEdge(p[proj[1]]);
2010 hProj->SetName(Form(
"%s_%.3f_%.3f", aStack->GetName(), binLowEdge, binUpEdge));
2011 hProj->SetTitle(Form(
"%s [%.3f,%.3f]", aStack->GetName(), binLowEdge, binUpEdge));
2016 for (
int bin = 1; bin <= hProj->GetNbinsX(); ++bin) {
2017 double val = hProj->GetBinContent(bin);
2018 double err = hProj->GetBinError(bin);
2020 if (stackMin > val - err) stackMin = val - err;
2021 if (stackMax < val + err) stackMax = val + err;
2023 else if (mode ==
"V") {
2024 if (stackMin > val) stackMin = val;
2025 if (stackMax < val) stackMax = val;
2029 hProj->SetMarkerStyle(20);
2030 hProj->SetMarkerColor(iStack + 1);
2032 TH1 * hProjClone = (TH1 *)hProj->Clone();
2035 hProjClone->SetDirectory(
nullptr);
2036 hStack->Add(hProjClone);
2042 hStack->SetMinimum(-1111);
2043 hStack->SetMaximum(-1111);
2047 if (minmax.size() > 0) {
2048 if (minmax.size() == 2) {
2049 stackMin = minmax[0];
2050 stackMax = minmax[1];
2052 else if (minmax.size() == 1) {
2054 double percent = minmax[0];
2055 double center = 0.5 * (stackMax + stackMin);
2056 double halfRange = 0.5 * (stackMax - stackMin);
2057 double margin = percent * halfRange;
2058 stackMin = center - (halfRange + margin);
2059 stackMax = center + (halfRange + margin);
2064 if (stackMin == stackMax) {
2065 if (stackMin == 0.0) {
2074 hStack->SetMinimum(stackMin);
2075 hStack->SetMaximum(stackMax);
2078 if (hStack->GetNhists() == 0) {
2079 NLogError(
"No histograms were added to the stack for pad %d with projection IDs: %s", iPad,
2092 stackList->Add(hStack);
2099 if (stackList->GetEntries() > 0) {
2100 nPads = stackList->GetEntries();
2101 c->DivideSquare(nPads);
2102 for (
int iPad = 0; iPad < nPads; iPad++) {
2104 THStack * hStack = (THStack *)stackList->At(iPad);
2106 hStack->Draw(
"nostack E");
2107 NLogTrace(
"Drawing stack with option: %s in pad %d %d",
"nostack E", iPad + 1, hStack->GetNhists());
2108 hStack->GetHistogram()->GetXaxis()->SetTitle(projNames[0].c_str());
2109 hStack->GetHistogram()->GetYaxis()->SetTitle(parameterName.c_str());
2110 if (dims.size() > 1) gPad->BuildLegend(0.75, 0.75, 0.95, 0.95,
"");
2111 c->ModifiedUpdate();