Skip to content

Commit e564a63

Browse files
author
Olivier Delaune
committed
Implement variable rebinning 2-D histogram classes (ROOT-5224)
Implemented for TProfile2D as well
1 parent b92b913 commit e564a63

4 files changed

Lines changed: 180 additions & 40 deletions

File tree

hist/hist/inc/TH2.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class TH2 : public TH1 {
107107
virtual TH2 *RebinX(Int_t ngroup=2, const char *newname=""); // *MENU*
108108
virtual TH2 *RebinY(Int_t ngroup=2, const char *newname=""); // *MENU*
109109
virtual TH2 *Rebin(Int_t ngroup=2, const char*newname="", const Double_t *xbins=0); // re-implementation of the TH1 function using RebinX
110-
virtual TH2 *Rebin2D(Int_t nxgroup=2, Int_t nygroup=2, const char *newname=""); // *MENU*
110+
virtual TH2 *Rebin2D(Int_t nxgroup=2, Int_t nygroup=2, const char *newname="", const Double_t *xbins=0, const Double_t *ybins=0); // *MENU*
111111
TProfile *ProfileX(const char *name="_pfx", Int_t firstybin=1, Int_t lastybin=-1, Option_t *option="") const; // *MENU*
112112
TProfile *ProfileY(const char *name="_pfy", Int_t firstxbin=1, Int_t lastxbin=-1, Option_t *option="") const; // *MENU*
113113
TH1D *ProjectionX(const char *name="_px", Int_t firstybin=0, Int_t lastybin=-1, Option_t *option="") const; // *MENU*

hist/hist/inc/TProfile2D.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class TProfile2D : public TH2D {
130130
TProfile *ProfileY(const char *name="_pfy", Int_t firstxbin=0, Int_t lastxbin=-1, Option_t *option="") const; // *MENU*
131131
virtual void PutStats(Double_t *stats);
132132
virtual void Reset(Option_t *option="");
133-
virtual TProfile2D *Rebin2D(Int_t nxgroup=2, Int_t nygroup=2, const char *newname="");
133+
virtual TProfile2D *Rebin2D(Int_t nxgroup=2, Int_t nygroup=2, const char *newname="", const Double_t *xbins=0, const Double_t *ybins=0);
134134
virtual TProfile2D *RebinX(Int_t ngroup=2, const char *newname="");
135135
virtual TProfile2D *RebinY(Int_t ngroup=2, const char *newname="");
136136
virtual void SavePrimitive(std::ostream &out, Option_t *option = "");

hist/hist/src/TH2.cxx

Lines changed: 110 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

hist/hist/src/TProfile2D.cxx

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,8 @@ void TProfile2D::ExtendAxis(Double_t x, TAxis *axis)
14201420
////////////////////////////////////////////////////////////////////////////////
14211421
/// Rebin this histogram grouping nxgroup/nygroup bins along the xaxis/yaxis together.
14221422
///
1423+
/// ## case 1 xbins=0 || ybins=0
1424+
///
14231425
/// if newname is not blank a new profile hnew is created.
14241426
/// else the current histogram is modified (default)
14251427
/// The parameter nxgroup/nygroup indicate how many bins along the xaxis/yaxis of this
@@ -1444,8 +1446,27 @@ void TProfile2D::ExtendAxis(Double_t x, TAxis *axis)
14441446
/// ybin=newybins*nygroup and the remaining bins are added to
14451447
/// the overflow bin.
14461448
/// Statistics will be recomputed from the new bin contents.
1449+
///
1450+
/// ## case 2 xbins!=0 && ybins!=0
1451+
/// a new profile is created (you should specify newname).
1452+
/// The parameter nxgroup (nygroup) is the number of variable size bins for the x-axis
1453+
/// (y-axis) in the created profile.
1454+
/// The arrays xbins and ybins must contain nxgroup+1 and nygroup+1 elements that
1455+
/// represent the low-edge of the x and y bins respectively.
1456+
/// The data of the old bins are added to the new bin which contains the bin center
1457+
/// of the old bins. It is possible that information from the old binning are attached
1458+
/// to the under-/overflow bins of the new binning.
1459+
///
1460+
/// examples: if hp is an existing TProfile2D with 100 bins on x-axis
1461+
/// and 100 bins y-axis
1462+
///
1463+
/// ~~~ {.cpp}
1464+
/// Double_t xbins[25] = {...} array of low-edges for x-axis (xbins[25] is the upper edge of last bin)
1465+
/// Double_t ybins[25] = {...} array of low-edges for y-axis (ybins[25] is the upper edge of last bin)
1466+
/// hp->Rebin(24,24,"hpnew",xbins,ybins); //creates a new variable bin size profile hpnew
1467+
/// ~~~
14471468

1448-
TProfile2D * TProfile2D::Rebin2D(Int_t nxgroup ,Int_t nygroup,const char * newname ) {
1469+
TProfile2D * TProfile2D::Rebin2D(Int_t nxgroup ,Int_t nygroup,const char * newname, const Double_t *xbins, const Double_t *ybins) {
14491470
//something to do?
14501471
if((nxgroup != 1) || (nygroup != 1)){
14511472
Int_t nxbins = fXaxis.GetNbins();
@@ -1455,23 +1476,46 @@ TProfile2D * TProfile2D::Rebin2D(Int_t nxgroup ,Int_t nygroup,const char * newna
14551476
Double_t ymin = fYaxis.GetXmin();
14561477
Double_t ymax = fYaxis.GetXmax();
14571478
if ((nxgroup <= 0) || (nxgroup > nxbins)) {
1458-
Error("Rebin", "Illegal value of nxgroup=%d",nxgroup);
1479+
Error("Rebin2D", "Illegal value of nxgroup=%d",nxgroup);
14591480
return 0;
14601481
}
14611482
if ((nygroup <= 0) || (nygroup > nybins)) {
1462-
Error("Rebin", "Illegal value of nygroup=%d",nygroup);
1483+
Error("Rebin2D", "Illegal value of nygroup=%d",nygroup);
14631484
return 0;
14641485
}
14651486

14661487
Int_t newxbins = nxbins/nxgroup;
1467-
Int_t newybins = nybins/nygroup;
1488+
if (!xbins) {
1489+
Int_t nbg = nxbins/nxgroup;
1490+
//warning if bins are added to the overflow bin
1491+
if (nbg*nxgroup != nxbins) {
1492+
Warning("Rebin2D", "nxgroup=%d should be an exact divider of nxbins=%d",nxgroup,nxbins);
1493+
}
1494+
}
1495+
else {
1496+
// in the case of xbins given (rebinning in variable bins) ngroup is the new number of bins.
1497+
// and number of grouped bins is not constant.
1498+
// when looping for setting the contents for the new histogram we
1499+
// need to loop on all bins of original histogram. Set then nxgroup=nxbins
1500+
newxbins = nxgroup;
1501+
nxgroup = nxbins;
1502+
}
14681503

1469-
//warning if bins are added to the overflow bin
1470-
if(newxbins*nxgroup != nxbins) {
1471-
Warning("Rebin", "nxgroup=%d should be an exact divider of nxbins=%d",nxgroup,nxbins);
1504+
Int_t newybins = nybins/nygroup;
1505+
if (!ybins) {
1506+
Int_t nbg = nybins/nygroup;
1507+
//warning if bins are added to the overflow bin
1508+
if (nbg*nygroup != nybins) {
1509+
Warning("Rebin2D", "nygroup=%d should be an exact divider of nybins=%d",nygroup,nybins);
1510+
}
14721511
}
1473-
if(newybins*nygroup != nybins) {
1474-
Warning("Rebin", "nygroup=%d should be an exact divider of nybins=%d",nygroup,nybins);
1512+
else {
1513+
// in the case of ybins given (rebinning in variable bins) ngroup is the new number of bins.
1514+
// and number of grouped bins is not constant.
1515+
// when looping for setting the contents for the new histogram we
1516+
// need to loop on all bins of original histogram. Set then nygroup=nybins
1517+
newybins = nygroup;
1518+
nygroup = nybins;
14751519
}
14761520

14771521
//save old bin contents in new arrays
@@ -1492,35 +1536,38 @@ TProfile2D * TProfile2D::Rebin2D(Int_t nxgroup ,Int_t nygroup,const char * newna
14921536

14931537
// create a clone of the old profile if newname is specified
14941538
TProfile2D *hnew = this;
1495-
if(newname && strlen(newname) > 0) {
1539+
if((newname && strlen(newname) > 0) || xbins || ybins) {
14961540
hnew = (TProfile2D*)Clone(newname);
14971541
}
14981542

14991543
// in case of nxgroup/nygroup not an exact divider of nxbins/nybins,
15001544
// top limit is changed (see NOTE in method comment)
1501-
if(newxbins*nxgroup != nxbins) {
1545+
if(!xbins && (newxbins*nxgroup != nxbins)) {
15021546
xmax = fXaxis.GetBinUpEdge(newxbins*nxgroup);
15031547
hnew->fTsumw = 0; //stats must be reset because top bins will be moved to overflow bin
15041548
}
1505-
if(newybins*nygroup != nybins) {
1549+
if(!ybins && (newybins*nygroup != nybins)) {
15061550
ymax = fYaxis.GetBinUpEdge(newybins*nygroup);
15071551
hnew->fTsumw = 0; //stats must be reset because top bins will be moved to overflow bin
15081552
}
15091553

15101554
//rebin the axis
1511-
if((fXaxis.GetXbins()->GetSize() > 0) || (fYaxis.GetXbins()->GetSize() > 0)){
1512-
Double_t* xbins = new Double_t[newxbins+1];
1513-
Double_t* ybins = new Double_t[newybins+1];
1555+
if((!xbins && (fXaxis.GetXbins()->GetSize() > 0)) || (!ybins && (fYaxis.GetXbins()->GetSize() > 0))){
1556+
// for rebinning of variable bins in a constant group
1557+
Double_t* xbinsTmp = new Double_t[newxbins+1];
1558+
Double_t* ybinsTmp = new Double_t[newybins+1];
15141559
for(Int_t i=0; i < newxbins+1; i++)
1515-
xbins[i] = fXaxis.GetBinLowEdge(1+i*nxgroup);
1560+
xbinsTmp[i] = fXaxis.GetBinLowEdge(1+i*nxgroup);
15161561
for(Int_t j=0; j < newybins+1; j++)
1517-
ybins[j] = fYaxis.GetBinLowEdge(1+j*nygroup);
1562+
ybinsTmp[j] = fYaxis.GetBinLowEdge(1+j*nygroup);
15181563
hnew->SetBins(newxbins,xbins,newybins,ybins);
1519-
delete [] xbins;
1520-
delete [] ybins;
1521-
}
1564+
delete [] xbinsTmp;
1565+
delete [] ybinsTmp;
1566+
// when rebinning in variable bins
1567+
} else if (xbins && ybins) {
1568+
hnew->SetBins(newxbins,xbins,newybins,ybins);
15221569
//fixed bin size
1523-
else{
1570+
} else{
15241571
hnew->SetBins(newxbins,xmin,xmax,newybins,ymin,ymax);
15251572
}
15261573

0 commit comments

Comments
 (0)