THLimitsFinder.cxx

Go to the documentation of this file.
00001 // @(#)root/hist:$Id: THLimitsFinder.cxx 35262 2010-09-14 09:51:49Z brun $
00002 // Author: Rene Brun   14/01/2002
00003 /*************************************************************************
00004  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00005  * All rights reserved.                                                  *
00006  *                                                                       *
00007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00009  *************************************************************************/
00010 
00011 //////////////////////////////////////////////////////////////////////////
00012 //                                                                      //
00013 // THLimitsFinder                                                       //
00014 //                                                                      //
00015 // Class to compute nice axis limits.
00016 //
00017 // This class is called by default by the histograming system
00018 // and also by TTree::Draw, TTreePlayer::DrawSelect.
00019 //
00020 // A different finder may be specified via THLimitsFinder::SetFinder.
00021 //
00022 //////////////////////////////////////////////////////////////////////////
00023 
00024 #include "TH1.h"
00025 #include "TMath.h"
00026 #include "THLimitsFinder.h"
00027 
00028 THLimitsFinder *THLimitsFinder::fgLimitsFinder = 0;
00029 
00030 ClassImp(THLimitsFinder)
00031 
00032 //______________________________________________________________________________
00033 THLimitsFinder::THLimitsFinder()
00034 {
00035 }
00036 
00037 //______________________________________________________________________________
00038 THLimitsFinder::~THLimitsFinder()
00039 {
00040 }
00041 
00042 
00043 //______________________________________________________________________________
00044 Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax)
00045 {
00046 // compute the best axis limits for the X axis.
00047 // If the bit kIsInteger is set, the number of channels is also recomputed.
00048 // The axis parameters are replaced by the optimized parameters
00049 // example:
00050 //  With the input parameters xmin=-1.467 and xmax=2.344, the function
00051 //  will compute better limits -1.8 and 2.7 and store them in the axis.
00052          
00053    Int_t newbins;
00054    TAxis *xaxis = h->GetXaxis();
00055    
00056    if (xmin >= xmax) {
00057       if (xaxis->GetLabels()) {xmin  = 0; xmax  = xmin +xaxis->GetNbins();}
00058       else                    {xmin -= 1; xmax += 1;}
00059    }   
00060    
00061    THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
00062                                   newbins,xmin,xmax,
00063                                   xaxis->TestBit(TAxis::kIsInteger));
00064    
00065    h->SetBins(newbins,xmin,xmax);
00066  
00067    return 0;
00068 }
00069 
00070 //______________________________________________________________________________
00071 Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax)
00072 {
00073 // compute the best axis limits for the X and Y axis.
00074 // If the bit kIsInteger is set, the number of channels is also recomputed.
00075 // The axis parameters are replaced by the optimized parameters
00076 
00077    Int_t newbinsx,newbinsy;
00078    TAxis *xaxis = h->GetXaxis();
00079    TAxis *yaxis = h->GetYaxis();
00080    
00081    if (xmin >= xmax) {
00082       if (xaxis->GetLabels()) {xmin  = 0; xmax  = xmin +xaxis->GetNbins();}
00083       else                    {xmin -= 1; xmax += 1;}
00084    }   
00085    if (ymin >= ymax) {
00086       if (yaxis->GetLabels()) {ymin  = 0; ymax  = ymin +yaxis->GetNbins();}
00087       else                    {ymin -= 1; ymax += 1;}
00088    }      
00089    
00090    THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
00091                                   newbinsx,xmin,xmax,
00092                                   xaxis->TestBit(TAxis::kIsInteger));
00093    
00094    THLimitsFinder::OptimizeLimits(yaxis->GetNbins(),
00095                                   newbinsy,ymin,ymax,
00096                                   yaxis->TestBit(TAxis::kIsInteger));
00097   
00098    h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax);
00099    return 0;
00100 }
00101 
00102 //______________________________________________________________________________
00103 Int_t THLimitsFinder::FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax)
00104 {
00105 // compute the best axis limits for the X, Y and Z axis.
00106 // If the bit kIsInteger is set, the number of channels is also recomputed.
00107 // The axis parameters are replaced by the optimized parameters
00108 
00109    Int_t newbinsx,newbinsy,newbinsz;
00110    TAxis *xaxis = h->GetXaxis();
00111    TAxis *yaxis = h->GetYaxis();
00112    TAxis *zaxis = h->GetZaxis();
00113    
00114    if (xmin >= xmax) {
00115       if (xaxis->GetLabels()) {xmin  = 0; xmax  = xmin +xaxis->GetNbins();}
00116       else                    {xmin -= 1; xmax += 1;}
00117    }   
00118    if (ymin >= ymax) {
00119       if (yaxis->GetLabels()) {ymin  = 0; ymax  = ymin +yaxis->GetNbins();}
00120       else                    {ymin -= 1; ymax += 1;}
00121    }      
00122    if (zmin >= zmax) {
00123       if (zaxis->GetLabels()) {zmin  = 0; zmax  = zmin +zaxis->GetNbins();}
00124       else                    {zmin -= 1; zmax += 1;}
00125    }         
00126    
00127    THLimitsFinder::OptimizeLimits(xaxis->GetNbins(),
00128                                   newbinsx,xmin,xmax,
00129                                   xaxis->TestBit(TAxis::kIsInteger));
00130    
00131    THLimitsFinder::OptimizeLimits(yaxis->GetNbins(),
00132                                   newbinsy,ymin,ymax,
00133                                   yaxis->TestBit(TAxis::kIsInteger));
00134    
00135    THLimitsFinder::OptimizeLimits(zaxis->GetNbins(),
00136                                   newbinsz,zmin,zmax,
00137                                   zaxis->TestBit(TAxis::kIsInteger));
00138   
00139    h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax,newbinsz,zmin,zmax);
00140    return 0;
00141 }
00142 
00143 //______________________________________________________________________________
00144 THLimitsFinder *THLimitsFinder::GetLimitsFinder() 
00145 {
00146 // Return pointer to the current finder.
00147 // Create one if none exists
00148 // Use SetLimitsFinder to set a user defined finder.
00149    
00150    if (!fgLimitsFinder) fgLimitsFinder = new THLimitsFinder();
00151    return fgLimitsFinder;
00152 }
00153 
00154 //______________________________________________________________________________
00155 void THLimitsFinder::SetLimitsFinder(THLimitsFinder *finder) 
00156 {
00157 // This static function can be used to specify a finder derived from THLimitsFinder.
00158 // The finder may redefine the functions FindGoodLimits.
00159 // Note that the redefined functions may call THLimitsFinder::FindGoodLimits.
00160       
00161    fgLimitsFinder = finder;
00162 }
00163 
00164 //______________________________________________________________________________
00165 void THLimitsFinder::Optimize(Double_t A1,  Double_t A2,  Int_t nold ,Double_t &BinLow, Double_t &BinHigh, 
00166                       Int_t &nbins, Double_t &BinWidth, Option_t *option)
00167 {
00168 // static function to compute reasonable axis limits
00169 //
00170 // Input parameters:
00171 //
00172 //  A1,A2 : Old WMIN,WMAX .
00173 //  BinLow,BinHigh : New WMIN,WMAX .
00174 //  nold   : Old NDIV .
00175 //  nbins    : New NDIV .
00176 
00177    Int_t lwid, kwid;
00178    Int_t ntemp = 0;
00179    Int_t jlog  = 0;
00180    Double_t siground = 0;
00181    Double_t alb, awidth, sigfig;
00182    Double_t timemulti = 1;
00183    Int_t roundmode =0;
00184 
00185    Int_t optionTime;
00186    if(strchr(option,'t')) optionTime = 1;  else optionTime = 0;
00187 
00188    nbins = nold;
00189 
00190    Double_t al = TMath::Min(A1,A2);
00191    Double_t ah = TMath::Max(A1,A2);
00192    if (al == ah) ah = al+1;
00193    // if nold  ==  -1 , program uses binwidth input from calling routine
00194    if (nold == -1 && BinWidth > 0 ) goto L90;
00195    ntemp = TMath::Max(nold,2);
00196    if (ntemp < 1) ntemp = 1;
00197 
00198 L20:
00199    awidth = (ah-al)/Double_t(ntemp);
00200    timemulti = 1;
00201    if (awidth >= FLT_MAX) goto LOK;  //in float.h
00202    if (awidth <= 0)       goto LOK;
00203 
00204 //      If time representation, bin width should be rounded to seconds
00205 //      minutes, hours or days
00206 
00207    if (optionTime && awidth>=60) { // if width in seconds, treat it as normal
00208       //   width in minutes
00209       awidth /= 60; timemulti *=60;
00210       roundmode = 1; // round minutes (60)
00211       //   width in hours ?
00212       if (awidth>=60) {
00213          awidth /= 60; timemulti *= 60;
00214          roundmode = 2; // round hours (24)
00215          //   width in days ?
00216          if (awidth>=24) {
00217             awidth /= 24; timemulti *= 24;
00218             roundmode = 3; // round days (30)
00219             //   width in months ?
00220             if (awidth>=30.43685) { // Mean month length in 1900.
00221                awidth /= 30.43685; timemulti *= 30.43685;
00222                roundmode = 2; // round months (12)
00223                //   width in years ?
00224                if (awidth>=12) {
00225                   awidth /= 12; timemulti *= 12;
00226                   roundmode = 0; // round years (10)
00227                }
00228             }
00229          }
00230       }
00231    }
00232 //      Get nominal bin width in exponential form
00233 
00234    jlog   = Int_t(TMath::Log10(awidth));
00235    if (jlog <-200 || jlog > 200) {
00236       BinLow   = 0;
00237       BinHigh  = 1;
00238       BinWidth = 0.01;
00239       nbins    = 100;
00240       return;
00241    }
00242    if (awidth <= 1 && (!optionTime || timemulti==1) ) jlog--;
00243    sigfig = awidth*TMath::Power(10,-jlog) -1e-10;
00244    //in the above statement, it is important to substract 1e-10
00245    //to avoid precision problems if the tests below
00246    
00247 //      Round mantissa
00248 
00249    switch (roundmode) {
00250 
00251 //      Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
00252       case 1: // case 60
00253          if      (sigfig <= 1)    siground = 1;
00254          else if (sigfig <= 1.5 && jlog==1)    siground = 1.5;
00255          else if (sigfig <= 2)    siground = 2;
00256          else if (sigfig <= 3 && jlog ==1)    siground = 3;
00257          else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
00258          else if (jlog==0)        {siground = 1; jlog++;}
00259          else                     siground = 6;
00260          break;
00261       case 2: // case 12 and 24
00262 
00263 //      Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
00264          if      (sigfig <= 1 && jlog==0)    siground = 1;
00265          else if (sigfig <= 1.2 && jlog==1)    siground = 1.2;
00266          else if (sigfig <= 2 && jlog==0)    siground = 2;
00267          else if (sigfig <= 2.4 && jlog==1)    siground = 2.4;
00268          else if (sigfig <= 3)    siground = 3;
00269          else if (sigfig <= 6)    siground = 6;
00270          else if (jlog==0)        siground = 12;
00271          else                     siground = 2.4;
00272          break;
00273 
00274 //-      Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
00275       case 3: // case 30
00276          if      (sigfig <= 1 && jlog==0)    siground = 1;
00277          else if (sigfig <= 1.4 && jlog==1)    siground = 1.4;
00278          else if (sigfig <= 3 && jlog ==1)    siground = 3;
00279          else                     siground = 7;
00280          break;
00281       default :
00282       
00283 //      Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
00284          if      (sigfig <= 1)    siground = 1;
00285          else if (sigfig <= 2)    siground = 2;
00286          else if (sigfig <= 5 && (!optionTime || jlog<1))  siground = 5;
00287          else if (sigfig <= 6 && optionTime && jlog==1)    siground = 6;
00288          else                    {siground = 1;   jlog++; }
00289          break;
00290    }
00291 
00292    BinWidth = siground*TMath::Power(10,jlog);
00293    if (optionTime) BinWidth *= timemulti;
00294 
00295 //      Get new bounds from new width BinWidth
00296 
00297 L90:
00298    alb  = al/BinWidth;
00299    if (TMath::Abs(alb) > 1e9) {
00300       BinLow  = al;
00301       BinHigh = ah;
00302       if (nbins > 10*nold && nbins > 10000) nbins = nold;
00303       return;
00304    }
00305    lwid   = Int_t(alb);
00306    if (alb < 0) lwid--;
00307    BinLow     = BinWidth*Double_t(lwid);
00308    alb        = ah/BinWidth + 1.00001;
00309    kwid = Int_t(alb);
00310    if (alb < 0) kwid--;
00311    BinHigh = BinWidth*Double_t(kwid);
00312    nbins = kwid - lwid;
00313    if (nold == -1) goto LOK;
00314    if (nold <= 5) {          //    Request for one bin is difficult case
00315       if (nold > 1 || nbins == 1)goto LOK;
00316       BinWidth = BinWidth*2;
00317       nbins    = 1;
00318       goto LOK;
00319    }
00320    if (2*nbins == nold && !optionTime) {ntemp++; goto L20; }
00321 
00322 LOK:
00323    Double_t oldBinLow = BinLow;
00324    Double_t oldBinHigh = BinHigh;
00325    Int_t oldnbins = nbins;
00326 
00327    Double_t atest = BinWidth*0.0001;
00328    //if (TMath::Abs(BinLow-A1)  >= atest) { BinLow  += BinWidth;  nbins--; } //replaced by Damir in 3.10/02
00329    //if (TMath::Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth;  nbins--; } //by the next two lines
00330    if (al-BinLow  >= atest) { BinLow  += BinWidth;  nbins--; }
00331    if (BinHigh-ah >= atest) { BinHigh -= BinWidth;  nbins--; }
00332    if (!optionTime && BinLow >= BinHigh) {
00333       //this case may happen when nbins <=5
00334       BinLow = oldBinLow;
00335       BinHigh = oldBinHigh;
00336       nbins = oldnbins;
00337    }
00338    else if (optionTime && BinLow>=BinHigh) {
00339       nbins = 2*oldnbins;
00340       BinHigh = oldBinHigh;
00341       BinLow = oldBinLow;
00342       BinWidth = (oldBinHigh - oldBinLow)/nbins;
00343       atest = BinWidth*0.0001;
00344       if (al-BinLow  >= atest) { BinLow  += BinWidth;  nbins--; }
00345       if (BinHigh-ah >= atest) { BinHigh -= BinWidth;  nbins--; }
00346    }
00347 }
00348 
00349 //______________________________________________________________________________
00350 void THLimitsFinder::OptimizeLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
00351 {
00352 // Optimize axis limits.
00353 // When isInter=kTRUE, the function makes an integer binwidth
00354 // and recompute the number of bins accordingly.
00355    
00356    Double_t binlow,binhigh,binwidth=0;
00357    Int_t n=0;
00358    Double_t dx = 0.1*(xmax-xmin);
00359    if (isInteger) dx = 5*(xmax-xmin)/nbins;
00360    Double_t umin = xmin - dx;
00361    Double_t umax = xmax + dx;
00362    if (umin < 0 && xmin >= 0) umin = 0;
00363    if (umax > 0 && xmax <= 0) umax = 0;
00364    
00365    THLimitsFinder::Optimize(umin,umax,nbins,binlow,binhigh,n,binwidth,"");
00366    
00367    if (binwidth <= 0 || binwidth > 1.e+39) {
00368       xmin = -1;
00369       xmax = 1;
00370    } else {
00371       xmin    = binlow;
00372       xmax    = binhigh;
00373    }
00374    if (isInteger) {
00375       Int_t ixmin = Int_t(xmin);
00376       Int_t ixmax = Int_t(xmax);
00377       Double_t dxmin = Double_t(ixmin);
00378       Double_t dxmax = Double_t(ixmax);
00379       if (xmin < 0 && xmin != dxmin) xmin = dxmin - 1;
00380       else                           xmin = dxmin;
00381       if (xmax > 0 && xmax != dxmax)      xmax = dxmax + 1;
00382       else if (xmax ==0 && xmax == dxmax) xmax = 1;
00383       else                                xmax = dxmax;
00384       if (xmin >= xmax) xmax = xmin+1;
00385       Int_t bw = Int_t((xmax-xmin)/nbins);
00386       if (bw == 0) bw = 1;
00387       nbins = Int_t((xmax-xmin)/bw);
00388       if (xmin +nbins*bw < umax) {nbins++; xmax = xmin +nbins*bw;}
00389       if (xmin > umin)           {nbins++; xmin = xmax -nbins*bw;}
00390    }
00391    newbins = nbins;
00392 }

Generated on Tue Jul 5 14:24:20 2011 for ROOT_528-00b_version by  doxygen 1.5.1