Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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
15#include <algorithm>
16
18
19
20/** \class THLimitsFinder
21 \ingroup Histograms
22Class to compute nice axis limits.
23
24This class is called by default by the histogramming system
25and also by TTree::Draw, TTreePlayer::DrawSelect. TGaxis use it also to
26optimize axis labels.
27
28A different finder may be specified via THLimitsFinder::SetFinder.
29*/
30
31////////////////////////////////////////////////////////////////////////////////
32
36
37////////////////////////////////////////////////////////////////////////////////
38
42
43
44////////////////////////////////////////////////////////////////////////////////
45/// Compute the best axis limits for the X axis.
46///
47/// If the bit kIsInteger is set, the number of channels is also recomputed.
48/// The axis parameters are replaced by the optimized parameters.
49///
50/// Example:
51/// With the input parameters xmin=-1.467 and xmax=2.344, the function
52/// will compute better limits -1.8 and 2.7 and store them in the axis.
53
55{
57 TAxis *xaxis = h->GetXaxis();
58
59 if (xmin >= xmax) {
60 if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
61 else {xmin -= 1; xmax += 1;}
62 }
63
66 xaxis->TestBit(TAxis::kIsInteger));
67
68 h->SetBins(newbins,xmin,xmax);
69
70 return 0;
71}
72
73////////////////////////////////////////////////////////////////////////////////
74/// Compute the best axis limits for the X and Y axis
75/// if the corresponding `newbins` variable is set to 0, i.e. the default value.
76///
77/// If the bit kIsInteger is set, the number of channels is also recomputed.
78/// The axis parameters are replaced by the optimized parameters
79
82{
83 TAxis *xaxis = h->GetXaxis();
84 TAxis *yaxis = h->GetYaxis();
85
86 const Bool_t xbinAuto = newbinsx == 0;
87 const Bool_t ybinAuto = newbinsy == 0;
88
89 if (xbinAuto && xmin >= xmax) {
90 if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
91 else {xmin -= 1; xmax += 1;}
92 }
93 if (ybinAuto && ymin >= ymax) {
94 if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
95 else {ymin -= 1; ymax += 1;}
96 }
97
98 if (xbinAuto)
101 xaxis->TestBit(TAxis::kIsInteger));
102 if (ybinAuto)
105 yaxis->TestBit(TAxis::kIsInteger));
106
107 h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax);
108 return 0;
109}
110
111////////////////////////////////////////////////////////////////////////////////
112/// Compute the best axis limits and bins for the X, Y and Z axis
113/// if the corresponding `newbins` variable is set to 0, i.e. the default value.
114///
115/// If the bit kIsInteger is set, the number of channels is also recomputed.
116/// The axis parameters are replaced by the optimized parameters
117
120{
121 TAxis *xaxis = h->GetXaxis();
122 TAxis *yaxis = h->GetYaxis();
123 TAxis *zaxis = h->GetZaxis();
124
125 const Bool_t xbinAuto = newbinsx == 0;
126 const Bool_t ybinAuto = newbinsy == 0;
127 const Bool_t zbinAuto = newbinsz == 0;
128
129 if (xbinAuto && xmin >= xmax) {
130 if (xaxis->GetLabels()) {xmin = 0; xmax = xmin +xaxis->GetNbins();}
131 else {xmin -= 1; xmax += 1;}
132 }
133 if (ybinAuto && ymin >= ymax) {
134 if (yaxis->GetLabels()) {ymin = 0; ymax = ymin +yaxis->GetNbins();}
135 else {ymin -= 1; ymax += 1;}
136 }
137 if (zbinAuto && zmin >= zmax) {
138 if (zaxis->GetLabels()) {zmin = 0; zmax = zmin +zaxis->GetNbins();}
139 else {zmin -= 1; zmax += 1;}
140 }
141
142 if (xbinAuto)
145 xaxis->TestBit(TAxis::kIsInteger));
146 if (ybinAuto)
149 yaxis->TestBit(TAxis::kIsInteger));
150 if (zbinAuto)
152 newbinsz,zmin,zmax,
153 zaxis->TestBit(TAxis::kIsInteger));
154
155 h->SetBins(newbinsx,xmin,xmax,newbinsy,ymin,ymax,newbinsz,zmin,zmax);
156 return 0;
157}
158
159////////////////////////////////////////////////////////////////////////////////
160/// Return pointer to the current finder.
161///
162/// Create one if none exists
163/// Use SetLimitsFinder to set a user defined finder.
164
170
171////////////////////////////////////////////////////////////////////////////////
172/// This static function can be used to specify a finder derived from THLimitsFinder.
173///
174/// The finder may redefine the functions FindGoodLimits*.
175/// Note that the redefined functions may call THLimitsFinder::FindGoodLimits*.
176
181
182////////////////////////////////////////////////////////////////////////////////
183/// Static function to compute reasonable axis limits
184///
185/// Input parameters:
186///
187/// \param[in] A1,A2 : Original axis limits
188/// \param[in] BinLow,BinHigh : Optimized axis limits. They should be initialized by the
189/// calling method for instance to 0.
190/// \param[out] nold : Original number of divisions.
191/// \param[out] nbins : Optimized number of divisions.
192/// \param[out] BinWidth : Optimized bin width. It should be initialized by the
193/// calling method for instance to 0.
194/// \param[in] option : "T" means Time axis.
195
198 Int_t &nbins, Double_t &BinWidth,
200{
201 Int_t lwid, kwid;
202 Int_t ntemp = 0;
203 Int_t jlog = 0;
204 Double_t siground = 0;
207 Int_t roundmode =0;
208
210 if(strchr(option,'t')) optionTime = 1; else optionTime = 0;
211
212 nbins = nold;
213
216 if (al == ah) ah = al+1;
217 // if nold == -1 , program uses binwidth input from calling routine
218 if (nold == -1 && BinWidth > 0 ) goto L90;
219 ntemp = TMath::Max(nold,2);
220 if (ntemp < 1) ntemp = 1;
221
222L20:
224 timemulti = 1;
225 if (awidth >= FLT_MAX) goto LOK; //in float.h
226 if (awidth <= 0) goto LOK;
227
228// If time representation, bin width should be rounded to seconds
229// minutes, hours or days
230
231 if (optionTime && awidth>=60) { // if width in seconds, treat it as normal
232 // width in minutes
233 awidth /= 60; timemulti *=60;
234 roundmode = 1; // round minutes (60)
235 // width in hours ?
236 if (awidth>=60) {
237 awidth /= 60; timemulti *= 60;
238 roundmode = 2; // round hours (24)
239 // width in days ?
240 if (awidth>=24) {
241 awidth /= 24; timemulti *= 24;
242 roundmode = 3; // round days (30)
243 // width in months ?
244 if (awidth>=30.43685) { // Mean month length in 1900.
245 awidth /= 30.43685; timemulti *= 30.43685;
246 roundmode = 2; // round months (12)
247 // width in years ?
248 if (awidth>=12) {
249 awidth /= 12; timemulti *= 12;
250 roundmode = 0; // round years (10)
251 }
252 }
253 }
254 }
255 }
256// Get nominal bin width in exponential form
257
259 if (jlog <-200 || jlog > 200) {
260 BinLow = 0;
261 BinHigh = 1;
262 BinWidth = 0.01;
263 nbins = 100;
264 return;
265 }
266 if (awidth <= 1 && (!optionTime || timemulti==1) ) jlog--;
267 sigfig = awidth*TMath::Power(10,-jlog) -1e-10;
268 //in the above statement, it is important to subtract 1e-10
269 //to avoid precision problems if the tests below
270
271// Round mantissa
272
273 switch (roundmode) {
274
275// Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
276 case 1: // case 60
277 if (sigfig <= 1) siground = 1;
278 else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
279 else if (sigfig <= 2) siground = 2;
280 else if (sigfig <= 3 && jlog ==1) siground = 3;
281 else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
282 else if (jlog==0) {siground = 1; jlog++;}
283 else siground = 6;
284 break;
285 case 2: // case 12 and 24
286
287// Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
288 if (sigfig <= 1 && jlog==0) siground = 1;
289 else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
290 else if (sigfig <= 2 && jlog==0) siground = 2;
291 else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
292 else if (sigfig <= 3) siground = 3;
293 else if (sigfig <= 6) siground = 6;
294 else if (jlog==0) siground = 12;
295 else siground = 2.4;
296 break;
297
298//- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
299 case 3: // case 30
300 if (sigfig <= 1 && jlog==0) siground = 1;
301 else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
302 else if (sigfig <= 3 && jlog ==1) siground = 3;
303 else siground = 7;
304 break;
305 default :
306
307// Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
308 if (sigfig <= 1) siground = 1;
309 else if (sigfig <= 2) siground = 2;
310 else if (sigfig <= 5 && (!optionTime || jlog<1)) siground = 5;
311 else if (sigfig <= 6 && optionTime && jlog==1) siground = 6;
312 else {siground = 1; jlog++; }
313 break;
314 }
315
318
319// Get new bounds from new width BinWidth
320
321L90:
322 alb = al/BinWidth;
323 if (TMath::Abs(alb) > 1e9) {
324 BinLow = al;
325 BinHigh = ah;
326 if (nbins > 10*nold && nbins > 10000) nbins = nold;
327 return;
328 }
329 lwid = Int_t(alb);
330 if (alb < 0) lwid--;
332 alb = ah/BinWidth + 1.00001;
333 kwid = Int_t(alb);
334 if (alb < 0) kwid--;
336 nbins = kwid - lwid;
337 if (nold == -1) goto LOK;
338 if (nold <= 5) { // Request for one bin is difficult case
339 if (nold > 1 || nbins == 1)goto LOK;
340 BinWidth = BinWidth*2;
341 nbins = 1;
342 goto LOK;
343 }
344 if (2*nbins == nold && !optionTime) {ntemp++; goto L20; }
345
346LOK:
349 Int_t oldnbins = nbins;
350
351 Double_t atest = BinWidth*0.0001;
352 //if (TMath::Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02
353 //if (TMath::Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines
354 if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
355 if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
356 if (!optionTime && BinLow >= BinHigh) {
357 //this case may happen when nbins <=5
360 nbins = oldnbins;
361 }
362 else if (optionTime && BinLow>=BinHigh) {
363 nbins = 2*oldnbins;
366 BinWidth = (oldBinHigh - oldBinLow)/nbins;
367 atest = BinWidth*0.0001;
368 if (al-BinLow >= atest) { BinLow += BinWidth; nbins--; }
369 if (BinHigh-ah >= atest) { BinHigh -= BinWidth; nbins--; }
370 }
371}
372
373////////////////////////////////////////////////////////////////////////////////
374/// Optimize axis limits.
375///
376/// When isInter=kTRUE, the function makes an integer binwidth
377/// and recompute the number of bins accordingly.
378
380{
382 Int_t n=0;
383 Double_t dx = 0.1*(xmax-xmin);
384 if (isInteger) dx = 5*(xmax-xmin)/nbins;
385 Double_t umin = xmin - dx;
386 Double_t umax = xmax + dx;
387 if (umin < 0 && xmin >= 0) umin = 0;
388 if (umax > 0 && xmax <= 0) umax = 0;
389
391
392 if (binwidth <= 0 || binwidth > 1.e+39) {
393 xmin = -1;
394 xmax = 1;
395 } else {
396 const auto delta = 0.01 * (xmax - xmin);
397 xmin = std::min(binlow, xmin - delta);
398 xmax = std::max(binhigh, xmax + delta);
399 }
400 if (isInteger) {
405 if (xmin < 0 && xmin != dxmin) xmin = dxmin - 1;
406 else xmin = dxmin;
407 if (xmax > 0 && xmax != dxmax) xmax = dxmax + 1;
408 else if (xmax ==0 && xmax == dxmax) xmax = 1;
409 else xmax = dxmax;
410 if (xmin >= xmax) xmax = xmin+1;
411 Long64_t bw = Long64_t((xmax-xmin)/nbins);
412 if (bw == 0) bw = 1;
413 nbins = Int_t((xmax-xmin)/bw);
414 if (xmin +nbins*bw < umax) {nbins++; xmax = xmin +nbins*bw;}
415 if (xmin > umin) {nbins++; xmin = xmax -nbins*bw;}
416 }
417 newbins = nbins;
418}
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t option
float xmin
float ymin
float xmax
float ymax
Class to manage histogram axis.
Definition TAxis.h:32
@ kIsInteger
Definition TAxis.h:76
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
Class to compute nice axis limits.
static void SetLimitsFinder(THLimitsFinder *finder)
This static function can be used to specify a finder derived from THLimitsFinder.
~THLimitsFinder() override
static THLimitsFinder * GetLimitsFinder()
Return pointer to the current finder.
static void OptimizeLimits(Int_t nbins, Int_t &newbins, Double_t &xmin, Double_t &xmax, Bool_t isInteger)
Optimize axis limits.
virtual Int_t FindGoodLimitsXY(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t newbinsx=0, Int_t newbinsy=0)
Compute the best axis limits for the X and Y axis if the corresponding newbins variable is set to 0,...
static THLimitsFinder * fgLimitsFinder
! Pointer to hist limits finder
virtual Int_t FindGoodLimits(TH1 *h, Double_t xmin, Double_t xmax)
Compute the best axis limits for the X axis.
virtual Int_t FindGoodLimitsXYZ(TH1 *h, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax, Int_t newbinsx=0, Int_t newbinsy=0, Int_t newbinsz=0)
Compute the best axis limits and bins for the X, Y and Z axis if the corresponding newbins variable i...
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.
const Int_t n
Definition legend1.C:16
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:732
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:197
Double_t Log10(Double_t x)
Returns the common (base-10) logarithm of x.
Definition TMath.h:773
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122