Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGaxis.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Rene Brun, Olivier Couet 12/12/94
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
15 #include <math.h>
16 
17 #include "Riostream.h"
18 #include "TROOT.h"
19 #include "TGaxis.h"
20 #include "TAxisModLab.h"
21 #include "TVirtualPad.h"
22 #include "TVirtualX.h"
23 #include "TLine.h"
24 #include "TLatex.h"
25 #include "TStyle.h"
26 #include "TF1.h"
27 #include "TAxis.h"
28 #include "THashList.h"
29 #include "TObjString.h"
30 #include "TObject.h"
31 #include "TMath.h"
32 #include "THLimitsFinder.h"
33 #include "TColor.h"
34 #include "TClass.h"
35 #include "TTimeStamp.h"
36 #include "TSystem.h"
37 #include "TTimeStamp.h"
38 
39 Int_t TGaxis::fgMaxDigits = 5;
40 Float_t TGaxis::fXAxisExpXOffset = 0.; //Exponent X offset for the X axis
41 Float_t TGaxis::fXAxisExpYOffset = 0.; //Exponent Y offset for the X axis
42 Float_t TGaxis::fYAxisExpXOffset = 0.; //Exponent X offset for the Y axis
43 Float_t TGaxis::fYAxisExpYOffset = 0.; //Exponent Y offset for the Y axis
44 const Int_t kHori = BIT(9); //defined in TPad
45 
46 ClassImp(TGaxis);
47 
48 /** \class TGaxis
49 \ingroup BasicGraphics
50 
51 The axis painter class.
52 
53 Instances of this class are generated by the histograms and graphs painting
54 classes when `TAxis` are drawn. `TGaxis` is the "painter class" of
55 `TAxis`. Therefore it is mainly used via `TAxis`, even if is some
56 occasion it can be used directly to draw an axis which is not part of a graph
57 or an instance. For instance to draw an extra scale on a plot.
58 
59 - [Basic definition](#GA00)
60 - [Definition with a function](#GA01)
61 - [Logarithmic axis](#GA02)
62 - [Blank axis](#GA03)
63 - [Tick marks' orientation](#GA04)
64 - [Tick marks' size](#GA05)
65 - [Labels' positionning](#GA06)
66 - [Labels' orientation](#GA07)
67 - [Labels' position on tick marks](#GA08)
68 - [Labels' format](#GA09)
69 - [Alphanumeric labels](#GA10)
70 - [Changing axis labels](#GA10a)
71 - [Number of divisions optimisation](#GA11)
72 - [Maximum Number of Digits for the axis labels](#GA12)
73 - [Optional grid](#GA13)
74 - [Time axis](#GA14)
75 
76 ## <a name="GA00"></a> Basic definition
77 A `TGaxis` is defined the following way:
78 ~~~ {.cpp}
79  TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
80  Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt,
81  Double_t gridlength)
82 ~~~
83 Where:
84 
85 - xmin : X origin coordinate in user's coordinates space.
86 - xmax : X end axis coordinate in user's coordinates space.
87 - ymin : Y origin coordinate in user's coordinates space.
88 - ymax : Y end axis coordinate in user's coordinates space.
89 - wmin : Lowest value for the tick mark labels written on the axis.
90 - wmax : Highest value for the tick mark labels written on the axis.
91 - ndiv : Number of divisions.
92  - ndiv=N1 + 100*N2 + 10000*N3
93  - N1=number of 1st divisions.
94  - N2=number of 2nd divisions.
95  - N3=number of 3rd divisions. e.g.:
96  - ndiv=0 --> no tick marks.
97  - ndiv=2 --> 2 divisions, one tick mark in the middle of the axis.
98 - chopt : Drawing options (see below).
99 - gridlength: grid length on main tick marks.
100 
101 The example below generates various kind of axis.
102 
103 Begin_Macro(source)
104 {
105  TCanvas *c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,500);
106 
107  c1->Range(-10,-1,10,1);
108 
109  TGaxis *axis1 = new TGaxis(-4.5,-0.2,5.5,-0.2,-6,8,510,"");
110  axis1->SetName("axis1");
111  axis1->Draw();
112 
113  TGaxis *axis2 = new TGaxis(-4.5,0.2,5.5,0.2,0.001,10000,510,"G");
114  axis2->SetName("axis2");
115  axis2->Draw();
116 
117  TGaxis *axis3 = new TGaxis(-9,-0.8,-9,0.8,-8,8,50510,"");
118  axis3->SetName("axis3");
119  axis3->Draw();
120 
121  TGaxis *axis4 = new TGaxis(-7,-0.8,-7,0.8,1,10000,50510,"G");
122  axis4->SetName("axis4");
123  axis4->Draw();
124 
125  TGaxis *axis5 = new TGaxis(-4.5,-0.6,5.5,-0.6,1.2,1.32,80506,"-+");
126  axis5->SetName("axis5");
127  axis5->SetLabelSize(0.03);
128  axis5->SetTextFont(72);
129  axis5->SetLabelOffset(0.025);
130 
131  axis5->Draw();
132 
133  TGaxis *axis6 = new TGaxis(-4.5,0.6,5.5,0.6,100,900,50510,"-");
134  axis6->SetName("axis6");
135  axis6->Draw();
136 
137  TGaxis *axis7 = new TGaxis(8,-0.8,8,0.8,0,9000,50510,"+L");
138  axis7->SetName("axis7");
139  axis7->SetLabelOffset(0.01);
140  axis7->Draw();
141 
142  //one can make axis going top->bottom. However because of a long standing
143  //problem, the two x values should not be equal
144  TGaxis *axis8 = new TGaxis(6.5,0.8,6.499,-0.8,0,90,50510,"-");
145  axis8->SetName("axis8");
146  axis8->Draw();
147 }
148 End_Macro
149 
150 ## <a name="GA01"></a> Definition with a function
151 
152 Instead of the wmin,wmax arguments of the normal definition, the
153 name of a `TF1` function can be specified. This function will be used to
154 map the user coordinates to the axis values and ticks.
155 
156 A `TGaxis` is defined the following way:
157 ~~~ {.cpp}
158  TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
159  const char *func, Int_t ndiv, Option_t *chopt,
160  Double_t gridlength)
161 ~~~
162 Where:
163 
164 - xmin : X origin coordinate in user's coordinates space.
165 - xmax : X end axis coordinate in user's coordinates space.
166 - ymin : Y origin coordinate in user's coordinates space.
167 - ymax : Y end axis coordinate in user's coordinates space.
168 - func : function defining axis labels and tick marks.
169 - ndiv : Number of divisions.
170  - ndiv=N1 + 100*N2 + 10000*N3
171  - N1=number of 1st divisions.
172  - N2=number of 2nd divisions.
173  - N3=number of 3rd divisions. e.g.:
174  - ndiv=0 --> no tick marks.
175  - ndiv=2 --> 2 divisions, one tick mark in the middle of the axis.
176 - chopt : Drawing options (see below).
177 - gridlength: grid length on main tick marks.
178 
179 Examples:
180 
181 Begin_Macro(source)
182 {
183  TCanvas *c2 = new TCanvas("c2","c2",10,10,700,500);
184 
185  gPad->DrawFrame(0.,-2.,10.,2);
186 
187  TF1 *f1=new TF1("f1","-x",-10,10);
188  TGaxis *A1 = new TGaxis(0,2,10,2,"f1",510,"-");
189  A1->SetTitle("axis with decreasing values");
190  A1->Draw();
191 
192  TF1 *f2=new TF1("f2","exp(x)",0,2);
193  TGaxis *A2 = new TGaxis(1,1,9,1,"f2");
194  A2->SetTitle("exponential axis");
195  A2->SetLabelSize(0.03);
196  A2->SetTitleSize(0.03);
197  A2->SetTitleOffset(1.2);
198  A2->Draw();
199 
200  TF1 *f3=new TF1("f3","log10(x)",1,1000);
201  TGaxis *A3 = new TGaxis(2,-2,2,0,"f3",505,"");
202  A3->SetTitle("logarithmic axis");
203  A3->SetLabelSize(0.02);
204  A3->SetTitleSize(0.03);
205  A3->SetTitleOffset(0.); // Axis title automatically placed
206  A3->Draw();
207 }
208 End_Macro
209 
210 
211 ## <a name="GA02"></a> Logarithmic axis
212 
213 By default axis are linear. To define a `TGaxis` as logarithmic, it is
214 enough to create it with the option `"G"`.
215 
216 When plotting an histogram or a graph the logarithmic scale can be set using:
217 
218  - `gPad->SetLogx(1);` set the logarithmic scale on the X axis
219  - `gPad->SetLogy(1);` set the logarithmic scale on the Y axis
220 
221 When the `SetMoreLogLabels()` method is called more labels are drawn
222 when in logarithmic scale and there is a small number of decades (less than 3).
223 
224 ## <a name="GA03"></a> Blank axis
225 To draw only the axis tick marks without the axis body, it is enough to specify
226 the option `"B"`. It useful to superpose axis.
227 
228 ## <a name="GA04"></a> Tick marks' orientation
229 
230 By default tick marks are drawn on the positive side of the axis, except for
231 vertical axis for which the default is negative. The `chop` parameter
232 allows to control the tick marks orientation:
233 
234  - `chopt = "+"`: tick marks are drawn on Positive side. (default)
235  - `chopt ="-"`: tick mark are drawn on the negative side.
236  - `chopt = "+-"`: tick marks are drawn on both sides of the axis.
237  - `chopt = "U"`: Unlabelled axis, default is labeled.
238 
239 ## <a name="GA05"></a> Tick marks' size
240 
241 By default, tick marks have a length equal to 3 per cent of the axis length.
242 When the option "S" is specified, the length of the tick marks is equal to
243 `fTickSize*axis_length`, where `fTickSize` may be set via
244 `TGaxis::SetTickSize`.
245 
246 When plotting an histogram `h` the tick marks size can be changed using:
247 
248  - `h->GetXaxis()->SetTickLength(0.02);` set the tick length for the X axis
249  - `gStyle->SetTickLength(0.02,"x");` set the tick length for the X axis
250  of all histograms drawn after this instruction.
251 
252 A good way to remove tick marks on an axis is to set the tick length to 0:
253 `h->GetXaxis()->SetTickLength(0.);`
254 
255 ## <a name="GA06"></a> Labels' positionning
256 
257 Labels are normally drawn on side opposite to tick marks. However the option
258 `"="` allows to draw them on the same side. The distance between the labels and
259 the axis body can be changed with `SetLabelOffset`.
260 
261 ## <a name="GA07"></a> Labels' orientation
262 
263 By default axis labels are drawn parallel to the axis. However if the axis is vertical
264 then are drawn perpendicular to the axis.
265 
266 ## <a name="GA08"></a> Labels' position on tick marks
267 
268 By default axis labels are centered on tick marks. However, for vertical axis,
269 they are right adjusted. The `chop` parameter allows to control the labels'
270 position on tick marks:
271 
272  - `chopt = "R"`: labels are Right adjusted on tick mark.(default is centered)
273  - `chopt = "L"`: labels are Left adjusted on tick mark.
274  - `chopt = "C"`: labels are Centered on tick mark.
275  - `chopt = "M"`: In the Middle of the divisions.
276 
277 ## <a name="GA09"></a> Labels' format
278 
279 Blank characters are stripped, and then the label is correctly aligned. the dot,
280 if last character of the string, is also stripped, unless the option `"."`
281 (a dot, or period) is specified. if `SetDecimals(kTRUE)` has been called
282 all labels have the same number of decimals after the `"."`
283 The same is true if `gStyle->SetStripDecimals(kFALSE)` has been called.
284 
285 In the following, we have some parameters, like tick marks length and characters
286 height (in percentage of the length of the axis (user's coordinates))
287 The default values are as follows:
288 
289  - Primary tick marks: 3.0 %
290  - Secondary tick marks: 1.5 %
291  - Third order tick marks: .75 %
292  - Characters height for labels: 4%
293  - Labels offset: 1.0 %
294 
295 By default, an exponent of the form 10^N is used when the label values are either
296 all very small or very large. One can disable the exponent by calling
297 `axis.SetNoExponent(kTRUE)`.
298 
299 `TGaxis::SetExponentOffset(Float_t xoff, Float_t yoff, Option_t *axis)` is
300 static function to set X and Y offset of the axis 10^n notation. It is in % of
301 the pad size. It can be negative. `axis` specifies which axis
302 (`"x"` or/and `"y"`), default is `"x"` if `axis = "xz"`
303 set the two axes
304 
305 ## <a name="GA10"></a> Alphanumeric labels
306 
307 Axis labels can be any alphanumeric character strings. Such axis can be produced
308 only with histograms because the labels'definition is stored in `TAxis`.
309 The following example demonstrates how to create such labels.
310 
311 Begin_Macro(source)
312 ../../../tutorials/hist/hlabels2.C
313 End_Macro
314 
315 Because the alphanumeric labels are usually longer that the numeric labels, their
316 size is by default equal to `0.66666 * the_numeric_labels_size`.
317 
318 ## <a name="GA10a"></a> Changing axis labels
319 \since **ROOT version 6.07/07:**
320 
321 After an axis has been created, TGaxis::ChangeLabel allows to define new text
322 attributes for a given label. A fine tuning of the labels can be done. All the
323 attributes can be changed as well as the text label itself.
324 
325 When plotting an histogram or a graph the labels can be changed like in the
326 following example which shows a way to produce \f$\pi\f$-axis :
327 
328 Begin_Macro(source)
329 {
330  Double_t pi = TMath::Pi();
331  TF1* f = new TF1("f","TMath::Cos(x/TMath::Pi())", -pi, pi);
332  TH1* h = f->GetHistogram();
333  TAxis* a = h->GetXaxis();
334  a->SetNdivisions(-502);
335  a->ChangeLabel(1,-1,-1,-1,-1,-1,"-#pi");
336  a->ChangeLabel(-1,-1,-1,-1,-1,-1,"#pi");
337  f->Draw();
338 }
339 End_Macro
340 
341 ## <a name="GA11"></a> Number of divisions optimisation
342 
343 By default the number of divisions on axis is optimised to show a coherent
344 labelling of the main tick marks. The number of division (`ndiv`) is a
345 composite integer given by:
346 
347 ` ndiv = N1 + 100*N2 + 10000*N3`
348 
349  - `N1` = number of 1st divisions.
350  - `N2` = number of 2nd divisions.
351  - `N3` = number of 3rd divisions.
352 
353 by default the value of `N1`, `N2` and `N3` are maximum
354 values. After optimisation the real number of divisions will be smaller or
355 equal to these value. If one wants to bypass the optimisation, the option `"N"`
356 should be given when the `TGaxis` is created. The option `"I"`
357 also act on the number of division as it will force an integer labelling of
358 the axis.
359 
360 On an histogram pointer `h` the number of divisions can be set in different ways:.
361 
362 - Directly on the histogram. The following will set the number of division
363  to 510 on the X axis of `h`. To avoid optimization the number of divisions
364  should be negative (ie: -510);
365 ~~~ {.cpp}
366  h->SetNdivisions(510, "X");
367 ~~~
368 - On the axis itself:
369 ~~~ {.cpp}
370  h->GetXaxis()->SetNdivisions(510, kTRUE);
371 ~~~
372 
373 The first parameter is the number of division. If it is negative of if the
374 second parameter is kFALSE then the number of divisions is not optimised.
375 And other signature is also allowed:
376 ~~~ {.cpp}
377  h->GetXaxis()->SetNdivisions(10, 5, 0, kTRUE);
378 ~~~
379 ## <a name="GA12"></a> Maximum Number of Digits for the axis labels
380 
381 The static function `TGaxis::SetMaxDigits` sets the maximum number of
382 digits permitted for the axis labels above which the notation with 10^N is used.
383 For example, to accept 6 digits number like 900000 on an axis call
384 `TGaxis::SetMaxDigits(6)`. The default value is 5.
385 `fgMaxDigits` must be greater than 0.
386 
387 ## <a name="GA13"></a> Optional grid
388 
389 The option `"W"` allows to draw a grid on the primary tick marks. In case
390 of a log axis, the grid is only drawn for the primary tick marks if the number
391 of secondary and tertiary divisions is 0. `SetGridLength()` allows to define
392 the length of the grid.
393 
394 When plotting an histogram or a graph the grid can be set ON or OFF using:
395 
396  - `gPad->SetGridy(1);` set the grid on the X axis
397  - `gPad->SetGridx(1);` set the grid on the Y axis
398  - `gPad->SetGrid(1,1);` set the grid on both axis.
399 
400 ## <a name="GA14"></a> Time axis
401 
402 Histograms' axis can be defined as "time axis". To do that it is enough to activate
403 the TAxis::SetTimeDisplay attribute on a given axis. If `h` is an histogram, it is
404 done the following way:
405 
406 ~~~ .cpp
407 h->GetXaxis()->SetTimeDisplay(1); // The X axis is a time axis
408 ~~~
409 
410 Two parameters can be adjusted in order to define time axis:
411 
412 ### The time format:
413 
414 Defines the format of the labels along the time axis. It can be changed using the TAxis
415 TAxis::SetTimeFormat. The time format is the one used by the C function **strftime()**.
416 It's a string containing the following formatting characters:
417 
418  - for date :
419  - **%a** abbreviated weekday name
420  - **%b** abbreviated month name
421  - **%d** day of the month (01-31)
422  - **%m** month (01-12)
423  - **%y** year without century
424  - **%Y** year with century
425  - for time :
426  - **%H** hour (24-hour clock)
427  - **%I** hour (12-hour clock)
428  - **%p** local equivalent of AM or PM
429  - **%M** minute (00-59)
430  - **%S** seconds (00-61)
431  - **%%** %
432 
433  The other characters are output as is. For example to have a format like
434  `dd/mm/yyyy` one should do:
435 
436 ~~~ .cpp
437 h->GetXaxis()->SetTimeFormat("%d\/%m\/%Y");
438 ~~~
439 
440 ### The time offset:
441 
442 This is a time in seconds in the UNIX standard UTC format (this is an universal
443 time, not the local time), defining the starting date of an histogram axis.
444 This date should be greater than 01/01/95 and is given in seconds. There are
445 three ways to define the time offset:
446 
447 #### By setting the global default time offset:
448 
449 ~~~ .cpp
450 TDatime da(2003,02,28,12,00,00);
451 gStyle->SetTimeOffset(da.Convert());
452 ~~~
453 
454  If no time offset is defined for a particular axis, the default time offset
455  will be used. In the example above, notice the usage of TDateTime to translate
456  an explicit date into the time in seconds required by TAxis::SetTimeFormat.
457 
458 #### By setting a time offset to a particular axis:
459 
460 ~~~ .cpp
461 TDatime dh(2001,09,23,15,00,00);
462 h->GetXaxis()->SetTimeOffset(dh.Convert());
463 ~~~
464 
465 #### Together with the time format using TAxis::SetTimeFormat:
466 
467 The time offset can be specified using the control character `%F` after
468 the normal time format. **%F** is followed by the date in the format:
469 `yyyy-mm-dd hh:mm:ss`.
470 
471 Example:
472 
473 ~~~ .cpp
474 h->GetXaxis()->SetTimeFormat("%d\/%m\/%y%F2000-02-28 13:00:01");
475 ~~~
476 
477 
478 
479 Notice that this date format is the same used by the TDateString function
480 `AsSQLString`. If needed, this function can be used to translate a time in
481 seconds into a character string which can be appended after `%F`. If the time
482 format is not specified (before `%F), the automatic one will be used.
483 
484 If a time axis has no specified time offset, the global time offset will be
485 stored in the axis data structure.
486 
487 The following example illustrates the various possibilities.
488 
489 Begin_Macro(source)
490 {
491  gStyle->SetTitleH(0.08);
492 
493  TDatime da(2003,2,28,12,00,00);
494  gStyle->SetTimeOffset(da.Convert());
495 
496  auto ct = new TCanvas("ct","Time on axis",0,0,600,600);
497  ct->Divide(1,3);
498 
499  auto ht1 = new TH1F("ht1","ht1",30000,0.,200000.);
500  auto ht2 = new TH1F("ht2","ht2",30000,0.,200000.);
501  auto ht3 = new TH1F("ht3","ht3",30000,0.,200000.);
502  for (Int_t i=1;i<30000;i++) {
503  auto noise = gRandom->Gaus(0,120);
504  ht1->SetBinContent(i,noise);
505  ht2->SetBinContent(i,noise*noise);
506  ht3->SetBinContent(i,noise*noise*noise);
507  }
508 
509  ct->cd(1);
510  ht1->GetXaxis()->SetLabelSize(0.06);
511  ht1->GetXaxis()->SetTimeDisplay(1);
512  ht1->GetXaxis()->SetTimeFormat("%d/%m/%y%F2000-02-28 13:00:01");
513  ht1->Draw();
514 
515  ct->cd(2);
516  ht2->GetXaxis()->SetLabelSize(0.06);
517  ht2->GetXaxis()->SetTimeDisplay(1);
518  ht2->GetXaxis()->SetTimeFormat("%d/%m/%y");
519  ht2->Draw();
520 
521  ct->cd(3);
522  ht3->GetXaxis()->SetLabelSize(0.06);
523  TDatime dh(2001,9,23,15,00,00);
524  ht3->GetXaxis()->SetTimeDisplay(1);
525  ht3->GetXaxis()->SetTimeOffset(dh.Convert());
526  ht3->Draw();
527 }
528 End_Macro
529 
530 The histogram limits times in seconds. If `wmin` and `wmax` are the histogram
531 limits, the time axis will spread around the time offset value from `TimeOffset+wmin`
532 to `TimeOffset+wmax`. Until now all the examples had a lowest value equal to 0.
533 The following example demonstrates how to define the histogram limits relatively
534 to the time offset value.
535 
536 Begin_Macro(source)
537 {
538  // Define the time offset as 2003, January 1st
539  TDatime T0(2003,1,1,0,0,0);
540  auto X0 = T0.Convert();
541  gStyle->SetTimeOffset(X0);
542 
543  // Define the lowest histogram limit as 2002, September 23rd
544  TDatime T1(2002,9,23,0,0,0);
545  auto X1 = T1.Convert()-X0;
546 
547  // Define the highest histogram limit as 2003, March 7th
548  TDatime T2(2003,3,7,0,0,0);
549  auto X2 = T2.Convert(1)-X0;
550 
551  auto h1 = new TH1F("h1","test",100,X1,X2);
552 
553  TRandom r;
554  for (Int_t i=0;i<30000;i++) {
555  Double_t noise = r.Gaus(0.5*(X1+X2),0.1*(X2-X1));
556  h1->Fill(noise);
557  }
558 
559  h1->GetXaxis()->SetTimeDisplay(1);
560  h1->GetXaxis()->SetLabelSize(0.03);
561  h1->GetXaxis()->SetTimeFormat("%Y/%m/%d");
562  h1->Draw();
563 }
564 End_Macro
565 
566 
567 Usually time axis are created automatically via histograms, but one may also want
568 to draw a time axis outside an "histogram context". Therefore it is useful to
569 understand how TGaxis works for such axis.
570 
571 The time offset can be defined using one of the three methods described before.
572 The time axis will spread around the time offset value. Actually it will go from
573 `TimeOffset+wmin` to `TimeOffset+wmax` where `wmin` and `wmax` are the minimum
574 and maximum values (in seconds) of the axis. Let's take again an example. Having
575 defined "2003, February 28 at 12h" we would like to see the axis a day before and
576 a day after. A TGaxis can be created the following way (a day has 86400 seconds):
577 
578 ~~~ .cpp
579 TGaxis *axis = new TGaxis(x1,y1,x2,y2,-100000,150000,2405,"t");
580 ~~~
581 
582 the `t` option (in lower case) means it is a "time axis". The axis goes form
583 100000 seconds before `TimeOffset` and 150000 seconds after.
584 
585 So the complete macro is:
586 
587 Begin_Macro(source)
588 {
589  c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,100);
590  c1->Range(-10,-1,10,1);
591 
592  TGaxis *axis = new TGaxis(-8,0.,8,0.,-100000,150000,2405,"tS");
593  axis->SetLabelSize(0.2);
594  axis->SetTickSize(0.2);
595 
596  TDatime da(2003,02,28,12,00,00);
597  axis->SetTimeOffset(da.Convert());
598  axis->SetTimeFormat("%d-%m-%Y");
599  axis->Draw();
600  return c1;
601 }
602 End_Macro
603 
604 
605 Thanks to the TLatex directive `#splitline` it is possible to write the time
606 labels on two lines. In the previous example changing the `SetTimeFormat` line by
607 
608 ~~~ .cpp
609  axis->SetLabelOffset(0.15);
610  axis->SetTimeFormat("#splitline{%Y}{%d\/%m}");
611 ~~~
612 
613 will produce the following axis:
614 
615 Begin_Macro
616 {
617  c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,100);
618  c1->Range(-10,-1,10,1);
619 
620  TGaxis *axis = new TGaxis(-8,0.,8,0.,-100000,150000,2405,"tS");
621  axis->SetLabelSize(0.2);
622  axis->SetTickSize(0.2);
623 
624  TDatime da(2003,02,28,12,00,00);
625  axis->SetTimeOffset(da.Convert());
626  axis->SetLabelOffset(0.15);
627  axis->SetTimeFormat("#splitline{%Y}{%d/%m}");
628  axis->Draw();
629  return c1;
630 }
631 End_Macro
632 
633 
634 The following example shows time axis on a TGraph:
635 
636 Begin_Macro(source)
637 {
638  TDatime da1(2008,02,28,15,52,00);
639  TDatime da2(2008,02,28,15,53,00);
640 
641  double x[2],y[2];
642 
643  y[0] = 1.;
644  y[1] = 2.;
645  x[0] = da1.Convert();
646  x[1] = da2.Convert();
647 
648  TGraph mgr(2,x,y);
649  mgr.SetMarkerStyle(20);
650 
651  mgr.Draw("apl");
652  mgr.GetXaxis()->SetTimeDisplay(1);
653  mgr.GetXaxis()->SetNdivisions(-503);
654  mgr.GetXaxis()->SetTimeFormat("%Y-%m-%d %H:%M");
655  mgr.GetXaxis()->SetTimeOffset(0,"gmt");
656 }
657 End_Macro
658 
659 The following example compares what the system time function `gmtime`
660 and `localtime` give with what gives `TGaxis`. It can be used
661 as referenced test to check if the time option of `TGaxis` is working properly.
662 
663 Begin_Macro(source)
664 ../../../tutorials/graphs/timeonaxis3.C
665 End_Macro
666 
667 
668 The following macro illustrates the use, with histograms axis, of the time mode on the axis
669 with different time intervals and time formats.
670 
671 Begin_Macro(source)
672 ../../../tutorials/graphs/timeonaxis.C
673 End_Macro
674 
675 */
676 
677 ////////////////////////////////////////////////////////////////////////////////
678 /// TGaxis default constructor.
679 
680 TGaxis::TGaxis(): TLine(), TAttText(11,0,1,62,0.040)
681 {
682 
683  fGridLength = 0.;
684  fLabelOffset = 0.005;
685  fLabelSize = 0.040;
686  fLabelFont = 62;
687  fLabelColor = 1;
688  fTickSize = 0.030;
689  fTitleOffset = 1;
690  fTitleSize = fLabelSize;
691  fChopt = "";
692  fName = "";
693  fTitle = "";
694  fTimeFormat = "";
695  fFunctionName= "";
696  fFunction = 0;
697  fAxis = 0;
698  fNdiv = 0;
699  fNModLabs = 0;
700  fModLabs = 0;
701  fWmin = 0.;
702  fWmax = 0.;
703 }
704 
705 ////////////////////////////////////////////////////////////////////////////////
706 /// TGaxis normal constructor.
707 
708 TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
709  Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt,
710  Double_t gridlength)
711  : TLine(xmin,ymin,xmax,ymax), TAttText(11,0,1,62,0.040)
712 {
713 
714  fWmin = wmin;
715  fWmax = wmax;
716  fNdiv = ndiv;
717  fNModLabs = 0;
718  fModLabs = 0;
719  fGridLength = gridlength;
720  fLabelOffset = 0.005;
721  fLabelSize = 0.040;
722  fLabelFont = 62;
723  fLabelColor = 1;
724  fTickSize = 0.030;
725  fTitleOffset = 1;
726  fTitleSize = fLabelSize;
727  fChopt = chopt;
728  fName = "";
729  fTitle = "";
730  fTimeFormat = "";
731  fFunctionName= "";
732  fFunction = 0;
733  fAxis = 0;
734 }
735 
736 ////////////////////////////////////////////////////////////////////////////////
737 /// Constructor with a `TF1` to map axis values.
738 
739 TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
740  const char *funcname, Int_t ndiv, Option_t *chopt,
741  Double_t gridlength)
742  : TLine(xmin,ymin,xmax,ymax), TAttText(11,0,1,62,0.040)
743 {
744 
745  fFunction = (TF1*)gROOT->GetFunction(funcname);
746  if (!fFunction) {
747  Error("TGaxis", "calling constructor with an unknown function: %s", funcname);
748  fWmin = 0;
749  fWmax = 1;
750  } else {
751  fWmin = fFunction->GetXmin();
752  fWmax = fFunction->GetXmax();
753  }
754  fFunctionName= funcname;
755  fNdiv = ndiv;
756  fNModLabs = 0;
757  fModLabs = 0;
758  fGridLength = gridlength;
759  fLabelOffset = 0.005;
760  fLabelSize = 0.040;
761  fLabelFont = 62;
762  fLabelColor = 1;
763  fTickSize = 0.030;
764  fTitleOffset = 1;
765  fTitleSize = fLabelSize;
766  fChopt = chopt;
767  fName = "";
768  fTitle = "";
769  fTimeFormat = "";
770  fAxis = 0;
771 }
772 
773 ////////////////////////////////////////////////////////////////////////////////
774 /// Copy constructor.
775 
776 TGaxis::TGaxis(const TGaxis& ax) :
777  TLine(ax),
778  TAttText(ax),
779  fWmin(ax.fWmin),
780  fWmax(ax.fWmax),
781  fGridLength(ax.fGridLength),
782  fTickSize(ax.fTickSize),
783  fLabelOffset(ax.fLabelOffset),
784  fLabelSize(ax.fLabelSize),
785  fTitleOffset(ax.fTitleOffset),
786  fTitleSize(ax.fTitleSize),
787  fNdiv(ax.fNdiv),
788  fLabelColor(ax.fLabelColor),
789  fLabelFont(ax.fLabelFont),
790  fNModLabs(ax.fNModLabs),
791  fChopt(ax.fChopt),
792  fName(ax.fName),
793  fTitle(ax.fTitle),
794  fTimeFormat(ax.fTimeFormat),
795  fFunctionName(ax.fFunctionName),
796  fFunction(ax.fFunction),
797  fAxis(ax.fAxis),
798  fModLabs(ax.fModLabs)
799 {
800 }
801 
802 ////////////////////////////////////////////////////////////////////////////////
803 /// Assignment operator.
804 
805 TGaxis& TGaxis::operator=(const TGaxis& ax)
806 {
807 
808  if(this!=&ax) {
809  TLine::operator=(ax);
810  TAttText::operator=(ax);
811  fWmin=ax.fWmin;
812  fWmax=ax.fWmax;
813  fGridLength=ax.fGridLength;
814  fTickSize=ax.fTickSize;
815  fLabelOffset=ax.fLabelOffset;
816  fLabelSize=ax.fLabelSize;
817  fTitleOffset=ax.fTitleOffset;
818  fTitleSize=ax.fTitleSize;
819  fNdiv=ax.fNdiv;
820  fModLabs=ax.fModLabs;
821  fLabelColor=ax.fLabelColor;
822  fLabelFont=ax.fLabelFont;
823  fChopt=ax.fChopt;
824  fName=ax.fName;
825  fTitle=ax.fTitle;
826  fTimeFormat=ax.fTimeFormat;
827  fFunctionName=ax.fFunctionName;
828  fFunction=ax.fFunction;
829  fAxis=ax.fAxis;
830  fNModLabs=ax.fNModLabs;
831  }
832  return *this;
833 }
834 
835 ////////////////////////////////////////////////////////////////////////////////
836 /// TGaxis default destructor.
837 
838 TGaxis::~TGaxis()
839 {
840 }
841 
842 ////////////////////////////////////////////////////////////////////////////////
843 /// If center = kTRUE axis labels are centered in the center of the bin.
844 /// The default is to center on the primary tick marks.
845 /// This option does not make sense if there are more bins than tick marks.
846 
847 void TGaxis::CenterLabels(Bool_t center)
848 {
849 
850  if (center) SetBit(TAxis::kCenterLabels);
851  else ResetBit(TAxis::kCenterLabels);
852 }
853 
854 ////////////////////////////////////////////////////////////////////////////////
855 /// If center = kTRUE axis title will be centered. The default is right adjusted.
856 
857 void TGaxis::CenterTitle(Bool_t center)
858 {
859 
860  if (center) SetBit(TAxis::kCenterTitle);
861  else ResetBit(TAxis::kCenterTitle);
862 }
863 
864 ////////////////////////////////////////////////////////////////////////////////
865 /// Draw this axis with new attributes.
866 
867 void TGaxis::DrawAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
868  Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt,
869  Double_t gridlength)
870 {
871 
872  TGaxis *newaxis = new TGaxis(xmin,ymin,xmax,ymax,wmin,wmax,ndiv,chopt,gridlength);
873  newaxis->SetLineColor(fLineColor);
874  newaxis->SetLineWidth(fLineWidth);
875  newaxis->SetLineStyle(fLineStyle);
876  newaxis->SetTextAlign(fTextAlign);
877  newaxis->SetTextAngle(fTextAngle);
878  newaxis->SetTextColor(fTextColor);
879  newaxis->SetTextFont(fTextFont);
880  newaxis->SetTextSize(fTextSize);
881  newaxis->SetTitleSize(fTitleSize);
882  newaxis->SetTitleOffset(fTitleOffset);
883  newaxis->SetLabelFont(fLabelFont);
884  newaxis->SetLabelColor(fLabelColor);
885  newaxis->SetLabelSize(fLabelSize);
886  newaxis->SetLabelOffset(fLabelOffset);
887  newaxis->SetTickSize(fTickSize);
888  newaxis->SetBit(kCanDelete);
889  newaxis->SetTitle(GetTitle());
890  newaxis->SetBit(TAxis::kCenterTitle,TestBit(TAxis::kCenterTitle));
891  newaxis->AppendPad();
892 }
893 
894 ////////////////////////////////////////////////////////////////////////////////
895 /// Static function returning fgMaxDigits (See SetMaxDigits).
896 
897 Int_t TGaxis::GetMaxDigits()
898 {
899 
900  return fgMaxDigits;
901 }
902 
903 ////////////////////////////////////////////////////////////////////////////////
904 /// Internal method to import TAxis attributes to this TGaxis.
905 
906 void TGaxis::ImportAxisAttributes(TAxis *axis)
907 {
908 
909  fAxis = axis;
910  SetLineColor(axis->GetAxisColor());
911  SetTextColor(axis->GetTitleColor());
912  SetTextFont(axis->GetTitleFont());
913  SetLabelColor(axis->GetLabelColor());
914  SetLabelFont(axis->GetLabelFont());
915  SetLabelSize(axis->GetLabelSize());
916  SetLabelOffset(axis->GetLabelOffset());
917  SetTickSize(axis->GetTickLength());
918  SetTitle(axis->GetTitle());
919  SetTitleOffset(axis->GetTitleOffset());
920  SetTitleSize(axis->GetTitleSize());
921  SetBit(TAxis::kCenterTitle, axis->TestBit(TAxis::kCenterTitle));
922  SetBit(TAxis::kCenterLabels, axis->TestBit(TAxis::kCenterLabels));
923  SetBit(TAxis::kRotateTitle, axis->TestBit(TAxis::kRotateTitle));
924  SetBit(TAxis::kNoExponent, axis->TestBit(TAxis::kNoExponent));
925  SetBit(TAxis::kTickPlus, axis->TestBit(TAxis::kTickPlus));
926  SetBit(TAxis::kTickMinus, axis->TestBit(TAxis::kTickMinus));
927  SetBit(TAxis::kMoreLogLabels, axis->TestBit(TAxis::kMoreLogLabels));
928  if (axis->GetDecimals()) SetBit(TAxis::kDecimals); //the bit is in TAxis::fAxis2
929  SetTimeFormat(axis->GetTimeFormat());
930 }
931 
932 ////////////////////////////////////////////////////////////////////////////////
933 /// Draw this axis with its current attributes.
934 
935 void TGaxis::Paint(Option_t *)
936 {
937 
938  Double_t wmin = fWmin;
939  Double_t wmax = fWmax;
940  Int_t ndiv = fNdiv;
941 
942  // following code required to support toggle of lin/log scales
943  Double_t x1 = gPad->XtoPad(fX1);
944  Double_t y1 = gPad->YtoPad(fY1);
945  Double_t x2 = gPad->XtoPad(fX2);
946  Double_t y2 = gPad->YtoPad(fY2);
947 
948  PaintAxis(x1,y1,x2,y2,wmin,wmax,ndiv,fChopt.Data(),fGridLength);
949 }
950 
951 ////////////////////////////////////////////////////////////////////////////////
952 /// Control function to draw an axis.
953 /// Original authors: O.Couet C.E.Vandoni N.Cremel-Somon.
954 /// Modified and converted to C++ class by Rene Brun.
955 
956 void TGaxis::PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax,
957  Double_t &wmin, Double_t &wmax, Int_t &ndiv, Option_t *chopt,
958  Double_t gridlength, Bool_t drawGridOnly)
959 {
960 
961  const char *where = "PaintAxis";
962 
963  Double_t alfa, beta, ratio1, ratio2, grid_side;
964  Double_t axis_lengthN = 0;
965  Double_t axis_length0 = 0;
966  Double_t axis_length1 = 0;
967  Double_t axis_length;
968  Double_t atick[3];
969  Double_t tick_side;
970  Double_t charheight;
971  Double_t phil, phi, sinphi, cosphi, asinphi, acosphi;
972  Double_t binLow = 0., binLow2 = 0., binLow3 = 0.;
973  Double_t binHigh = 0., binHigh2 = 0., binHigh3 = 0.;
974  Double_t binWidth = 0., binWidth2 = 0., binWidth3 = 0.;
975  Double_t xpl1, xpl2, ypl1, ypl2;
976  Double_t xtick = 0;
977  Double_t xtick0, xtick1, dxtick=0;
978  Double_t ytick, ytick0, ytick1;
979  Double_t wlabel, dwlabel;
980  Double_t xfactor, yfactor;
981  Double_t xlabel, ylabel, dxlabel;
982  Double_t xone, xtwo;
983  Double_t rlab;
984  Double_t x0, x1, y0, y1, xx0, xx1, yy0, yy1;
985  xx0 = xx1 = yy0 = yy1 = 0;
986  Double_t xxmin, xxmax, yymin, yymax;
987  xxmin = xxmax = yymin = yymax = 0;
988  Double_t xlside, xmside;
989  Double_t ww, af, rne;
990  Double_t xx, yy;
991  Double_t xmnlog, x00, x11, h2, h2sav, axmul, y;
992  Float_t chupxvsav, chupyvsav;
993  Double_t rtxw, rtyw;
994  Int_t nlabels, nticks, nticks0, nticks1;
995  Int_t i, j, k, l, decade, ltick;
996  Int_t mside, lside;
997  Int_t nexe = 0;
998  Int_t lnlen = 0;
999  Int_t iexe, if1, if2, na, nf, ih1, ih2, nbinin, nch, kmod;
1000  Int_t optionLog,optionBlank,optionVert,optionPlus,optionMinus,optionUnlab,optionPara;
1001  Int_t optionDown,optionRight,optionLeft,optionCent,optionEqual,optionDecimals=0,optionDot;
1002  Int_t optionY,optionText,optionGrid,optionSize,optionNoopt,optionInt,optionM,optionUp,optionX;
1003  Int_t optionTime;
1004  Int_t first=0,last=0,labelnumber;
1005  Int_t xalign, yalign;
1006  Int_t nn1, nn2, nn3, n1a, n2a, n3a, nb2, nb3;
1007  Int_t nbins=10, n1aold, nn1old;
1008  Int_t maxDigits;
1009  n1aold = nn1old = 0;
1010  Int_t ndyn;
1011  Int_t nhilab = 0;
1012  Int_t idn;
1013  Bool_t flexe = 0;
1014  Bool_t flexpo,flexne;
1015  char *label;
1016  char *chtemp;
1017  char chlabel[256];
1018  char kchtemp[256];
1019  char chcoded[64];
1020  TLine *linegrid;
1021  TString timeformat;
1022  TString typolabel;
1023  time_t timelabel;
1024  Double_t timed, wTimeIni;
1025  struct tm* utctis;
1026  Double_t rangeOffset = 0;
1027 
1028  Double_t epsilon = 1e-5;
1029  const Double_t kPI = TMath::Pi();
1030 
1031  Double_t rwmi = wmin;
1032  Double_t rwma = wmax;
1033  chtemp = &kchtemp[0];
1034  label = &chlabel[0];
1035  linegrid = 0;
1036 
1037  fFunction = (TF1*)gROOT->GetFunction(fFunctionName.Data());
1038 
1039  Bool_t noExponent = TestBit(TAxis::kNoExponent);
1040 
1041 // If moreLogLabels = kTRUE more Log Intermediate Labels are drawn.
1042  Bool_t moreLogLabels = TestBit(TAxis::kMoreLogLabels);
1043 
1044 // the following parameters correspond to the pad range in NDC
1045 // and the user's coordinates in the pad
1046 
1047  Double_t padh = gPad->GetWh()*gPad->GetAbsHNDC();
1048  Double_t rwxmin = gPad->GetX1();
1049  Double_t rwxmax = gPad->GetX2();
1050  Double_t rwymin = gPad->GetY1();
1051  Double_t rwymax = gPad->GetY2();
1052 
1053  if(strchr(chopt,'G')) optionLog = 1; else optionLog = 0;
1054  if(strchr(chopt,'B')) optionBlank= 1; else optionBlank= 0;
1055  if(strchr(chopt,'V')) optionVert = 1; else optionVert = 0;
1056  if(strchr(chopt,'+')) optionPlus = 1; else optionPlus = 0;
1057  if(strchr(chopt,'-')) optionMinus= 1; else optionMinus= 0;
1058  if(strchr(chopt,'U')) optionUnlab= 1; else optionUnlab= 0;
1059  if(strchr(chopt,'P')) optionPara = 1; else optionPara = 0;
1060  if(strchr(chopt,'O')) optionDown = 1; else optionDown = 0;
1061  if(strchr(chopt,'R')) optionRight= 1; else optionRight= 0;
1062  if(strchr(chopt,'L')) optionLeft = 1; else optionLeft = 0;
1063  if(strchr(chopt,'C')) optionCent = 1; else optionCent = 0;
1064  if(strchr(chopt,'=')) optionEqual= 1; else optionEqual= 0;
1065  if(strchr(chopt,'Y')) optionY = 1; else optionY = 0;
1066  if(strchr(chopt,'T')) optionText = 1; else optionText = 0;
1067  if(strchr(chopt,'W')) optionGrid = 1; else optionGrid = 0;
1068  if(strchr(chopt,'S')) optionSize = 1; else optionSize = 0;
1069  if(strchr(chopt,'N')) optionNoopt= 1; else optionNoopt= 0;
1070  if(strchr(chopt,'I')) optionInt = 1; else optionInt = 0;
1071  if(strchr(chopt,'M')) optionM = 1; else optionM = 0;
1072  if(strchr(chopt,'0')) optionUp = 1; else optionUp = 0;
1073  if(strchr(chopt,'X')) optionX = 1; else optionX = 0;
1074  if(strchr(chopt,'t')) optionTime = 1; else optionTime = 0;
1075  if(strchr(chopt,'.')) optionDot = 1; else optionDot = 0;
1076  if (TestBit(TAxis::kTickPlus)) optionPlus = 2;
1077  if (TestBit(TAxis::kTickMinus)) optionMinus = 2;
1078  if (TestBit(TAxis::kCenterLabels)) optionM = 1;
1079  if (TestBit(TAxis::kDecimals)) optionDecimals = 1;
1080  if (!gStyle->GetStripDecimals()) optionDecimals = 1;
1081  if (fAxis) {
1082  if (fAxis->GetLabels()) {
1083  optionM = 1;
1084  optionText = 1;
1085  ndiv = fAxis->GetLast()-fAxis->GetFirst()+1;
1086  }
1087  TList *ml = fAxis->GetModifiedLabels();
1088  if (ml) {
1089  fModLabs = ml;
1090  fNModLabs = fModLabs->GetSize();
1091  } else {
1092  fModLabs = 0;
1093  fNModLabs = 0;
1094  }
1095  }
1096  if (ndiv < 0) {
1097  Error(where, "Invalid number of divisions: %d",ndiv);
1098  return;
1099  }
1100 
1101 // Set the grid length
1102 
1103  if (optionGrid) {
1104  if (gridlength == 0) gridlength = 0.8;
1105  linegrid = new TLine();
1106  linegrid->SetLineColor(gStyle->GetGridColor());
1107  if (linegrid->GetLineColor() == 0) linegrid->SetLineColor(GetLineColor());
1108  linegrid->SetLineStyle(gStyle->GetGridStyle());
1109  linegrid->SetLineWidth(gStyle->GetGridWidth());
1110  }
1111 
1112 // No labels if the axis label offset is big.
1113 // In that case the labels are not visible anyway.
1114 
1115  if (GetLabelOffset() > 1.1 ) optionUnlab = 1;
1116 
1117 // Determine time format
1118 
1119  Int_t idF = fTimeFormat.Index("%F");
1120  if (idF>=0) {
1121  timeformat = fTimeFormat(0,idF);
1122  } else {
1123  timeformat = fTimeFormat;
1124  }
1125 
1126  //GMT option
1127  if (fTimeFormat.Index("GMT")>=0) optionTime =2;
1128 
1129  // Determine the time offset and correct for time offset not being integer.
1130  Double_t timeoffset =0;
1131  if (optionTime) {
1132  if (idF>=0) {
1133  Int_t lnF = fTimeFormat.Length();
1134  TString stringtimeoffset = fTimeFormat(idF+2,lnF);
1135  Int_t year, mm, dd, hh, mi, ss;
1136  if (sscanf(stringtimeoffset.Data(), "%d-%d-%d %d:%d:%d", &year, &mm, &dd, &hh, &mi, &ss) == 6) {
1137  //Get time offset in seconds since EPOCH:
1138  struct tm tp;
1139  tp.tm_year = year-1900;
1140  tp.tm_mon = mm-1;
1141  tp.tm_mday = dd;
1142  tp.tm_hour = hh;
1143  tp.tm_min = mi;
1144  tp.tm_sec = ss;
1145  tp.tm_isdst = 0; //no DST for UTC (and forced to 0 in MktimeFromUTC function)
1146  timeoffset = TTimeStamp::MktimeFromUTC(&tp);
1147 
1148  // Add the time offset's decimal part if it is there
1149  Int_t ids = stringtimeoffset.Index("s");
1150  if (ids >= 0) {
1151  Float_t dp;
1152  Int_t lns = stringtimeoffset.Length();
1153  TString sdp = stringtimeoffset(ids+1,lns);
1154  sscanf(sdp.Data(),"%g",&dp);
1155  timeoffset += dp;
1156  }
1157  } else {
1158  Error(where, "Time offset has not the right format");
1159  }
1160  } else {
1161  timeoffset = gStyle->GetTimeOffset();
1162  }
1163  wmin += timeoffset - (int)(timeoffset);
1164  wmax += timeoffset - (int)(timeoffset);
1165 
1166  // correct for time offset at a good limit (min, hour, day, month, year)
1167  struct tm* tp0;
1168  time_t timetp = (time_t)((Long_t)(timeoffset));
1169  Double_t range = wmax - wmin;
1170  Long_t rangeBase = 60;
1171  if (range>60) rangeBase = 60*20; // minutes
1172  if (range>3600) rangeBase = 3600*20; // hours
1173  if (range>86400) rangeBase = 86400*20; // days
1174  if (range>2419200) rangeBase = 31556736; // months (average # days)
1175  rangeOffset = (Double_t) ((Long_t)(timeoffset)%rangeBase);
1176  if (range>31536000) {
1177  tp0 = gmtime(&timetp);
1178  tp0->tm_mon = 0;
1179  tp0->tm_mday = 1;
1180  tp0->tm_hour = 0;
1181  tp0->tm_min = 0;
1182  tp0->tm_sec = 0;
1183  tp0->tm_isdst = 1; // daylight saving time is on.
1184  rangeBase = (timetp-mktime(tp0)); // years
1185  rangeOffset = (Double_t) (rangeBase);
1186  }
1187  wmax += rangeOffset;
1188  wmin += rangeOffset;
1189  }
1190 
1191 // Determine number of divisions 1, 2 and 3 and the maximum digits for this axis
1192  n1a = (ndiv%100);
1193  n2a = (ndiv%10000 - n1a)/100;
1194  n3a = (ndiv%1000000 - n2a -n1a)/10000;
1195  nn3 = TMath::Max(n3a,1);
1196  nn2 = TMath::Max(n2a,1)*nn3;
1197  nn1 = TMath::Max(n1a,1)*nn2+1;
1198  nticks = nn1;
1199  maxDigits = (ndiv/1000000);
1200  if (maxDigits==0) maxDigits = fgMaxDigits;
1201 
1202 // Axis bining optimisation is ignored if:
1203 // - the first and the last label are equal
1204 // - the number of divisions is 0
1205 // - less than 1 primary division is requested
1206 // - logarithmic scale is requested
1207 
1208  if (wmin == wmax || ndiv == 0 || n1a <= 1 || optionLog) {
1209  optionNoopt = 1;
1210  optionInt = 0;
1211  }
1212 
1213 // Axis bining optimisation
1214  if ( (wmax-wmin) < 1 && optionInt) {
1215  Error(where, "option I not available");
1216  optionInt = 0;
1217  }
1218  if (!optionNoopt || optionInt ) {
1219 
1220 // Primary divisions optimisation
1221 // When integer labelling is required, Optimize is invoked first
1222 // and only if the result is not an integer labelling, AdjustBinSize is invoked.
1223 
1224  THLimitsFinder::Optimize(wmin,wmax,n1a,binLow,binHigh,nbins,binWidth,fChopt.Data());
1225  if (optionInt) {
1226  if (binLow != Double_t(int(binLow)) || binWidth != Double_t(int(binWidth))) {
1227  AdjustBinSize(wmin,wmax,n1a,binLow,binHigh,nbins,binWidth);
1228  }
1229  }
1230  if ((wmin-binLow) > epsilon) { binLow += binWidth; nbins--; }
1231  if ((binHigh-wmax) > epsilon) { binHigh -= binWidth; nbins--; }
1232  if (xmax == xmin) {
1233  rtyw = (ymax-ymin)/(wmax-wmin);
1234  xxmin = xmin;
1235  xxmax = xmax;
1236  yymin = rtyw*(binLow-wmin) + ymin;
1237  yymax = rtyw*(binHigh-wmin) + ymin;
1238  }
1239  else {
1240  rtxw = (xmax-xmin)/(wmax-wmin);
1241  xxmin = rtxw*(binLow-wmin) + xmin;
1242  xxmax = rtxw*(binHigh-wmin) + xmin;
1243  if (ymax == ymin) {
1244  yymin = ymin;
1245  yymax = ymax;
1246  }
1247  else {
1248  alfa = (ymax-ymin)/(xmax-xmin);
1249  beta = (ymin*xmax-ymax*xmin)/(xmax-xmin);
1250  yymin = alfa*xxmin + beta;
1251  yymax = alfa*xxmax + beta;
1252  }
1253  }
1254  if (fFunction) {
1255  yymin = ymin;
1256  yymax = ymax;
1257  xxmin = xmin;
1258  xxmax = xmax;
1259  } else {
1260  wmin = binLow;
1261  wmax = binHigh;
1262  }
1263 
1264 // Secondary divisions optimisation
1265  nb2 = n2a;
1266  if (!optionNoopt && n2a > 1 && binWidth > 0) {
1267  THLimitsFinder::Optimize(wmin,wmin+binWidth,n2a,binLow2,binHigh2,nb2,binWidth2,fChopt.Data());
1268  }
1269 
1270 // Tertiary divisions optimisation
1271  nb3 = n3a;
1272  if (!optionNoopt && n3a > 1 && binWidth2 > 0) {
1273  THLimitsFinder::Optimize(binLow2,binLow2+binWidth2,n3a,binLow3,binHigh3,nb3,binWidth3,fChopt.Data());
1274  }
1275  n1aold = n1a;
1276  nn1old = nn1;
1277  n1a = nbins;
1278  nn3 = TMath::Max(nb3,1);
1279  nn2 = TMath::Max(nb2,1)*nn3;
1280  nn1 = TMath::Max(n1a,1)*nn2+1;
1281  nticks = nn1;
1282  }
1283 
1284 // Coordinates are normalized
1285 
1286  ratio1 = 1/(rwxmax-rwxmin);
1287  ratio2 = 1/(rwymax-rwymin);
1288  x0 = ratio1*(xmin-rwxmin);
1289  x1 = ratio1*(xmax-rwxmin);
1290  y0 = ratio2*(ymin-rwymin);
1291  y1 = ratio2*(ymax-rwymin);
1292  if (!optionNoopt || optionInt ) {
1293  xx0 = ratio1*(xxmin-rwxmin);
1294  xx1 = ratio1*(xxmax-rwxmin);
1295  yy0 = ratio2*(yymin-rwymin);
1296  yy1 = ratio2*(yymax-rwymin);
1297  }
1298 
1299  if ((x0 == x1) && (y0 == y1)) {
1300  Error(where, "length of axis is 0");
1301  return;
1302  }
1303 
1304 // Title offset. If 0 it is automatically computed
1305  Double_t toffset = GetTitleOffset();
1306  Bool_t autotoff = kFALSE;
1307  if (toffset==0 && x1 == x0) autotoff = kTRUE;
1308 
1309 // Return wmin, wmax and the number of primary divisions
1310  if (optionX) {
1311  ndiv = n1a;
1312  return;
1313  }
1314 
1315  TLatex *textaxis = new TLatex();
1316  SetLineStyle(1); // axis line style
1317  Int_t TitleColor = GetTextColor();
1318  Int_t TitleFont = GetTextFont();
1319 
1320  if (!gPad->IsBatch()) {
1321  gVirtualX->GetCharacterUp(chupxvsav, chupyvsav);
1322  gVirtualX->SetClipOFF(gPad->GetCanvasID());
1323  }
1324 
1325 // Compute length of axis
1326  axis_length = TMath::Sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
1327  if (axis_length == 0) {
1328  Error(where, "length of axis is 0");
1329  goto L210;
1330  }
1331  if (!optionNoopt || optionInt) {
1332  axis_lengthN = TMath::Sqrt((xx1-xx0)*(xx1-xx0)+(yy1-yy0)*(yy1-yy0));
1333  axis_length0 = TMath::Sqrt((xx0-x0)*(xx0-x0)+(yy0-y0)*(yy0-y0));
1334  axis_length1 = TMath::Sqrt((x1-xx1)*(x1-xx1)+(y1-yy1)*(y1-yy1));
1335  if (axis_lengthN < epsilon) {
1336  optionNoopt = 1;
1337  optionInt = 0;
1338  wmin = rwmi;
1339  wmax = rwma;
1340  n1a = n1aold;
1341  nn1 = nn1old;
1342  nticks = nn1;
1343  if (optionTime) {
1344  wmin += timeoffset - (int)(timeoffset) + rangeOffset;
1345  wmax += timeoffset - (int)(timeoffset) + rangeOffset;
1346  }
1347  }
1348  }
1349 
1350  if (x0 == x1) {
1351  if (y1>=y0) phi = 0.5*kPI;
1352  else phi = 1.5*kPI;
1353  phil = phi;
1354  } else {
1355  phi = TMath::ATan2((y1-y0),(x1-x0));
1356  Int_t px0 = gPad->UtoPixel(x0);
1357  Int_t py0 = gPad->VtoPixel(y0);
1358  Int_t px1 = gPad->UtoPixel(x1);
1359  Int_t py1 = gPad->VtoPixel(y1);
1360  if (x0 < x1) phil = TMath::ATan2(Double_t(py0-py1), Double_t(px1-px0));
1361  else phil = TMath::ATan2(Double_t(py1-py0), Double_t(px0-px1));
1362  }
1363  cosphi = TMath::Cos(phi);
1364  sinphi = TMath::Sin(phi);
1365  acosphi = TMath::Abs(cosphi);
1366  asinphi = TMath::Abs(sinphi);
1367  if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; }
1368  if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; }
1369 
1370 // mside positive, tick marks on positive side
1371 // mside negative, tick marks on negative side
1372 // mside zero, tick marks on both sides
1373 // Default is positive except for vertical axis
1374 
1375  mside=1;
1376  if (x0 == x1 && y1 > y0) mside = -1;
1377  if (optionPlus) mside = 1;
1378  if (optionMinus) mside = -1;
1379  if (optionPlus && optionMinus) mside = 0;
1380  xmside = mside;
1381  lside = -mside;
1382  if (optionEqual) lside = mside;
1383  if (optionPlus && optionMinus) {
1384  lside = -1;
1385  if (optionEqual) lside=1;
1386  }
1387  xlside = lside;
1388 
1389 // Tick marks size
1390  if(xmside >= 0) tick_side = 1;
1391  else tick_side = -1;
1392  if (optionSize) atick[0] = tick_side*axis_length*fTickSize;
1393  else atick[0] = tick_side*axis_length*0.03;
1394 
1395  atick[1] = 0.5*atick[0];
1396  atick[2] = 0.5*atick[1];
1397 
1398 // Set the side of the grid
1399  if ((x0 == x1) && (y1 > y0)) grid_side =-1;
1400  else grid_side = 1;
1401 
1402 // Compute Values if Function is given
1403  if(fFunction) {
1404  rwmi = fFunction->Eval(wmin);
1405  rwma = fFunction->Eval(wmax);
1406  if(rwmi > rwma) {
1407  Double_t t = rwma;
1408  rwma = rwmi;
1409  rwmi = t;
1410  }
1411  }
1412 
1413 // Draw the axis if needed...
1414  if (!optionBlank) {
1415  xpl1 = x0;
1416  xpl2 = x1;
1417  ypl1 = y0;
1418  ypl2 = y1;
1419  PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1420  }
1421 
1422 // No bining
1423 
1424  if (ndiv == 0)goto L210;
1425  if (wmin == wmax) {
1426  Error(where, "wmin (%f) == wmax (%f)", wmin, wmax);
1427  goto L210;
1428  }
1429 
1430 // Labels preparation:
1431 // Get character height
1432 // Compute the labels orientation in case of overlaps
1433 // (with alphanumeric labels for horizontal axis).
1434 
1435  charheight = GetLabelSize();
1436  if (optionText && GetLabelFont()%10 != 3) charheight *= 0.66666;
1437  textaxis->SetTextFont(GetLabelFont());
1438  if ((GetLabelFont()%10 < 2) && optionLog) // force TLatex mode in PaintLatex
1439  textaxis->SetTextFont((Int_t)(GetLabelFont()/10)*10+2);
1440  textaxis->SetTextColor(GetLabelColor());
1441  textaxis->SetTextSize (charheight);
1442  textaxis->SetTextAngle(GetTextAngle());
1443  if (GetLabelFont()%10 > 2) {
1444  charheight /= padh;
1445  }
1446  if (!optionUp && !optionDown && !optionY && !optionUnlab) {
1447  if (!drawGridOnly && optionText && ((ymin == ymax) || (xmin == xmax))) {
1448  textaxis->SetTextAlign(32);
1449  optionText = 2;
1450  Int_t nl = fAxis->GetLast()-fAxis->GetFirst()+1;
1451  Double_t angle = 0;
1452  for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
1453  textaxis->SetText(0,0,fAxis->GetBinLabel(i));
1454  if (textaxis->GetXsize() < (xmax-xmin)/nl) continue;
1455  angle = -20;
1456  break;
1457  }
1458  for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
1459  if ((!strcmp(fAxis->GetName(),"xaxis") && !gPad->TestBit(kHori))
1460  ||(!strcmp(fAxis->GetName(),"yaxis") && gPad->TestBit(kHori))) {
1461  if (nl > 50) angle = 90;
1462  if (fAxis->TestBit(TAxis::kLabelsHori)) angle = 0;
1463  if (fAxis->TestBit(TAxis::kLabelsVert)) angle = 90;
1464  if (fAxis->TestBit(TAxis::kLabelsUp)) angle = 20;
1465  if (fAxis->TestBit(TAxis::kLabelsDown)) angle =-20;
1466  if (angle == 0) textaxis->SetTextAlign(23);
1467  if (angle == -20) textaxis->SetTextAlign(12);
1468  textaxis->SetTextAngle(angle);
1469  Double_t s = -3;
1470  if (ymin == gPad->GetUymax()) {
1471  if (angle == 0) textaxis->SetTextAlign(21);
1472  s = 3;
1473  }
1474  strncpy(chtemp, fAxis->GetBinLabel(i), 255);
1475  if (fNModLabs) ChangeLabelAttributes(i, fAxis->GetLabels()->GetSize()-1, textaxis, chtemp);
1476  textaxis->PaintLatex(fAxis->GetBinCenter(i),
1477  ymin + s*fAxis->GetLabelOffset()*(gPad->GetUymax()-gPad->GetUymin()),
1478  textaxis->GetTextAngle(),
1479  textaxis->GetTextSize(),
1480  chtemp);
1481  if (fNModLabs) ResetLabelAttributes(textaxis);
1482  } else if ((!strcmp(fAxis->GetName(),"yaxis") && !gPad->TestBit(kHori))
1483  || (!strcmp(fAxis->GetName(),"xaxis") && gPad->TestBit(kHori))) {
1484  Double_t s = -3;
1485  if (xmin == gPad->GetUxmax()) {
1486  textaxis->SetTextAlign(12);
1487  s = 3;
1488  }
1489  if (autotoff) {
1490  UInt_t w,h;
1491  textaxis->SetText(0.,0., fAxis->GetBinLabel(i));
1492  textaxis->GetBoundingBox(w,h);
1493  toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC()));
1494  }
1495  textaxis->PaintLatex(xmin + s*fAxis->GetLabelOffset()*(gPad->GetUxmax()-gPad->GetUxmin()),
1496  fAxis->GetBinCenter(i),
1497  0,
1498  textaxis->GetTextSize(),
1499  fAxis->GetBinLabel(i));
1500  } else {
1501  textaxis->PaintLatex(xmin - 3*fAxis->GetLabelOffset()*(gPad->GetUxmax()-gPad->GetUxmin()),
1502  ymin +(i-0.5)*(ymax-ymin)/nl,
1503  0,
1504  textaxis->GetTextSize(),
1505  fAxis->GetBinLabel(i));
1506  }
1507  }
1508  }
1509  }
1510 
1511 // Now determine orientation of labels on axis
1512  if (!gPad->IsBatch()) {
1513  if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi);
1514  else gVirtualX->SetCharacterUp(sinphi,-cosphi);
1515  if (x0 == x1) gVirtualX->SetCharacterUp(0,1);
1516  if (optionVert) gVirtualX->SetCharacterUp(0,1);
1517  if (optionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi);
1518  if (optionDown) gVirtualX->SetCharacterUp(cosphi,sinphi);
1519  }
1520 
1521 // Now determine text alignment
1522  xalign = 2;
1523  yalign = 1;
1524  if (x0 == x1) xalign = 3;
1525  if (y0 != y1) yalign = 2;
1526  if (optionCent) xalign = 2;
1527  if (optionRight) xalign = 3;
1528  if (optionLeft) xalign = 1;
1529  if (TMath::Abs(cosphi) > 0.9) {
1530  xalign = 2;
1531  } else {
1532  if (cosphi*sinphi > 0) xalign = 1;
1533  if (cosphi*sinphi < 0) xalign = 3;
1534  }
1535  textaxis->SetTextAlign(10*xalign+yalign);
1536 
1537 // Position of labels in Y
1538  if (x0 == x1) {
1539  if (optionPlus && !optionMinus) {
1540  if (optionEqual) ylabel = fLabelOffset/2 + atick[0];
1541  else ylabel = -fLabelOffset;
1542  } else {
1543  ylabel = fLabelOffset;
1544  if (lside < 0) ylabel += atick[0];
1545  }
1546  } else if (y0 == y1) {
1547  if (optionMinus && !optionPlus) {
1548  if ((GetLabelFont() % 10) == 3 ) {
1549  ylabel = fLabelOffset+0.5*
1550  ((gPad->AbsPixeltoY(0)-gPad->AbsPixeltoY((Int_t)fLabelSize))/
1551  (gPad->GetY2() - gPad->GetY1()));
1552  } else {
1553  ylabel = fLabelOffset+0.5*fLabelSize;
1554  }
1555  ylabel += TMath::Abs(atick[0]);
1556  } else {
1557  ylabel = -fLabelOffset;
1558  if (mside <= 0) ylabel -= TMath::Abs(atick[0]);
1559  }
1560  if (optionLog) ylabel -= 0.5*charheight;
1561  } else {
1562  if (mside+lside >= 0) ylabel = fLabelOffset;
1563  else ylabel = -fLabelOffset;
1564  }
1565  if (optionText) ylabel /= 2;
1566 
1567 // Draw the linear tick marks if needed...
1568  if (!optionLog) {
1569  if (ndiv) {
1570  if (fFunction) {
1571  dxtick=(binHigh-binLow)/Double_t(nticks-1);
1572  } else {
1573  if (optionNoopt && !optionInt) dxtick=axis_length/Double_t(nticks-1);
1574  else dxtick=axis_lengthN/Double_t(nticks-1);
1575  }
1576  for (k=0;k<nticks; k++) {
1577  ltick = 2;
1578  if (k%nn3 == 0) ltick = 1;
1579  if (k%nn2 == 0) ltick = 0;
1580  if (fFunction) {
1581  Double_t xf = binLow+Double_t(k)*dxtick;
1582  Double_t zz = fFunction->Eval(xf)-rwmi;
1583  xtick = zz* axis_length / TMath::Abs(rwma-rwmi);
1584  } else {
1585  xtick = Double_t(k)*dxtick;
1586  }
1587  ytick = 0;
1588  if (!mside) ytick -= atick[ltick];
1589  if ( optionNoopt && !optionInt) {
1590  Rotate(xtick,ytick,cosphi,sinphi,x0,y0,xpl2,ypl2);
1591  Rotate(xtick,atick[ltick],cosphi,sinphi,x0,y0,xpl1,ypl1);
1592  }
1593  else {
1594  Rotate(xtick,ytick,cosphi,sinphi,xx0,yy0,xpl2,ypl2);
1595  Rotate(xtick,atick[ltick],cosphi,sinphi,xx0,yy0,xpl1,ypl1);
1596  }
1597  if (optionVert) {
1598  if ((x0 != x1) && (y0 != y1)) {
1599  if (mside) {
1600  xpl1 = xpl2;
1601  if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
1602  else ypl1 = ypl2 - atick[ltick];
1603  }
1604  else {
1605  xpl1 = 0.5*(xpl1 + xpl2);
1606  xpl2 = xpl1;
1607  ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
1608  ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
1609  }
1610  }
1611  }
1612  if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1613 
1614  if (optionGrid) {
1615  if (ltick == 0) {
1616  if (optionNoopt && !optionInt) {
1617  Rotate(xtick,0,cosphi,sinphi,x0,y0 ,xpl2,ypl2);
1618  Rotate(xtick,grid_side*gridlength ,cosphi,sinphi,x0,y0 ,xpl1,ypl1);
1619  }
1620  else {
1621  Rotate(xtick,0,cosphi ,sinphi,xx0,yy0 ,xpl2,ypl2);
1622  Rotate(xtick,grid_side*gridlength ,cosphi,sinphi,xx0,yy0 ,xpl1,ypl1);
1623  }
1624  linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1625  }
1626  }
1627  }
1628  xtick0 = 0;
1629  xtick1 = xtick;
1630 
1631  if (fFunction) axis_length0 = binLow-wmin;
1632  if ((!optionNoopt || optionInt) && axis_length0) {
1633  nticks0 = Int_t(axis_length0/dxtick);
1634  if (nticks0 > 1000) nticks0 = 1000;
1635  for (k=0; k<=nticks0; k++) {
1636  ltick = 2;
1637  if (k%nn3 == 0) ltick = 1;
1638  if (k%nn2 == 0) ltick = 0;
1639  ytick0 = 0;
1640  if (!mside) ytick0 -= atick[ltick];
1641  if (fFunction) {
1642  xtick0 = (fFunction->Eval(binLow - Double_t(k)*dxtick)-rwmi)
1643  * axis_length / TMath::Abs(rwma-rwmi);
1644  }
1645  Rotate(xtick0,ytick0,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2);
1646  Rotate(xtick0,atick[ltick],cosphi,sinphi,xx0,yy0 ,xpl1,ypl1);
1647  if (optionVert) {
1648  if ((x0 != x1) && (y0 != y1)) {
1649  if (mside) {
1650  xpl1 = xpl2;
1651  if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
1652  else ypl1 = ypl2 - atick[ltick];
1653  }
1654  else {
1655  xpl1 = 0.5*(xpl1 + xpl2);
1656  xpl2 = xpl1;
1657  ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
1658  ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
1659  }
1660  }
1661  }
1662  if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1663 
1664  if (optionGrid) {
1665  if (ltick == 0) {
1666  Rotate(xtick0,0,cosphi,sinphi,xx0,yy0,xpl2,ypl2);
1667  Rotate(xtick0,grid_side*gridlength ,cosphi,sinphi,xx0,yy0 ,xpl1,ypl1);
1668  linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1669  }
1670  }
1671  xtick0 -= dxtick;
1672  }
1673  }
1674 
1675  if (fFunction) axis_length1 = wmax-binHigh;
1676  if ((!optionNoopt || optionInt) && axis_length1) {
1677  nticks1 = int(axis_length1/dxtick);
1678  if (nticks1 > 1000) nticks1 = 1000;
1679  for (k=0; k<=nticks1; k++) {
1680  ltick = 2;
1681  if (k%nn3 == 0) ltick = 1;
1682  if (k%nn2 == 0) ltick = 0;
1683  ytick1 = 0;
1684  if (!mside) ytick1 -= atick[ltick];
1685  if (fFunction) {
1686  xtick1 = (fFunction->Eval(binHigh + Double_t(k)*dxtick)-rwmi)
1687  * axis_length / TMath::Abs(rwma-rwmi);
1688  }
1689  Rotate(xtick1,ytick1,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2);
1690  Rotate(xtick1,atick[ltick],cosphi,sinphi,xx0,yy0 ,xpl1,ypl1);
1691  if (optionVert) {
1692  if ((x0 != x1) && (y0 != y1)) {
1693  if (mside) {
1694  xpl1 = xpl2;
1695  if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
1696  else ypl1 = ypl2 - atick[ltick];
1697  }
1698  else {
1699  xpl1 = 0.5*(xpl1 + xpl2);
1700  xpl2 = xpl1;
1701  ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
1702  ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
1703  }
1704  }
1705  }
1706  if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1707  if (optionGrid) {
1708  if (ltick == 0) {
1709  Rotate(xtick1,0,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2);
1710  Rotate(xtick1,grid_side*gridlength,cosphi,sinphi,xx0,yy0,xpl1,ypl1);
1711  linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
1712  }
1713  }
1714  xtick1 += dxtick;
1715  }
1716  }
1717  }
1718  }
1719 
1720 // Draw the numeric labels if needed...
1721  if (!drawGridOnly && !optionUnlab) {
1722  if (!optionLog) {
1723  if (n1a) {
1724 // Spacing of labels
1725  if ((wmin == wmax) || (ndiv == 0)) {
1726  Error(where, "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
1727  goto L210;
1728  }
1729  wlabel = wmin;
1730  dwlabel = (wmax-wmin)/Double_t(n1a);
1731  if (optionNoopt && !optionInt) dxlabel = axis_length/Double_t(n1a);
1732  else dxlabel = axis_lengthN/Double_t(n1a);
1733 
1734  if (!optionText && !optionTime) {
1735 
1736 // We have to decide what format to generate
1737 // (for numeric labels only)
1738 // Test the magnitude, decide format
1739  flexe = kFALSE;
1740  nexe = 0;
1741  flexpo = kFALSE;
1742  flexne = kFALSE;
1743  ww = TMath::Max(TMath::Abs(wmin),TMath::Abs(wmax));
1744 
1745 // First case : (wmax-wmin)/n1a less than 0.001
1746 // (0.001 fgMaxDigits of 5 (fgMaxDigits) characters). Then we use x 10 n
1747 // format. If af >=0 x10 n cannot be used
1748  Double_t xmicros = 0.00099;
1749  if (maxDigits) xmicros = TMath::Power(10,-maxDigits);
1750  if (!noExponent && (TMath::Abs(wmax-wmin)/Double_t(n1a)) < xmicros) {
1751  af = TMath::Log10(ww) + epsilon;
1752  if (af < 0) {
1753  flexe = kTRUE;
1754  nexe = int(af);
1755  iexe = TMath::Abs(nexe);
1756  if (iexe%3 == 1) iexe += 2;
1757  else if(iexe%3 == 2) iexe += 1;
1758  if (nexe < 0) nexe = -iexe;
1759  else nexe = iexe;
1760  wlabel = wlabel*TMath::Power(10,iexe);
1761  dwlabel = dwlabel*TMath::Power(10,iexe);
1762  if1 = maxDigits;
1763  if2 = maxDigits-2;
1764  goto L110;
1765  }
1766  }
1767  if (ww >= 1) af = TMath::Log10(ww);
1768  else af = TMath::Log10(ww*0.0001);
1769  af += epsilon;
1770  nf = Int_t(af)+1;
1771  if (!noExponent && nf > maxDigits) flexpo = kTRUE;
1772  if (!noExponent && nf < -maxDigits) flexne = kTRUE;
1773 
1774 // Use x 10 n format. (only powers of 3 allowed)
1775 
1776  if (flexpo) {
1777  flexe = kTRUE;
1778  while (1) {
1779  nexe++;
1780  ww /= 10;
1781  wlabel /= 10;
1782  dwlabel /= 10;
1783  if (nexe%3 == 0 && ww <= TMath::Power(10,maxDigits-1)) break;
1784  }
1785  }
1786 
1787  if (flexne) {
1788  flexe = kTRUE;
1789  rne = 1/TMath::Power(10,maxDigits-2);
1790  while (1) {
1791  nexe--;
1792  ww *= 10;
1793  wlabel *= 10;
1794  dwlabel *= 10;
1795  if (nexe%3 == 0 && ww >= rne) break;
1796  }
1797  }
1798 
1799  na = 0;
1800  for (i=maxDigits-1; i>0; i--) {
1801  if (TMath::Abs(ww) < TMath::Power(10,i)) na = maxDigits-i;
1802  }
1803  ndyn = n1a;
1804  while (ndyn) {
1805  Double_t wdyn = TMath::Abs((wmax-wmin)/ndyn);
1806  if (wdyn <= 0.999 && na < maxDigits-2) {
1807  na++;
1808  ndyn /= 10;
1809  }
1810  else break;
1811  }
1812 // if1 and if2 are the two digits defining the format used to produce the
1813 // labels. The format used will be %[if1].[if2]f .
1814 // if1 and if2 are positive (small) integers.
1815  if2 = na;
1816  if1 = TMath::Max(nf+na,maxDigits)+1;
1817 L110:
1818  if (TMath::Min(wmin,wmax) < 0)if1 = if1+1;
1819  if1 = TMath::Min(if1,32);
1820 
1821 // In some cases, if1 and if2 are too small....
1822  while (dwlabel < TMath::Power(10,-if2)) {
1823  if1++;
1824  if2++;
1825  }
1826  if (if1 > 14) if1 = 14;
1827  if (if2 > 14) if2 = 14;
1828  if (if1 < 0) if1 = 0;
1829  int len = 0;
1830  if (if2 > 0) {
1831  len = snprintf(chcoded,sizeof(chcoded),"%%%d.%df",if1,if2);
1832  } else {
1833  len = snprintf(chcoded,sizeof(chcoded),"%%%d.%df",if1+1,1);
1834  }
1835  // check improbable error condition, suppress gcc9 warnings
1836  if ((len < 0) || (len >= (int) sizeof(chcoded)))
1837  strcpy(chcoded,"%7.3f");
1838  }
1839 
1840 // We draw labels
1841 
1842  snprintf(chtemp,256,"%g",dwlabel);
1843  Int_t ndecimals = 0;
1844  if (optionDecimals) {
1845  char *dot = strchr(chtemp,'.');
1846  if (dot) {
1847  ndecimals = chtemp + strlen(chtemp) -dot;
1848  } else {
1849  char *exp;
1850  exp = strstr(chtemp,"e-");
1851  if (exp) {
1852  sscanf(&exp[2],"%d",&ndecimals);
1853  ndecimals++;
1854  }
1855  }
1856  }
1857  if (optionM) nlabels = n1a-1;
1858  else nlabels = n1a;
1859  wTimeIni = wlabel;
1860  for ( k=0; k<=nlabels; k++) {
1861  if (fFunction) {
1862  Double_t xf = binLow+Double_t(k*nn2)*dxtick;
1863  Double_t zz = fFunction->Eval(xf)-rwmi;
1864  wlabel = xf;
1865  xlabel = zz* axis_length / TMath::Abs(rwma-rwmi);
1866  } else {
1867  xlabel = dxlabel*k;
1868  }
1869  if (optionM) xlabel += 0.5*dxlabel;
1870 
1871  if (!optionText && !optionTime) {
1872  snprintf(label,256,chcoded,wlabel);
1873  label[28] = 0;
1874  wlabel += dwlabel;
1875 
1876  LabelsLimits(label,first,last); //Eliminate blanks
1877 
1878  if (label[first] == '.') { //check if '.' is preceded by a digit
1879  strncpy(chtemp, "0",256);
1880  strlcat(chtemp, &label[first],256);
1881  strncpy(label, chtemp,256);
1882  first = 1; last = strlen(label);
1883  }
1884  if (label[first] == '-' && label[first+1] == '.') {
1885  strncpy(chtemp, "-0",256);
1886  strlcat(chtemp, &label[first+1],256);
1887  strncpy(label, chtemp, 256);
1888  first = 1; last = strlen(label);
1889  }
1890 
1891 // We eliminate the non significant 0 after '.'
1892  if (ndecimals) {
1893  char *adot = strchr(label,'.');
1894  if (adot) adot[ndecimals] = 0;
1895  } else {
1896  while (label[last] == '0') { label[last] = 0; last--;}
1897  }
1898 
1899 // We eliminate the dot, unless dot is forced.
1900  if (label[last] == '.') {
1901  if (!optionDot) { label[last] = 0; last--;}
1902  }
1903 
1904 // Make sure the label is not "-0"
1905  if (last-first == 1 && label[first] == '-'
1906  && label[last] == '0') {
1907  strncpy(label, "0", 256);
1908  label[last] = 0;
1909  }
1910  }
1911 
1912 // Generate the time labels
1913 
1914  if (optionTime) {
1915  timed = wlabel + (int)(timeoffset) - rangeOffset;
1916  timelabel = (time_t)((Long_t)(timed));
1917  if (optionTime == 1) {
1918  utctis = localtime(&timelabel);
1919  } else {
1920  utctis = gmtime(&timelabel);
1921  }
1922  TString timeformattmp;
1923  if (timeformat.Length() < 220) timeformattmp = timeformat;
1924  else timeformattmp = "#splitline{Format}{too long}";
1925 
1926 // Appends fractional part if seconds displayed
1927  if (dwlabel<0.9) {
1928  double tmpdb;
1929  int tmplast;
1930  snprintf(label, 256, "%%S%7.5f", modf(timed,&tmpdb));
1931  tmplast = strlen(label)-1;
1932 
1933 // We eliminate the non significant 0 after '.'
1934  while (label[tmplast] == '0') {
1935  label[tmplast] = 0; tmplast--;
1936  }
1937 
1938  timeformattmp.ReplaceAll("%S",label);
1939 // replace the "0." at the beginning by "s"
1940  timeformattmp.ReplaceAll("%S0.","%Ss");
1941 
1942  }
1943 
1944  if (utctis != nullptr) {
1945  strftime(label, 256, timeformattmp.Data(), utctis);
1946  } else {
1947  strncpy(label, "invalid", 256);
1948  }
1949  strncpy(chtemp, &label[0], 256);
1950  first = 0; last=strlen(label)-1;
1951  wlabel = wTimeIni + (k+1)*dwlabel;
1952  }
1953 
1954 // We generate labels (numeric or alphanumeric).
1955 
1956  if (optionNoopt && !optionInt)
1957  Rotate (xlabel,ylabel,cosphi,sinphi,x0,y0,xx,yy);
1958  else Rotate (xlabel,ylabel,cosphi,sinphi,xx0,yy0,xx,yy);
1959  if (y0 == y1 && !optionDown && !optionUp) {
1960  yy -= 0.80*charheight;
1961  }
1962  if (optionVert) {
1963  if (x0 != x1 && y0 != y1) {
1964  if (optionNoopt && !optionInt)
1965  Rotate (xlabel,0,cosphi,sinphi,x0,y0,xx,yy);
1966  else Rotate (xlabel,0,cosphi,sinphi,xx0,yy0,xx,yy);
1967  if (cosphi > 0 ) yy += ylabel;
1968  if (cosphi < 0 ) yy -= ylabel;
1969  }
1970  }
1971  if (!optionY || (x0 == x1)) {
1972  if (!optionText) {
1973  if (first > last) strncpy(chtemp, " ", 256);
1974  else strncpy(chtemp, &label[first], 255);
1975  if (fNModLabs) ChangeLabelAttributes(k+1, nlabels, textaxis, chtemp);
1976  typolabel = chtemp;
1977  if (!optionTime) typolabel.ReplaceAll("-", "#minus");
1978  if (autotoff) {
1979  UInt_t w,h;
1980  textaxis->SetText(0.,0., typolabel.Data());
1981  textaxis->GetBoundingBox(w,h);
1982  toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC()));
1983  }
1984  textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()),
1985  gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()),
1986  textaxis->GetTextAngle(),
1987  textaxis->GetTextSize(),
1988  typolabel.Data());
1989  if (fNModLabs) ResetLabelAttributes(textaxis);
1990  } else {
1991  if (optionText == 1) textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()),
1992  gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()),
1993  0,
1994  textaxis->GetTextSize(),
1995  fAxis->GetBinLabel(k+fAxis->GetFirst()));
1996  }
1997  } else {
1998 
1999 // Text alignment is down
2000  if (!optionText) lnlen = last-first+1;
2001  else {
2002  if (k+1 > nhilab) lnlen = 0;
2003  }
2004  for ( l=1; l<=lnlen; l++) {
2005  if (!optionText) *chtemp = label[first+l-2];
2006  else {
2007  if (lnlen == 0) strncpy(chtemp, " ", 256);
2008  else strncpy(chtemp, "1", 256);
2009  }
2010  typolabel = chtemp;
2011  typolabel.ReplaceAll("-", "#minus");
2012  textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()),
2013  gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()),
2014  0,
2015  textaxis->GetTextSize(),
2016  typolabel.Data());
2017  yy -= charheight*1.3;
2018  }
2019  }
2020  }
2021 
2022 // We use the format x 10 ** n
2023 
2024  if (flexe && !optionText && nexe) {
2025  snprintf(label,256,"#times10^{%d}", nexe);
2026  if (x0 != x1) { xfactor = axis_length+0.1*charheight; yfactor = 0; }
2027  else { xfactor = y1-y0+0.1*charheight; yfactor = 0; }
2028  Rotate (xfactor,yfactor,cosphi,sinphi,x0,y0,xx,yy);
2029  textaxis->SetTextAlign(11);
2030  if (GetLabelFont()%10 < 2) // force TLatex mode in PaintLatex
2031  textaxis->SetTextFont((Int_t)(GetLabelFont()/10)*10+2);
2032  if (fAxis && !strcmp(fAxis->GetName(),"xaxis")) {
2033  xx = xx + fXAxisExpXOffset;
2034  yy = yy + fXAxisExpYOffset;
2035  }
2036  if (fAxis && !strcmp(fAxis->GetName(),"yaxis")) {
2037  xx = xx + fYAxisExpXOffset;
2038  yy = yy + fYAxisExpYOffset;
2039  }
2040  typolabel = label;
2041  typolabel.ReplaceAll("-", "#minus");
2042  textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()),
2043  gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()),
2044  0,
2045  textaxis->GetTextSize(),
2046  typolabel.Data());
2047  }
2048  }
2049  }
2050  }
2051 
2052 // Log axis
2053 
2054  if (optionLog && ndiv) {
2055  UInt_t xi1=0,xi2=0,wi=0,yi1=0,yi2=0,hi=0,xl=0,xh=0;
2056  Bool_t firstintlab = kTRUE, overlap = kFALSE;
2057  if ((wmin == wmax) || (ndiv == 0)) {
2058  Error(where, "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
2059  goto L210;
2060  }
2061  if (wmin <= 0) {
2062  Error(where, "negative logarithmic axis");
2063  goto L210;
2064  }
2065  if (wmax <= 0) {
2066  Error(where, "negative logarithmic axis");
2067  goto L210;
2068  }
2069  xmnlog = TMath::Log10(wmin);
2070  if (xmnlog > 0) xmnlog += 1.E-6;
2071  else xmnlog -= 1.E-6;
2072  x00 = 0;
2073  x11 = axis_length;
2074  h2 = TMath::Log10(wmax);
2075  h2sav = h2;
2076  if (h2 > 0) h2 += 1.E-6;
2077  else h2 -= 1.E-6;
2078  ih1 = int(xmnlog);
2079  ih2 = 1+int(h2);
2080  nbinin = ih2-ih1+1;
2081  axmul = (x11-x00)/(h2sav-xmnlog);
2082 
2083 // Plot decade and intermediate tick marks
2084  decade = ih1-2;
2085  labelnumber = ih1;
2086  if ( xmnlog > 0 && (xmnlog-Double_t(ih1) > 0) ) labelnumber++;
2087  Int_t changelablogid = 0;
2088  Int_t changelablognum = 0;
2089  for (j=1; j<=nbinin; j++) {
2090 
2091 // Plot decade
2092  firstintlab = kTRUE, overlap = kFALSE;
2093  decade++;
2094  if (x0 == x1 && j == 1) ylabel += charheight*0.33;
2095  if (y0 == y1 && j == 1) ylabel -= charheight*0.65;
2096  xone = x00+axmul*(Double_t(decade)-xmnlog);
2097  //the following statement is a trick to circumvent a gcc bug
2098  if (j < 0) printf("j=%d\n",j);
2099  if (x00 > xone) goto L160;
2100  if ((xone-x11)>epsilon) break;
2101  xtwo = xone;
2102  y = 0;
2103  if (!mside) y -= atick[0];
2104  Rotate(xone,y,cosphi,sinphi,x0,y0,xpl2,ypl2);
2105  Rotate(xtwo,atick[0],cosphi,sinphi,x0,y0,xpl1,ypl1);
2106  if (optionVert) {
2107  if ((x0 != x1) && (y0 != y1)) {
2108  if (mside) {
2109  xpl1=xpl2;
2110  if (cosphi > 0) ypl1 = ypl2 + atick[0];
2111  else ypl1 = ypl2 - atick[0];
2112  }
2113  else {
2114  xpl1 = 0.5*(xpl1 + xpl2);
2115  xpl2 = xpl1;
2116  ypl1 = 0.5*(ypl1 + ypl2) + atick[0];
2117  ypl2 = 0.5*(ypl1 + ypl2) - atick[0];
2118  }
2119  }
2120  }
2121  if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
2122 
2123  if (optionGrid) {
2124  Rotate(xone,0,cosphi,sinphi,x0,y0,xpl2,ypl2);
2125  Rotate(xone,grid_side*gridlength,cosphi,sinphi,x0,y0,xpl1,ypl1);
2126  linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
2127  }
2128 
2129  if (!drawGridOnly && !optionUnlab) {
2130 
2131 // We generate labels (numeric only).
2132  if (noExponent) {
2133  rlab = TMath::Power(10,labelnumber);
2134  snprintf(label,256, "%f", rlab);
2135  LabelsLimits(label,first,last);
2136  while (last > first) {
2137  if (label[last] != '0') break;
2138  label[last] = 0;
2139  last--;
2140  }
2141  if (label[last] == '.') {label[last] = 0; last--;}
2142  } else {
2143  snprintf(label,256, "%d", labelnumber);
2144  LabelsLimits(label,first,last);
2145  }
2146  Rotate (xone,ylabel,cosphi,sinphi,x0,y0,xx,yy);
2147  if ((x0 == x1) && !optionPara) {
2148  if (lside < 0) {
2149  if (mside < 0) {
2150  if (labelnumber == 0) nch=1;
2151  else nch=2;
2152  xx += nch*charheight;
2153  } else {
2154  xx += 0.25*charheight;
2155  }
2156  }
2157  xx += 0.25*charheight;
2158  }
2159  if ((y0 == y1) && !optionDown && !optionUp) {
2160  if (noExponent) yy += 0.33*charheight;
2161  }
2162  if (n1a == 0)goto L210;
2163  kmod = nbinin/n1a;
2164  if (kmod == 0) kmod=1000000;
2165  if ((nbinin <= n1a) || (j == 1) || (j == nbinin) || ((nbinin > n1a) && (j%kmod == 0))) {
2166  if (labelnumber == 0) {
2167  snprintf(chtemp,256, "1");
2168  } else if (labelnumber == 1) {
2169  snprintf(chtemp,256, "10");
2170  } else {
2171  if (noExponent) {
2172  chtemp = &label[first];
2173  } else {
2174  snprintf(chtemp,256, "10^{%d}", labelnumber);
2175  }
2176  }
2177  if (fNModLabs) {
2178  if (changelablogid == 0) changelablognum = nbinin-j;
2179  changelablogid++;
2180  ChangeLabelAttributes(changelablogid, changelablognum, textaxis, chtemp);
2181  }
2182  typolabel = chtemp;
2183  typolabel.ReplaceAll("-", "#minus");
2184  if (autotoff) {
2185  UInt_t w,h;
2186  textaxis->SetText(0.,0., typolabel.Data());
2187  textaxis->GetBoundingBox(w,h);
2188  toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC()));
2189  }
2190  textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()),
2191  gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()),
2192  0, textaxis->GetTextSize(), typolabel.Data());
2193  if (fNModLabs) ResetLabelAttributes(textaxis);
2194  }
2195  labelnumber++;
2196  }
2197 L160:
2198  for (k=2;k<10;k++) {
2199 
2200 // Plot intermediate tick marks
2201  xone = x00+axmul*(TMath::Log10(Double_t(k))+Double_t(decade)-xmnlog);
2202  if (x00 > xone) continue;
2203  if (xone > x11) goto L200;
2204  y = 0;
2205  if (!mside) y -= atick[1];
2206  xtwo = xone;
2207  Rotate(xone,y,cosphi,sinphi,x0,y0,xpl2,ypl2);
2208  Rotate(xtwo,atick[1],cosphi,sinphi,x0,y0,xpl1,ypl1);
2209  if (optionVert) {
2210  if ((x0 != x1) && (y0 != y1)) {
2211  if (mside) {
2212  xpl1 = xpl2;
2213  if (cosphi > 0) ypl1 = ypl2 + atick[1];
2214  else ypl1 = ypl2 - atick[1];
2215  }
2216  else {
2217  xpl1 = 0.5*(xpl1+xpl2);
2218  xpl2 = xpl1;
2219  ypl1 = 0.5*(ypl1+ypl2) + atick[1];
2220  ypl2 = 0.5*(ypl1+ypl2) - atick[1];
2221  }
2222  }
2223  }
2224  idn = n1a*2;
2225  if ((nbinin <= idn) || ((nbinin > idn) && (k == 5))) {
2226  if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
2227 
2228 // Draw the intermediate LOG labels if requested
2229 
2230  if (moreLogLabels && !optionUnlab && !drawGridOnly && !overlap) {
2231  if (noExponent) {
2232  rlab = Double_t(k)*TMath::Power(10,labelnumber-1);
2233  snprintf(chtemp,256, "%g", rlab);
2234  } else {
2235  if (labelnumber-1 == 0) {
2236  snprintf(chtemp,256, "%d", k);
2237  } else if (labelnumber-1 == 1) {
2238  snprintf(chtemp,256, "%d", 10*k);
2239  } else {
2240  snprintf(chtemp,256, "%d#times10^{%d}", k, labelnumber-1);
2241  }
2242  }
2243  Rotate (xone,ylabel,cosphi,sinphi,x0,y0,xx,yy);
2244  if ((x0 == x1) && !optionPara) {
2245  if (lside < 0) {
2246  if (mside < 0) {
2247  if (labelnumber == 0) nch=1;
2248  else nch=2;
2249  xx += nch*charheight;
2250  } else {
2251  if (labelnumber >= 0) xx += 0.25*charheight;
2252  else xx += 0.50*charheight;
2253  }
2254  }
2255  xx += 0.25*charheight;
2256  }
2257  if ((y0 == y1) && !optionDown && !optionUp) {
2258  if (noExponent) yy += 0.33*charheight;
2259  }
2260  if (optionVert) {
2261  if ((x0 != x1) && (y0 != y1)) {
2262  Rotate(xone,ylabel,cosphi,sinphi,x0,y0,xx,yy);
2263  if (cosphi > 0) yy += ylabel;
2264  else yy -= ylabel;
2265  }
2266  }
2267  textaxis->SetTitle(chtemp);
2268  Double_t u = gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1());
2269  Double_t v = gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1());
2270  if (firstintlab) {
2271  textaxis->GetBoundingBox(wi, hi); wi=(UInt_t)(wi*1.3); hi=(UInt_t)(hi*1.3);
2272  xi1 = gPad->XtoAbsPixel(u);
2273  yi1 = gPad->YtoAbsPixel(v);
2274  firstintlab = kFALSE;
2275  typolabel = chtemp;
2276  typolabel.ReplaceAll("-", "#minus");
2277  textaxis->PaintLatex(u,v,0,textaxis->GetTextSize(),typolabel.Data());
2278  } else {
2279  xi2 = gPad->XtoAbsPixel(u);
2280  yi2 = gPad->YtoAbsPixel(v);
2281  xl = TMath::Min(xi1,xi2);
2282  xh = TMath::Max(xi1,xi2);
2283  if ((x0 == x1 && yi1-hi <= yi2) || (y0 == y1 && xl+wi >= xh)){
2284  overlap = kTRUE;
2285  } else {
2286  xi1 = xi2;
2287  yi1 = yi2;
2288  textaxis->GetBoundingBox(wi, hi); wi=(UInt_t)(wi*1.3); hi=(UInt_t)(hi*1.3);
2289  typolabel = chtemp;
2290  typolabel.ReplaceAll("-", "#minus");
2291  textaxis->PaintLatex(u,v,0,textaxis->GetTextSize(),typolabel.Data());
2292  }
2293  }
2294  }
2295 
2296 // Draw the intermediate LOG grid if only three decades are requested
2297  if (optionGrid && nbinin <= 5 && ndiv > 100) {
2298  Rotate(xone,0,cosphi,sinphi,x0,y0,xpl2, ypl2);
2299  Rotate(xone,grid_side*gridlength,cosphi,sinphi,x0,y0, xpl1,ypl1);
2300  linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2);
2301  }
2302  } //endif ((nbinin <= idn) ||
2303  } //endfor (k=2;k<10;k++)
2304  } //endfor (j=1; j<=nbinin; j++)
2305 L200:
2306  Int_t dummy = 0; if (dummy) { }
2307  } //endif (optionLog && ndiv)
2308 
2309 // Draw axis title if it exists
2310  if (!drawGridOnly && strlen(GetTitle())) {
2311  textaxis->SetTextSize (GetTitleSize());
2312  charheight = GetTitleSize();
2313  if ((GetTextFont() % 10) > 2) {
2314  charheight = charheight/gPad->GetWh();
2315  }
2316  if (x1 == x0) {
2317  if (autotoff) {
2318  if (toffset) ylabel = xlside*charheight+toffset;
2319  else ylabel = xlside*1.6*charheight;
2320  } else {
2321  ylabel = xlside*1.6*charheight*toffset;
2322  }
2323  } else {
2324  ylabel = xlside*1.3*charheight*toffset;
2325  }
2326  if (y1 == y0) {
2327  if (toffset == 0.) toffset = gStyle->GetTitleOffset("X");
2328  ylabel = xlside*1.6*charheight*toffset;
2329  }
2330  Double_t axispos;
2331  if (TestBit(TAxis::kCenterTitle)) axispos = 0.5*axis_length;
2332  else axispos = axis_length;
2333  if (TestBit(TAxis::kRotateTitle)) {
2334  if (x1 >= x0) {
2335  if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22);
2336  else textaxis->SetTextAlign(12);
2337  } else {
2338  if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22);
2339  else textaxis->SetTextAlign(32);
2340  }
2341  phil+=kPI;
2342  } else {
2343  if (x1 >= x0) {
2344  if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22);
2345  else textaxis->SetTextAlign(32);
2346  } else {
2347  if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22);
2348  else textaxis->SetTextAlign(12);
2349  }
2350  }
2351  Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1);
2352  textaxis->SetTextColor(TitleColor);
2353  textaxis->SetTextFont(TitleFont);
2354  textaxis->PaintLatex(gPad->GetX1() + xpl1*(gPad->GetX2() - gPad->GetX1()),
2355  gPad->GetY1() + ypl1*(gPad->GetY2() - gPad->GetY1()),
2356  phil*180/kPI,
2357  GetTitleSize(),
2358  GetTitle());
2359  }
2360 
2361 L210:
2362  if (optionGrid) delete linegrid;
2363  delete textaxis;
2364 }
2365 
2366 ////////////////////////////////////////////////////////////////////////////////
2367 /// Internal method for axis labels optimisation. This method adjusts the bining
2368 /// of the axis in order to have integer values for the labels.
2369 ///
2370 /// \param[in] A1,A2 Old WMIN,WMAX
2371 /// \param[out] binLow,binHigh New WMIN,WMAX
2372 /// \param[in] nold Old NDIV (primary divisions)
2373 /// \param[out] nbins New NDIV
2374 /// \param[out] binWidth Bin width
2375 
2376 void TGaxis::AdjustBinSize(Double_t A1, Double_t A2, Int_t nold
2377  ,Double_t &binLow, Double_t &binHigh, Int_t &nbins, Double_t &binWidth)
2378 {
2379 
2380  binWidth = TMath::Abs(A2-A1)/Double_t(nold);
2381  if (binWidth <= 1) { binWidth = 1; binLow = int(A1); }
2382  else {
2383  Int_t width = int(binWidth/5) + 1;
2384  binWidth = 5*width;
2385  binLow = int(A1/binWidth)*binWidth;
2386 
2387 // We determine binLow to have one tick mark at 0
2388 // if there are negative labels.
2389 
2390  if (A1 < 0) {
2391  for (Int_t ic=0; ic<1000; ic++) {
2392  Double_t rbl = binLow/binWidth;
2393  Int_t ibl = int(binLow/binWidth);
2394  if ( (rbl-ibl) == 0 || ic > width) { binLow -= 5; break;}
2395  }
2396  }
2397  }
2398  binHigh = int(A2);
2399  nbins = 0;
2400  Double_t xb = binLow;
2401  while (xb <= binHigh) {
2402  xb += binWidth;
2403  nbins++;
2404  }
2405  binHigh = xb - binWidth;
2406 }
2407 
2408 ////////////////////////////////////////////////////////////////////////////////
2409 /// Internal method to find first and last character of a label.
2410 
2411 void TGaxis::LabelsLimits(const char *label, Int_t &first, Int_t &last)
2412 {
2413  last = strlen(label)-1;
2414  for (Int_t i=0; i<=last; i++) {
2415  if (strchr("1234567890-+.", label[i]) ) { first = i; return; }
2416  }
2417  Error("LabelsLimits", "attempt to draw a blank label");
2418 }
2419 
2420 ////////////////////////////////////////////////////////////////////////////////
2421 /// Internal method to rotate axis coordinates.
2422 
2423 void TGaxis::Rotate(Double_t X, Double_t Y, Double_t CFI, Double_t SFI
2424  ,Double_t XT, Double_t YT, Double_t &U, Double_t &V)
2425 {
2426  U = CFI*X-SFI*Y+XT;
2427  V = SFI*X+CFI*Y+YT;
2428 }
2429 
2430 ////////////////////////////////////////////////////////////////////////////////
2431 /// Save primitive as a C++ statement(s) on output stream out
2432 
2433 void TGaxis::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
2434 {
2435  char quote = '"';
2436  if (gROOT->ClassSaved(TGaxis::Class())) {
2437  out<<" ";
2438  } else {
2439  out<<" TGaxis *";
2440  }
2441  out<<"gaxis = new TGaxis("<<fX1<<","<<fY1<<","<<fX2<<","<<fY2
2442  <<","<<fWmin<<","<<fWmax<<","<<fNdiv<<","<<quote<<fChopt.Data()<<quote<<");"<<std::endl;
2443  out<<" gaxis->SetLabelOffset("<<GetLabelOffset()<<");"<<std::endl;
2444  out<<" gaxis->SetLabelSize("<<GetLabelSize()<<");"<<std::endl;
2445  out<<" gaxis->SetTickSize("<<GetTickSize()<<");"<<std::endl;
2446  out<<" gaxis->SetGridLength("<<GetGridLength()<<");"<<std::endl;
2447  out<<" gaxis->SetTitleOffset("<<GetTitleOffset()<<");"<<std::endl;
2448  out<<" gaxis->SetTitleSize("<<GetTitleSize()<<");"<<std::endl;
2449  out<<" gaxis->SetTitleColor("<<GetTextColor()<<");"<<std::endl;
2450  out<<" gaxis->SetTitleFont("<<GetTextFont()<<");"<<std::endl;
2451 
2452  if (strlen(GetName())) {
2453  out<<" gaxis->SetName("<<quote<<GetName()<<quote<<");"<<std::endl;
2454  }
2455  if (strlen(GetTitle())) {
2456  out<<" gaxis->SetTitle("<<quote<<GetTitle()<<quote<<");"<<std::endl;
2457  }
2458 
2459  if (fLabelColor != 1) {
2460  if (fLabelColor > 228) {
2461  TColor::SaveColor(out, fLabelColor);
2462  out<<" gaxis->SetLabelColor(ci);" << std::endl;
2463  } else
2464  out<<" gaxis->SetLabelColor("<<GetLabelColor()<<");"<<std::endl;
2465  }
2466  if (fLineColor != 1) {
2467  if (fLineColor > 228) {
2468  TColor::SaveColor(out, fLineColor);
2469  out<<" gaxis->SetLineColor(ci);" << std::endl;
2470  } else
2471  out<<" gaxis->SetLineColor("<<GetLineColor()<<");"<<std::endl;
2472  }
2473  if (fLineStyle != 1) {
2474  out<<" gaxis->SetLineStyle("<<GetLineStyle()<<");"<<std::endl;
2475  }
2476  if (fLineWidth != 1) {
2477  out<<" gaxis->SetLineWidth("<<GetLineWidth()<<");"<<std::endl;
2478  }
2479  if (fLabelFont != 62) {
2480  out<<" gaxis->SetLabelFont("<<GetLabelFont()<<");"<<std::endl;
2481  }
2482  if (TestBit(TAxis::kMoreLogLabels)) {
2483  out<<" gaxis->SetMoreLogLabels();"<<std::endl;
2484  }
2485  if (TestBit(TAxis::kNoExponent)) {
2486  out<<" gaxis->SetNoExponent();"<<std::endl;
2487  }
2488 
2489  out<<" gaxis->Draw();"<<std::endl;
2490 }
2491 
2492 ////////////////////////////////////////////////////////////////////////////////
2493 /// Set the decimals flag. By default, blank characters are stripped, and then the
2494 /// label is correctly aligned. The dot, if last character of the string, is also
2495 /// stripped, unless this option is specified. One can disable the option by
2496 /// calling `axis.SetDecimals(kTRUE)`.
2497 /// Note the bit is set in fBits (as opposed to fBits2 in TAxis!)
2498 
2499 void TGaxis::SetDecimals(Bool_t dot)
2500 {
2501  if (dot) SetBit(TAxis::kDecimals);
2502  else ResetBit(TAxis::kDecimals);
2503 }
2504 
2505 ////////////////////////////////////////////////////////////////////////////////
2506 /// Specify a function to map the axis values.
2507 
2508 void TGaxis::SetFunction(const char *funcname)
2509 {
2510  fFunctionName = funcname;
2511  if (!funcname[0]) {
2512  fFunction = 0;
2513  return;
2514  }
2515  fFunction = (TF1*)gROOT->GetFunction(funcname);
2516  if (!fFunction) {
2517  Error("SetFunction", "unknown function: %s", funcname);
2518  } else {
2519  fWmin = fFunction->GetXmin();
2520  fWmax = fFunction->GetXmax();
2521  }
2522 }
2523 
2524 ////////////////////////////////////////////////////////////////////////////////
2525 /// Define new text attributes for the label number "labNum". It allows to do a
2526 /// fine tuning of the labels. All the attributes can be changed, even the
2527 /// label text itself.
2528 ///
2529 /// \param[in] labNum Number of the label to be changed, negative numbers start from the end
2530 /// \param[in] labAngle New angle value
2531 /// \param[in] labSize New size (0 erase the label)
2532 /// \param[in] labAlign New alignment value
2533 /// \param[in] labColor New label color
2534 /// \param[in] labFont New label font
2535 /// \param[in] labText New label text
2536 ///
2537 /// If an attribute should not be changed just give the value
2538 /// "-1".The following macro gives an example:
2539 ///
2540 /// Begin_Macro(source)
2541 /// {
2542 /// c1 = new TCanvas("c1","Examples of Gaxis",10,10,900,500);
2543 /// c1->Range(-6,-0.1,6,0.1);
2544 /// TGaxis *axis1 = new TGaxis(-5.5,0.,5.5,0.,0.0,100,510,"");
2545 /// axis1->SetName("axis1");
2546 /// axis1->SetTitle("Axis Title");
2547 /// axis1->SetTitleSize(0.05);
2548 /// axis1->SetTitleColor(kBlue);
2549 /// axis1->SetTitleFont(42);
2550 /// axis1->ChangeLabel(1,-1,-1,-1,2);
2551 /// axis1->ChangeLabel(3,-1,0.);
2552 /// axis1->ChangeLabel(5,30.,-1,0);
2553 /// axis1->ChangeLabel(6,-1,-1,-1,3,-1,"6th label");
2554 /// axis1->ChangeLabel(-2,-1,-1,-1,3,-1,"2nd to last label");
2555 /// axis1->Draw();
2556 /// }
2557 /// End_Macro
2558 ///
2559 /// If labnum=0 the list of modified labels is reset.
2560 
2561 void TGaxis::ChangeLabel(Int_t labNum, Double_t labAngle, Double_t labSize,
2562  Int_t labAlign, Int_t labColor, Int_t labFont,
2563  TString labText)
2564 {
2565  fNModLabs++;
2566  if (!fModLabs) fModLabs = new TList();
2567 
2568  // Reset the list of modified labels.
2569  if (labNum == 0) {
2570  delete fModLabs;
2571  fModLabs = 0;
2572  fNModLabs = 0;
2573  return;
2574  }
2575 
2576  TAxisModLab *ml = new TAxisModLab();
2577  ml->SetLabNum(labNum);
2578  ml->SetAngle(labAngle);
2579  ml->SetSize(labSize);
2580  ml->SetAlign(labAlign);
2581  ml->SetColor(labColor);
2582  ml->SetFont(labFont);
2583  ml->SetText(labText);
2584 
2585  fModLabs->Add((TObject*)ml);
2586 }
2587 
2588 ////////////////////////////////////////////////////////////////////////////////
2589 /// Change the label attributes of label number i. If needed.
2590 ///
2591 /// \param[in] i Current label number to be changed if needed
2592 /// \param[in] nlabels Totals number of labels on for this axis (useful when i is counted from the end)
2593 /// \param[in] t Original TLatex string holding the label to be changed
2594 /// \param[in] c Text string to be drawn
2595 
2596 static Double_t SavedTextAngle;
2597 static Double_t SavedTextSize;
2598 static Int_t SavedTextAlign;
2599 static Int_t SavedTextColor;
2600 static Int_t SavedTextFont;;
2601 
2602 void TGaxis::ChangeLabelAttributes(Int_t i, Int_t nlabels, TLatex* t, char* c)
2603 {
2604  if (!fModLabs) return;
2605 
2606  TIter next(fModLabs);
2607  TAxisModLab *ml;
2608  Int_t labNum;
2609  while ( (ml = (TAxisModLab*)next()) ) {
2610  SavedTextAngle = t->GetTextAngle();
2611  SavedTextSize = t->GetTextSize();
2612  SavedTextAlign = t->GetTextAlign();
2613  SavedTextColor = t->GetTextColor();
2614  SavedTextFont = t->GetTextFont();
2615  labNum = ml->GetLabNum();
2616  if (labNum < 0) labNum = nlabels + labNum + 2;
2617  if (i == labNum) {
2618  if (ml->GetAngle()>=0.) t->SetTextAngle(ml->GetAngle());
2619  if (ml->GetSize()>=0.) t->SetTextSize(ml->GetSize());
2620  if (ml->GetAlign()>0) t->SetTextAlign(ml->GetAlign());
2621  if (ml->GetColor()>=0) t->SetTextColor(ml->GetColor());
2622  if (ml->GetFont()>0) t->SetTextFont(ml->GetFont());
2623  if (!(ml->GetText().IsNull())) strncpy(c, (ml->GetText()).Data(), 256);
2624  return;
2625  }
2626  }
2627 }
2628 
2629 ////////////////////////////////////////////////////////////////////////////////
2630 /// Reset the label attributes to the value they have before the last call to
2631 /// ChangeLabelAttributes.
2632 
2633 void TGaxis::ResetLabelAttributes(TLatex* t)
2634 {
2635  t->SetTextAngle(SavedTextAngle);
2636  t->SetTextSize(SavedTextSize);
2637  t->SetTextAlign(SavedTextAlign);
2638  t->SetTextColor(SavedTextColor);
2639  t->SetTextFont(SavedTextFont);
2640 }
2641 
2642 ////////////////////////////////////////////////////////////////////////////////
2643 /// Static function to set `fgMaxDigits` for axis.`fgMaxDigits` is
2644 /// the maximum number of digits permitted for the axis labels above which the
2645 /// notation with 10^N is used.For example, to accept 6 digits number like 900000
2646 /// on an axis call `TGaxis::SetMaxDigits(6)`. The default value is 5.
2647 /// `fgMaxDigits` must be greater than 0.
2648 
2649 void TGaxis::SetMaxDigits(Int_t maxd)
2650 {
2651  fgMaxDigits = maxd;
2652  if (maxd < 1) fgMaxDigits = 1;
2653 }
2654 
2655 ////////////////////////////////////////////////////////////////////////////////
2656 /// Change the name of the axis.
2657 
2658 void TGaxis::SetName(const char *name)
2659 {
2660  fName = name;
2661 }
2662 
2663 ////////////////////////////////////////////////////////////////////////////////
2664 /// Set the kMoreLogLabels bit flag. When this option is selected more labels are
2665 /// drawn when in logarithmic scale and there is a small number of decades (less than 3).
2666 /// Note that this option is automatically inherited from TAxis
2667 
2668 void TGaxis::SetMoreLogLabels(Bool_t more)
2669 {
2670  if (more) SetBit(TAxis::kMoreLogLabels);
2671  else ResetBit(TAxis::kMoreLogLabels);
2672 }
2673 
2674 ////////////////////////////////////////////////////////////////////////////////
2675 /// Set the NoExponent flag. By default, an exponent of the form 10^N is used
2676 /// when the label values are either all very small or very large. One can disable
2677 /// the exponent by calling axis.SetNoExponent(kTRUE).
2678 
2679 void TGaxis::SetNoExponent(Bool_t noExponent)
2680 {
2681  if (noExponent) SetBit(TAxis::kNoExponent);
2682  else ResetBit(TAxis::kNoExponent);
2683 }
2684 
2685 ////////////////////////////////////////////////////////////////////////////////
2686 /// To set axis options.
2687 
2688 void TGaxis::SetOption(Option_t *option)
2689 {
2690  fChopt = option;
2691 }
2692 
2693 ////////////////////////////////////////////////////////////////////////////////
2694 /// Change the title of the axis.
2695 
2696 void TGaxis::SetTitle(const char *title)
2697 {
2698  fTitle = title;
2699 }
2700 
2701 ////////////////////////////////////////////////////////////////////////////////
2702 /// Change the format used for time plotting.
2703 /// The format string for date and time use the same options as the one used
2704 /// in the standard strftime C function, i.e. :
2705 ///
2706 /// for date :
2707 ///
2708 /// - `%a` abbreviated weekday name
2709 /// - `%b` abbreviated month name
2710 /// - `%d` day of the month (01-31)
2711 /// - `%m` month (01-12)
2712 /// - `%y` year without century
2713 ///
2714 /// for time :
2715 ///
2716 /// - `%H` hour (24-hour clock)
2717 /// - `%I` hour (12-hour clock)
2718 /// - `%p` local equivalent of AM or PM
2719 /// - `%M` minute (00-59)
2720 /// - `%S` seconds (00-61)
2721 /// - `%%` %
2722 
2723 void TGaxis::SetTimeFormat(const char *tformat)
2724 {
2725  TString timeformat = tformat;
2726 
2727  if (timeformat.Index("%F")>=0 || timeformat.IsNull()) {
2728  fTimeFormat = timeformat;
2729  return;
2730  }
2731 
2732  Int_t idF = fTimeFormat.Index("%F");
2733  if (idF>=0) {
2734  Int_t lnF = fTimeFormat.Length();
2735  TString stringtimeoffset = fTimeFormat(idF,lnF);
2736  fTimeFormat = tformat;
2737  fTimeFormat.Append(stringtimeoffset);
2738  } else {
2739  fTimeFormat = tformat;
2740  SetTimeOffset(gStyle->GetTimeOffset());
2741  }
2742 }
2743 
2744 ////////////////////////////////////////////////////////////////////////////////
2745 /// Change the time offset. If option = "gmt", set display mode to GMT.
2746 
2747 void TGaxis::SetTimeOffset(Double_t toffset, Option_t *option)
2748 {
2749  TString opt = option;
2750  opt.ToLower();
2751 
2752  char tmp[20];
2753  time_t timeoff;
2754  struct tm* utctis;
2755  Int_t idF = fTimeFormat.Index("%F");
2756  if (idF>=0) fTimeFormat.Remove(idF);
2757  fTimeFormat.Append("%F");
2758 
2759  timeoff = (time_t)((Long_t)(toffset));
2760 
2761  // offset is always saved in GMT to allow file transport
2762  // to different time zones
2763  utctis = gmtime(&timeoff);
2764 
2765  if (utctis != nullptr) {
2766  strftime(tmp, 20,"%Y-%m-%d %H:%M:%S",utctis);
2767  fTimeFormat.Append(tmp);
2768  } else {
2769  fTimeFormat.Append("1970-01-01 00:00:00");
2770  }
2771 
2772  // append the decimal part of the time offset
2773  Double_t ds = toffset-(Int_t)toffset;
2774  snprintf(tmp,20,"s%g",ds);
2775  fTimeFormat.Append(tmp);
2776 
2777  // add GMT/local option
2778  if (opt.Contains("gmt")) fTimeFormat.Append(" GMT");
2779 }
2780 
2781 ////////////////////////////////////////////////////////////////////////////////
2782 /// Static function to set X and Y offset of the axis 10^n notation.
2783 /// It is in % of the pad size. It can be negative.
2784 /// axis specifies which axis ("x","y"), default = "x"
2785 /// if axis="xz" set the two axes
2786 
2787 void TGaxis::SetExponentOffset(Float_t xoff, Float_t yoff, Option_t *axis)
2788 {
2789  TString opt = axis;
2790  opt.ToLower();
2791 
2792  if (opt.Contains("x")) {
2793  fXAxisExpXOffset = xoff;
2794  fXAxisExpYOffset = yoff;
2795  }
2796  if (opt.Contains("y")) {
2797  fYAxisExpXOffset = xoff;
2798  fYAxisExpYOffset = yoff;
2799  }
2800 }
2801 
2802 ////////////////////////////////////////////////////////////////////////////////
2803 /// Stream an object of class TGaxis.
2804 
2805 void TGaxis::Streamer(TBuffer &R__b)
2806 {
2807  if (R__b.IsReading()) {
2808  UInt_t R__s, R__c;
2809  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
2810  if (R__v > 3) {
2811  R__b.ReadClassBuffer(TGaxis::Class(), this, R__v, R__s, R__c);
2812  return;
2813  }
2814  //====process old versions before automatic schema evolution
2815  TLine::Streamer(R__b);
2816  TAttText::Streamer(R__b);
2817  R__b >> fNdiv;
2818  R__b >> fWmin;
2819  R__b >> fWmax;
2820  R__b >> fGridLength;
2821  R__b >> fTickSize;
2822  R__b >> fLabelOffset;
2823  R__b >> fLabelSize;
2824  R__b >> fTitleOffset;
2825  R__b >> fTitleSize;
2826  R__b >> fLabelFont;
2827  if (R__v > 2) {
2828  R__b >> fLabelColor;
2829  }
2830  fChopt.Streamer(R__b);
2831  fName.Streamer(R__b);
2832  fTitle.Streamer(R__b);
2833  fTimeFormat.Streamer(R__b);
2834  if (R__v > 1) {
2835  fFunctionName.Streamer(R__b);
2836  fFunction = (TF1*)gROOT->GetFunction(fFunctionName.Data());
2837  }
2838  R__b.CheckByteCount(R__s, R__c, TGaxis::IsA());
2839  //====end of old versions
2840 
2841  } else {
2842  R__b.WriteClassBuffer(TGaxis::Class(),this);
2843  }
2844 }