Logo ROOT   6.14/05
Reference Guide
THLimitsFinder.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Rene Brun 14/01/2002
3 /*************************************************************************
4  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 #include "TH1.h"
12 #include "TMath.h"
13 #include "THLimitsFinder.h"
14 
16 
18 
19 /** \class THLimitsFinder
20  \ingroup Hist
21 Class to compute nice axis limits.
22 
23 This class is called by default by the histogramming system
24 and also by TTree::Draw, TTreePlayer::DrawSelect. TGaxis use it also to
25 optimize axis labels.
26 
27 A different finder may be specified via THLimitsFinder::SetFinder.
28 */
29 
30 ////////////////////////////////////////////////////////////////////////////////
31 
33 {
34 }
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 
39 {
40 }
41 
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Compute the best axis limits for the X axis.
45 ///
46 /// If the bit kIsInteger is set, the number of channels is also recomputed.
47 /// The axis parameters are replaced by the optimized parameters.
48 ///
49 /// Example:
50 /// With the input parameters xmin=-1.467 and xmax=2.344, the function
51 /// will compute better limits -1.8 and 2.7 and store them in the axis.
52 
54 {
55  Int_t newbins;
56  TAxis *xaxis = h->GetXaxis();
57 
58  if (xmin >= xmax) {
59  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
60  else {xmin -= 1; xmax += 1;}
61  }
62 
64  newbins,xmin,xmax,
65  xaxis->TestBit(TAxis::kIsInteger));
66 
67  h->SetBins(newbins,xmin,xmax);
68 
69  return 0;
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////////
73 /// Compute the best axis limits for the X and Y axis.
74 ///
75 /// If the bit kIsInteger is set, the number of channels is also recomputed.
76 /// The axis parameters are replaced by the optimized parameters
77 
79 {
80  Int_t newbinsx,newbinsy;
81  TAxis *xaxis = h->GetXaxis();
82  TAxis *yaxis = h->GetYaxis();
83 
84  if (xmin >= xmax) {
85  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
86  else {xmin -= 1; xmax += 1;}
87  }
88  if (ymin >= ymax) {
89  if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
90  else {ymin -= 1; ymax += 1;}
91  }
92 
94  newbinsx,xmin,xmax,
95  xaxis->TestBit(TAxis::kIsInteger));
96 
98  newbinsy,ymin,ymax,
99  yaxis->TestBit(TAxis::kIsInteger));
100 
101  h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax);
102  return 0;
103 }
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 /// Compute the best axis limits for the X, Y and Z axis.
107 ///
108 /// If the bit kIsInteger is set, the number of channels is also recomputed.
109 /// The axis parameters are replaced by the optimized parameters
110 
112 {
113  Int_t newbinsx,newbinsy,newbinsz;
114  TAxis *xaxis = h->GetXaxis();
115  TAxis *yaxis = h->GetYaxis();
116  TAxis *zaxis = h->GetZaxis();
117 
118  if (xmin >= xmax) {
119  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
120  else {xmin -= 1; xmax += 1;}
121  }
122  if (ymin >= ymax) {
123  if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
124  else {ymin -= 1; ymax += 1;}
125  }
126  if (zmin >= zmax) {
127  if (zaxis->GetLabels()) {zmin = 0; zmax = zmin +zaxis->GetNbins();}
128  else {zmin -= 1; zmax += 1;}
129  }
130 
132  newbinsx,xmin,xmax,
133  xaxis->TestBit(TAxis::kIsInteger));
134 
136  newbinsy,ymin,ymax,
137  yaxis->TestBit(TAxis::kIsInteger));
138 
140  newbinsz,zmin,zmax,
141  zaxis->TestBit(TAxis::kIsInteger));
142 
143  h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax,newbinsz,zmin,zmax);
144  return 0;
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 /// Return pointer to the current finder.
149 ///
150 /// Create one if none exists
151 /// Use SetLimitsFinder to set a user defined finder.
152 
154 {
156  return fgLimitsFinder;
157 }
158 
159 ////////////////////////////////////////////////////////////////////////////////
160 /// This static function can be used to specify a finder derived from THLimitsFinder.
161 ///
162 /// The finder may redefine the functions FindGoodLimits.
163 /// Note that the redefined functions may call THLimitsFinder::FindGoodLimits.
164 
166 {
167  fgLimitsFinder = finder;
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 /// Static function to compute reasonable axis limits
172 ///
173 /// Input parameters:
174 ///
175 /// \param[in] A1,A2 : Original axis limits
176 /// \param[in] BinLow,BinHigh : Optimized axis limits. They should be initialized by the
177 /// calling method for instance to 0.
178 /// \param[out] nold : Original number of divisions.
179 /// \param[out] nbins : Optimized number of divisions.
180 /// \param[out] BinWidth : Optimized bin width. It should be initialized by the
181 /// calling method for instance to 0.
182 /// \param[in] option : "T" means Time axis.
183 
185  Double_t &BinLow, Double_t &BinHigh,
186  Int_t &nbins, Double_t &BinWidth,
187  Option_t *option)
188 {
189  Int_t lwid, kwid;
190  Int_t ntemp = 0;
191  Int_t jlog = 0;
192  Double_t siground = 0;
193  Double_t alb, awidth, sigfig;
194  Double_t timemulti = 1;
195  Int_t roundmode =0;
196 
197  Int_t optionTime;
198  if(strchr(option,'t')) optionTime = 1; else optionTime = 0;
199 
200  nbins = nold;
201 
202  Double_t al = TMath::Min(A1,A2);
203  Double_t ah = TMath::Max(A1,A2);
204  if (al == ah) ah = al+1;
205  // if nold == -1 , program uses binwidth input from calling routine
206  if (nold == -1 && BinWidth > 0 ) goto L90;
207  ntemp = TMath::Max(nold,2);
208  if (ntemp < 1) ntemp = 1;
209 
210 L20:
211  awidth = (ah-al)/Double_t(ntemp);
212  timemulti = 1;
213  if (awidth >= FLT_MAX) goto LOK; //in float.h
214  if (awidth <= 0) goto LOK;
215 
216 // If time representation, bin width should be rounded to seconds
217 // minutes, hours or days
218 
219  if (optionTime && awidth>=60) { // if width in seconds, treat it as normal
220  // width in minutes
221  awidth /= 60; timemulti *=60;
222  roundmode = 1; // round minutes (60)
223  // width in hours ?
224  if (awidth>=60) {
225  awidth /= 60; timemulti *= 60;
226  roundmode = 2; // round hours (24)
227  // width in days ?
228  if (awidth>=24) {
229  awidth /= 24; timemulti *= 24;
230  roundmode = 3; // round days (30)
231  // width in months ?
232  if (awidth>=30.43685) { // Mean month length in 1900.
233  awidth /= 30.43685; timemulti *= 30.43685;
234  roundmode = 2; // round months (12)
235  // width in years ?
236  if (awidth>=12) {
237  awidth /= 12; timemulti *= 12;
238  roundmode = 0; // round years (10)
239  }
240  }
241  }
242  }
243  }
244 // Get nominal bin width in exponential form
245 
246  jlog = Int_t(TMath::Log10(awidth));
247  if (jlog <-200 || jlog > 200) {
248  BinLow = 0;
249  BinHigh = 1;
250  BinWidth = 0.01;
251  nbins = 100;
252  return;
253  }
254  if (awidth <= 1 && (!optionTime || timemulti==1) ) jlog--;
255  sigfig = awidth*TMath::Power(10,-jlog) -1e-10;
256  //in the above statement, it is important to subtract 1e-10
257  //to avoid precision problems if the tests below
258 
259 // Round mantissa
260 
261  switch (roundmode) {
262 
263 // Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
264  case 1: // case 60
265  if (sigfig <= 1) siground = 1;
266  else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
267  else if (sigfig <= 2) siground = 2;
268  else if (sigfig <= 3 && jlog ==1) siground = 3;
269  else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
270  else if (jlog==0) {siground = 1; jlog++;}
271  else siground = 6;
272  break;
273  case 2: // case 12 and 24
274 
275 // Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
276  if (sigfig <= 1 && jlog==0) siground = 1;
277  else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
278  else if (sigfig <= 2 && jlog==0) siground = 2;
279  else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
280  else if (sigfig <= 3) siground = 3;
281  else if (sigfig <= 6) siground = 6;
282  else if (jlog==0) siground = 12;
283  else siground = 2.4;
284  break;
285 
286 //- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
287  case 3: // case 30
288  if (sigfig <= 1 && jlog==0) siground = 1;
289  else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
290  else if (sigfig <= 3 && jlog ==1) siground = 3;
291  else siground = 7;
292  break;
293  default :
294 
295 // Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
296  if (sigfig <= 1) siground = 1;
297  else if (sigfig <= 2) siground = 2;
298  else if (sigfig <= 5 && (!optionTime || jlog<1)) siground = 5;
299  else if (sigfig <= 6 && optionTime && jlog==1) siground = 6;
300  else {siground = 1; jlog++; }
301  break;
302  }
303 
304  BinWidth = siground*TMath::Power(10,jlog);
305  if (optionTime) BinWidth *= timemulti;
306 
307 // Get new bounds from new width BinWidth
308 
309 L90:
310  alb = al/BinWidth;
311  if (TMath::Abs(alb) > 1e9) {
312  BinLow = al;
313  BinHigh = ah;
314  if (nbins > 10*nold && nbins > 10000) nbins = nold;
315  return;
316  }
317  lwid = Int_t(alb);
318  if (alb < 0) lwid--;
319  BinLow = BinWidth*Double_t(lwid);
320  alb = ah/BinWidth + 1.00001;
321  kwid = Int_t(alb);
322  if (alb < 0) kwid--;
323  BinHigh = BinWidth*Double_t(kwid);
324  nbins = kwid - lwid;
325  if (nold == -1) goto LOK;
326  if (nold <= 5) { // Request for one bin is difficult case
327  if (nold > 1 || nbins == 1)goto LOK;
328  BinWidth = BinWidth*2;
329  nbins = 1;
330  goto LOK;
331  }
332  if (2*nbins == nold && !optionTime) {ntemp++; goto L20; }
333 
334 LOK:
335  Double_t oldBinLow = BinLow;
336  Double_t oldBinHigh = BinHigh;
337  Int_t oldnbins = nbins;
338 
339  Double_t atest = BinWidth*0.0001;
340  //if (TMath::Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02
341  //if (TMath::Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines
342  if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
343  if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
344  if (!optionTime && BinLow >= BinHigh) {
345  //this case may happen when nbins <=5
346  BinLow = oldBinLow;
347  BinHigh = oldBinHigh;
348  nbins = oldnbins;
349  }
350  else if (optionTime && BinLow>=BinHigh) {
351  nbins = 2*oldnbins;
352  BinHigh = oldBinHigh;
353  BinLow = oldBinLow;
354  BinWidth = (oldBinHigh - oldBinLow)/nbins;
355  atest = BinWidth*0.0001;
356  if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
357  if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
358  }
359 }
360 
361 ////////////////////////////////////////////////////////////////////////////////
362 /// Optimize axis limits.
363 ///
364 /// When isInter=kTRUE, the function makes an integer binwidth
365 /// and recompute the number of bins accordingly.
366 
368 {
369  Double_t binlow = 0,binhigh = 0,binwidth=0;
370  Int_t n=0;
371  Double_t dx = 0.1*(xmax-xmin);
372  if (isInteger) dx = 5*(xmax-xmin)/nbins;
373  Double_t umin = xmin - dx;
374  Double_t umax = xmax + dx;
375  if (umin < 0 && xmin >= 0) umin = 0;
376  if (umax > 0 && xmax <= 0) umax = 0;
377 
378  THLimitsFinder::Optimize(umin,umax,nbins,binlow,binhigh,n,binwidth,"");
379 
380  if (binwidth <= 0 || binwidth > 1.e+39) {
381  xmin = -1;
382  xmax = 1;
383  } else {
384  xmin = binlow;
385  xmax = binhigh;
386  }
387  if (isInteger) {
388  Int_t ixmin = Int_t(xmin);
389  Int_t ixmax = Int_t(xmax);
390  Double_t dxmin = Double_t(ixmin);
391  Double_t dxmax = Double_t(ixmax);
392  if (xmin < 0 && xmin != dxmin) xmin = dxmin - 1;
393  else xmin = dxmin;
394  if (xmax > 0 && xmax != dxmax) xmax = dxmax + 1;
395  else if (xmax ==0 && xmax == dxmax) xmax = 1;
396  else xmax = dxmax;
397  if (xmin >= xmax) xmax = xmin+1;
398  Int_t bw = Int_t((xmax-xmin)/nbins);
399  if (bw == 0) bw = 1;
400  nbins = Int_t((xmax-xmin)/bw);
401  if (xmin +nbins*bw < umax) {nbins++; xmax = xmin +nbins*bw;}
402  if (xmin > umin) {nbins++; xmin = xmax -nbins*bw;}
403  }
404  newbins = nbins;
405 }
float xmin
Definition: THbookFile.cxx:93
virtual ~THLimitsFinder()
const char Option_t
Definition: RtypesCore.h:62
float ymin
Definition: THbookFile.cxx:93
Class to compute nice axis limits.
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
Definition: TH1.cxx:8061
static void Optimize(Double_t A1, Double_t A2, Int_t nold, Double_t &BinLow, Double_t &BinHigh, Int_t &nbins, Double_t &BWID, Option_t *option="")
Static function to compute reasonable axis limits.
static THLimitsFinder * GetLimitsFinder()
Return pointer to the current finder.
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual Int_t FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax)
Compute the best axis limits for the X axis.
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
static void OptimizeLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
Optimize axis limits.
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Definition: TMath.h:734
THashList * GetLabels() const
Definition: TAxis.h:117
Double_t Log10(Double_t x)
Definition: TMath.h:763
static void SetLimitsFinder(THLimitsFinder *finder)
This static function can be used to specify a finder derived from THLimitsFinder. ...
float ymax
Definition: THbookFile.cxx:93
Class to manage histogram axis.
Definition: TAxis.h:30
TAxis * GetYaxis()
Definition: TH1.h:316
float xmax
Definition: THbookFile.cxx:93
THLimitsFinder()
Pointer to hist limits finder.
#define h(i)
Definition: RSha256.hxx:106
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
The TH1 histogram class.
Definition: TH1.h:56
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
TAxis * GetZaxis()
Definition: TH1.h:317
static THLimitsFinder * fgLimitsFinder
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
Int_t GetNbins() const
Definition: TAxis.h:121
const Int_t n
Definition: legend1.C:16
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition: TH1.h:315