[ROOT-5542] TH1::RecomputeAxisLimits is not able to recompute a user defined equidistant binning. Created: 23/Sep/13  Updated: 15/May/19  Resolved: 04/Apr/14

Status: Closed
Project: ROOT
Component/s: Math Libraries
Affects Version/s: 5.34/00
Fix Version/s: None

Type: Bug Priority: High
Reporter: Andreas Bachlechner Assignee: Lorenzo Moneta
Resolution: Fixed Votes: 1
Labels: None
Environment:

All


Attachments: File mergeExample.cc     File recomputeAxis.cc    
Development:

 Description   

TH1::RecomputeAxisLimits fails if one binning is user defined. But even for userdefinded binnings it could work when the widths are all the same.
So it has not only to check if the binning is user defined but in addition allow an equidistant user binning.
Attached is a short root script to demonstrate the differences.



 Comments   
Comment by Lorenzo Moneta [ 24/Sep/13 ]

Hi,

This is an internal function used inside TH1::Merge. Merge of histogram with different user defined bins is not supported. Can you elaborate a bit more on your use case, to understand exactly what you need

Thank you

Lorenzo

Comment by Andreas Bachlechner [ 24/Sep/13 ]

Short example script where Merge fails due to TH1::RecomputeAxisLimits() not be able to handle equidistant user defined binnings.

Comment by Andreas Bachlechner [ 24/Sep/13 ]

I want to merge histograms that have a equidistant but user defined binning. An example is given in "mergeExample.cc" where testA() shows that a not user defined binning works but testB() uses the same but user defined binning and fails. At the moment I get the error that recompute axis limits finds inconsistent limits.
Output of attached example script mergeExample.cc testB() function:
Error in <TH1D::Merge>: Cannot merge histograms - limits are inconsistent:
first: (3, 4.500000, 6.000000), second: (5, 2.000000, 4.500000)
This is because TH1::RecomputeAxisLimits only checks for the existence of a user defined binning and not if the bin width and limits fit.

Comment by Andreas Bachlechner [ 10/Oct/13 ]

As a fix one can check that the user binning is equidistant.

--- a/hist/hist/src/TH1.cxx
+++ b/hist/hist/src/TH1.cxx
@@ -5092,6 +5092,21 @@ Bool_t TH1::SameLimitsAndNBins(const TAxis& axis1, const TAxis& axis2)
       return kFALSE;
 }
 
+static inline bool IsEquidistantBinning(const TAxis& axis)
+{
+  // not able to check if there is only one axis entry
+  bool isEquidistant = true;
+  const Double_t firstBinWidth = axis.GetBinWidth(1);
+  for (int i = 1; i < axis.GetNbins(); ++i) {
+    const Double_t binWidth = axis.GetBinWidth(i);
+    const bool match = TMath::AreEqualAbs(firstBinWidth, binWidth, DBL_MIN);
+    isEquidistant &= match;
+    if (!match)
+      break;
+  }
+  return isEquidistant;
+}
+
 //______________________________________________________________________________
 Bool_t TH1::RecomputeAxisLimits(TAxis& destAxis, const TAxis& anAxis)
 {
@@ -5100,8 +5115,8 @@ Bool_t TH1::RecomputeAxisLimits(TAxis& destAxis, const TAxis& anAxis)
    if (SameLimitsAndNBins(destAxis, anAxis))
       return kTRUE;
 
-   if (destAxis.GetXbins()->fN || anAxis.GetXbins()->fN)
-      return kFALSE;       // user binning not supported
+   if ((destAxis.GetXbins()->fN || anAxis.GetXbins()->fN) && (!IsEquidistantBinning(destAxis) || !IsEquidistantBinning(anAxis)))
+      return kFALSE;       // not equidistant user binning not supported
 
    Double_t width1 = destAxis.GetBinWidth(0);
    Double_t width2 = anAxis.GetBinWidth(0);

Comment by Lorenzo Moneta [ 04/Apr/14 ]

Your suggested patch (plus some extra small changes) is now committed in the git repository.

Thank you for the report and for the patch

Lorenzo

Generated at Sun Sep 22 01:29:42 CEST 2019 using Jira 7.13.1#713001-sha1:5e06076c2d215a6f699b7e5c90ab2fae7ba5a1ce.