// @(#)root/graf:$Id$ // Author: Rene Brun, Olivier Couet 12/12/94 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include #include #include #include #include "Riostream.h" #include "TROOT.h" #include "TBuffer.h" #include "TGaxis.h" #include "TAxisModLab.h" #include "TVirtualPad.h" #include "TVirtualX.h" #include "TLine.h" #include "TLatex.h" #include "TStyle.h" #include "TF1.h" #include "TAxis.h" #include "THashList.h" #include "TObject.h" #include "TMath.h" #include "THLimitsFinder.h" #include "TColor.h" #include "TClass.h" #include "TTimeStamp.h" #include "TSystem.h" Int_t TGaxis::fgMaxDigits = 5; Float_t TGaxis::fXAxisExpXOffset = 0.; //Exponent X offset for the X axis Float_t TGaxis::fXAxisExpYOffset = 0.; //Exponent Y offset for the X axis Float_t TGaxis::fYAxisExpXOffset = 0.; //Exponent X offset for the Y axis Float_t TGaxis::fYAxisExpYOffset = 0.; //Exponent Y offset for the Y axis const Int_t kHori = BIT(9); //defined in TPad ClassImp(TGaxis); /** \class TGaxis \ingroup BasicGraphics The axis painter class. Instances of this class are generated by the histograms and graphs painting classes when `TAxis` are drawn. `TGaxis` is the "painter class" of `TAxis`. Therefore it is mainly used via `TAxis`, even if is some occasion it can be used directly to draw an axis which is not part of a graph or an instance. For instance to draw an extra scale on a plot. - [Basic definition](#GA00) - [Definition with a function](#GA01) - [Logarithmic axis](#GA02) - [Blank axis](#GA03) - [Tick marks' orientation](#GA04) - [Tick marks' size](#GA05) - [Labels' positionning](#GA06) - [Labels' orientation](#GA07) - [Labels' position on tick marks](#GA08) - [Labels' format](#GA09) - [Alphanumeric labels](#GA10) - [Changing axis labels](#GA10a) - [Number of divisions optimisation](#GA11) - [Maximum Number of Digits for the axis labels](#GA12) - [Optional grid](#GA13) - [Time axis](#GA14) ## Basic definition A `TGaxis` is defined the following way: ~~~ {.cpp} TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt, Double_t gridlength) ~~~ Where: - xmin : X origin coordinate in user's coordinates space. - xmax : X end axis coordinate in user's coordinates space. - ymin : Y origin coordinate in user's coordinates space. - ymax : Y end axis coordinate in user's coordinates space. - wmin : Lowest value for the tick mark labels written on the axis. - wmax : Highest value for the tick mark labels written on the axis. - ndiv : Number of divisions. - ndiv=N1 + 100*N2 + 10000*N3 - N1=number of 1st divisions. - N2=number of 2nd divisions. - N3=number of 3rd divisions. e.g.: - ndiv=0 --> no tick marks. - ndiv=2 --> 2 divisions, one tick mark in the middle of the axis. - chopt : Drawing options (see below). - gridlength: grid length on main tick marks. The example below generates various kind of axis. Begin_Macro(source) { TCanvas *c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,500); c1->Range(-10,-1,10,1); TGaxis *axis1 = new TGaxis(-4.5,-0.2,5.5,-0.2,-6,8,510,""); axis1->SetName("axis1"); axis1->Draw(); TGaxis *axis2 = new TGaxis(-4.5,0.2,5.5,0.2,0.001,10000,510,"G"); axis2->SetName("axis2"); axis2->Draw(); TGaxis *axis3 = new TGaxis(-9,-0.8,-9,0.8,-8,8,50510,""); axis3->SetName("axis3"); axis3->Draw(); TGaxis *axis4 = new TGaxis(-7,-0.8,-7,0.8,1,10000,50510,"G"); axis4->SetName("axis4"); axis4->Draw(); TGaxis *axis5 = new TGaxis(-4.5,-0.6,5.5,-0.6,1.2,1.32,80506,"-+"); axis5->SetName("axis5"); axis5->SetLabelSize(0.03); axis5->SetTextFont(72); axis5->SetLabelOffset(0.025); axis5->Draw(); TGaxis *axis6 = new TGaxis(-4.5,0.6,5.5,0.6,100,900,50510,"-"); axis6->SetName("axis6"); axis6->Draw(); TGaxis *axis7 = new TGaxis(8,-0.8,8,0.8,0,9000,50510,"+L"); axis7->SetName("axis7"); axis7->SetLabelOffset(0.01); axis7->Draw(); //one can make axis going top->bottom. However because of a long standing //problem, the two x values should not be equal TGaxis *axis8 = new TGaxis(6.5,0.8,6.499,-0.8,0,90,50510,"-"); axis8->SetName("axis8"); axis8->Draw(); } End_Macro ## Definition with a function Instead of the wmin,wmax arguments of the normal definition, the name of a `TF1` function can be specified. This function will be used to map the user coordinates to the axis values and ticks. A `TGaxis` is defined the following way: ~~~ {.cpp} TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *func, Int_t ndiv, Option_t *chopt, Double_t gridlength) ~~~ Where: - xmin : X origin coordinate in user's coordinates space. - xmax : X end axis coordinate in user's coordinates space. - ymin : Y origin coordinate in user's coordinates space. - ymax : Y end axis coordinate in user's coordinates space. - func : function defining axis labels and tick marks. - ndiv : Number of divisions. - ndiv=N1 + 100*N2 + 10000*N3 - N1=number of 1st divisions. - N2=number of 2nd divisions. - N3=number of 3rd divisions. e.g.: - ndiv=0 --> no tick marks. - ndiv=2 --> 2 divisions, one tick mark in the middle of the axis. - chopt : Drawing options (see below). - gridlength: grid length on main tick marks. Examples: Begin_Macro(source) { TCanvas *c2 = new TCanvas("c2","c2",10,10,700,500); gPad->DrawFrame(0.,-2.,10.,2); TF1 *f1=new TF1("f1","-x",-10,10); TGaxis *A1 = new TGaxis(0,2,10,2,"f1",510,"-"); A1->SetTitle("axis with decreasing values"); A1->Draw(); TF1 *f2=new TF1("f2","exp(x)",0,2); TGaxis *A2 = new TGaxis(1,1,9,1,"f2"); A2->SetTitle("exponential axis"); A2->SetLabelSize(0.03); A2->SetTitleSize(0.03); A2->SetTitleOffset(1.2); A2->Draw(); TF1 *f3=new TF1("f3","log10(x)",1,1000); TGaxis *A3 = new TGaxis(2,-2,2,0,"f3",505,""); A3->SetTitle("logarithmic axis"); A3->SetLabelSize(0.02); A3->SetTitleSize(0.03); A3->SetTitleOffset(0.); // Axis title automatically placed A3->Draw(); } End_Macro ## Logarithmic axis By default axis are linear. To define a `TGaxis` as logarithmic, it is enough to create it with the option `"G"`. When plotting an histogram or a graph the logarithmic scale can be set using: - `gPad->SetLogx(1);` set the logarithmic scale on the X axis - `gPad->SetLogy(1);` set the logarithmic scale on the Y axis When the `SetMoreLogLabels()` method is called more labels are drawn when in logarithmic scale and there is a small number of decades (less than 3). ## Blank axis To draw only the axis tick marks without the axis body, it is enough to specify the option `"B"`. It useful to superpose axis. ## Tick marks' orientation By default tick marks are drawn on the positive side of the axis, except for vertical axis for which the default is negative. The `chop` parameter allows to control the tick marks orientation: - `chopt = "+"`: tick marks are drawn on Positive side. (default) - `chopt ="-"`: tick mark are drawn on the negative side. - `chopt = "+-"`: tick marks are drawn on both sides of the axis. - `chopt = "U"`: Unlabelled axis, default is labeled. ## Tick marks' size By default, tick marks have a length equal to 3 per cent of the axis length. When the option "S" is specified, the length of the tick marks is equal to `fTickSize*axis_length`, where `fTickSize` may be set via `TGaxis::SetTickSize`. When plotting an histogram `h` the tick marks size can be changed using: - `h->GetXaxis()->SetTickLength(0.02);` set the tick length for the X axis - `gStyle->SetTickLength(0.02,"x");` set the tick length for the X axis of all histograms drawn after this instruction. A good way to remove tick marks on an axis is to set the tick length to 0: `h->GetXaxis()->SetTickLength(0.);` ## Labels' positionning Labels are normally drawn on side opposite to tick marks. However the option `"="` allows to draw them on the same side. The distance between the labels and the axis body can be changed with `SetLabelOffset`. ## Labels' orientation By default axis labels are drawn parallel to the axis. However if the axis is vertical then are drawn perpendicular to the axis. ## Labels' position on tick marks By default axis labels are centered on tick marks. However, for vertical axis, they are right adjusted. The `chop` parameter allows to control the labels' position on tick marks: - `chopt = "R"`: labels are Right adjusted on tick mark.(default is centered) - `chopt = "L"`: labels are Left adjusted on tick mark. - `chopt = "C"`: labels are Centered on tick mark. - `chopt = "M"`: In the Middle of the divisions. ## Labels' format Blank characters are stripped, and then the label is correctly aligned. the dot, if last character of the string, is also stripped, unless the option `"."` (a dot, or period) is specified. if `SetDecimals(kTRUE)` has been called all labels have the same number of decimals after the `"."` The same is true if `gStyle->SetStripDecimals(kFALSE)` has been called. In the following, we have some parameters, like tick marks length and characters height (in percentage of the length of the axis (user's coordinates)) The default values are as follows: - Primary tick marks: 3.0 % - Secondary tick marks: 1.5 % - Third order tick marks: .75 % - Characters height for labels: 4% - Labels offset: 1.0 % By default, an exponent of the form 10^N is used when the label values are either all very small or very large. One can disable the exponent by calling `axis.SetNoExponent(kTRUE)`. `TGaxis::SetExponentOffset(Float_t xoff, Float_t yoff, Option_t *axis)` is static function to set X and Y offset of the axis 10^n notation. It is in % of the pad size. It can be negative. `axis` specifies which axis (`"x"` or/and `"y"`), default is `"x"` if `axis = "xz"` set the two axes ## Alphanumeric labels Axis labels can be any alphanumeric character strings. Such axis can be produced only with histograms because the labels'definition is stored in `TAxis`. The following example demonstrates how to create such labels. Begin_Macro(source) ../../../tutorials/hist/hlabels2.C End_Macro Because the alphanumeric labels are usually longer that the numeric labels, their size is by default equal to `0.66666 * the_numeric_labels_size`. ## Changing axis labels \since **ROOT version 6.07/07:** After an axis has been created, TGaxis::ChangeLabel allows to define new text attributes for a given label. A fine tuning of the labels can be done. All the attributes can be changed as well as the text label itself. When plotting an histogram or a graph the labels can be changed like in the following example which shows a way to produce \f$\pi\f$-axis : Begin_Macro(source) { Double_t pi = TMath::Pi(); TF1* f = new TF1("f","TMath::Cos(x/TMath::Pi())", -pi, pi); TAxis* a = f->GetXaxis(); a->SetNdivisions(-502); a->ChangeLabel(1,-1,-1,-1,-1,-1,"-#pi"); a->ChangeLabel(-1,-1,-1,-1,-1,-1,"#pi"); f->Draw(); } End_Macro ## Number of divisions optimisation By default the number of divisions on axis is optimised to show a coherent labelling of the main tick marks. The number of division (`ndiv`) is a composite integer given by: ` ndiv = N1 + 100*N2 + 10000*N3` - `N1` = number of 1st divisions. - `N2` = number of 2nd divisions. - `N3` = number of 3rd divisions. by default the value of `N1`, `N2` and `N3` are maximum values. After optimisation the real number of divisions will be smaller or equal to these value. If one wants to bypass the optimisation, the option `"N"` should be given when the `TGaxis` is created. The option `"I"` also act on the number of division as it will force an integer labelling of the axis. On an histogram pointer `h` the number of divisions can be set in different ways:. - Directly on the histogram. The following will set the number of division to 510 on the X axis of `h`. To avoid optimization the number of divisions should be negative (ie: -510); ~~~ {.cpp} h->SetNdivisions(510, "X"); ~~~ - On the axis itself: ~~~ {.cpp} h->GetXaxis()->SetNdivisions(510, kTRUE); ~~~ The first parameter is the number of division. If it is negative of if the second parameter is kFALSE then the number of divisions is not optimised. And other signature is also allowed: ~~~ {.cpp} h->GetXaxis()->SetNdivisions(10, 5, 0, kTRUE); ~~~ ## Maximum Number of Digits for the axis labels The static function `TGaxis::SetMaxDigits` sets the maximum number of digits permitted for the axis labels above which the notation with 10^N is used. For example, to accept 6 digits number like 900000 on an axis call `TGaxis::SetMaxDigits(6)`. The default value is 5. `fgMaxDigits` must be greater than 0. ## Optional grid The option `"W"` allows to draw a grid on the primary tick marks. In case of a log axis, the grid is only drawn for the primary tick marks if the number of secondary and tertiary divisions is 0. `SetGridLength()` allows to define the length of the grid. When plotting an histogram or a graph the grid can be set ON or OFF using: - `gPad->SetGridy(1);` set the grid on the X axis - `gPad->SetGridx(1);` set the grid on the Y axis - `gPad->SetGrid(1,1);` set the grid on both axis. ## Time axis Histograms' axis can be defined as "time axis". To do that it is enough to activate the TAxis::SetTimeDisplay attribute on a given axis. If `h` is an histogram, it is done the following way: ~~~ .cpp h->GetXaxis()->SetTimeDisplay(1); // The X axis is a time axis ~~~ Two parameters can be adjusted in order to define time axis: ### The time format: Defines the format of the labels along the time axis. It can be changed using the TAxis TAxis::SetTimeFormat. The time format is the one used by the C function **strftime()**. It's a string containing the following formatting characters: - for date : - **%a** abbreviated weekday name - **%b** abbreviated month name - **%d** day of the month (01-31) - **%m** month (01-12) - **%y** year without century - **%Y** year with century - for time : - **%H** hour (24-hour clock) - **%I** hour (12-hour clock) - **%p** local equivalent of AM or PM - **%M** minute (00-59) - **%S** seconds (00-61) - **%%** % The other characters are output as is. For example to have a format like `dd/mm/yyyy` one should do: ~~~ .cpp h->GetXaxis()->SetTimeFormat("%d\/%m\/%Y"); ~~~ ### The time offset: This is a time in seconds in the UNIX standard UTC format (this is an universal time, not the local time), defining the starting date of an histogram axis. This date should be greater than 01/01/95 and is given in seconds. There are three ways to define the time offset: #### By setting the global default time offset: ~~~ .cpp TDatime da(2003,02,28,12,00,00); gStyle->SetTimeOffset(da.Convert()); ~~~ If no time offset is defined for a particular axis, the default time offset will be used. In the example above, notice the usage of TDateTime to translate an explicit date into the time in seconds required by TAxis::SetTimeFormat. #### By setting a time offset to a particular axis: ~~~ .cpp TDatime dh(2001,09,23,15,00,00); h->GetXaxis()->SetTimeOffset(dh.Convert()); ~~~ #### Together with the time format using TAxis::SetTimeFormat: The time offset can be specified using the control character `%F` after the normal time format. **%F** is followed by the date in the format: `yyyy-mm-dd hh:mm:ss`. Example: ~~~ .cpp h->GetXaxis()->SetTimeFormat("%d\/%m\/%y%F2000-02-28 13:00:01"); ~~~ Notice that this date format is the same used by the TDateString function `AsSQLString`. If needed, this function can be used to translate a time in seconds into a character string which can be appended after `%F`. If the time format is not specified (before `%F), the automatic one will be used. If a time axis has no specified time offset, the global time offset will be stored in the axis data structure. The following example illustrates the various possibilities. Begin_Macro(source) { gStyle->SetTitleH(0.08); TDatime da(2003,2,28,12,00,00); gStyle->SetTimeOffset(da.Convert()); auto ct = new TCanvas("ct","Time on axis",0,0,600,600); ct->Divide(1,3); auto ht1 = new TH1F("ht1","ht1",30000,0.,200000.); auto ht2 = new TH1F("ht2","ht2",30000,0.,200000.); auto ht3 = new TH1F("ht3","ht3",30000,0.,200000.); for (Int_t i=1;i<30000;i++) { auto noise = gRandom->Gaus(0,120); ht1->SetBinContent(i,noise); ht2->SetBinContent(i,noise*noise); ht3->SetBinContent(i,noise*noise*noise); } ct->cd(1); ht1->GetXaxis()->SetLabelSize(0.06); ht1->GetXaxis()->SetTimeDisplay(1); ht1->GetXaxis()->SetTimeFormat("%d/%m/%y%F2000-02-28 13:00:01"); ht1->Draw(); ct->cd(2); ht2->GetXaxis()->SetLabelSize(0.06); ht2->GetXaxis()->SetTimeDisplay(1); ht2->GetXaxis()->SetTimeFormat("%d/%m/%y"); ht2->Draw(); ct->cd(3); ht3->GetXaxis()->SetLabelSize(0.06); TDatime dh(2001,9,23,15,00,00); ht3->GetXaxis()->SetTimeDisplay(1); ht3->GetXaxis()->SetTimeOffset(dh.Convert()); ht3->Draw(); } End_Macro The histogram limits times in seconds. If `wmin` and `wmax` are the histogram limits, the time axis will spread around the time offset value from `TimeOffset+wmin` to `TimeOffset+wmax`. Until now all the examples had a lowest value equal to 0. The following example demonstrates how to define the histogram limits relatively to the time offset value. Begin_Macro(source) { // Define the time offset as 2003, January 1st TDatime T0(2003,1,1,0,0,0); auto X0 = T0.Convert(); gStyle->SetTimeOffset(X0); // Define the lowest histogram limit as 2002, September 23rd TDatime T1(2002,9,23,0,0,0); auto X1 = T1.Convert()-X0; // Define the highest histogram limit as 2003, March 7th TDatime T2(2003,3,7,0,0,0); auto X2 = T2.Convert(1)-X0; auto h1 = new TH1F("h1","test",100,X1,X2); TRandom r; for (Int_t i=0;i<30000;i++) { Double_t noise = r.Gaus(0.5*(X1+X2),0.1*(X2-X1)); h1->Fill(noise); } h1->GetXaxis()->SetTimeDisplay(1); h1->GetXaxis()->SetLabelSize(0.03); h1->GetXaxis()->SetTimeFormat("%Y/%m/%d"); h1->Draw(); } End_Macro Usually time axis are created automatically via histograms, but one may also want to draw a time axis outside an "histogram context". Therefore it is useful to understand how TGaxis works for such axis. The time offset can be defined using one of the three methods described before. The time axis will spread around the time offset value. Actually it will go from `TimeOffset+wmin` to `TimeOffset+wmax` where `wmin` and `wmax` are the minimum and maximum values (in seconds) of the axis. Let's take again an example. Having defined "2003, February 28 at 12h" we would like to see the axis a day before and a day after. A TGaxis can be created the following way (a day has 86400 seconds): ~~~ .cpp TGaxis *axis = new TGaxis(x1,y1,x2,y2,-100000,150000,2405,"t"); ~~~ the `t` option (in lower case) means it is a "time axis". The axis goes form 100000 seconds before `TimeOffset` and 150000 seconds after. So the complete macro is: Begin_Macro(source) { c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,100); c1->Range(-10,-1,10,1); TGaxis *axis = new TGaxis(-8,0.,8,0.,-100000,150000,2405,"tS"); axis->SetLabelSize(0.2); axis->SetTickSize(0.2); TDatime da(2003,02,28,12,00,00); axis->SetTimeOffset(da.Convert()); axis->SetTimeFormat("%d-%m-%Y"); axis->Draw(); return c1; } End_Macro Thanks to the TLatex directive `#splitline` it is possible to write the time labels on two lines. In the previous example changing the `SetTimeFormat` line by ~~~ .cpp axis->SetLabelOffset(0.15); axis->SetTimeFormat("#splitline{%Y}{%d\/%m}"); ~~~ will produce the following axis: Begin_Macro { c1 = new TCanvas("c1","Examples of TGaxis",10,10,700,100); c1->Range(-10,-1,10,1); TGaxis *axis = new TGaxis(-8,0.,8,0.,-100000,150000,2405,"tS"); axis->SetLabelSize(0.2); axis->SetTickSize(0.2); TDatime da(2003,02,28,12,00,00); axis->SetTimeOffset(da.Convert()); axis->SetLabelOffset(0.15); axis->SetTimeFormat("#splitline{%Y}{%d/%m}"); axis->Draw(); return c1; } End_Macro The following example shows time axis on a TGraph: Begin_Macro(source) { TDatime da1(2008,02,28,15,52,00); TDatime da2(2008,02,28,15,53,00); double x[2],y[2]; y[0] = 1.; y[1] = 2.; x[0] = da1.Convert(); x[1] = da2.Convert(); TGraph mgr(2,x,y); mgr.SetMarkerStyle(20); mgr.Draw("apl"); mgr.GetXaxis()->SetTimeDisplay(1); mgr.GetXaxis()->SetNdivisions(-503); mgr.GetXaxis()->SetTimeFormat("%Y-%m-%d %H:%M"); mgr.GetXaxis()->SetTimeOffset(0,"gmt"); } End_Macro The following example compares what the system time function `gmtime` and `localtime` give with what gives `TGaxis`. It can be used as referenced test to check if the time option of `TGaxis` is working properly. Begin_Macro(source) ../../../tutorials/graphs/timeonaxis3.C End_Macro The following macro illustrates the use, with histograms axis, of the time mode on the axis with different time intervals and time formats. Begin_Macro(source) ../../../tutorials/graphs/timeonaxis.C End_Macro */ //////////////////////////////////////////////////////////////////////////////// /// TGaxis default constructor. TGaxis::TGaxis(): TLine(), TAttText(11,0,1,62,0.040) { fGridLength = 0.; fLabelOffset = 0.005; fLabelSize = 0.040; fLabelFont = 62; fLabelColor = 1; fTickSize = 0.030; fTitleOffset = 1; fTitleSize = fLabelSize; fChopt = ""; fName = ""; fTitle = ""; fTimeFormat = ""; fFunctionName= ""; fFunction = 0; fAxis = 0; fNdiv = 0; fNModLabs = 0; fModLabs = 0; fWmin = 0.; fWmax = 0.; } //////////////////////////////////////////////////////////////////////////////// /// TGaxis normal constructor. TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt, Double_t gridlength) : TLine(xmin,ymin,xmax,ymax), TAttText(11,0,1,62,0.040) { fWmin = wmin; fWmax = wmax; fNdiv = ndiv; fNModLabs = 0; fModLabs = 0; fGridLength = gridlength; fLabelOffset = 0.005; fLabelSize = 0.040; fLabelFont = 62; fLabelColor = 1; fTickSize = 0.030; fTitleOffset = 1; fTitleSize = fLabelSize; fChopt = chopt; fName = ""; fTitle = ""; fTimeFormat = ""; fFunctionName= ""; fFunction = 0; fAxis = 0; } //////////////////////////////////////////////////////////////////////////////// /// Constructor with a `TF1` to map axis values. TGaxis::TGaxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, const char *funcname, Int_t ndiv, Option_t *chopt, Double_t gridlength) : TLine(xmin,ymin,xmax,ymax), TAttText(11,0,1,62,0.040) { fFunction = (TF1*)gROOT->GetFunction(funcname); if (!fFunction) { Error("TGaxis", "calling constructor with an unknown function: %s", funcname); fWmin = 0; fWmax = 1; } else { fWmin = fFunction->GetXmin(); fWmax = fFunction->GetXmax(); } fFunctionName= funcname; fNdiv = ndiv; fNModLabs = 0; fModLabs = 0; fGridLength = gridlength; fLabelOffset = 0.005; fLabelSize = 0.040; fLabelFont = 62; fLabelColor = 1; fTickSize = 0.030; fTitleOffset = 1; fTitleSize = fLabelSize; fChopt = chopt; fName = ""; fTitle = ""; fTimeFormat = ""; fAxis = 0; } //////////////////////////////////////////////////////////////////////////////// /// Copy constructor. TGaxis::TGaxis(const TGaxis& ax) : TLine(ax), TAttText(ax), fWmin(ax.fWmin), fWmax(ax.fWmax), fGridLength(ax.fGridLength), fTickSize(ax.fTickSize), fLabelOffset(ax.fLabelOffset), fLabelSize(ax.fLabelSize), fTitleOffset(ax.fTitleOffset), fTitleSize(ax.fTitleSize), fNdiv(ax.fNdiv), fLabelColor(ax.fLabelColor), fLabelFont(ax.fLabelFont), fNModLabs(ax.fNModLabs), fChopt(ax.fChopt), fName(ax.fName), fTitle(ax.fTitle), fTimeFormat(ax.fTimeFormat), fFunctionName(ax.fFunctionName), fFunction(ax.fFunction), fAxis(ax.fAxis), fModLabs(ax.fModLabs) { } //////////////////////////////////////////////////////////////////////////////// /// Assignment operator. TGaxis& TGaxis::operator=(const TGaxis& ax) { if(this!=&ax) { TLine::operator=(ax); TAttText::operator=(ax); fWmin=ax.fWmin; fWmax=ax.fWmax; fGridLength=ax.fGridLength; fTickSize=ax.fTickSize; fLabelOffset=ax.fLabelOffset; fLabelSize=ax.fLabelSize; fTitleOffset=ax.fTitleOffset; fTitleSize=ax.fTitleSize; fNdiv=ax.fNdiv; fModLabs=ax.fModLabs; fLabelColor=ax.fLabelColor; fLabelFont=ax.fLabelFont; fChopt=ax.fChopt; fName=ax.fName; fTitle=ax.fTitle; fTimeFormat=ax.fTimeFormat; fFunctionName=ax.fFunctionName; fFunction=ax.fFunction; fAxis=ax.fAxis; fNModLabs=ax.fNModLabs; } return *this; } //////////////////////////////////////////////////////////////////////////////// /// TGaxis default destructor. TGaxis::~TGaxis() { } //////////////////////////////////////////////////////////////////////////////// /// If center = kTRUE axis labels are centered in the center of the bin. /// The default is to center on the primary tick marks. /// This option does not make sense if there are more bins than tick marks. void TGaxis::CenterLabels(Bool_t center) { if (center) SetBit(TAxis::kCenterLabels); else ResetBit(TAxis::kCenterLabels); } //////////////////////////////////////////////////////////////////////////////// /// If center = kTRUE axis title will be centered. The default is right adjusted. void TGaxis::CenterTitle(Bool_t center) { if (center) SetBit(TAxis::kCenterTitle); else ResetBit(TAxis::kCenterTitle); } //////////////////////////////////////////////////////////////////////////////// /// Draw this axis with new attributes. void TGaxis::DrawAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t wmin, Double_t wmax, Int_t ndiv, Option_t *chopt, Double_t gridlength) { TGaxis *newaxis = new TGaxis(xmin,ymin,xmax,ymax,wmin,wmax,ndiv,chopt,gridlength); newaxis->SetLineColor(fLineColor); newaxis->SetLineWidth(fLineWidth); newaxis->SetLineStyle(fLineStyle); newaxis->SetTextAlign(fTextAlign); newaxis->SetTextAngle(fTextAngle); newaxis->SetTextColor(fTextColor); newaxis->SetTextFont(fTextFont); newaxis->SetTextSize(fTextSize); newaxis->SetTitleSize(fTitleSize); newaxis->SetTitleOffset(fTitleOffset); newaxis->SetLabelFont(fLabelFont); newaxis->SetLabelColor(fLabelColor); newaxis->SetLabelSize(fLabelSize); newaxis->SetLabelOffset(fLabelOffset); newaxis->SetTickSize(fTickSize); newaxis->SetBit(kCanDelete); newaxis->SetTitle(GetTitle()); newaxis->SetBit(TAxis::kCenterTitle,TestBit(TAxis::kCenterTitle)); newaxis->AppendPad(); } //////////////////////////////////////////////////////////////////////////////// /// Static function returning fgMaxDigits (See SetMaxDigits). Int_t TGaxis::GetMaxDigits() { return fgMaxDigits; } //////////////////////////////////////////////////////////////////////////////// /// Internal method to import TAxis attributes to this TGaxis. void TGaxis::ImportAxisAttributes(TAxis *axis) { fAxis = axis; SetLineColor(axis->GetAxisColor()); SetTextColor(axis->GetTitleColor()); SetTextFont(axis->GetTitleFont()); SetLabelColor(axis->GetLabelColor()); SetLabelFont(axis->GetLabelFont()); SetLabelSize(axis->GetLabelSize()); SetLabelOffset(axis->GetLabelOffset()); SetTickSize(axis->GetTickLength()); SetTitle(axis->GetTitle()); SetTitleOffset(axis->GetTitleOffset()); SetTitleSize(axis->GetTitleSize()); SetBit(TAxis::kCenterTitle, axis->TestBit(TAxis::kCenterTitle)); SetBit(TAxis::kCenterLabels, axis->TestBit(TAxis::kCenterLabels)); SetBit(TAxis::kRotateTitle, axis->TestBit(TAxis::kRotateTitle)); SetBit(TAxis::kNoExponent, axis->TestBit(TAxis::kNoExponent)); SetBit(TAxis::kTickPlus, axis->TestBit(TAxis::kTickPlus)); SetBit(TAxis::kTickMinus, axis->TestBit(TAxis::kTickMinus)); SetBit(TAxis::kMoreLogLabels, axis->TestBit(TAxis::kMoreLogLabels)); if (axis->GetDecimals()) SetBit(TAxis::kDecimals); //the bit is in TAxis::fAxis2 SetTimeFormat(axis->GetTimeFormat()); } //////////////////////////////////////////////////////////////////////////////// /// Draw this axis with its current attributes. void TGaxis::Paint(Option_t *) { Double_t wmin = fWmin; Double_t wmax = fWmax; Int_t ndiv = fNdiv; // following code required to support toggle of lin/log scales Double_t x1 = gPad->XtoPad(fX1); Double_t y1 = gPad->YtoPad(fY1); Double_t x2 = gPad->XtoPad(fX2); Double_t y2 = gPad->YtoPad(fY2); PaintAxis(x1,y1,x2,y2,wmin,wmax,ndiv,fChopt.Data(),fGridLength); } //////////////////////////////////////////////////////////////////////////////// /// Control function to draw an axis. /// Original authors: O.Couet C.E.Vandoni N.Cremel-Somon. /// Modified and converted to C++ class by Rene Brun. void TGaxis::PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t &wmin, Double_t &wmax, Int_t &ndiv, Option_t *chopt, Double_t gridlength, Bool_t drawGridOnly) { const char *where = "PaintAxis"; Double_t alfa, beta, ratio1, ratio2, grid_side; Double_t axis_lengthN = 0; Double_t axis_length0 = 0; Double_t axis_length1 = 0; Double_t axis_length; Double_t atick[3]; Double_t tick_side; Double_t charheight; Double_t phil, phi, sinphi, cosphi, asinphi, acosphi; Double_t binLow = 0., binLow2 = 0., binLow3 = 0.; Double_t binHigh = 0., binHigh2 = 0., binHigh3 = 0.; Double_t binWidth = 0., binWidth2 = 0., binWidth3 = 0.; Double_t xpl1, xpl2, ypl1, ypl2; Double_t xtick = 0; Double_t xtick0, xtick1, dxtick=0; Double_t ytick, ytick0, ytick1; Double_t wlabel, dwlabel; Double_t xfactor, yfactor; Double_t xlabel, ylabel, dxlabel; Double_t xone, xtwo; Double_t rlab; Double_t x0, x1, y0, y1, xx0, xx1, yy0, yy1; xx0 = xx1 = yy0 = yy1 = 0; Double_t xxmin, xxmax, yymin, yymax; xxmin = xxmax = yymin = yymax = 0; Double_t xlside, xmside; Double_t ww, af, rne; Double_t xx, yy; Double_t xmnlog, x00, x11, h2, h2sav, axmul, y; Float_t chupxvsav, chupyvsav; Double_t rtxw, rtyw; Int_t nlabels, nticks, nticks0, nticks1; Int_t i, j, k, l, decade, ltick; Int_t mside, lside; Int_t nexe = 0; Int_t lnlen = 0; Int_t iexe, if1, if2, na, nf, ih1, ih2, nbinin, nch, kmod; Int_t optionLog,optionBlank,optionVert,optionPlus,optionMinus,optionUnlab,optionPara; Int_t optionDown,optionRight,optionLeft,optionCent,optionEqual,optionDecimals=0,optionDot; Int_t optionY,optionText,optionGrid,optionSize,optionNoopt,optionInt,optionM,optionUp,optionX; Int_t optionTime; Int_t first=0,last=0,labelnumber; Int_t xalign, yalign; Int_t nn1, nn2, nn3, n1a, n2a, n3a, nb2, nb3; Int_t nbins=10, n1aold, nn1old; Int_t maxDigits; n1aold = nn1old = 0; Int_t ndyn; Int_t nhilab = 0; Int_t idn; Bool_t flexe = 0; Bool_t flexpo,flexne; char *label; char *chtemp; char chlabel[256]; char kchtemp[256]; char chcoded[64]; TLine *linegrid; TString timeformat; TString typolabel; time_t timelabel; Double_t timed, wTimeIni; struct tm* utctis; Double_t rangeOffset = 0; Double_t epsilon = 1e-5; const Double_t kPI = TMath::Pi(); Double_t rwmi = wmin; Double_t rwma = wmax; chtemp = &kchtemp[0]; label = &chlabel[0]; linegrid = 0; fFunction = (TF1*)gROOT->GetFunction(fFunctionName.Data()); Bool_t noExponent = TestBit(TAxis::kNoExponent); // If moreLogLabels = kTRUE more Log Intermediate Labels are drawn. Bool_t moreLogLabels = TestBit(TAxis::kMoreLogLabels); // the following parameters correspond to the pad range in NDC // and the user's coordinates in the pad Double_t padh = gPad->GetWh()*gPad->GetAbsHNDC(); Double_t rwxmin = gPad->GetX1(); Double_t rwxmax = gPad->GetX2(); Double_t rwymin = gPad->GetY1(); Double_t rwymax = gPad->GetY2(); if(strchr(chopt,'G')) optionLog = 1; else optionLog = 0; if(strchr(chopt,'B')) optionBlank= 1; else optionBlank= 0; if(strchr(chopt,'V')) optionVert = 1; else optionVert = 0; if(strchr(chopt,'+')) optionPlus = 1; else optionPlus = 0; if(strchr(chopt,'-')) optionMinus= 1; else optionMinus= 0; if(strchr(chopt,'U')) optionUnlab= 1; else optionUnlab= 0; if(strchr(chopt,'P')) optionPara = 1; else optionPara = 0; if(strchr(chopt,'O')) optionDown = 1; else optionDown = 0; if(strchr(chopt,'R')) optionRight= 1; else optionRight= 0; if(strchr(chopt,'L')) optionLeft = 1; else optionLeft = 0; if(strchr(chopt,'C')) optionCent = 1; else optionCent = 0; if(strchr(chopt,'=')) optionEqual= 1; else optionEqual= 0; if(strchr(chopt,'Y')) optionY = 1; else optionY = 0; if(strchr(chopt,'T')) optionText = 1; else optionText = 0; if(strchr(chopt,'W')) optionGrid = 1; else optionGrid = 0; if(strchr(chopt,'S')) optionSize = 1; else optionSize = 0; if(strchr(chopt,'N')) optionNoopt= 1; else optionNoopt= 0; if(strchr(chopt,'I')) optionInt = 1; else optionInt = 0; if(strchr(chopt,'M')) optionM = 1; else optionM = 0; if(strchr(chopt,'0')) optionUp = 1; else optionUp = 0; if(strchr(chopt,'X')) optionX = 1; else optionX = 0; if(strchr(chopt,'t')) optionTime = 1; else optionTime = 0; if(strchr(chopt,'.')) optionDot = 1; else optionDot = 0; if (TestBit(TAxis::kTickPlus)) optionPlus = 2; if (TestBit(TAxis::kTickMinus)) optionMinus = 2; if (TestBit(TAxis::kCenterLabels)) optionM = 1; if (TestBit(TAxis::kDecimals)) optionDecimals = 1; if (!gStyle->GetStripDecimals()) optionDecimals = 1; if (fAxis) { if (fAxis->GetLabels()) { optionM = 1; optionText = 1; ndiv = fAxis->GetLast()-fAxis->GetFirst()+1; } TList *ml = fAxis->GetModifiedLabels(); if (ml) { fModLabs = ml; fNModLabs = fModLabs->GetSize(); } else { fModLabs = 0; fNModLabs = 0; } } if (ndiv < 0) { Error(where, "Invalid number of divisions: %d",ndiv); return; } // Set the grid length if (optionGrid) { if (gridlength == 0) gridlength = 0.8; linegrid = new TLine(); linegrid->SetLineColor(gStyle->GetGridColor()); if (linegrid->GetLineColor() == 0) linegrid->SetLineColor(GetLineColor()); linegrid->SetLineStyle(gStyle->GetGridStyle()); linegrid->SetLineWidth(gStyle->GetGridWidth()); } // No labels if the axis label offset is big. // In that case the labels are not visible anyway. if (GetLabelOffset() > 1.1 ) optionUnlab = 1; // Determine time format Int_t idF = fTimeFormat.Index("%F"); if (idF>=0) { timeformat = fTimeFormat(0,idF); } else { timeformat = fTimeFormat; } //GMT option if (fTimeFormat.Index("GMT")>=0) optionTime =2; // Determine the time offset and correct for time offset not being integer. Double_t timeoffset =0; if (optionTime) { if (idF>=0) { Int_t lnF = fTimeFormat.Length(); TString stringtimeoffset = fTimeFormat(idF+2,lnF); Int_t year, mm, dd, hh, mi, ss; if (sscanf(stringtimeoffset.Data(), "%d-%d-%d %d:%d:%d", &year, &mm, &dd, &hh, &mi, &ss) == 6) { //Get time offset in seconds since EPOCH: struct tm tp; tp.tm_year = year-1900; tp.tm_mon = mm-1; tp.tm_mday = dd; tp.tm_hour = hh; tp.tm_min = mi; tp.tm_sec = ss; tp.tm_isdst = 0; //no DST for UTC (and forced to 0 in MktimeFromUTC function) timeoffset = TTimeStamp::MktimeFromUTC(&tp); // Add the time offset's decimal part if it is there Int_t ids = stringtimeoffset.Index("s"); if (ids >= 0) { Float_t dp; Int_t lns = stringtimeoffset.Length(); TString sdp = stringtimeoffset(ids+1,lns); sscanf(sdp.Data(),"%g",&dp); timeoffset += dp; } } else { Error(where, "Time offset has not the right format"); } } else { timeoffset = gStyle->GetTimeOffset(); } wmin += timeoffset - (int)(timeoffset); wmax += timeoffset - (int)(timeoffset); // correct for time offset at a good limit (min, hour, day, month, year) struct tm* tp0; time_t timetp = (time_t)((Long_t)(timeoffset)); Double_t range = wmax - wmin; Long_t rangeBase = 60; if (range>60) rangeBase = 60*20; // minutes if (range>3600) rangeBase = 3600*20; // hours if (range>86400) rangeBase = 86400*20; // days if (range>2419200) rangeBase = 31556736; // months (average # days) rangeOffset = (Double_t) ((Long_t)(timeoffset)%rangeBase); if (range>31536000) { tp0 = gmtime(&timetp); tp0->tm_mon = 0; tp0->tm_mday = 1; tp0->tm_hour = 0; tp0->tm_min = 0; tp0->tm_sec = 0; tp0->tm_isdst = 1; // daylight saving time is on. rangeBase = (timetp-mktime(tp0)); // years rangeOffset = (Double_t) (rangeBase); } wmax += rangeOffset; wmin += rangeOffset; } // Determine number of divisions 1, 2 and 3 and the maximum digits for this axis n1a = (ndiv%100); n2a = (ndiv%10000 - n1a)/100; n3a = (ndiv%1000000 - n2a -n1a)/10000; nn3 = TMath::Max(n3a,1); nn2 = TMath::Max(n2a,1)*nn3; nn1 = TMath::Max(n1a,1)*nn2+1; nticks = nn1; maxDigits = (ndiv/1000000); if (maxDigits==0) maxDigits = fgMaxDigits; // Axis bining optimisation is ignored if: // - the first and the last label are equal // - the number of divisions is 0 // - less than 1 primary division is requested // - logarithmic scale is requested if (wmin == wmax || ndiv == 0 || n1a <= 1 || optionLog) { optionNoopt = 1; optionInt = 0; } // Axis bining optimisation if ( (wmax-wmin) < 1 && optionInt) { Error(where, "option I not available"); optionInt = 0; } if (!optionNoopt || optionInt ) { // Primary divisions optimisation // When integer labelling is required, Optimize is invoked first // and only if the result is not an integer labelling, AdjustBinSize is invoked. THLimitsFinder::Optimize(wmin,wmax,n1a,binLow,binHigh,nbins,binWidth,fChopt.Data()); if (optionInt) { if (binLow != Double_t(int(binLow)) || binWidth != Double_t(int(binWidth))) { AdjustBinSize(wmin,wmax,n1a,binLow,binHigh,nbins,binWidth); } } if ((wmin-binLow) > epsilon) { binLow += binWidth; nbins--; } if ((binHigh-wmax) > epsilon) { binHigh -= binWidth; nbins--; } if (xmax == xmin) { rtyw = (ymax-ymin)/(wmax-wmin); xxmin = xmin; xxmax = xmax; yymin = rtyw*(binLow-wmin) + ymin; yymax = rtyw*(binHigh-wmin) + ymin; } else { rtxw = (xmax-xmin)/(wmax-wmin); xxmin = rtxw*(binLow-wmin) + xmin; xxmax = rtxw*(binHigh-wmin) + xmin; if (ymax == ymin) { yymin = ymin; yymax = ymax; } else { alfa = (ymax-ymin)/(xmax-xmin); beta = (ymin*xmax-ymax*xmin)/(xmax-xmin); yymin = alfa*xxmin + beta; yymax = alfa*xxmax + beta; } } if (fFunction) { yymin = ymin; yymax = ymax; xxmin = xmin; xxmax = xmax; } else { wmin = binLow; wmax = binHigh; } // Secondary divisions optimisation nb2 = n2a; if (!optionNoopt && n2a > 1 && binWidth > 0) { THLimitsFinder::Optimize(wmin,wmin+binWidth,n2a,binLow2,binHigh2,nb2,binWidth2,fChopt.Data()); } // Tertiary divisions optimisation nb3 = n3a; if (!optionNoopt && n3a > 1 && binWidth2 > 0) { THLimitsFinder::Optimize(binLow2,binLow2+binWidth2,n3a,binLow3,binHigh3,nb3,binWidth3,fChopt.Data()); } n1aold = n1a; nn1old = nn1; n1a = nbins; nn3 = TMath::Max(nb3,1); nn2 = TMath::Max(nb2,1)*nn3; nn1 = TMath::Max(n1a,1)*nn2+1; nticks = nn1; } // Coordinates are normalized ratio1 = 1/(rwxmax-rwxmin); ratio2 = 1/(rwymax-rwymin); x0 = ratio1*(xmin-rwxmin); x1 = ratio1*(xmax-rwxmin); y0 = ratio2*(ymin-rwymin); y1 = ratio2*(ymax-rwymin); if (!optionNoopt || optionInt ) { xx0 = ratio1*(xxmin-rwxmin); xx1 = ratio1*(xxmax-rwxmin); yy0 = ratio2*(yymin-rwymin); yy1 = ratio2*(yymax-rwymin); } if ((x0 == x1) && (y0 == y1)) { Error(where, "length of axis is 0"); return; } // Title offset. If 0 it is automatically computed Double_t toffset = GetTitleOffset(); Bool_t autotoff = kFALSE; if (toffset==0 && x1 == x0) autotoff = kTRUE; // Return wmin, wmax and the number of primary divisions if (optionX) { ndiv = n1a; return; } TLatex *textaxis = new TLatex(); SetLineStyle(1); // axis line style Int_t TitleColor = GetTextColor(); Int_t TitleFont = GetTextFont(); if (!gPad->IsBatch()) { gVirtualX->GetCharacterUp(chupxvsav, chupyvsav); gVirtualX->SetClipOFF(gPad->GetCanvasID()); } // Compute length of axis axis_length = TMath::Sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0)); if (axis_length == 0) { Error(where, "length of axis is 0"); goto L210; } if (!optionNoopt || optionInt) { axis_lengthN = TMath::Sqrt((xx1-xx0)*(xx1-xx0)+(yy1-yy0)*(yy1-yy0)); axis_length0 = TMath::Sqrt((xx0-x0)*(xx0-x0)+(yy0-y0)*(yy0-y0)); axis_length1 = TMath::Sqrt((x1-xx1)*(x1-xx1)+(y1-yy1)*(y1-yy1)); if (axis_lengthN < epsilon) { optionNoopt = 1; optionInt = 0; wmin = rwmi; wmax = rwma; n1a = n1aold; nn1 = nn1old; nticks = nn1; if (optionTime) { wmin += timeoffset - (int)(timeoffset) + rangeOffset; wmax += timeoffset - (int)(timeoffset) + rangeOffset; } } } if (x0 == x1) { if (y1>=y0) phi = 0.5*kPI; else phi = 1.5*kPI; phil = phi; } else { phi = TMath::ATan2((y1-y0),(x1-x0)); Int_t px0 = gPad->UtoPixel(x0); Int_t py0 = gPad->VtoPixel(y0); Int_t px1 = gPad->UtoPixel(x1); Int_t py1 = gPad->VtoPixel(y1); if (x0 < x1) phil = TMath::ATan2(Double_t(py0-py1), Double_t(px1-px0)); else phil = TMath::ATan2(Double_t(py1-py0), Double_t(px0-px1)); } cosphi = TMath::Cos(phi); sinphi = TMath::Sin(phi); acosphi = TMath::Abs(cosphi); asinphi = TMath::Abs(sinphi); if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; } if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; } // mside positive, tick marks on positive side // mside negative, tick marks on negative side // mside zero, tick marks on both sides // Default is positive except for vertical axis mside=1; if (x0 == x1 && y1 > y0) mside = -1; if (optionPlus) mside = 1; if (optionMinus) mside = -1; if (optionPlus && optionMinus) mside = 0; xmside = mside; lside = -mside; if (optionEqual) lside = mside; if (optionPlus && optionMinus) { lside = -1; if (optionEqual) lside=1; } xlside = lside; // Tick marks size if(xmside >= 0) tick_side = 1; else tick_side = -1; if (optionSize) atick[0] = tick_side*axis_length*fTickSize; else atick[0] = tick_side*axis_length*0.03; atick[1] = 0.5*atick[0]; atick[2] = 0.5*atick[1]; // Set the side of the grid if ((x0 == x1) && (y1 > y0)) grid_side =-1; else grid_side = 1; // Compute Values if Function is given if(fFunction) { rwmi = fFunction->Eval(wmin); rwma = fFunction->Eval(wmax); if(rwmi > rwma) { Double_t t = rwma; rwma = rwmi; rwmi = t; } } // Draw the axis if needed... if (!optionBlank) { xpl1 = x0; xpl2 = x1; ypl1 = y0; ypl2 = y1; PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } // No bining if (ndiv == 0)goto L210; if (wmin == wmax) { Error(where, "wmin (%f) == wmax (%f)", wmin, wmax); goto L210; } // Labels preparation: // Get character height // Compute the labels orientation in case of overlaps // (with alphanumeric labels for horizontal axis). charheight = GetLabelSize(); if (optionText && GetLabelFont()%10 != 3) charheight *= 0.66666; textaxis->SetTextFont(GetLabelFont()); if ((GetLabelFont()%10 < 2) && optionLog) // force TLatex mode in PaintLatex textaxis->SetTextFont((Int_t)(GetLabelFont()/10)*10+2); textaxis->SetTextColor(GetLabelColor()); textaxis->SetTextSize (charheight); textaxis->SetTextAngle(GetTextAngle()); if (GetLabelFont()%10 > 2) { charheight /= padh; } if (!optionUp && !optionDown && !optionY && !optionUnlab) { if (!drawGridOnly && optionText && ((ymin == ymax) || (xmin == xmax))) { textaxis->SetTextAlign(32); optionText = 2; Int_t nl = fAxis->GetLast()-fAxis->GetFirst()+1; Double_t angle = 0; for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) { textaxis->SetText(0,0,fAxis->GetBinLabel(i)); if (textaxis->GetXsize() < (xmax-xmin)/nl) continue; angle = -20; break; } for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) { if ((!strcmp(fAxis->GetName(),"xaxis") && !gPad->TestBit(kHori)) ||(!strcmp(fAxis->GetName(),"yaxis") && gPad->TestBit(kHori))) { if (nl > 50) angle = 90; if (fAxis->TestBit(TAxis::kLabelsHori)) angle = 0; if (fAxis->TestBit(TAxis::kLabelsVert)) angle = 90; if (fAxis->TestBit(TAxis::kLabelsUp)) angle = 20; if (fAxis->TestBit(TAxis::kLabelsDown)) angle =-20; if (angle == 0) textaxis->SetTextAlign(23); if (angle == -20) textaxis->SetTextAlign(12); textaxis->SetTextAngle(angle); Double_t s = -3; if (ymin == gPad->GetUymax()) { if (angle == 0) textaxis->SetTextAlign(21); s = 3; } strncpy(chtemp, fAxis->GetBinLabel(i), 255); if (fNModLabs) ChangeLabelAttributes(i, fAxis->GetLabels()->GetSize()-1, textaxis, chtemp); textaxis->PaintLatex(fAxis->GetBinCenter(i), ymin + s*fAxis->GetLabelOffset()*(gPad->GetUymax()-gPad->GetUymin()), textaxis->GetTextAngle(), textaxis->GetTextSize(), chtemp); if (fNModLabs) ResetLabelAttributes(textaxis); } else if ((!strcmp(fAxis->GetName(),"yaxis") && !gPad->TestBit(kHori)) || (!strcmp(fAxis->GetName(),"xaxis") && gPad->TestBit(kHori))) { Double_t s = -3; if (xmin == gPad->GetUxmax()) { textaxis->SetTextAlign(12); s = 3; } if (autotoff) { UInt_t w,h; textaxis->SetText(0.,0., fAxis->GetBinLabel(i)); textaxis->GetBoundingBox(w,h); toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC())); } textaxis->PaintLatex(xmin + s*fAxis->GetLabelOffset()*(gPad->GetUxmax()-gPad->GetUxmin()), fAxis->GetBinCenter(i), 0, textaxis->GetTextSize(), fAxis->GetBinLabel(i)); } else { textaxis->PaintLatex(xmin - 3*fAxis->GetLabelOffset()*(gPad->GetUxmax()-gPad->GetUxmin()), ymin +(i-0.5)*(ymax-ymin)/nl, 0, textaxis->GetTextSize(), fAxis->GetBinLabel(i)); } } } } // Now determine orientation of labels on axis if (!gPad->IsBatch()) { if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi); else gVirtualX->SetCharacterUp(sinphi,-cosphi); if (x0 == x1) gVirtualX->SetCharacterUp(0,1); if (optionVert) gVirtualX->SetCharacterUp(0,1); if (optionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi); if (optionDown) gVirtualX->SetCharacterUp(cosphi,sinphi); } // Now determine text alignment xalign = 2; yalign = 1; if (x0 == x1) xalign = 3; if (y0 != y1) yalign = 2; if (optionCent) xalign = 2; if (optionRight) xalign = 3; if (optionLeft) xalign = 1; if (TMath::Abs(cosphi) > 0.9) { xalign = 2; } else { if (cosphi*sinphi > 0) xalign = 1; if (cosphi*sinphi < 0) xalign = 3; } textaxis->SetTextAlign(10*xalign+yalign); // Position of labels in Y if (x0 == x1) { if (optionPlus && !optionMinus) { if (optionEqual) ylabel = fLabelOffset/2 + atick[0]; else ylabel = -fLabelOffset; } else { ylabel = fLabelOffset; if (lside < 0) ylabel += atick[0]; } } else if (y0 == y1) { if (optionMinus && !optionPlus) { if ((GetLabelFont() % 10) == 3 ) { ylabel = fLabelOffset+0.5* ((gPad->AbsPixeltoY(0)-gPad->AbsPixeltoY((Int_t)fLabelSize))/ (gPad->GetY2() - gPad->GetY1())); } else { ylabel = fLabelOffset+0.5*fLabelSize; } ylabel += TMath::Abs(atick[0]); } else { ylabel = -fLabelOffset; if (mside <= 0) ylabel -= TMath::Abs(atick[0]); } if (optionLog) ylabel -= 0.5*charheight; } else { if (mside+lside >= 0) ylabel = fLabelOffset; else ylabel = -fLabelOffset; } if (optionText) ylabel /= 2; // Draw the linear tick marks if needed... if (!optionLog) { if (ndiv) { if (fFunction) { dxtick=(binHigh-binLow)/Double_t(nticks-1); } else { if (optionNoopt && !optionInt) dxtick=axis_length/Double_t(nticks-1); else dxtick=axis_lengthN/Double_t(nticks-1); } for (k=0;kEval(xf)-rwmi; xtick = zz* axis_length / TMath::Abs(rwma-rwmi); } else { xtick = Double_t(k)*dxtick; } ytick = 0; if (!mside) ytick -= atick[ltick]; if ( optionNoopt && !optionInt) { Rotate(xtick,ytick,cosphi,sinphi,x0,y0,xpl2,ypl2); Rotate(xtick,atick[ltick],cosphi,sinphi,x0,y0,xpl1,ypl1); } else { Rotate(xtick,ytick,cosphi,sinphi,xx0,yy0,xpl2,ypl2); Rotate(xtick,atick[ltick],cosphi,sinphi,xx0,yy0,xpl1,ypl1); } if (optionVert) { if ((x0 != x1) && (y0 != y1)) { if (mside) { xpl1 = xpl2; if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; else ypl1 = ypl2 - atick[ltick]; } else { xpl1 = 0.5*(xpl1 + xpl2); xpl2 = xpl1; ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; } } } if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2); if (optionGrid) { if (ltick == 0) { if (optionNoopt && !optionInt) { Rotate(xtick,0,cosphi,sinphi,x0,y0 ,xpl2,ypl2); Rotate(xtick,grid_side*gridlength ,cosphi,sinphi,x0,y0 ,xpl1,ypl1); } else { Rotate(xtick,0,cosphi ,sinphi,xx0,yy0 ,xpl2,ypl2); Rotate(xtick,grid_side*gridlength ,cosphi,sinphi,xx0,yy0 ,xpl1,ypl1); } linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } } } xtick0 = 0; xtick1 = xtick; if (fFunction) axis_length0 = binLow-wmin; if ((!optionNoopt || optionInt) && axis_length0) { nticks0 = Int_t(axis_length0/dxtick); if (nticks0 > 1000) nticks0 = 1000; for (k=0; k<=nticks0; k++) { ltick = 2; if (k%nn3 == 0) ltick = 1; if (k%nn2 == 0) ltick = 0; ytick0 = 0; if (!mside) ytick0 -= atick[ltick]; if (fFunction) { xtick0 = (fFunction->Eval(binLow - Double_t(k)*dxtick)-rwmi) * axis_length / TMath::Abs(rwma-rwmi); } Rotate(xtick0,ytick0,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2); Rotate(xtick0,atick[ltick],cosphi,sinphi,xx0,yy0 ,xpl1,ypl1); if (optionVert) { if ((x0 != x1) && (y0 != y1)) { if (mside) { xpl1 = xpl2; if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; else ypl1 = ypl2 - atick[ltick]; } else { xpl1 = 0.5*(xpl1 + xpl2); xpl2 = xpl1; ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; } } } if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2); if (optionGrid) { if (ltick == 0) { Rotate(xtick0,0,cosphi,sinphi,xx0,yy0,xpl2,ypl2); Rotate(xtick0,grid_side*gridlength ,cosphi,sinphi,xx0,yy0 ,xpl1,ypl1); linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } } xtick0 -= dxtick; } } if (fFunction) axis_length1 = wmax-binHigh; if ((!optionNoopt || optionInt) && axis_length1) { nticks1 = int(axis_length1/dxtick); if (nticks1 > 1000) nticks1 = 1000; for (k=0; k<=nticks1; k++) { ltick = 2; if (k%nn3 == 0) ltick = 1; if (k%nn2 == 0) ltick = 0; ytick1 = 0; if (!mside) ytick1 -= atick[ltick]; if (fFunction) { xtick1 = (fFunction->Eval(binHigh + Double_t(k)*dxtick)-rwmi) * axis_length / TMath::Abs(rwma-rwmi); } Rotate(xtick1,ytick1,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2); Rotate(xtick1,atick[ltick],cosphi,sinphi,xx0,yy0 ,xpl1,ypl1); if (optionVert) { if ((x0 != x1) && (y0 != y1)) { if (mside) { xpl1 = xpl2; if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; else ypl1 = ypl2 - atick[ltick]; } else { xpl1 = 0.5*(xpl1 + xpl2); xpl2 = xpl1; ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; } } } if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2); if (optionGrid) { if (ltick == 0) { Rotate(xtick1,0,cosphi,sinphi,xx0,yy0 ,xpl2,ypl2); Rotate(xtick1,grid_side*gridlength,cosphi,sinphi,xx0,yy0,xpl1,ypl1); linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } } xtick1 += dxtick; } } } } // Draw the numeric labels if needed... if (!drawGridOnly && !optionUnlab) { if (!optionLog) { if (n1a) { // Spacing of labels if ((wmin == wmax) || (ndiv == 0)) { Error(where, "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax); goto L210; } wlabel = wmin; dwlabel = (wmax-wmin)/Double_t(n1a); if (optionNoopt && !optionInt) dxlabel = axis_length/Double_t(n1a); else dxlabel = axis_lengthN/Double_t(n1a); if (!optionText && !optionTime) { // We have to decide what format to generate // (for numeric labels only) // Test the magnitude, decide format flexe = kFALSE; nexe = 0; flexpo = kFALSE; flexne = kFALSE; ww = TMath::Max(TMath::Abs(wmin),TMath::Abs(wmax)); // First case : (wmax-wmin)/n1a less than 0.001 // (0.001 fgMaxDigits of 5 (fgMaxDigits) characters). Then we use x 10 n // format. If af >=0 x10 n cannot be used Double_t xmicros = 0.00099; if (maxDigits) xmicros = TMath::Power(10,-maxDigits); if (!noExponent && (TMath::Abs(wmax-wmin)/Double_t(n1a)) < xmicros) { af = TMath::Log10(ww) + epsilon; if (af < 0) { flexe = kTRUE; nexe = int(af); iexe = TMath::Abs(nexe); if (iexe%3 == 1) iexe += 2; else if(iexe%3 == 2) iexe += 1; if (nexe < 0) nexe = -iexe; else nexe = iexe; wlabel = wlabel*TMath::Power(10,iexe); dwlabel = dwlabel*TMath::Power(10,iexe); if1 = maxDigits; if2 = maxDigits-2; goto L110; } } if (ww >= 1) af = TMath::Log10(ww); else af = TMath::Log10(ww*0.0001); af += epsilon; nf = Int_t(af)+1; if (!noExponent && nf > maxDigits) flexpo = kTRUE; if (!noExponent && nf < -maxDigits) flexne = kTRUE; // Use x 10 n format. (only powers of 3 allowed) if (flexpo) { flexe = kTRUE; while (1) { nexe++; ww /= 10; wlabel /= 10; dwlabel /= 10; if (nexe%3 == 0 && ww <= TMath::Power(10,maxDigits-1)) break; } } if (flexne) { flexe = kTRUE; rne = 1/TMath::Power(10,maxDigits-2); while (1) { nexe--; ww *= 10; wlabel *= 10; dwlabel *= 10; if (nexe%3 == 0 && ww >= rne) break; } } na = 0; for (i=maxDigits-1; i>0; i--) { if (TMath::Abs(ww) < TMath::Power(10,i)) na = maxDigits-i; } ndyn = n1a; while (ndyn) { Double_t wdyn = TMath::Abs((wmax-wmin)/ndyn); if (wdyn <= 0.999 && na < maxDigits-2) { na++; ndyn /= 10; } else break; } // if1 and if2 are the two digits defining the format used to produce the // labels. The format used will be %[if1].[if2]f . // if1 and if2 are positive (small) integers. if2 = na; if1 = TMath::Max(nf+na,maxDigits)+1; L110: if (TMath::Min(wmin,wmax) < 0)if1 = if1+1; if1 = TMath::Min(if1,32); // In some cases, if1 and if2 are too small.... while (dwlabel < TMath::Power(10,-if2)) { if1++; if2++; } if (if1 > 14) if1 = 14; if (if2 > 14) if2 = 14; if (if1 < 0) if1 = 0; int len = 0; if (if2 > 0) { len = snprintf(chcoded,sizeof(chcoded),"%%%d.%df",if1,if2); } else { len = snprintf(chcoded,sizeof(chcoded),"%%%d.%df",if1+1,1); } // check improbable error condition, suppress gcc9 warnings if ((len < 0) || (len >= (int) sizeof(chcoded))) strcpy(chcoded,"%7.3f"); } // We draw labels snprintf(chtemp,256,"%g",dwlabel); Int_t ndecimals = 0; if (optionDecimals) { char *dot = strchr(chtemp,'.'); if (dot) { ndecimals = chtemp + strlen(chtemp) -dot; } else { char *exp; exp = strstr(chtemp,"e-"); if (exp) { sscanf(&exp[2],"%d",&ndecimals); ndecimals++; } } } if (optionM) nlabels = n1a-1; else nlabels = n1a; wTimeIni = wlabel; for ( k=0; k<=nlabels; k++) { if (fFunction) { Double_t xf = binLow+Double_t(k*nn2)*dxtick; Double_t zz = fFunction->Eval(xf)-rwmi; wlabel = xf; xlabel = zz* axis_length / TMath::Abs(rwma-rwmi); } else { xlabel = dxlabel*k; } if (optionM) xlabel += 0.5*dxlabel; if (!optionText && !optionTime) { snprintf(label,256,chcoded,wlabel); label[28] = 0; wlabel += dwlabel; LabelsLimits(label,first,last); //Eliminate blanks if (label[first] == '.') { //check if '.' is preceded by a digit strncpy(chtemp, "0",256); strlcat(chtemp, &label[first],256); strncpy(label, chtemp,256); first = 1; last = strlen(label); } if (label[first] == '-' && label[first+1] == '.') { strncpy(chtemp, "-0",256); strlcat(chtemp, &label[first+1],256); strncpy(label, chtemp, 256); first = 1; last = strlen(label); } // We eliminate the non significant 0 after '.' if (ndecimals) { char *adot = strchr(label,'.'); if (adot) adot[ndecimals] = 0; } else { while (label[last] == '0') { label[last] = 0; last--;} } // We eliminate the dot, unless dot is forced. if (label[last] == '.') { if (!optionDot) { label[last] = 0; last--;} } // Make sure the label is not "-0" if (last-first == 1 && label[first] == '-' && label[last] == '0') { strncpy(label, "0", 256); label[last] = 0; } } // Generate the time labels if (optionTime) { timed = wlabel + (int)(timeoffset) - rangeOffset; timelabel = (time_t)((Long_t)(timed)); if (optionTime == 1) { utctis = localtime(&timelabel); } else { utctis = gmtime(&timelabel); } TString timeformattmp; if (timeformat.Length() < 220) timeformattmp = timeformat; else timeformattmp = "#splitline{Format}{too long}"; // Appends fractional part if seconds displayed if (dwlabel<0.9) { double tmpdb; int tmplast; snprintf(label, 256, "%%S%7.5f", modf(timed,&tmpdb)); tmplast = strlen(label)-1; // We eliminate the non significant 0 after '.' while (label[tmplast] == '0') { label[tmplast] = 0; tmplast--; } timeformattmp.ReplaceAll("%S",label); // replace the "0." at the beginning by "s" timeformattmp.ReplaceAll("%S0.","%Ss"); } if (utctis != nullptr) { strftime(label, 256, timeformattmp.Data(), utctis); } else { strncpy(label, "invalid", 256); } strncpy(chtemp, &label[0], 256); first = 0; last=strlen(label)-1; wlabel = wTimeIni + (k+1)*dwlabel; } // We generate labels (numeric or alphanumeric). if (optionNoopt && !optionInt) Rotate (xlabel,ylabel,cosphi,sinphi,x0,y0,xx,yy); else Rotate (xlabel,ylabel,cosphi,sinphi,xx0,yy0,xx,yy); if (y0 == y1 && !optionDown && !optionUp) { yy -= 0.80*charheight; } if (optionVert) { if (x0 != x1 && y0 != y1) { if (optionNoopt && !optionInt) Rotate (xlabel,0,cosphi,sinphi,x0,y0,xx,yy); else Rotate (xlabel,0,cosphi,sinphi,xx0,yy0,xx,yy); if (cosphi > 0 ) yy += ylabel; if (cosphi < 0 ) yy -= ylabel; } } if (!optionY || (x0 == x1)) { if (!optionText) { if (first > last) strncpy(chtemp, " ", 256); else strncpy(chtemp, &label[first], 255); if (fNModLabs) ChangeLabelAttributes(k+1, nlabels, textaxis, chtemp); typolabel = chtemp; if (!optionTime) typolabel.ReplaceAll("-", "#minus"); if (autotoff) { UInt_t w,h; textaxis->SetText(0.,0., typolabel.Data()); textaxis->GetBoundingBox(w,h); toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC())); } textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), textaxis->GetTextAngle(), textaxis->GetTextSize(), typolabel.Data()); if (fNModLabs) ResetLabelAttributes(textaxis); } else { if (optionText == 1) textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), 0, textaxis->GetTextSize(), fAxis->GetBinLabel(k+fAxis->GetFirst())); } } else { // Text alignment is down if (!optionText) lnlen = last-first+1; else { if (k+1 > nhilab) lnlen = 0; } for ( l=1; l<=lnlen; l++) { if (!optionText) *chtemp = label[first+l-2]; else { if (lnlen == 0) strncpy(chtemp, " ", 256); else strncpy(chtemp, "1", 256); } typolabel = chtemp; typolabel.ReplaceAll("-", "#minus"); textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), 0, textaxis->GetTextSize(), typolabel.Data()); yy -= charheight*1.3; } } } // We use the format x 10 ** n if (flexe && !optionText && nexe) { snprintf(label,256,"#times10^{%d}", nexe); if (x0 != x1) { xfactor = axis_length+0.1*charheight; yfactor = 0; } else { xfactor = y1-y0+0.1*charheight; yfactor = 0; } Rotate (xfactor,yfactor,cosphi,sinphi,x0,y0,xx,yy); textaxis->SetTextAlign(11); if (GetLabelFont()%10 < 2) // force TLatex mode in PaintLatex textaxis->SetTextFont((Int_t)(GetLabelFont()/10)*10+2); if (fAxis && !strcmp(fAxis->GetName(),"xaxis")) { xx = xx + fXAxisExpXOffset; yy = yy + fXAxisExpYOffset; } if (fAxis && !strcmp(fAxis->GetName(),"yaxis")) { xx = xx + fYAxisExpXOffset; yy = yy + fYAxisExpYOffset; } typolabel = label; typolabel.ReplaceAll("-", "#minus"); textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), 0, textaxis->GetTextSize(), typolabel.Data()); } } } } // Log axis if (optionLog && ndiv) { UInt_t xi1=0,xi2=0,wi=0,yi1=0,yi2=0,hi=0,xl=0,xh=0; Bool_t firstintlab = kTRUE, overlap = kFALSE; if ((wmin == wmax) || (ndiv == 0)) { Error(where, "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax); goto L210; } if (wmin <= 0) { Error(where, "negative logarithmic axis"); goto L210; } if (wmax <= 0) { Error(where, "negative logarithmic axis"); goto L210; } xmnlog = TMath::Log10(wmin); if (xmnlog > 0) xmnlog += 1.E-6; else xmnlog -= 1.E-6; x00 = 0; x11 = axis_length; h2 = TMath::Log10(wmax); h2sav = h2; if (h2 > 0) h2 += 1.E-6; else h2 -= 1.E-6; ih1 = int(xmnlog); ih2 = 1+int(h2); nbinin = ih2-ih1+1; axmul = (x11-x00)/(h2sav-xmnlog); // Plot decade and intermediate tick marks decade = ih1-2; labelnumber = ih1; if ( xmnlog > 0 && (xmnlog-Double_t(ih1) > 0) ) labelnumber++; Int_t changelablogid = 0; Int_t changelablognum = 0; for (j=1; j<=nbinin; j++) { // Plot decade firstintlab = kTRUE, overlap = kFALSE; decade++; if (x0 == x1 && j == 1) ylabel += charheight*0.33; if (y0 == y1 && j == 1) ylabel -= charheight*0.65; xone = x00+axmul*(Double_t(decade)-xmnlog); //the following statement is a trick to circumvent a gcc bug if (j < 0) printf("j=%d\n",j); if (x00 > xone) goto L160; if ((xone-x11)>epsilon) break; xtwo = xone; y = 0; if (!mside) y -= atick[0]; Rotate(xone,y,cosphi,sinphi,x0,y0,xpl2,ypl2); Rotate(xtwo,atick[0],cosphi,sinphi,x0,y0,xpl1,ypl1); if (optionVert) { if ((x0 != x1) && (y0 != y1)) { if (mside) { xpl1=xpl2; if (cosphi > 0) ypl1 = ypl2 + atick[0]; else ypl1 = ypl2 - atick[0]; } else { xpl1 = 0.5*(xpl1 + xpl2); xpl2 = xpl1; ypl1 = 0.5*(ypl1 + ypl2) + atick[0]; ypl2 = 0.5*(ypl1 + ypl2) - atick[0]; } } } if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2); if (optionGrid) { Rotate(xone,0,cosphi,sinphi,x0,y0,xpl2,ypl2); Rotate(xone,grid_side*gridlength,cosphi,sinphi,x0,y0,xpl1,ypl1); linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } if (!drawGridOnly && !optionUnlab) { // We generate labels (numeric only). if (noExponent) { rlab = TMath::Power(10,labelnumber); snprintf(label,256, "%f", rlab); LabelsLimits(label,first,last); while (last > first) { if (label[last] != '0') break; label[last] = 0; last--; } if (label[last] == '.') {label[last] = 0; last--;} } else { snprintf(label,256, "%d", labelnumber); LabelsLimits(label,first,last); } Rotate (xone,ylabel,cosphi,sinphi,x0,y0,xx,yy); if ((x0 == x1) && !optionPara) { if (lside < 0) { if (mside < 0) { if (labelnumber == 0) nch=1; else nch=2; xx += nch*charheight; } else { xx += 0.25*charheight; } } xx += 0.25*charheight; } if ((y0 == y1) && !optionDown && !optionUp) { if (noExponent) yy += 0.33*charheight; } if (n1a == 0)goto L210; kmod = nbinin/n1a; if (kmod == 0) kmod=1000000; if ((nbinin <= n1a) || (j == 1) || (j == nbinin) || ((nbinin > n1a) && (j%kmod == 0))) { if (labelnumber == 0) { snprintf(chtemp,256, "1"); } else if (labelnumber == 1) { snprintf(chtemp,256, "10"); } else { if (noExponent) { chtemp = &label[first]; } else { snprintf(chtemp,256, "10^{%d}", labelnumber); } } if (fNModLabs) { if (changelablogid == 0) changelablognum = nbinin-j; changelablogid++; ChangeLabelAttributes(changelablogid, changelablognum, textaxis, chtemp); } typolabel = chtemp; typolabel.ReplaceAll("-", "#minus"); if (autotoff) { UInt_t w,h; textaxis->SetText(0.,0., typolabel.Data()); textaxis->GetBoundingBox(w,h); toffset = TMath::Max(toffset,(double)w/((double)gPad->GetWw()*gPad->GetWNDC())); } textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), 0, textaxis->GetTextSize(), typolabel.Data()); if (fNModLabs) ResetLabelAttributes(textaxis); } labelnumber++; } L160: for (k=2;k<10;k++) { // Plot intermediate tick marks xone = x00+axmul*(TMath::Log10(Double_t(k))+Double_t(decade)-xmnlog); if (x00 > xone) continue; if (xone > x11) goto L200; y = 0; if (!mside) y -= atick[1]; xtwo = xone; Rotate(xone,y,cosphi,sinphi,x0,y0,xpl2,ypl2); Rotate(xtwo,atick[1],cosphi,sinphi,x0,y0,xpl1,ypl1); if (optionVert) { if ((x0 != x1) && (y0 != y1)) { if (mside) { xpl1 = xpl2; if (cosphi > 0) ypl1 = ypl2 + atick[1]; else ypl1 = ypl2 - atick[1]; } else { xpl1 = 0.5*(xpl1+xpl2); xpl2 = xpl1; ypl1 = 0.5*(ypl1+ypl2) + atick[1]; ypl2 = 0.5*(ypl1+ypl2) - atick[1]; } } } idn = n1a*2; if ((nbinin <= idn) || ((nbinin > idn) && (k == 5))) { if (!drawGridOnly) PaintLineNDC(xpl1, ypl1, xpl2, ypl2); // Draw the intermediate LOG labels if requested if (moreLogLabels && !optionUnlab && !drawGridOnly && !overlap) { if (noExponent) { rlab = Double_t(k)*TMath::Power(10,labelnumber-1); snprintf(chtemp,256, "%g", rlab); } else { if (labelnumber-1 == 0) { snprintf(chtemp,256, "%d", k); } else if (labelnumber-1 == 1) { snprintf(chtemp,256, "%d", 10*k); } else { snprintf(chtemp,256, "%d#times10^{%d}", k, labelnumber-1); } } Rotate (xone,ylabel,cosphi,sinphi,x0,y0,xx,yy); if ((x0 == x1) && !optionPara) { if (lside < 0) { if (mside < 0) { if (labelnumber == 0) nch=1; else nch=2; xx += nch*charheight; } else { if (labelnumber >= 0) xx += 0.25*charheight; else xx += 0.50*charheight; } } xx += 0.25*charheight; } if ((y0 == y1) && !optionDown && !optionUp) { if (noExponent) yy += 0.33*charheight; } if (optionVert) { if ((x0 != x1) && (y0 != y1)) { Rotate(xone,ylabel,cosphi,sinphi,x0,y0,xx,yy); if (cosphi > 0) yy += ylabel; else yy -= ylabel; } } textaxis->SetTitle(chtemp); Double_t u = gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()); Double_t v = gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()); if (firstintlab) { textaxis->GetBoundingBox(wi, hi); wi=(UInt_t)(wi*1.3); hi=(UInt_t)(hi*1.3); xi1 = gPad->XtoAbsPixel(u); yi1 = gPad->YtoAbsPixel(v); firstintlab = kFALSE; typolabel = chtemp; typolabel.ReplaceAll("-", "#minus"); textaxis->PaintLatex(u,v,0,textaxis->GetTextSize(),typolabel.Data()); } else { xi2 = gPad->XtoAbsPixel(u); yi2 = gPad->YtoAbsPixel(v); xl = TMath::Min(xi1,xi2); xh = TMath::Max(xi1,xi2); if ((x0 == x1 && yi1-hi <= yi2) || (y0 == y1 && xl+wi >= xh)){ overlap = kTRUE; } else { xi1 = xi2; yi1 = yi2; textaxis->GetBoundingBox(wi, hi); wi=(UInt_t)(wi*1.3); hi=(UInt_t)(hi*1.3); typolabel = chtemp; typolabel.ReplaceAll("-", "#minus"); textaxis->PaintLatex(u,v,0,textaxis->GetTextSize(),typolabel.Data()); } } } // Draw the intermediate LOG grid if only three decades are requested if (optionGrid && nbinin <= 5 && ndiv > 100) { Rotate(xone,0,cosphi,sinphi,x0,y0,xpl2, ypl2); Rotate(xone,grid_side*gridlength,cosphi,sinphi,x0,y0, xpl1,ypl1); linegrid->PaintLineNDC(xpl1, ypl1, xpl2, ypl2); } } //endif ((nbinin <= idn) || } //endfor (k=2;k<10;k++) } //endfor (j=1; j<=nbinin; j++) L200: Int_t dummy = 0; if (dummy) { } } //endif (optionLog && ndiv) // Draw axis title if it exists if (!drawGridOnly && strlen(GetTitle())) { textaxis->SetTextSize (GetTitleSize()); charheight = GetTitleSize(); if ((GetTextFont() % 10) > 2) { charheight = charheight/gPad->GetWh(); } if (x1 == x0) { if (autotoff) { if (toffset) ylabel = xlside*charheight+toffset; else ylabel = xlside*1.6*charheight; } else { ylabel = xlside*1.6*charheight*toffset; } } else { ylabel = xlside*1.3*charheight*toffset; } if (y1 == y0) { if (toffset == 0.) toffset = gStyle->GetTitleOffset("X"); ylabel = xlside*1.6*charheight*toffset; } Double_t axispos; if (TestBit(TAxis::kCenterTitle)) axispos = 0.5*axis_length; else axispos = axis_length; if (TestBit(TAxis::kRotateTitle)) { if (x1 >= x0) { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(12); } else { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(32); } phil+=kPI; } else { if (x1 >= x0) { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(32); } else { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(12); } } Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1); textaxis->SetTextColor(TitleColor); textaxis->SetTextFont(TitleFont); textaxis->PaintLatex(gPad->GetX1() + xpl1*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + ypl1*(gPad->GetY2() - gPad->GetY1()), phil*180/kPI, GetTitleSize(), GetTitle()); } L210: if (optionGrid) delete linegrid; delete textaxis; } //////////////////////////////////////////////////////////////////////////////// /// Internal method for axis labels optimisation. This method adjusts the bining /// of the axis in order to have integer values for the labels. /// /// \param[in] A1,A2 Old WMIN,WMAX /// \param[out] binLow,binHigh New WMIN,WMAX /// \param[in] nold Old NDIV (primary divisions) /// \param[out] nbins New NDIV /// \param[out] binWidth Bin width void TGaxis::AdjustBinSize(Double_t A1, Double_t A2, Int_t nold ,Double_t &binLow, Double_t &binHigh, Int_t &nbins, Double_t &binWidth) { binWidth = TMath::Abs(A2-A1)/Double_t(nold); if (binWidth <= 1) { binWidth = 1; binLow = int(A1); } else { Int_t width = int(binWidth/5) + 1; binWidth = 5*width; binLow = int(A1/binWidth)*binWidth; // We determine binLow to have one tick mark at 0 // if there are negative labels. if (A1 < 0) { for (Int_t ic=0; ic<1000; ic++) { Double_t rbl = binLow/binWidth; Int_t ibl = int(binLow/binWidth); if ( (rbl-ibl) == 0 || ic > width) { binLow -= 5; break;} } } } binHigh = int(A2); nbins = 0; Double_t xb = binLow; while (xb <= binHigh) { xb += binWidth; nbins++; } binHigh = xb - binWidth; } //////////////////////////////////////////////////////////////////////////////// /// Internal method to find first and last character of a label. void TGaxis::LabelsLimits(const char *label, Int_t &first, Int_t &last) { last = strlen(label)-1; for (Int_t i=0; i<=last; i++) { if (strchr("1234567890-+.", label[i]) ) { first = i; return; } } Error("LabelsLimits", "attempt to draw a blank label"); } //////////////////////////////////////////////////////////////////////////////// /// Internal method to rotate axis coordinates. void TGaxis::Rotate(Double_t X, Double_t Y, Double_t CFI, Double_t SFI ,Double_t XT, Double_t YT, Double_t &U, Double_t &V) { U = CFI*X-SFI*Y+XT; V = SFI*X+CFI*Y+YT; } //////////////////////////////////////////////////////////////////////////////// /// Save primitive as a C++ statement(s) on output stream out void TGaxis::SavePrimitive(std::ostream &out, Option_t * /*= ""*/) { char quote = '"'; if (gROOT->ClassSaved(TGaxis::Class())) { out<<" "; } else { out<<" TGaxis *"; } out<<"gaxis = new TGaxis("<SetLabelOffset("<SetLabelSize("<SetTickSize("<SetGridLength("<SetTitleOffset("<SetTitleSize("<SetTitleColor("<SetTitleFont("<SetName("<SetTitle("< 228) { TColor::SaveColor(out, fLabelColor); out<<" gaxis->SetLabelColor(ci);" << std::endl; } else out<<" gaxis->SetLabelColor("< 228) { TColor::SaveColor(out, fLineColor); out<<" gaxis->SetLineColor(ci);" << std::endl; } else out<<" gaxis->SetLineColor("<SetLineStyle("<SetLineWidth("<SetLabelFont("<SetMoreLogLabels();"<SetNoExponent();"<Draw();"<GetFunction(funcname); if (!fFunction) { Error("SetFunction", "unknown function: %s", funcname); } else { fWmin = fFunction->GetXmin(); fWmax = fFunction->GetXmax(); } } //////////////////////////////////////////////////////////////////////////////// /// Define new text attributes for the label number "labNum". It allows to do a /// fine tuning of the labels. All the attributes can be changed, even the /// label text itself. /// /// \param[in] labNum Number of the label to be changed, negative numbers start from the end /// \param[in] labAngle New angle value /// \param[in] labSize New size (0 erase the label) /// \param[in] labAlign New alignment value /// \param[in] labColor New label color /// \param[in] labFont New label font /// \param[in] labText New label text /// /// If an attribute should not be changed just give the value /// "-1".The following macro gives an example: /// /// Begin_Macro(source) /// { /// c1 = new TCanvas("c1","Examples of Gaxis",10,10,900,500); /// c1->Range(-6,-0.1,6,0.1); /// TGaxis *axis1 = new TGaxis(-5.5,0.,5.5,0.,0.0,100,510,""); /// axis1->SetName("axis1"); /// axis1->SetTitle("Axis Title"); /// axis1->SetTitleSize(0.05); /// axis1->SetTitleColor(kBlue); /// axis1->SetTitleFont(42); /// axis1->ChangeLabel(1,-1,-1,-1,2); /// axis1->ChangeLabel(3,-1,0.); /// axis1->ChangeLabel(5,30.,-1,0); /// axis1->ChangeLabel(6,-1,-1,-1,3,-1,"6th label"); /// axis1->ChangeLabel(-2,-1,-1,-1,3,-1,"2nd to last label"); /// axis1->Draw(); /// } /// End_Macro /// /// If labnum=0 the list of modified labels is reset. void TGaxis::ChangeLabel(Int_t labNum, Double_t labAngle, Double_t labSize, Int_t labAlign, Int_t labColor, Int_t labFont, TString labText) { fNModLabs++; if (!fModLabs) fModLabs = new TList(); // Reset the list of modified labels. if (labNum == 0) { delete fModLabs; fModLabs = 0; fNModLabs = 0; return; } TAxisModLab *ml = new TAxisModLab(); ml->SetLabNum(labNum); ml->SetAngle(labAngle); ml->SetSize(labSize); ml->SetAlign(labAlign); ml->SetColor(labColor); ml->SetFont(labFont); ml->SetText(labText); fModLabs->Add((TObject*)ml); } //////////////////////////////////////////////////////////////////////////////// /// Change the label attributes of label number i. If needed. /// /// \param[in] i Current label number to be changed if needed /// \param[in] nlabels Totals number of labels on for this axis (useful when i is counted from the end) /// \param[in] t Original TLatex string holding the label to be changed /// \param[in] c Text string to be drawn static Double_t SavedTextAngle; static Double_t SavedTextSize; static Int_t SavedTextAlign; static Int_t SavedTextColor; static Int_t SavedTextFont;; void TGaxis::ChangeLabelAttributes(Int_t i, Int_t nlabels, TLatex* t, char* c) { if (!fModLabs) return; TIter next(fModLabs); TAxisModLab *ml; Int_t labNum; while ( (ml = (TAxisModLab*)next()) ) { SavedTextAngle = t->GetTextAngle(); SavedTextSize = t->GetTextSize(); SavedTextAlign = t->GetTextAlign(); SavedTextColor = t->GetTextColor(); SavedTextFont = t->GetTextFont(); labNum = ml->GetLabNum(); if (labNum < 0) labNum = nlabels + labNum + 2; if (i == labNum) { if (ml->GetAngle()>=0.) t->SetTextAngle(ml->GetAngle()); if (ml->GetSize()>=0.) t->SetTextSize(ml->GetSize()); if (ml->GetAlign()>0) t->SetTextAlign(ml->GetAlign()); if (ml->GetColor()>=0) t->SetTextColor(ml->GetColor()); if (ml->GetFont()>0) t->SetTextFont(ml->GetFont()); if (!(ml->GetText().IsNull())) strncpy(c, (ml->GetText()).Data(), 256); return; } } } //////////////////////////////////////////////////////////////////////////////// /// Reset the label attributes to the value they have before the last call to /// ChangeLabelAttributes. void TGaxis::ResetLabelAttributes(TLatex* t) { t->SetTextAngle(SavedTextAngle); t->SetTextSize(SavedTextSize); t->SetTextAlign(SavedTextAlign); t->SetTextColor(SavedTextColor); t->SetTextFont(SavedTextFont); } //////////////////////////////////////////////////////////////////////////////// /// Static function to set `fgMaxDigits` for axis.`fgMaxDigits` is /// the maximum number of digits permitted for the axis labels above which the /// notation with 10^N is used.For example, to accept 6 digits number like 900000 /// on an axis call `TGaxis::SetMaxDigits(6)`. The default value is 5. /// `fgMaxDigits` must be greater than 0. void TGaxis::SetMaxDigits(Int_t maxd) { fgMaxDigits = maxd; if (maxd < 1) fgMaxDigits = 1; } //////////////////////////////////////////////////////////////////////////////// /// Change the name of the axis. void TGaxis::SetName(const char *name) { fName = name; } //////////////////////////////////////////////////////////////////////////////// /// Set the kMoreLogLabels bit flag. When this option is selected more labels are /// drawn when in logarithmic scale and there is a small number of decades (less than 3). /// Note that this option is automatically inherited from TAxis void TGaxis::SetMoreLogLabels(Bool_t more) { if (more) SetBit(TAxis::kMoreLogLabels); else ResetBit(TAxis::kMoreLogLabels); } //////////////////////////////////////////////////////////////////////////////// /// Set the NoExponent flag. By default, an exponent of the form 10^N is used /// when the label values are either all very small or very large. One can disable /// the exponent by calling axis.SetNoExponent(kTRUE). void TGaxis::SetNoExponent(Bool_t noExponent) { if (noExponent) SetBit(TAxis::kNoExponent); else ResetBit(TAxis::kNoExponent); } //////////////////////////////////////////////////////////////////////////////// /// To set axis options. void TGaxis::SetOption(Option_t *option) { fChopt = option; } //////////////////////////////////////////////////////////////////////////////// /// Change the title of the axis. void TGaxis::SetTitle(const char *title) { fTitle = title; } //////////////////////////////////////////////////////////////////////////////// /// Change the format used for time plotting. /// The format string for date and time use the same options as the one used /// in the standard strftime C function, i.e. : /// /// for date : /// /// - `%a` abbreviated weekday name /// - `%b` abbreviated month name /// - `%d` day of the month (01-31) /// - `%m` month (01-12) /// - `%y` year without century /// /// for time : /// /// - `%H` hour (24-hour clock) /// - `%I` hour (12-hour clock) /// - `%p` local equivalent of AM or PM /// - `%M` minute (00-59) /// - `%S` seconds (00-61) /// - `%%` % void TGaxis::SetTimeFormat(const char *tformat) { TString timeformat = tformat; if (timeformat.Index("%F")>=0 || timeformat.IsNull()) { fTimeFormat = timeformat; return; } Int_t idF = fTimeFormat.Index("%F"); if (idF>=0) { Int_t lnF = fTimeFormat.Length(); TString stringtimeoffset = fTimeFormat(idF,lnF); fTimeFormat = tformat; fTimeFormat.Append(stringtimeoffset); } else { fTimeFormat = tformat; SetTimeOffset(gStyle->GetTimeOffset()); } } //////////////////////////////////////////////////////////////////////////////// /// Change the time offset. If option = "gmt", set display mode to GMT. void TGaxis::SetTimeOffset(Double_t toffset, Option_t *option) { TString opt = option; opt.ToLower(); char tmp[20]; time_t timeoff; struct tm* utctis; Int_t idF = fTimeFormat.Index("%F"); if (idF>=0) fTimeFormat.Remove(idF); fTimeFormat.Append("%F"); timeoff = (time_t)((Long_t)(toffset)); // offset is always saved in GMT to allow file transport // to different time zones utctis = gmtime(&timeoff); if (utctis != nullptr) { strftime(tmp, 20,"%Y-%m-%d %H:%M:%S",utctis); fTimeFormat.Append(tmp); } else { fTimeFormat.Append("1970-01-01 00:00:00"); } // append the decimal part of the time offset Double_t ds = toffset-(Int_t)toffset; snprintf(tmp,20,"s%g",ds); fTimeFormat.Append(tmp); // add GMT/local option if (opt.Contains("gmt")) fTimeFormat.Append(" GMT"); } //////////////////////////////////////////////////////////////////////////////// /// Static function to set X and Y offset of the axis 10^n notation. /// It is in % of the pad size. It can be negative. /// axis specifies which axis ("x","y"), default = "x" /// if axis="xz" set the two axes void TGaxis::SetExponentOffset(Float_t xoff, Float_t yoff, Option_t *axis) { TString opt = axis; opt.ToLower(); if (opt.Contains("x")) { fXAxisExpXOffset = xoff; fXAxisExpYOffset = yoff; } if (opt.Contains("y")) { fYAxisExpXOffset = xoff; fYAxisExpYOffset = yoff; } } //////////////////////////////////////////////////////////////////////////////// /// Stream an object of class TGaxis. void TGaxis::Streamer(TBuffer &R__b) { if (R__b.IsReading()) { UInt_t R__s, R__c; Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v > 3) { R__b.ReadClassBuffer(TGaxis::Class(), this, R__v, R__s, R__c); return; } //====process old versions before automatic schema evolution TLine::Streamer(R__b); TAttText::Streamer(R__b); R__b >> fNdiv; R__b >> fWmin; R__b >> fWmax; R__b >> fGridLength; R__b >> fTickSize; R__b >> fLabelOffset; R__b >> fLabelSize; R__b >> fTitleOffset; R__b >> fTitleSize; R__b >> fLabelFont; if (R__v > 2) { R__b >> fLabelColor; } fChopt.Streamer(R__b); fName.Streamer(R__b); fTitle.Streamer(R__b); fTimeFormat.Streamer(R__b); if (R__v > 1) { fFunctionName.Streamer(R__b); fFunction = (TF1*)gROOT->GetFunction(fFunctionName.Data()); } R__b.CheckByteCount(R__s, R__c, TGaxis::IsA()); //====end of old versions } else { R__b.WriteClassBuffer(TGaxis::Class(),this); } }