Logo ROOT   6.10/09
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 //////////////////////////////////////////////////////////////////////////
12 // //
13 // THLimitsFinder //
14 // //
15 // Class to compute nice axis limits.
16 //
17 // This class is called by default by the histograming system
18 // and also by TTree::Draw, TTreePlayer::DrawSelect.
19 //
20 // A different finder may be specified via THLimitsFinder::SetFinder.
21 //
22 //////////////////////////////////////////////////////////////////////////
23 
24 #include "TH1.h"
25 #include "TMath.h"
26 #include "THLimitsFinder.h"
27 
29 
31 
32 /** \class THLimitsFinder
33  \ingroup Hist
34 Class to find nice axis limits
35 */
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
40 {
41 }
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 
46 {
47 }
48 
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// compute the best axis limits for the X axis.
52 /// If the bit kIsInteger is set, the number of channels is also recomputed.
53 /// The axis parameters are replaced by the optimized parameters
54 /// example:
55 /// With the input parameters xmin=-1.467 and xmax=2.344, the function
56 /// will compute better limits -1.8 and 2.7 and store them in the axis.
57 
59 {
60  Int_t newbins;
61  TAxis *xaxis = h->GetXaxis();
62 
63  if (xmin >= xmax) {
64  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
65  else {xmin -= 1; xmax += 1;}
66  }
67 
69  newbins,xmin,xmax,
70  xaxis->TestBit(TAxis::kIsInteger));
71 
72  h->SetBins(newbins,xmin,xmax);
73 
74  return 0;
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// compute the best axis limits for the X and Y axis.
79 /// If the bit kIsInteger is set, the number of channels is also recomputed.
80 /// The axis parameters are replaced by the optimized parameters
81 
83 {
84  Int_t newbinsx,newbinsy;
85  TAxis *xaxis = h->GetXaxis();
86  TAxis *yaxis = h->GetYaxis();
87 
88  if (xmin >= xmax) {
89  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
90  else {xmin -= 1; xmax += 1;}
91  }
92  if (ymin >= ymax) {
93  if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
94  else {ymin -= 1; ymax += 1;}
95  }
96 
98  newbinsx,xmin,xmax,
99  xaxis->TestBit(TAxis::kIsInteger));
100 
102  newbinsy,ymin,ymax,
103  yaxis->TestBit(TAxis::kIsInteger));
104 
105  h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax);
106  return 0;
107 }
108 
109 ////////////////////////////////////////////////////////////////////////////////
110 /// compute the best axis limits for the X, Y and Z axis.
111 /// If the bit kIsInteger is set, the number of channels is also recomputed.
112 /// The axis parameters are replaced by the optimized parameters
113 
115 {
116  Int_t newbinsx,newbinsy,newbinsz;
117  TAxis *xaxis = h->GetXaxis();
118  TAxis *yaxis = h->GetYaxis();
119  TAxis *zaxis = h->GetZaxis();
120 
121  if (xmin >= xmax) {
122  if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
123  else {xmin -= 1; xmax += 1;}
124  }
125  if (ymin >= ymax) {
126  if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
127  else {ymin -= 1; ymax += 1;}
128  }
129  if (zmin >= zmax) {
130  if (zaxis->GetLabels()) {zmin = 0; zmax = zmin +zaxis->GetNbins();}
131  else {zmin -= 1; zmax += 1;}
132  }
133 
135  newbinsx,xmin,xmax,
136  xaxis->TestBit(TAxis::kIsInteger));
137 
139  newbinsy,ymin,ymax,
140  yaxis->TestBit(TAxis::kIsInteger));
141 
143  newbinsz,zmin,zmax,
144  zaxis->TestBit(TAxis::kIsInteger));
145 
146  h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax,newbinsz,zmin,zmax);
147  return 0;
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Return pointer to the current finder.
152 /// Create one if none exists
153 /// Use SetLimitsFinder to set a user defined finder.
154 
156 {
158  return fgLimitsFinder;
159 }
160 
161 ////////////////////////////////////////////////////////////////////////////////
162 /// This static function can be used to specify a finder derived from THLimitsFinder.
163 /// The finder may redefine the functions FindGoodLimits.
164 /// Note that the redefined functions may call THLimitsFinder::FindGoodLimits.
165 
167 {
168  fgLimitsFinder = finder;
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// static function to compute reasonable axis limits
173 ///
174 /// Input parameters:
175 ///
176 /// A1,A2 : Original axis limits
177 /// BinLow,BinHigh : Optimized axis limits. They should be initialized by the
178 /// calling method for instance to 0.
179 /// nold : Original number of divisions.
180 /// nbins : Optimized number of divisions.
181 /// BinWidth : Optimized bin width. It should be initialized by the
182 /// calling method for instance to 0.
183 /// option : "T" means Time axis.
184 
186  Double_t &BinLow, Double_t &BinHigh,
187  Int_t &nbins, Double_t &BinWidth,
188  Option_t *option)
189 {
190  Int_t lwid, kwid;
191  Int_t ntemp = 0;
192  Int_t jlog = 0;
193  Double_t siground = 0;
194  Double_t alb, awidth, sigfig;
195  Double_t timemulti = 1;
196  Int_t roundmode =0;
197 
198  Int_t optionTime;
199  if(strchr(option,'t')) optionTime = 1; else optionTime = 0;
200 
201  nbins = nold;
202 
203  Double_t al = TMath::Min(A1,A2);
204  Double_t ah = TMath::Max(A1,A2);
205  if (al == ah) ah = al+1;
206  // if nold == -1 , program uses binwidth input from calling routine
207  if (nold == -1 && BinWidth > 0 ) goto L90;
208  ntemp = TMath::Max(nold,2);
209  if (ntemp < 1) ntemp = 1;
210 
211 L20:
212  awidth = (ah-al)/Double_t(ntemp);
213  timemulti = 1;
214  if (awidth >= FLT_MAX) goto LOK; //in float.h
215  if (awidth <= 0) goto LOK;
216 
217 // If time representation, bin width should be rounded to seconds
218 // minutes, hours or days
219 
220  if (optionTime && awidth>=60) { // if width in seconds, treat it as normal
221  // width in minutes
222  awidth /= 60; timemulti *=60;
223  roundmode = 1; // round minutes (60)
224  // width in hours ?
225  if (awidth>=60) {
226  awidth /= 60; timemulti *= 60;
227  roundmode = 2; // round hours (24)
228  // width in days ?
229  if (awidth>=24) {
230  awidth /= 24; timemulti *= 24;
231  roundmode = 3; // round days (30)
232  // width in months ?
233  if (awidth>=30.43685) { // Mean month length in 1900.
234  awidth /= 30.43685; timemulti *= 30.43685;
235  roundmode = 2; // round months (12)
236  // width in years ?
237  if (awidth>=12) {
238  awidth /= 12; timemulti *= 12;
239  roundmode = 0; // round years (10)
240  }
241  }
242  }
243  }
244  }
245 // Get nominal bin width in exponential form
246 
247  jlog = Int_t(TMath::Log10(awidth));
248  if (jlog <-200 || jlog > 200) {
249  BinLow = 0;
250  BinHigh = 1;
251  BinWidth = 0.01;
252  nbins = 100;
253  return;
254  }
255  if (awidth <= 1 && (!optionTime || timemulti==1) ) jlog--;
256  sigfig = awidth*TMath::Power(10,-jlog) -1e-10;
257  //in the above statement, it is important to substract 1e-10
258  //to avoid precision problems if the tests below
259 
260 // Round mantissa
261 
262  switch (roundmode) {
263 
264 // Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
265  case 1: // case 60
266  if (sigfig <= 1) siground = 1;
267  else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
268  else if (sigfig <= 2) siground = 2;
269  else if (sigfig <= 3 && jlog ==1) siground = 3;
270  else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
271  else if (jlog==0) {siground = 1; jlog++;}
272  else siground = 6;
273  break;
274  case 2: // case 12 and 24
275 
276 // Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
277  if (sigfig <= 1 && jlog==0) siground = 1;
278  else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
279  else if (sigfig <= 2 && jlog==0) siground = 2;
280  else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
281  else if (sigfig <= 3) siground = 3;
282  else if (sigfig <= 6) siground = 6;
283  else if (jlog==0) siground = 12;
284  else siground = 2.4;
285  break;
286 
287 //- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
288  case 3: // case 30
289  if (sigfig <= 1 && jlog==0) siground = 1;
290  else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
291  else if (sigfig <= 3 && jlog ==1) siground = 3;
292  else siground = 7;
293  break;
294  default :
295 
296 // Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
297  if (sigfig <= 1) siground = 1;
298  else if (sigfig <= 2) siground = 2;
299  else if (sigfig <= 5 && (!optionTime || jlog<1)) siground = 5;
300  else if (sigfig <= 6 && optionTime && jlog==1) siground = 6;
301  else {siground = 1; jlog++; }
302  break;
303  }
304 
305  BinWidth = siground*TMath::Power(10,jlog);
306  if (optionTime) BinWidth *= timemulti;
307 
308 // Get new bounds from new width BinWidth
309 
310 L90:
311  alb = al/BinWidth;
312  if (TMath::Abs(alb) > 1e9) {
313  BinLow = al;
314  BinHigh = ah;
315  if (nbins > 10*nold && nbins > 10000) nbins = nold;
316  return;
317  }
318  lwid = Int_t(alb);
319  if (alb < 0) lwid--;
320  BinLow = BinWidth*Double_t(lwid);
321  alb = ah/BinWidth + 1.00001;
322  kwid = Int_t(alb);
323  if (alb < 0) kwid--;
324  BinHigh = BinWidth*Double_t(kwid);
325  nbins = kwid - lwid;
326  if (nold == -1) goto LOK;
327  if (nold <= 5) { // Request for one bin is difficult case
328  if (nold > 1 || nbins == 1)goto LOK;
329  BinWidth = BinWidth*2;
330  nbins = 1;
331  goto LOK;
332  }
333  if (2*nbins == nold && !optionTime) {ntemp++; goto L20; }
334 
335 LOK:
336  Double_t oldBinLow = BinLow;
337  Double_t oldBinHigh = BinHigh;
338  Int_t oldnbins = nbins;
339 
340  Double_t atest = BinWidth*0.0001;
341  //if (TMath::Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02
342  //if (TMath::Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines
343  if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
344  if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
345  if (!optionTime && BinLow >= BinHigh) {
346  //this case may happen when nbins <=5
347  BinLow = oldBinLow;
348  BinHigh = oldBinHigh;
349  nbins = oldnbins;
350  }
351  else if (optionTime && BinLow>=BinHigh) {
352  nbins = 2*oldnbins;
353  BinHigh = oldBinHigh;
354  BinLow = oldBinLow;
355  BinWidth = (oldBinHigh - oldBinLow)/nbins;
356  atest = BinWidth*0.0001;
357  if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
358  if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
359  }
360 }
361 
362 ////////////////////////////////////////////////////////////////////////////////
363 /// Optimize axis limits.
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 find nice axis limits.
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
Definition: TH1.cxx:7883
TH1 * h
Definition: legend2.C:5
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.
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
int nbins[3]
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:628
THashList * GetLabels() const
Definition: TAxis.h:117
Double_t Log10(Double_t x)
Definition: TMath.h:652
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:301
float xmax
Definition: THbookFile.cxx:93
THLimitsFinder()
Pointer to hist limits finder.
#define ClassImp(name)
Definition: Rtypes.h:336
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:302
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()
Definition: TH1.h:300