@@ -1501,9 +1501,12 @@ TH2 *TH2::Rebin(Int_t ngroup, const char *newname, const Double_t *xbins)
15011501 Info (" Rebin" ," Rebinning only the x-axis. Use Rebin2D for rebinning both axes" );
15021502 return RebinX (ngroup, newname);
15031503}
1504+
15041505// //////////////////////////////////////////////////////////////////////////////
15051506// / Rebin this histogram grouping nxgroup/nygroup bins along the xaxis/yaxis together.
15061507// /
1508+ // / #### case 1 xbins=0 || ybins=0
1509+ // /
15071510// / if newname is not blank a new temporary histogram hnew is created.
15081511// / else the current histogram is modified (default)
15091512// / The parameter nxgroup/nygroup indicate how many bins along the xaxis/yaxis of this
@@ -1526,8 +1529,35 @@ TH2 *TH2::Rebin(Int_t ngroup, const char *newname, const Double_t *xbins)
15261529// / ybin=newybins*nygroup and the corresponding bins are added to
15271530// / the overflow bin.
15281531// / Statistics will be recomputed from the new bin contents.
1532+ // /
1533+ // / #### case 2 xbins!=0 && ybins!=0
1534+ // /
1535+ // / A new histogram is created (you should specify newname).
1536+ // / The parameter nxgroup (nygroup) is the number of variable size bins for the x-axis
1537+ // / (y-axis) in the created histogram.
1538+ // / The arrays xbins and ybins must contain nxgroup+1 and nygroups+1 elements
1539+ // / that represent the low-edges of the x and y bins respectively.
1540+ // / If the original histogram has errors stored (via Sumw2), the resulting
1541+ // / histograms has new errors correctly calculated.
1542+ // /
1543+ // / NOTE: The bin edges specified in xbins and ybins should correspond
1544+ // / to bin edges in the original histogram. If a bin edge in the new histogram
1545+ // / is in the middle of a bin in the original histogram, all entries in
1546+ // / the split bin in the original histogram will be transfered to the
1547+ // / lower of the two possible bins in the new histogram. This is
1548+ // / probably not what you want. A warning message is emitted in this
1549+ // / case
1550+ // /
1551+ // / examples: if h2 is an existing TH2F histogram with 100 bins on x-axis
1552+ // / and 100 bins y-axis
1553+ // /
1554+ // / ~~~ {.cpp}
1555+ // / Double_t xbins[25] = {...} array of low-edges for x-axis (xbins[25] is the upper edge of last bin)
1556+ // / Double_t ybins[25] = {...} array of low-edges for y-axis (ybins[25] is the upper edge of last bin)
1557+ // / h1->Rebin(24,24,"hnew",xbins,ybins); //creates a new variable bin size histogram hnew
1558+ // / ~~~
15291559
1530- TH2 *TH2 ::Rebin2D(Int_t nxgroup, Int_t nygroup, const char *newname)
1560+ TH2 *TH2 ::Rebin2D(Int_t nxgroup, Int_t nygroup, const char *newname, const Double_t *xbins, const Double_t *ybins )
15311561{
15321562 Int_t nxbins = fXaxis .GetNbins ();
15331563 Int_t nybins = fYaxis .GetNbins ();
@@ -1550,37 +1580,94 @@ TH2 *TH2::Rebin2D(Int_t nxgroup, Int_t nygroup, const char *newname)
15501580 Error (" Rebin2D" , " Illegal value of nygroup=%d" ,nygroup);
15511581 return 0 ;
15521582 }
1583+ if (!newname && xbins) {
1584+ Error (" Rebin" ," if xbins is specified, newname must be given" );
1585+ return 0 ;
1586+ }
1587+ if (!newname && ybins) {
1588+ Error (" Rebin" ," if ybins is specified, newname must be given" );
1589+ return 0 ;
1590+ }
15531591
15541592 Int_t newxbins = nxbins / nxgroup;
1555- Int_t newybins = nybins / nygroup;
15561593 Int_t newnx = newxbins + 2 ; // regular bins + overflow / underflow
1594+ if (!xbins) {
1595+ Int_t nbgx = nxbins/nxgroup;
1596+ if (nbgx*nxgroup != nxbins) {
1597+ Warning (" Rebin2D" , " nxgroup=%d is not an exact divider of nxbins=%d." ,nxgroup,nxbins);
1598+ }
1599+ }
1600+ else {
1601+ // in the case that xbins is given (rebinning in variable bins), nxgroup is
1602+ // the new number of bins and number of grouped bins is not constant.
1603+ // when looping for setting the contents for the new histogram we
1604+ // need to loop on all bins of original histogram. Then set nxgroup=nxbins
1605+ newxbins = nxgroup;
1606+ nxgroup = nxbins;
1607+ }
1608+
1609+ Int_t newybins = nybins / nygroup;
15571610 Int_t newny = newybins + 2 ; // regular bins + overflow / underflow
1611+ if (!ybins) {
1612+ Int_t nbgy = nybins/nygroup;
1613+ if (nbgy*nygroup != nybins) {
1614+ Warning (" Rebin2D" , " nygroup=%d is not an exact divider of nybins=%d." ,nygroup,nybins);
1615+ }
1616+ }
1617+ else {
1618+ // in the case that ybins is given (rebinning in variable bins), nygroup is
1619+ // the new number of bins and number of grouped bins is not constant.
1620+ // when looping for setting the contents for the new histogram we
1621+ // need to loop on all bins of original histogram. Then set nygroup=nybins
1622+ newybins = nygroup;
1623+ nygroup = nybins;
1624+ }
15581625
15591626 // Save old bin contents into a new array
1627+ Double_t entries = fEntries ;
15601628 Double_t *oldBins = new Double_t[fNcells ];
15611629 for (Int_t i = 0 ; i < fNcells ; ++i) oldBins[i] = RetrieveBinContent (i);
15621630
15631631 Double_t* oldErrors = NULL ;
1564- if (fSumw2 .fN ) {
1632+ if (fSumw2 .fN != 0 ) {
15651633 oldErrors = new Double_t[fNcells ];
15661634 for (Int_t i = 0 ; i < fNcells ; ++i) oldErrors[i] = GetBinErrorSqUnchecked (i);
15671635 }
15681636
1637+ // rebin will not include underflow/overflow if new axis range is larger than old axis range
1638+ if (xbins) {
1639+ if (xbins[0 ] < fXaxis .GetXmin () && oldBins[0 ] != 0 )
1640+ Warning (" Rebin2D" ," underflow entries for X axis will not be used when rebinning" );
1641+ if (xbins[newxbins] > fXaxis .GetXmax () && oldBins[nxbins+1 ] != 0 )
1642+ Warning (" Rebin2D" ," overflow entries for X axis will not be used when rebinning" );
1643+ }
1644+ if (ybins) {
1645+ if (ybins[0 ] < fYaxis .GetXmin () && oldBins[0 ] != 0 )
1646+ Warning (" Rebin2D" ," underflow entries for Y axis will not be used when rebinning" );
1647+ if (ybins[newybins] > fYaxis .GetXmax () && oldBins[nybins+1 ] != 0 )
1648+ Warning (" Rebin2D" ," overflow entries for Y axis will not be used when rebinning" );
1649+ }
1650+
15691651 // create a clone of the old histogram if newname is specified
15701652 TH2 * hnew = this ;
1571- if (newname && strlen (newname)) {
1572- hnew = (TH2 *)Clone ();
1573- hnew->SetName (newname);
1653+ if ((newname && strlen (newname)) || xbins || ybins) {
1654+ hnew = (TH2 *)Clone (newname);
15741655 }
15751656
1657+ // reset can extend bit to avoid an axis extension in SetBinContent
1658+ UInt_t oldExtendBitMask = hnew->SetCanExtend (kNoAxis );
1659+
1660+ // save original statistics
1661+ Double_t stat[kNstat ];
1662+ GetStats (stat);
15761663 bool resetStat = false ;
15771664
15781665 // change axis specs and rebuild bin contents array
1579- if (newxbins * nxgroup != nxbins) {
1666+ if (!xbins && ( newxbins * nxgroup != nxbins) ) {
15801667 xmax = fXaxis .GetBinUpEdge (newxbins * nxgroup);
15811668 resetStat = true ; // stats must be reset because top bins will be moved to overflow bin
15821669 }
1583- if (newybins * nygroup != nybins) {
1670+ if (!ybins && ( newybins * nygroup != nybins) ) {
15841671 ymax = fYaxis .GetBinUpEdge (newybins * nygroup);
15851672 resetStat = true ; // stats must be reset because top bins will be moved to overflow bin
15861673 }
@@ -1613,15 +1700,17 @@ TH2 *TH2::Rebin2D(Int_t nxgroup, Int_t nygroup, const char *newname)
16131700
16141701 // copy merged bin contents (ignore under/overflows)
16151702 if (nxgroup != 1 || nygroup != 1 ) {
1616- if (fXaxis .GetXbins ()->GetSize () > 0 || fYaxis .GetXbins ()->GetSize () > 0 ){
1703+ if ((!xbins && fXaxis .GetXbins ()->GetSize () > 0 ) || (!ybins && fYaxis .GetXbins ()->GetSize () > 0 ) ){
16171704 // variable bin sizes in x or y, don't treat both cases separately
1618- Double_t *xbins = new Double_t[newxbins + 1 ];
1619- for (Int_t i = 0 ; i <= newxbins; ++i) xbins[i] = fXaxis .GetBinLowEdge (1 + i * nxgroup);
1620- Double_t *ybins = new Double_t[newybins + 1 ];
1621- for (Int_t i = 0 ; i <= newybins; ++i) ybins[i] = fYaxis .GetBinLowEdge (1 + i * nygroup);
1622- hnew->SetBins (newxbins, xbins, newybins, ybins); // changes also errors array (if any)
1623- delete [] xbins;
1624- delete [] ybins;
1705+ Double_t *xbinsTmp = new Double_t[newxbins + 1 ];
1706+ for (Int_t i = 0 ; i <= newxbins; ++i) xbinsTmp[i] = fXaxis .GetBinLowEdge (1 + i * nxgroup);
1707+ Double_t *ybinsTmp = new Double_t[newybins + 1 ];
1708+ for (Int_t i = 0 ; i <= newybins; ++i) ybinsTmp[i] = fYaxis .GetBinLowEdge (1 + i * nygroup);
1709+ hnew->SetBins (newxbins, xbinsTmp, newybins, ybinsTmp); // changes also errors array (if any)
1710+ delete [] xbinsTmp;
1711+ delete [] ybinsTmp;
1712+ } else if (xbins && ybins) {
1713+ hnew->SetBins (newxbins,xbins, newybins, ybins);
16251714 } else {
16261715 hnew->SetBins (newxbins, xmin, xmax, newybins, ymin, ymax); // changes also errors array
16271716 }
@@ -1699,7 +1788,11 @@ TH2 *TH2::Rebin2D(Int_t nxgroup, Int_t nygroup, const char *newname)
16991788 fYaxis .SetTitleColor (yTitleColor);
17001789 fYaxis .SetTitleFont (yTitleFont);
17011790
1702- if (resetStat) hnew->ResetStats ();
1791+ hnew->SetCanExtend (oldExtendBitMask); // restore previous state
1792+
1793+ // restore statistics and entries modified by SetBinContent
1794+ hnew->SetEntries (entries);
1795+ if (!resetStat) hnew->PutStats (stat);
17031796
17041797 delete [] oldBins;
17051798 if (oldErrors) delete [] oldErrors;
0 commit comments