#include "TH1.h"
#include "TMath.h"
#include "THLimitsFinder.h"
THLimitsFinder *THLimitsFinder::fgLimitsFinder = 0;
ClassImp(THLimitsFinder)
THLimitsFinder::THLimitsFinder()
{
}
THLimitsFinder::~THLimitsFinder()
{
}
Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax)
{
Int_t newbins;
TAxis *xaxis = h->GetXaxis();
if (xmin >= xmax) {
if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
else {xmin -= 1; xmax += 1;}
}
THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
newbins,xmin,xmax,
xaxis->TestBit(TAxis::kIsInteger));
h->SetBins(newbins,xmin,xmax);
return 0;
}
Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax)
{
Int_t newbinsx,newbinsy;
TAxis *xaxis = h->GetXaxis();
TAxis *yaxis = h->GetYaxis();
if (xmin >= xmax) {
if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
else {xmin -= 1; xmax += 1;}
}
if (ymin >= ymax) {
if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
else {ymin -= 1; ymax += 1;}
}
THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
newbinsx,xmin,xmax,
xaxis->TestBit(TAxis::kIsInteger));
THLimitsFinder::OptimizeLimits(yaxis->GetNbins(),
newbinsy,ymin,ymax,
yaxis->TestBit(TAxis::kIsInteger));
h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax);
return 0;
}
Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax)
{
Int_t newbinsx,newbinsy,newbinsz;
TAxis *xaxis = h->GetXaxis();
TAxis *yaxis = h->GetYaxis();
TAxis *zaxis = h->GetZaxis();
if (xmin >= xmax) {
if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
else {xmin -= 1; xmax += 1;}
}
if (ymin >= ymax) {
if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
else {ymin -= 1; ymax += 1;}
}
if (zmin >= zmax) {
if (zaxis->GetLabels()) {zmin = 0; zmax = zmin +zaxis->GetNbins();}
else {zmin -= 1; zmax += 1;}
}
THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
newbinsx,xmin,xmax,
xaxis->TestBit(TAxis::kIsInteger));
THLimitsFinder::OptimizeLimits(yaxis->GetNbins(),
newbinsy,ymin,ymax,
yaxis->TestBit(TAxis::kIsInteger));
THLimitsFinder::OptimizeLimits(zaxis->GetNbins(),
newbinsz,zmin,zmax,
zaxis->TestBit(TAxis::kIsInteger));
h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax,newbinsz,zmin,zmax);
return 0;
}
THLimitsFinder *THLimitsFinder::GetLimitsFinder()
{
if (!fgLimitsFinder) fgLimitsFinder = new THLimitsFinder();
return fgLimitsFinder;
}
void THLimitsFinder::SetLimitsFinder(THLimitsFinder *finder)
{
fgLimitsFinder = finder;
}
void THLimitsFinder::Optimize(Double_t A1, Double_t A2, Int_t nold ,
Double_t &BinLow, Double_t &BinHigh,
Int_t &nbins, Double_t &BinWidth,
Option_t *option)
{
Int_t lwid, kwid;
Int_t ntemp = 0;
Int_t jlog = 0;
Double_t siground = 0;
Double_t alb, awidth, sigfig;
Double_t timemulti = 1;
Int_t roundmode =0;
Int_t optionTime;
if(strchr(option,'t')) optionTime = 1; else optionTime = 0;
nbins = nold;
Double_t al = TMath::Min(A1,A2);
Double_t ah = TMath::Max(A1,A2);
if (al == ah) ah = al+1;
if (nold == -1 && BinWidth > 0 ) goto L90;
ntemp = TMath::Max(nold,2);
if (ntemp < 1) ntemp = 1;
L20:
awidth = (ah-al)/Double_t(ntemp);
timemulti = 1;
if (awidth >= FLT_MAX) goto LOK;
if (awidth <= 0) goto LOK;
if (optionTime && awidth>=60) {
awidth /= 60; timemulti *=60;
roundmode = 1;
if (awidth>=60) {
awidth /= 60; timemulti *= 60;
roundmode = 2;
if (awidth>=24) {
awidth /= 24; timemulti *= 24;
roundmode = 3;
if (awidth>=30.43685) {
awidth /= 30.43685; timemulti *= 30.43685;
roundmode = 2;
if (awidth>=12) {
awidth /= 12; timemulti *= 12;
roundmode = 0;
}
}
}
}
}
jlog = Int_t(TMath::Log10(awidth));
if (jlog <-200 || jlog > 200) {
BinLow = 0;
BinHigh = 1;
BinWidth = 0.01;
nbins = 100;
return;
}
if (awidth <= 1 && (!optionTime || timemulti==1) ) jlog--;
sigfig = awidth*TMath::Power(10,-jlog) -1e-10;
switch (roundmode) {
case 1:
if (sigfig <= 1) siground = 1;
else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
else if (sigfig <= 2) siground = 2;
else if (sigfig <= 3 && jlog ==1) siground = 3;
else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5;
else if (jlog==0) {siground = 1; jlog++;}
else siground = 6;
break;
case 2:
if (sigfig <= 1 && jlog==0) siground = 1;
else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
else if (sigfig <= 2 && jlog==0) siground = 2;
else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
else if (sigfig <= 3) siground = 3;
else if (sigfig <= 6) siground = 6;
else if (jlog==0) siground = 12;
else siground = 2.4;
break;
case 3:
if (sigfig <= 1 && jlog==0) siground = 1;
else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
else if (sigfig <= 3 && jlog ==1) siground = 3;
else siground = 7;
break;
default :
if (sigfig <= 1) siground = 1;
else if (sigfig <= 2) siground = 2;
else if (sigfig <= 5 && (!optionTime || jlog<1)) siground = 5;
else if (sigfig <= 6 && optionTime && jlog==1) siground = 6;
else {siground = 1; jlog++; }
break;
}
BinWidth = siground*TMath::Power(10,jlog);
if (optionTime) BinWidth *= timemulti;
L90:
alb = al/BinWidth;
if (TMath::Abs(alb) > 1e9) {
BinLow = al;
BinHigh = ah;
if (nbins > 10*nold && nbins > 10000) nbins = nold;
return;
}
lwid = Int_t(alb);
if (alb < 0) lwid--;
BinLow = BinWidth*Double_t(lwid);
alb = ah/BinWidth + 1.00001;
kwid = Int_t(alb);
if (alb < 0) kwid--;
BinHigh = BinWidth*Double_t(kwid);
nbins = kwid - lwid;
if (nold == -1) goto LOK;
if (nold <= 5) {
if (nold > 1 || nbins == 1)goto LOK;
BinWidth = BinWidth*2;
nbins = 1;
goto LOK;
}
if (2*nbins == nold && !optionTime) {ntemp++; goto L20; }
LOK:
Double_t oldBinLow = BinLow;
Double_t oldBinHigh = BinHigh;
Int_t oldnbins = nbins;
Double_t atest = BinWidth*0.0001;
if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
if (!optionTime && BinLow >= BinHigh) {
BinLow = oldBinLow;
BinHigh = oldBinHigh;
nbins = oldnbins;
}
else if (optionTime && BinLow>=BinHigh) {
nbins = 2*oldnbins;
BinHigh = oldBinHigh;
BinLow = oldBinLow;
BinWidth = (oldBinHigh - oldBinLow)/nbins;
atest = BinWidth*0.0001;
if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
}
}
void THLimitsFinder::OptimizeLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
{
Double_t binlow = 0,binhigh = 0,binwidth=0;
Int_t n=0;
Double_t dx = 0.1*(xmax-xmin);
if (isInteger) dx = 5*(xmax-xmin)/nbins;
Double_t umin = xmin - dx;
Double_t umax = xmax + dx;
if (umin < 0 && xmin >= 0) umin = 0;
if (umax > 0 && xmax <= 0) umax = 0;
THLimitsFinder::Optimize(umin,umax,nbins,binlow,binhigh,n,binwidth,"");
if (binwidth <= 0 || binwidth > 1.e+39) {
xmin = -1;
xmax = 1;
} else {
xmin = binlow;
xmax = binhigh;
}
if (isInteger) {
Int_t ixmin = Int_t(xmin);
Int_t ixmax = Int_t(xmax);
Double_t dxmin = Double_t(ixmin);
Double_t dxmax = Double_t(ixmax);
if (xmin < 0 && xmin != dxmin) xmin = dxmin - 1;
else xmin = dxmin;
if (xmax > 0 && xmax != dxmax) xmax = dxmax + 1;
else if (xmax ==0 && xmax == dxmax) xmax = 1;
else xmax = dxmax;
if (xmin >= xmax) xmax = xmin+1;
Int_t bw = Int_t((xmax-xmin)/nbins);
if (bw == 0) bw = 1;
nbins = Int_t((xmax-xmin)/bw);
if (xmin +nbins*bw < umax) {nbins++; xmax = xmin +nbins*bw;}
if (xmin > umin) {nbins++; xmin = xmax -nbins*bw;}
}
newbins = nbins;
}