From 74dee977efcc9b6eb77b2a498b00e52ea310ed01 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 22 Apr 2025 12:46:54 +0200 Subject: [PATCH 01/20] [hist] Implement AutoZoom of TH1/TH2/TH3/TAxis to filled range Fixes https://github.com/root-project/root/issues/14538 --- core/base/inc/TVirtualPad.h | 1 + hist/hist/inc/TAxis.h | 1 + hist/hist/inc/TH1.h | 7 +- hist/hist/src/TAxis.cxx | 85 +++++++++++++++++ hist/hist/src/TH1.cxx | 182 +++++++++++++++++++++++++++++++++++- 5 files changed, 269 insertions(+), 7 deletions(-) diff --git a/core/base/inc/TVirtualPad.h b/core/base/inc/TVirtualPad.h index b51e86c9d3d2f..b7d71263ab713 100644 --- a/core/base/inc/TVirtualPad.h +++ b/core/base/inc/TVirtualPad.h @@ -95,6 +95,7 @@ class TVirtualPad : public TObject, public TAttLine, public TAttFill, virtual void DrawClassObject(const TObject *obj, Option_t *option="") = 0; virtual TH1F *DrawFrame(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *title="") = 0; virtual void ExecuteEventAxis(Int_t event, Int_t px, Int_t py, TAxis *axis) = 0; + virtual void AutoZoomed() { Emit("AutoZoomed()"); } // *SIGNAL* virtual void UnZoomed() { Emit("UnZoomed()"); } // *SIGNAL* virtual Short_t GetBorderMode() const = 0; virtual Short_t GetBorderSize() const = 0; diff --git a/hist/hist/inc/TAxis.h b/hist/hist/inc/TAxis.h index 69c8b59806892..ed88c8cbe2267 100644 --- a/hist/hist/inc/TAxis.h +++ b/hist/hist/inc/TAxis.h @@ -173,6 +173,7 @@ class TAxis : public TNamed, public TAttAxis { virtual void SetTimeDisplay(Int_t value) {fTimeDisplay = (value != 0);} // *TOGGLE* virtual void SetTimeFormat(const char *format=""); // *MENU* virtual void SetTimeOffset(Double_t toffset, Option_t *option="local"); + virtual void AutoZoom(); // *MENU* virtual void UnZoom(); // *MENU* virtual void ZoomOut(Double_t factor=0, Double_t offset=0); // *MENU* diff --git a/hist/hist/inc/TH1.h b/hist/hist/inc/TH1.h index afdddd087e055..635de2442a3c3 100644 --- a/hist/hist/inc/TH1.h +++ b/hist/hist/inc/TH1.h @@ -97,7 +97,7 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { friend class TH1Merger; protected: - Int_t fNcells; ///< Number of bins(1D), cells (2D) +U/Overflows + Int_t fNcells; ///< Number of bins (1D) / total of cells (2D) / voxels (3D) +Under/Overflows TAxis fXaxis; ///< X axis descriptor TAxis fYaxis; ///< Y axis descriptor TAxis fZaxis; ///< Z axis descriptor @@ -209,6 +209,8 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { virtual void AddBinContent(Int_t bin, Double_t w) = 0; static void AddDirectory(Bool_t add=kTRUE); static Bool_t AddDirectoryStatus(); + virtual void AutoZoom(); // *MENU* + virtual void UnZoom(); // *MENU* void Browse(TBrowser *b) override; virtual Bool_t CanExtendAllAxes() const; virtual Double_t Chi2Test(const TH1* h2, Option_t *option = "UU", Double_t *res = nullptr) const; @@ -323,10 +325,11 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { virtual Int_t GetQuantiles(Int_t n, Double_t *xp, const Double_t *p = nullptr); virtual Double_t GetRandom(TRandom * rng = nullptr) const; + void GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const bool includeUnderOverflow) const; virtual void GetStats(Double_t *stats) const; virtual Double_t GetStdDev(Int_t axis=1) const; virtual Double_t GetStdDevError(Int_t axis=1) const; - Double_t GetSumOfAllWeights(const bool includeOverflow) const; + Double_t GetSumOfAllWeights(const bool includeUnderOverflow) const; /// Return the sum of weights across all bins excluding under/overflows. /// \see TH1::GetSumOfAllWeights() virtual Double_t GetSumOfWeights() const { return GetSumOfAllWeights(false); } diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index dcefcf4117a7f..41aa74452549e 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1328,6 +1328,91 @@ void TAxis::UnZoom() gPad->UnZoomed(); } +//////////////////////////////////////////////////////////////////////////////// +/// Automatically zoom the current axis to the range of the parent histogram +/// filled with non-zero contents (weights or errors) +/// \note For the bin content axis (yaxis) of a TH1 or (zaxis) of a TH2, +/// UnZoom is called instead. TH3, the PaletteAxis does not implement AutoZoom nor UnZoom + +void TAxis::AutoZoom() +{ + if (!gPad) { + Warning("TAxis::AutoZoom","Cannot AutoZoom if gPad does not exist. Did you mean to draw the TAxis first?"); + return; + } + gPad->SetView(); + if (!GetParent()) { + Warning("TAxis::AutoZoom","Cannot AutoZoom if parent does not exist. Did you mean to draw the TAxis first?"); + return; + } + auto dim = strstr(GetName(), "xaxis") ? 0 : strstr(GetName(), "yaxis") ? 1 : strstr(GetName(), "zaxis") ? 2 : -1; + TH1 *hobj1 = static_cast(GetParent()); + Int_t first = -1, last = -1; + if (hobj1 && !strstr(hobj1->GetName(), "hframe")) { + auto ndims = hobj1->GetDimension(); + // Sanity checks + if (dim == 0) { + if (ndims != 1 && ndims != 2 && ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom xaxis if TH has %d dimension(s)", ndims); + return; + } + } else if (dim == 1) { + if (ndims == 1) { + UnZoom(); // For a TH1, it acts as an AutoZoom of the yaxis (bin content axis) + return; + } + if (ndims != 2 && ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom yaxis if TH has %d dimension(s)", ndims); + return; + } + } else if (dim == 2) { + if (ndims == 2) { + UnZoom(); // For a TH2, it acts as an AutoZoom of the zaxis (bin content axis) + return; + } + if (ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom zaxis if TH has %d dimension(s)", ndims); + return; + } + } + + hobj1->GetRangeOfFilledWeights(dim, first, last, false); + SetRange(first, last); + } + if (first == -1 && last == -1) { + // Must autozoom all histograms in the pad + Double_t globalMin = DBL_MAX; + Double_t globalMax = DBL_MIN; + TIter next(gPad->GetListOfPrimitives()); + while (TObject *obj= next()) { + if (!obj || !obj->InheritsFrom(TH1::Class())) + continue; + TH1 *hobj = static_cast(obj); + if (!obj || !obj->InheritsFrom(TH1::Class())) + continue; + if (!strstr(hobj->GetName(), "hframe")) { + hobj->GetRangeOfFilledWeights(dim, first, last, false); + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); + globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); + } + } + } + while (TObject *obj = next()) { + if (!obj || !obj->InheritsFrom(TH1::Class())) + continue; + TH1 *hobj = static_cast(obj); + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + ax->SetRangeUser(globalMin, globalMax); + } + } + } + + gPad->AutoZoomed(); +} + //////////////////////////////////////////////////////////////////////////////// /// Zoom out by a factor of 'factor' (default =2) /// uses previous zoom factor by default diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index d252261cc3bd2..eacbfcbda3d84 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -744,6 +744,54 @@ Bool_t TH1::AddDirectoryStatus() return fgAddDirectory; } +//////////////////////////////////////////////////////////////////////////////// +/// Autozoom histogram in all their axes +/// \see TAxis::AutoZoom + +void TH1::AutoZoom() +{ + const auto ndims = GetDimension(); + if (ndims < 1 || ndims > 3) + return; + // First apply autozoom in pure coordinate axis + if (ndims >= 1) + GetXaxis()->AutoZoom(); + if (ndims >= 2) + GetYaxis()->AutoZoom(); + if (ndims >= 3) + GetZaxis()->AutoZoom(); + // Now apply autozoom in the bin content axis if it's a TH1 or TH2 + if (ndims == 1) + GetYaxis()->AutoZoom(); + else if (ndims == 2) + GetZaxis()->AutoZoom(); + // For 3D, there is no UnZoom or AutoZoom implemented for TPaletteAxis +} + +//////////////////////////////////////////////////////////////////////////////// +/// Unzoom histogram in all their axes +/// \see TAxis::UnZoom + +void TH1::UnZoom() +{ + const auto ndims = GetDimension(); + if (ndims < 1 || ndims > 3) + return; + // First apply Unzoom in pure coordinate axis + if (ndims >= 1) + GetXaxis()->UnZoom(); + if (ndims >= 2) + GetYaxis()->UnZoom(); + if (ndims >= 3) + GetZaxis()->UnZoom(); + // Now apply unzoom in the bin content axis if it's a TH1 or TH2 + if (ndims == 1) + GetYaxis()->UnZoom(); + else if (ndims == 2) + GetZaxis()->UnZoom(); + // For 3D, there is no UnZoom or AutoZoom implemented for TPaletteAxis +} + //////////////////////////////////////////////////////////////////////////////// /// Browse the Histogram object. @@ -7904,19 +7952,143 @@ void TH1::ResetStats() if (fSumw2.fN > 0 && fTsumw > 0 && stats[1] > 0 ) fEntries = stats[0]*stats[0]/ stats[1]; } +void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const bool includeUnderOverflow) const +{ + if (fBuffer) const_cast(this)->BufferEmpty(); + + const Int_t start = (includeUnderOverflow ? 0 : 1); + const Int_t lastX = fXaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastY = fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastZ = fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + + const auto ndims = GetDimension(); + R__ASSERT(dim == 0 || dim == 1 || dim == 2); + if (ndims == 1) { + R__ASSERT(dim == 0); + } else if (ndims == 2) { + R__ASSERT(dim == 0 || dim == 1); + } else if (ndims == 3) { + R__ASSERT(dim == 0 || dim == 1 || dim == 2); + } + + if (dim == 0) { + first = start; + for(Int_t binx = start; binx <= lastX; binx++) { + for(auto biny = start; biny <= lastY; biny++) { + for(auto binz = start; binz <= lastZ; binz++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + first = binx; + // Break: + binx = lastX; + biny = lastY; + binz = lastZ; + } + } + } + } + last = lastX; + for(Int_t binx = lastX; binx >= start; binx--) { + for(auto biny = start; biny <= lastY; biny++) { + for(auto binz = start; binz <= lastZ; binz++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + last = binx; + // Break: + binx = start; + biny = lastY; + binz = lastZ; + } + } + } + } + return; + } else if (dim == 1) { + first = start; + for(auto biny = start; biny <= lastY; biny++) { + for(Int_t binx = start; binx <= lastX; binx++) { + for(auto binz = start; binz <= lastZ; binz++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + first = biny; + // Break: + binx = lastX; + biny = lastY; + binz = lastZ; + } + } + } + } + last = lastY; + for(Int_t biny = lastY; biny >= start; biny--) { + for(auto binx = start; binx <= lastX; binx++) { + for(auto binz = start; binz <= lastZ; binz++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + last = biny; + // Break: + binx = lastX; + biny = start; + binz = lastZ; + } + } + } + } + return; + } else if (dim == 2) { + first = start; + for(auto binz = start; binz <= lastZ; binz++) { + for(Int_t binx = start; binx <= lastX; binx++) { + for(auto biny = start; biny <= lastY; biny++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + first = biny; + // Break: + binx = lastX; + biny = lastY; + binz = lastZ; + } + } + } + } + last = lastZ; + for(Int_t binz = lastZ; binz >= start; binz--) { + for(auto binx = start; binx <= lastX; binx++) { + for(auto biny = start; biny <= lastY; biny++) { + auto bin = GetBin(binx, biny, binz); + if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) + { + last = binz; + // Break: + binx = lastX; + biny = lastY; + binz = start; + } + } + } + } + return; + } +} + //////////////////////////////////////////////////////////////////////////////// /// Return the sum of all weights /// \param includeOverflow true to include under/overflows bins, false to exclude those. /// \note Different from TH1::GetSumOfWeights, that always excludes those -Double_t TH1::GetSumOfAllWeights(const bool includeOverflow) const +Double_t TH1::GetSumOfAllWeights(const bool includeUnderOverflow) const { if (fBuffer) const_cast(this)->BufferEmpty(); - const Int_t start = (includeOverflow ? 0 : 1); - const Int_t lastX = fXaxis.GetNbins() + (includeOverflow ? 1 : 0); - const Int_t lastY = fYaxis.GetNbins() + (includeOverflow ? 1 : 0); - const Int_t lastZ = fZaxis.GetNbins() + (includeOverflow ? 1 : 0); + const Int_t start = (includeUnderOverflow ? 0 : 1); + const Int_t lastX = fXaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastY = fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastZ = fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); Double_t sum =0; for(auto binz = start; binz <= lastZ; binz++) { for(auto biny = start; biny <= lastY; biny++) { From e38a65df295e6f17c152a947339a8f26315b77ea Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 22 Apr 2025 15:48:22 +0200 Subject: [PATCH 02/20] [hist] remove irrelevant return as pointed out by linev --- hist/hist/src/TH1.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index eacbfcbda3d84..be12ec20b5ef7 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -8004,7 +8004,6 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } } - return; } else if (dim == 1) { first = start; for(auto biny = start; biny <= lastY; biny++) { @@ -8038,7 +8037,6 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } } - return; } else if (dim == 2) { first = start; for(auto binz = start; binz <= lastZ; binz++) { @@ -8072,7 +8070,6 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } } - return; } } From ffce7dd6c575af5ee4b0d8b08b0a9fc1506bda7f Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 22 Apr 2025 16:04:38 +0200 Subject: [PATCH 03/20] [hist] prevent spurious looping on dimensions not belonging to the derived class as found out by linev --- hist/hist/src/TH1.cxx | 67 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index be12ec20b5ef7..7cb7cad12ae95 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -7956,12 +7956,14 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co { if (fBuffer) const_cast(this)->BufferEmpty(); - const Int_t start = (includeUnderOverflow ? 0 : 1); + const auto ndims = GetDimension(); + const Int_t startX = (includeUnderOverflow ? 0 : 1); + const Int_t startY = ndims < 2 ? 1 : startX; + const Int_t startZ = ndims < 3 ? 1 : startX; const Int_t lastX = fXaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); - const Int_t lastY = fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); - const Int_t lastZ = fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastY = ndims < 2 ? 1 : fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastZ = ndims < 3 ? 1 : fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); - const auto ndims = GetDimension(); R__ASSERT(dim == 0 || dim == 1 || dim == 2); if (ndims == 1) { R__ASSERT(dim == 0); @@ -7972,10 +7974,10 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } if (dim == 0) { - first = start; - for(Int_t binx = start; binx <= lastX; binx++) { - for(auto biny = start; biny <= lastY; biny++) { - for(auto binz = start; binz <= lastZ; binz++) { + first = startX; + for(Int_t binx = startX; binx <= lastX; binx++) { + for(auto biny = startY; biny <= lastY; biny++) { + for(auto binz = startZ; binz <= lastZ; binz++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { @@ -7989,15 +7991,15 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } last = lastX; - for(Int_t binx = lastX; binx >= start; binx--) { - for(auto biny = start; biny <= lastY; biny++) { - for(auto binz = start; binz <= lastZ; binz++) { + for(Int_t binx = lastX; binx >= startX; binx--) { + for(auto biny = startY; biny <= lastY; biny++) { + for(auto binz = startZ; binz <= lastZ; binz++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { last = binx; // Break: - binx = start; + binx = startX; biny = lastY; binz = lastZ; } @@ -8005,10 +8007,10 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } } else if (dim == 1) { - first = start; - for(auto biny = start; biny <= lastY; biny++) { - for(Int_t binx = start; binx <= lastX; binx++) { - for(auto binz = start; binz <= lastZ; binz++) { + first = startY; + for(auto biny = startY; biny <= lastY; biny++) { + for(Int_t binx = startX; binx <= lastX; binx++) { + for(auto binz = startZ; binz <= lastZ; binz++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { @@ -8022,26 +8024,26 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } last = lastY; - for(Int_t biny = lastY; biny >= start; biny--) { - for(auto binx = start; binx <= lastX; binx++) { - for(auto binz = start; binz <= lastZ; binz++) { + for(Int_t biny = lastY; biny >= startY; biny--) { + for(auto binx = startX; binx <= lastX; binx++) { + for(auto binz = startZ; binz <= lastZ; binz++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { last = biny; // Break: binx = lastX; - biny = start; + biny = startY; binz = lastZ; } } } } } else if (dim == 2) { - first = start; - for(auto binz = start; binz <= lastZ; binz++) { - for(Int_t binx = start; binx <= lastX; binx++) { - for(auto biny = start; biny <= lastY; biny++) { + first = startZ; + for(auto binz = startZ; binz <= lastZ; binz++) { + for(Int_t binx = startX; binx <= lastX; binx++) { + for(auto biny = startY; biny <= lastY; biny++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { @@ -8055,9 +8057,9 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } last = lastZ; - for(Int_t binz = lastZ; binz >= start; binz--) { - for(auto binx = start; binx <= lastX; binx++) { - for(auto biny = start; biny <= lastY; biny++) { + for(Int_t binz = lastZ; binz >= startZ; binz--) { + for(auto binx = startX; binx <= lastX; binx++) { + for(auto biny = startY; biny <= lastY; biny++) { auto bin = GetBin(binx, biny, binz); if (RetrieveBinContent(bin) != 0 || GetBinError(bin) != 0) { @@ -8065,7 +8067,7 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co // Break: binx = lastX; biny = lastY; - binz = start; + binz = startZ; } } } @@ -8082,13 +8084,14 @@ Double_t TH1::GetSumOfAllWeights(const bool includeUnderOverflow) const { if (fBuffer) const_cast(this)->BufferEmpty(); + const auto ndims = GetDimension(); const Int_t start = (includeUnderOverflow ? 0 : 1); const Int_t lastX = fXaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); - const Int_t lastY = fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); - const Int_t lastZ = fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastY = ndims < 2 ? 1 : fYaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); + const Int_t lastZ = ndims < 3 ? 1 : fZaxis.GetNbins() + (includeUnderOverflow ? 1 : 0); Double_t sum =0; - for(auto binz = start; binz <= lastZ; binz++) { - for(auto biny = start; biny <= lastY; biny++) { + for(auto binz = ndims < 3 ? 1 : start; binz <= lastZ; binz++) { + for(auto biny = ndims < 2 ? 1 : start; biny <= lastY; biny++) { for(auto binx = start; binx <= lastX; binx++) { const auto bin = GetBin(binx, biny, binz); sum += RetrieveBinContent(bin); From 01052a72a9270e13aefafbed6dcf7d993e1096d1 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 22 Apr 2025 16:07:54 +0200 Subject: [PATCH 04/20] [skip-ci] clarifying note on when this part of code is called --- hist/hist/src/TAxis.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index 41aa74452549e..07dc036814d73 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1379,7 +1379,7 @@ void TAxis::AutoZoom() hobj1->GetRangeOfFilledWeights(dim, first, last, false); SetRange(first, last); } - if (first == -1 && last == -1) { + if (first == -1 && last == -1) { // This only happens if parent histogram was missing, or if it was called "hframe" // Must autozoom all histograms in the pad Double_t globalMin = DBL_MAX; Double_t globalMax = DBL_MIN; From 539fd11c43072c1f4e70fbece72dfdec2ace1fae Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 22 Apr 2025 18:13:53 +0200 Subject: [PATCH 05/20] [hist] Split: 1 autozooms parent histogram, 1 autozooms all hists on pad --- hist/hist/inc/TAxis.h | 1 + hist/hist/src/TAxis.cxx | 132 ++++++++++++++++++++++------------------ 2 files changed, 73 insertions(+), 60 deletions(-) diff --git a/hist/hist/inc/TAxis.h b/hist/hist/inc/TAxis.h index ed88c8cbe2267..038231a6c231f 100644 --- a/hist/hist/inc/TAxis.h +++ b/hist/hist/inc/TAxis.h @@ -174,6 +174,7 @@ class TAxis : public TNamed, public TAttAxis { virtual void SetTimeFormat(const char *format=""); // *MENU* virtual void SetTimeOffset(Double_t toffset, Option_t *option="local"); virtual void AutoZoom(); // *MENU* + virtual void AutoZoomAll(); // *MENU* virtual void UnZoom(); // *MENU* virtual void ZoomOut(Double_t factor=0, Double_t offset=0); // *MENU* diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index 07dc036814d73..e113a90435f2b 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1336,11 +1336,6 @@ void TAxis::UnZoom() void TAxis::AutoZoom() { - if (!gPad) { - Warning("TAxis::AutoZoom","Cannot AutoZoom if gPad does not exist. Did you mean to draw the TAxis first?"); - return; - } - gPad->SetView(); if (!GetParent()) { Warning("TAxis::AutoZoom","Cannot AutoZoom if parent does not exist. Did you mean to draw the TAxis first?"); return; @@ -1348,65 +1343,82 @@ void TAxis::AutoZoom() auto dim = strstr(GetName(), "xaxis") ? 0 : strstr(GetName(), "yaxis") ? 1 : strstr(GetName(), "zaxis") ? 2 : -1; TH1 *hobj1 = static_cast(GetParent()); Int_t first = -1, last = -1; - if (hobj1 && !strstr(hobj1->GetName(), "hframe")) { - auto ndims = hobj1->GetDimension(); - // Sanity checks - if (dim == 0) { - if (ndims != 1 && ndims != 2 && ndims != 3) { - Warning("TAxis::AutoZoom","Cannot AutoZoom xaxis if TH has %d dimension(s)", ndims); - return; - } - } else if (dim == 1) { - if (ndims == 1) { - UnZoom(); // For a TH1, it acts as an AutoZoom of the yaxis (bin content axis) - return; - } - if (ndims != 2 && ndims != 3) { - Warning("TAxis::AutoZoom","Cannot AutoZoom yaxis if TH has %d dimension(s)", ndims); - return; - } - } else if (dim == 2) { - if (ndims == 2) { - UnZoom(); // For a TH2, it acts as an AutoZoom of the zaxis (bin content axis) - return; - } - if (ndims != 3) { - Warning("TAxis::AutoZoom","Cannot AutoZoom zaxis if TH has %d dimension(s)", ndims); - return; - } + + auto ndims = hobj1->GetDimension(); + // Sanity checks + if (dim == 0) { + if (ndims != 1 && ndims != 2 && ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom xaxis if TH has %d dimension(s)", ndims); + return; + } + } else if (dim == 1) { + if (ndims == 1) { + UnZoom(); // For a TH1, it acts as an AutoZoom of the yaxis (bin content axis) + return; + } + if (ndims != 2 && ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom yaxis if TH has %d dimension(s)", ndims); + return; + } + } else if (dim == 2) { + if (ndims == 2) { + UnZoom(); // For a TH2, it acts as an AutoZoom of the zaxis (bin content axis) + return; + } + if (ndims != 3) { + Warning("TAxis::AutoZoom","Cannot AutoZoom zaxis if TH has %d dimension(s)", ndims); + return; } + } + + hobj1->GetRangeOfFilledWeights(dim, first, last, false); + SetRange(first, last); + + if (gPad) + gPad->AutoZoomed(); +} - hobj1->GetRangeOfFilledWeights(dim, first, last, false); - SetRange(first, last); +//////////////////////////////////////////////////////////////////////////////// +/// Automatically zoom the current axis to the range of all histograms overlaid +/// in this pad and detect shared range filled with non-zero contents (weights or errors) +/// \note For the bin content axis (yaxis) of a TH1 or (zaxis) of a TH2, +/// UnZoom is called instead. TH3, the PaletteAxis does not implement AutoZoom nor UnZoom + +void TAxis::AutoZoomAll() +{ + if (!gPad) { + Warning("TAxis::AutoZoom","Cannot AutoZoom if gPad does not exist. Did you mean to draw the TAxis first?"); + return; } - if (first == -1 && last == -1) { // This only happens if parent histogram was missing, or if it was called "hframe" - // Must autozoom all histograms in the pad - Double_t globalMin = DBL_MAX; - Double_t globalMax = DBL_MIN; - TIter next(gPad->GetListOfPrimitives()); - while (TObject *obj= next()) { - if (!obj || !obj->InheritsFrom(TH1::Class())) - continue; - TH1 *hobj = static_cast(obj); - if (!obj || !obj->InheritsFrom(TH1::Class())) - continue; - if (!strstr(hobj->GetName(), "hframe")) { - hobj->GetRangeOfFilledWeights(dim, first, last, false); - TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; - if (ax) { - globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); - globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); - } - } + gPad->SetView(); + auto dim = strstr(GetName(), "xaxis") ? 0 : strstr(GetName(), "yaxis") ? 1 : strstr(GetName(), "zaxis") ? 2 : -1; + Int_t first = -1, last = -1; + + Double_t globalMin = DBL_MAX; + Double_t globalMax = DBL_MIN; + TIter next(gPad->GetListOfPrimitives()); + while (TObject *obj= next()) { + if (!obj || !obj->InheritsFrom(TH1::Class())) + continue; + TH1 *hobj = static_cast(obj); + if (dim > hobj->GetDimension()) + continue; + hobj->GetRangeOfFilledWeights(dim, first, last, false); + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); + globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); } - while (TObject *obj = next()) { - if (!obj || !obj->InheritsFrom(TH1::Class())) - continue; - TH1 *hobj = static_cast(obj); - TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; - if (ax) { - ax->SetRangeUser(globalMin, globalMax); - } + } + while (TObject *obj = next()) { + if (!obj || !obj->InheritsFrom(TH1::Class())) + continue; + TH1 *hobj = static_cast(obj); + if (dim > hobj->GetDimension()) + continue; + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + ax->SetRangeUser(globalMin, globalMax); } } From 8d20f37ae84a99ffdc8863f4ebe0474f11049fe9 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 08:32:58 +0200 Subject: [PATCH 06/20] [test] adapt roottests to new menu functions --- roottest/root/io/filemerger/CMakeLists.txt | 28 ++++++++++----------- roottest/root/meta/MemberComments.ref | 4 +++ roottest/root/meta/MemberComments_win32.ref | 4 +++ roottest/root/meta/MemberComments_win64.ref | 4 +++ 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/roottest/root/io/filemerger/CMakeLists.txt b/roottest/root/io/filemerger/CMakeLists.txt index 35f983bc6f159..e1451dc1e5d24 100644 --- a/roottest/root/io/filemerger/CMakeLists.txt +++ b/roottest/root/io/filemerger/CMakeLists.txt @@ -1,6 +1,6 @@ ROOTTEST_ADD_TEST(execKeyOrder - MACRO execKeyOrder.C - OUTREF execKeyOrder.ref) + MACRO execKeyOrder.C + OUTREF execKeyOrder.ref) ROOTTEST_ADD_TEST(execCreateAndMerge @@ -75,7 +75,7 @@ if(ZLIB_CF) else() ROOTTEST_ADD_TEST(merged-zlib PRECMD ${ROOT_hadd_CMD} -f101 mzlibfile1-4.root mzlibfile1-2.root mzlibfile3-4.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mzlibfile1-4.root\",101,5014,20)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mzlibfile1-4.root\",101,5020,20)" DEPENDS datagen-hadd-mzlibfile12 DEPENDS datagen-hadd-mzlibfile34) endif() @@ -95,7 +95,7 @@ if(${LZ4_VERSION} VERSION_LESS "1.7.5") elseif(${LZ4_VERSION} VERSION_GREATER_EQUAL "1.7.5") ROOTTEST_ADD_TEST(merged-lz4 PRECMD ${ROOT_hadd_CMD} -f404 mlz4file1-4.root mlz4file1-2.root mlz4file3-4.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mlz4file1-4.root\",404,5395,5)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mlz4file1-4.root\",404,5415,5)" DEPENDS datagen-hadd-mlz4file12 DEPENDS datagen-hadd-mlz4file34) endif() @@ -212,7 +212,7 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simplek-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -fk404 hsimpleK404.root hsimpleK209.root hsimpleK.root hsimple.root hsimple9.root hsimple209.root hsimple409.root hsimple92.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047492,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047502,30)" DEPENDS roottest-root-io-filemerger-hsimple DEPENDS simple-lz4-compr-level9 DEPENDS simple-lzma-compr-level9 @@ -222,17 +222,17 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simple-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -f404 hsimple404.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517262,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517292,15)" DEPENDS roottest-root-io-filemerger-hsimple) ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517008,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517020,15)" DEPENDS roottest-root-io-filemerger-hsimple) ROOTTEST_ADD_TEST(simple-lz4-compr-level1 PRECMD ${ROOT_hadd_CMD} -f401 hsimple401.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,519976,5)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,520007,5)" DEPENDS roottest-root-io-filemerger-hsimple) else() ROOTTEST_ADD_TEST(simple-default-compr-level9 @@ -325,7 +325,7 @@ if(${compression_default} STREQUAL "zlib") elseif(${LZ4_VERSION} VERSION_GREATER_EQUAL "1.7.5") ROOTTEST_ADD_TEST(simplek-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -fk404 hsimpleK404.root hsimpleK209.root hsimpleK.root hsimple.root hsimple9.root hsimple209.root hsimple409.root hsimple92.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047492,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047512,30)" DEPENDS roottest-root-io-filemerger-hsimple DEPENDS simple-lz4-compr-level9 DEPENDS simple-lzma-compr-level9 @@ -335,22 +335,22 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simple-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -f404 hsimple404.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517262,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517292,15)" DEPENDS roottest-root-io-filemerger-hsimple) if(CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,516975,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517004,30)" DEPENDS roottest-root-io-filemerger-hsimple) else() ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517008,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517020,15)" DEPENDS roottest-root-io-filemerger-hsimple) endif() ROOTTEST_ADD_TEST(simple-lz4-compr-level1 PRECMD ${ROOT_hadd_CMD} -f401 hsimple401.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,519976,10)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,520007,10)" DEPENDS roottest-root-io-filemerger-hsimple) endif() @@ -368,5 +368,5 @@ endif() ROOTTEST_ADD_TEST(simple-lzma-compr-level9 PRECMD ${ROOT_hadd_CMD} -f209 hsimple209.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple209.root\",25000,209,392709,17)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple209.root\",25000,209,392716,17)" DEPENDS roottest-root-io-filemerger-hsimple) diff --git a/roottest/root/meta/MemberComments.ref b/roottest/root/meta/MemberComments.ref index 25e00ec5c00b1..37caa172a5920 100644 --- a/roottest/root/meta/MemberComments.ref +++ b/roottest/root/meta/MemberComments.ref @@ -588,6 +588,10 @@ OBJ: TList TList Doubly linked list : 0 TH1::Class()->GetMenuItems(): OBJ: TList TList Doubly linked list : 0 + OBJ: TMethod AutoZoom *MENU* : 0 + void TH1::AutoZoom() + OBJ: TMethod UnZoom *MENU* : 0 + void TH1::UnZoom() OBJ: TMethod DrawPanel *MENU* : 0 void TH1::DrawPanel() OBJ: TMethod Fit *MENU* : 0 diff --git a/roottest/root/meta/MemberComments_win32.ref b/roottest/root/meta/MemberComments_win32.ref index c63169024ce6f..70e555751413f 100644 --- a/roottest/root/meta/MemberComments_win32.ref +++ b/roottest/root/meta/MemberComments_win32.ref @@ -588,6 +588,10 @@ OBJ: TList TList Doubly linked list : 0 TH1::Class()->GetMenuItems(): OBJ: TList TList Doubly linked list : 0 + OBJ: TMethod AutoZoom *MENU* : 0 + void TH1::AutoZoom() + OBJ: TMethod UnZoom *MENU* : 0 + void TH1::UnZoom() OBJ: TMethod DrawPanel *MENU* : 0 void TH1::DrawPanel() OBJ: TMethod Fit *MENU* : 0 diff --git a/roottest/root/meta/MemberComments_win64.ref b/roottest/root/meta/MemberComments_win64.ref index c63169024ce6f..70e555751413f 100644 --- a/roottest/root/meta/MemberComments_win64.ref +++ b/roottest/root/meta/MemberComments_win64.ref @@ -588,6 +588,10 @@ OBJ: TList TList Doubly linked list : 0 TH1::Class()->GetMenuItems(): OBJ: TList TList Doubly linked list : 0 + OBJ: TMethod AutoZoom *MENU* : 0 + void TH1::AutoZoom() + OBJ: TMethod UnZoom *MENU* : 0 + void TH1::UnZoom() OBJ: TMethod DrawPanel *MENU* : 0 void TH1::DrawPanel() OBJ: TMethod Fit *MENU* : 0 From 844b55882a5a1171388d36b6f3a2fe46b600bc61 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 09:57:28 +0200 Subject: [PATCH 07/20] [roottest] adapt again --- roottest/root/io/filemerger/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roottest/root/io/filemerger/CMakeLists.txt b/roottest/root/io/filemerger/CMakeLists.txt index e1451dc1e5d24..94b547c17140a 100644 --- a/roottest/root/io/filemerger/CMakeLists.txt +++ b/roottest/root/io/filemerger/CMakeLists.txt @@ -345,7 +345,7 @@ if(${compression_default} STREQUAL "zlib") else() ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517020,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517024,15)" DEPENDS roottest-root-io-filemerger-hsimple) endif() ROOTTEST_ADD_TEST(simple-lz4-compr-level1 From 4e56fa05682b8f23d23e59c28a820400d0d65733 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 09:58:57 +0200 Subject: [PATCH 08/20] [test] give more informative error output on stress failure --- test/stress.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stress.cxx b/test/stress.cxx index 4db3b572c5b7a..010bcca866b75 100644 --- a/test/stress.cxx +++ b/test/stress.cxx @@ -376,7 +376,7 @@ void stress2() if (OK) printf("OK\n"); else { printf("FAILED\n"); - printf("%-8s last =%lld, comp=%f\n"," ",last,comp); + printf("%-8s last =%lld, comp=%f vs lastgood =%lld\n"," ", last, comp, lastgood); } if (gPrintSubBench) { printf("Test 2 : "); gBenchmark->Show("stress");gBenchmark->Start("stress"); } } From cb159c33ad550088d6b21719e7691bf5bcf913ea Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 10:00:11 +0200 Subject: [PATCH 09/20] [test] fix spacing --- test/stress.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stress.cxx b/test/stress.cxx index 010bcca866b75..c96b2c274c320 100644 --- a/test/stress.cxx +++ b/test/stress.cxx @@ -376,7 +376,7 @@ void stress2() if (OK) printf("OK\n"); else { printf("FAILED\n"); - printf("%-8s last =%lld, comp=%f vs lastgood =%lld\n"," ", last, comp, lastgood); + printf("%-8s last=%lld, comp=%f vs lastgood=%lld\n"," ", last, comp, lastgood); } if (gPrintSubBench) { printf("Test 2 : "); gBenchmark->Show("stress");gBenchmark->Start("stress"); } } From 45030104a82fe8899149330390cf335a89cc57ff Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 11:28:11 +0200 Subject: [PATCH 10/20] [test] add some extra bytes --- test/stress.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stress.cxx b/test/stress.cxx index c96b2c274c320..4b6d447eb5c26 100644 --- a/test/stress.cxx +++ b/test/stress.cxx @@ -366,7 +366,7 @@ void stress2() OK = kFALSE; #else #ifdef R__HAS_CLOUDFLARE_ZLIB - Long64_t lastgood = 9813; + Long64_t lastgood = 9826; // changes for TH1 PR#18459 #else Long64_t lastgood = 10100; // changes in TFormula (v13) #endif From ace3e2065eb4f2f82de54fd8c3b227355cc44583 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 16:01:20 +0200 Subject: [PATCH 11/20] [hist] fix bug in max starting value and reset iterator before reusing --- hist/hist/src/TAxis.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index e113a90435f2b..f8ebe140ab227 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1395,7 +1395,7 @@ void TAxis::AutoZoomAll() Int_t first = -1, last = -1; Double_t globalMin = DBL_MAX; - Double_t globalMax = DBL_MIN; + Double_t globalMax = -DBL_MAX; TIter next(gPad->GetListOfPrimitives()); while (TObject *obj= next()) { if (!obj || !obj->InheritsFrom(TH1::Class())) @@ -1410,6 +1410,7 @@ void TAxis::AutoZoomAll() globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); } } + next.Reset(); while (TObject *obj = next()) { if (!obj || !obj->InheritsFrom(TH1::Class())) continue; From 50fc50c612dc2ae2143f6992919885b8c1da5207 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 16:38:08 +0200 Subject: [PATCH 12/20] [hist] allow specifying a margin in GetRangeOfFilledWeights --- hist/hist/src/TH1.cxx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index 7cb7cad12ae95..af076d55fc6e6 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -7952,7 +7952,16 @@ void TH1::ResetStats() if (fSumw2.fN > 0 && fTsumw > 0 && stats[1] > 0 ) fEntries = stats[0]*stats[0]/ stats[1]; } -void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const bool includeUnderOverflow) const +//////////////////////////////////////////////////////////////////////////////// +/// Get the range of the histogram that is filled with non-empty contents (i.e. +/// non-zero content and non-zero error). +/// \param dim 0 for the x-axis, 1 for the y-axis, 2 for the z-axis, must be <= GetDimension() +/// \param first where the first non-empty bin index will be stored (minus margin) +/// \param last where the last non-empty bin index will be stored (plus margin) +/// \param margin number of bins to enlarge each side of the range, to leave some room +/// \param includeUnderOverflow when searching for non-empty bins, set to true to include the under/overflow bins + +void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const Int_t margin, const bool includeUnderOverflow) const { if (fBuffer) const_cast(this)->BufferEmpty(); @@ -8073,6 +8082,9 @@ void TH1::GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, co } } } + // Apply some margins + first = std::max(dim == 0 ? startX : dim == 1 ? startY : startZ, first - margin); + last = std::min(dim == 0 ? lastX : dim == 1 ? lastY : lastZ, last + margin); } //////////////////////////////////////////////////////////////////////////////// From e523e5de36d2fe61ae65637ba4e8d68971b7b786 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 16:40:41 +0200 Subject: [PATCH 13/20] [hist] adapt calls to new margin signature and add a margin of 1 bin --- hist/hist/inc/TH1.h | 2 +- hist/hist/src/TAxis.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hist/hist/inc/TH1.h b/hist/hist/inc/TH1.h index 635de2442a3c3..b3d3e89bffd81 100644 --- a/hist/hist/inc/TH1.h +++ b/hist/hist/inc/TH1.h @@ -325,7 +325,7 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { virtual Int_t GetQuantiles(Int_t n, Double_t *xp, const Double_t *p = nullptr); virtual Double_t GetRandom(TRandom * rng = nullptr) const; - void GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const bool includeUnderOverflow) const; + void GetRangeOfFilledWeights(const Int_t dim, Int_t& first, Int_t& last, const Int_t margin, const bool includeUnderOverflow) const; virtual void GetStats(Double_t *stats) const; virtual Double_t GetStdDev(Int_t axis=1) const; virtual Double_t GetStdDevError(Int_t axis=1) const; diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index f8ebe140ab227..951f7e716af60 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1371,7 +1371,7 @@ void TAxis::AutoZoom() } } - hobj1->GetRangeOfFilledWeights(dim, first, last, false); + hobj1->GetRangeOfFilledWeights(dim, first, last, 1, false); SetRange(first, last); if (gPad) @@ -1403,7 +1403,7 @@ void TAxis::AutoZoomAll() TH1 *hobj = static_cast(obj); if (dim > hobj->GetDimension()) continue; - hobj->GetRangeOfFilledWeights(dim, first, last, false); + hobj->GetRangeOfFilledWeights(dim, first, last, 1, false); TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; if (ax) { globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); From 343011b93db49ada01ed97017b334631350f48fb Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 17:18:37 +0200 Subject: [PATCH 14/20] [hist] add safety check for static_cast --- hist/hist/src/TAxis.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index 951f7e716af60..762db504d1e3d 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1340,6 +1340,10 @@ void TAxis::AutoZoom() Warning("TAxis::AutoZoom","Cannot AutoZoom if parent does not exist. Did you mean to draw the TAxis first?"); return; } + if (!GetParent()->InheritsFrom(TH1::Class())) { + Warning("TAxis::AutoZoom","Cannot AutoZoom if axis parent (of type `%s`) does not derive from TH1.", GetParent()->ClassName()); + return; + } auto dim = strstr(GetName(), "xaxis") ? 0 : strstr(GetName(), "yaxis") ? 1 : strstr(GetName(), "zaxis") ? 2 : -1; TH1 *hobj1 = static_cast(GetParent()); Int_t first = -1, last = -1; From 8145622939d5e257374ea5624540e60e9ed75753 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 23 Apr 2025 17:30:35 +0200 Subject: [PATCH 15/20] [hist] support THStack Autozoom --- hist/hist/src/TAxis.cxx | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index 762db504d1e3d..d741585d17ba8 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -17,6 +17,7 @@ #include "TList.h" #include "TAxisModLab.h" #include "TH1.h" +#include "THStack.h" #include "TObjString.h" #include "TDatime.h" #include "TTimeStamp.h" @@ -1402,23 +1403,41 @@ void TAxis::AutoZoomAll() Double_t globalMax = -DBL_MAX; TIter next(gPad->GetListOfPrimitives()); while (TObject *obj= next()) { - if (!obj || !obj->InheritsFrom(TH1::Class())) + if (!obj) continue; - TH1 *hobj = static_cast(obj); - if (dim > hobj->GetDimension()) - continue; - hobj->GetRangeOfFilledWeights(dim, first, last, 1, false); - TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; - if (ax) { - globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); - globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); + if (obj->InheritsFrom(TH1::Class())) { + TH1 *hobj = static_cast(obj); + if (dim > hobj->GetDimension()) + continue; + hobj->GetRangeOfFilledWeights(dim, first, last, 1, false); + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); + globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); + } + } else if (obj->InheritsFrom(THStack::Class())) { + THStack *hs = static_cast(obj); + TIter hsnext(hs->begin()); + while (TObject *hsobj= hsnext()) { + if (!hsobj) + continue; + TH1 *hobj = static_cast(hsobj); + if (dim > hobj->GetDimension()) + continue; + hobj->GetRangeOfFilledWeights(dim, first, last, 1, false); + TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; + if (ax) { + globalMin = std::min(globalMin, ax->GetBinLowEdge(first)); + globalMax = std::max(globalMax, ax->GetBinUpEdge(last)); + } + } } } next.Reset(); while (TObject *obj = next()) { - if (!obj || !obj->InheritsFrom(TH1::Class())) + if (!obj || (!obj->InheritsFrom(TH1::Class()) && !obj->InheritsFrom(THStack::Class()))) continue; - TH1 *hobj = static_cast(obj); + TH1 *hobj = obj->InheritsFrom(TH1::Class()) ? static_cast(obj) : static_cast(obj)->GetHistogram(); if (dim > hobj->GetDimension()) continue; TAxis *ax = (dim == 0) ? hobj->GetXaxis() : (dim == 1) ? hobj->GetYaxis() : (dim == 2) ? hobj->GetZaxis() : nullptr; From 18f5411426532cfbcfcaf966b1aef958202eecc0 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Thu, 24 Apr 2025 14:50:59 +0200 Subject: [PATCH 16/20] [test] undo test changes --- roottest/root/io/filemerger/CMakeLists.txt | 24 +++++++++++----------- test/stress.cxx | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/roottest/root/io/filemerger/CMakeLists.txt b/roottest/root/io/filemerger/CMakeLists.txt index 94b547c17140a..f4a5b048575db 100644 --- a/roottest/root/io/filemerger/CMakeLists.txt +++ b/roottest/root/io/filemerger/CMakeLists.txt @@ -75,7 +75,7 @@ if(ZLIB_CF) else() ROOTTEST_ADD_TEST(merged-zlib PRECMD ${ROOT_hadd_CMD} -f101 mzlibfile1-4.root mzlibfile1-2.root mzlibfile3-4.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mzlibfile1-4.root\",101,5020,20)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mzlibfile1-4.root\",101,5014,20)" DEPENDS datagen-hadd-mzlibfile12 DEPENDS datagen-hadd-mzlibfile34) endif() @@ -95,7 +95,7 @@ if(${LZ4_VERSION} VERSION_LESS "1.7.5") elseif(${LZ4_VERSION} VERSION_GREATER_EQUAL "1.7.5") ROOTTEST_ADD_TEST(merged-lz4 PRECMD ${ROOT_hadd_CMD} -f404 mlz4file1-4.root mlz4file1-2.root mlz4file3-4.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mlz4file1-4.root\",404,5415,5)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testMergedFile.C(\"mlz4file1-4.root\",404,5395,5)" DEPENDS datagen-hadd-mlz4file12 DEPENDS datagen-hadd-mlz4file34) endif() @@ -212,7 +212,7 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simplek-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -fk404 hsimpleK404.root hsimpleK209.root hsimpleK.root hsimple.root hsimple9.root hsimple209.root hsimple409.root hsimple92.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047502,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047492,30)" DEPENDS roottest-root-io-filemerger-hsimple DEPENDS simple-lz4-compr-level9 DEPENDS simple-lzma-compr-level9 @@ -222,17 +222,17 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simple-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -f404 hsimple404.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517292,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517262,15)" DEPENDS roottest-root-io-filemerger-hsimple) ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517020,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517008,15)" DEPENDS roottest-root-io-filemerger-hsimple) ROOTTEST_ADD_TEST(simple-lz4-compr-level1 PRECMD ${ROOT_hadd_CMD} -f401 hsimple401.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,520007,5)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,519976,5)" DEPENDS roottest-root-io-filemerger-hsimple) else() ROOTTEST_ADD_TEST(simple-default-compr-level9 @@ -325,7 +325,7 @@ if(${compression_default} STREQUAL "zlib") elseif(${LZ4_VERSION} VERSION_GREATER_EQUAL "1.7.5") ROOTTEST_ADD_TEST(simplek-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -fk404 hsimpleK404.root hsimpleK209.root hsimpleK.root hsimple.root hsimple9.root hsimple209.root hsimple409.root hsimple92.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047512,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimpleK404.root\",24*25000,404,12047492,30)" DEPENDS roottest-root-io-filemerger-hsimple DEPENDS simple-lz4-compr-level9 DEPENDS simple-lzma-compr-level9 @@ -335,22 +335,22 @@ if(${compression_default} STREQUAL "zlib") ROOTTEST_ADD_TEST(simple-lz4-compr-level4 PRECMD ${ROOT_hadd_CMD} -f404 hsimple404.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517292,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple404.root\",25000,404,517262,15)" DEPENDS roottest-root-io-filemerger-hsimple) if(CMAKE_SYSTEM_PROCESSOR MATCHES aarch64) ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517004,30)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,516975,30)" DEPENDS roottest-root-io-filemerger-hsimple) else() ROOTTEST_ADD_TEST(simple-lz4-compr-level9 PRECMD ${ROOT_hadd_CMD} -f409 hsimple409.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517024,15)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple409.root\",25000,409,517008,15)" DEPENDS roottest-root-io-filemerger-hsimple) endif() ROOTTEST_ADD_TEST(simple-lz4-compr-level1 PRECMD ${ROOT_hadd_CMD} -f401 hsimple401.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,520007,10)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple401.root\",25000,401,519976,10)" DEPENDS roottest-root-io-filemerger-hsimple) endif() @@ -368,5 +368,5 @@ endif() ROOTTEST_ADD_TEST(simple-lzma-compr-level9 PRECMD ${ROOT_hadd_CMD} -f209 hsimple209.root hsimple.root - COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple209.root\",25000,209,392716,17)" + COMMAND ${ROOT_root_CMD} -q -l -b "${CMAKE_CURRENT_SOURCE_DIR}/testSimpleFile.C(\"hsimple209.root\",25000,209,392709,17)" DEPENDS roottest-root-io-filemerger-hsimple) diff --git a/test/stress.cxx b/test/stress.cxx index 4b6d447eb5c26..c96b2c274c320 100644 --- a/test/stress.cxx +++ b/test/stress.cxx @@ -366,7 +366,7 @@ void stress2() OK = kFALSE; #else #ifdef R__HAS_CLOUDFLARE_ZLIB - Long64_t lastgood = 9826; // changes for TH1 PR#18459 + Long64_t lastgood = 9813; #else Long64_t lastgood = 10100; // changes in TFormula (v13) #endif From 96856bd3e2675048924760fea81d4312f4fea2d3 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Thu, 24 Apr 2025 14:51:50 +0200 Subject: [PATCH 17/20] [hist] restore original class comment in order not to change streamerinfo checksum --- hist/hist/inc/TH1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/inc/TH1.h b/hist/hist/inc/TH1.h index b3d3e89bffd81..8112e76bcd651 100644 --- a/hist/hist/inc/TH1.h +++ b/hist/hist/inc/TH1.h @@ -97,7 +97,7 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { friend class TH1Merger; protected: - Int_t fNcells; ///< Number of bins (1D) / total of cells (2D) / voxels (3D) +Under/Overflows + Int_t fNcells; ///< Number of bins(1D), cells (2D) +U/Overflows TAxis fXaxis; ///< X axis descriptor TAxis fYaxis; ///< Y axis descriptor TAxis fZaxis; ///< Z axis descriptor From 43ff9d6e97a4c0346d05843d92e6a98d79858693 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Fri, 25 Apr 2025 09:22:04 +0200 Subject: [PATCH 18/20] [hist] Unzoom: add sanity check before casting --- hist/hist/src/TAxis.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index d741585d17ba8..da6a9c7ab725c 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1270,7 +1270,7 @@ void TAxis::UnZoom() //unzoom object owning this axis SetRange(0,0); - TH1 *hobj1 = (TH1*)GetParent(); + TH1 *hobj1 = GetParent()->InheritsFrom(TH1::Class()) ? static_cast(GetParent()) : nullptr; if (!strstr(GetName(),"xaxis")) { if (!hobj1) return; if (hobj1->GetDimension() == 2) { From 3e1c376f1480d4d237b67eda9c22e13661f493f7 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Fri, 25 Apr 2025 09:46:05 +0200 Subject: [PATCH 19/20] [hist] fix nullptr access thanks to linev --- hist/hist/src/TAxis.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index da6a9c7ab725c..c68aaf38377e4 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1270,7 +1270,7 @@ void TAxis::UnZoom() //unzoom object owning this axis SetRange(0,0); - TH1 *hobj1 = GetParent()->InheritsFrom(TH1::Class()) ? static_cast(GetParent()) : nullptr; + TH1 *hobj1 = GetParent() && GetParent()->InheritsFrom(TH1::Class()) ? static_cast(GetParent()) : nullptr; if (!strstr(GetName(),"xaxis")) { if (!hobj1) return; if (hobj1->GetDimension() == 2) { From d4400a6ef21536290d8b7343cae69fd4f31ccf51 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Fri, 25 Apr 2025 10:38:18 +0200 Subject: [PATCH 20/20] [hist] prevent Unzoom from Zooming in Default drawing histogram option is to leave a YMARGIN range of 10% in YMAX. So if you call Unzoom, it was calling GetMaximum, which calculated the exact maximum, and then called SetMaximum, thus overwriting the stored value. Use instead GetMaximumStored to prevent recalculation if not set by user. --- hist/hist/src/TAxis.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TAxis.cxx b/hist/hist/src/TAxis.cxx index c68aaf38377e4..eaf2a5fd71dcb 100644 --- a/hist/hist/src/TAxis.cxx +++ b/hist/hist/src/TAxis.cxx @@ -1285,7 +1285,7 @@ void TAxis::UnZoom() hobj1->SetMinimum(fXmin); hobj1->SetMaximum(fXmax); } else { - if (fXmin==hobj1->GetMinimum() && fXmax==hobj1->GetMaximum()) { + if (fXmin==hobj1->GetMinimumStored() && fXmax==hobj1->GetMaximumStored()) { hobj1->SetMinimum(fXmin); hobj1->SetMaximum(fXmax); } else {