// @(#)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 "TGaxis.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 "TObjString.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) - [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(); return c1; } 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); gStyle->SetOptStat(0); TH2F *h2 = new TH2F("h","Axes",100,0,10,100,-2,2); h2->Draw(); 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,"G"); A3->SetTitle("logarithmic axis"); A3->SetLabelSize(0.03); A3->SetTitleSize(0.03); A3->SetTitleOffset(1.2); A3->Draw(); return c2; } 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. ## 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`. ## 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 Axis labels may be considered as times, plotted in a defined time format. The format is set with `SetTimeFormat()`. The `TGaxis` minimum (`wmin`) and maximum (`wmax`) values are considered as two time values in seconds. The time axis will be spread around the time offset value (set with `SetTimeOffset()`). Actually it will go from `TimeOffset+wmin`to `TimeOffset+wmax` Usually time axis are created automatically via histograms, but one may also want to draw a time axis outside an "histogram context". This can be done thanks to the option `"T"` of `TGaxis`. 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.3); 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 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 An other example showing how to define the time offset as 2003, January 1st using histograms axis. Begin_Macro(source) ../../../tutorials/graphs/timeonaxis2.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; 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; 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; 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), fChopt(ax.fChopt), fName(ax.fName), fTitle(ax.fTitle), fTimeFormat(ax.fTimeFormat), fFunctionName(ax.fFunctionName), fFunction(ax.fFunction), fAxis(ax.fAxis) { } //////////////////////////////////////////////////////////////////////////////// /// 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; 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; } 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; 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 *coded; char chlabel[256]; char kchtemp[256]; char chcoded[8]; 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; } } 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) { 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 = -1; //automatic determination of daylight saving time TString tz = (TString)gSystem->Getenv("TZ"); //save timezone Bool_t isUTC = kFALSE; if (gSystem->Getenv("TZ") && tz.Length()==0) isUTC=kTRUE; gSystem->Setenv("TZ", "UTC"); //sets timezone to UTC tzset(); timeoffset = mktime(&tp); //restore TZ if (tz.Length()) { gSystem->Setenv("TZ", tz.Data()); } else { if (isUTC) gSystem->Setenv("TZ", ""); else gSystem->Unsetenv("TZ"); } tzset(); // 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 n1a = ndiv%100; n2a = (ndiv%10000 - n1a)/100; n3a = ndiv/10000; nn3 = TMath::Max(n3a,1); nn2 = TMath::Max(n2a,1)*nn3; nn1 = TMath::Max(n1a,1)*nn2+1; nticks= nn1; // 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; } // Return wmin, wmax and the number of primary divisions if (optionX) { ndiv = n1a; return; } Int_t maxDigits = fgMaxDigits; TLatex *textaxis = new TLatex(); SetLineStyle(1); // axis line style textaxis->SetTextColor(GetTextColor()); textaxis->SetTextFont(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) { phi = 0.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); } // Draw axis title if it exists if (!drawGridOnly && strlen(GetTitle())) { textaxis->SetTextSize (GetTitleSize()); charheight = GetTitleSize(); if ((GetTextFont() % 10) > 2) { charheight = charheight/gPad->GetWh(); } Double_t toffset = GetTitleOffset(); //////if (toffset < 0.1) toffset = 1; // Negative offset should be allowed if (x1 == x0) ylabel = xlside*1.6*charheight*toffset; else ylabel = xlside*1.3*charheight*toffset; if (y1 == y0) 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); Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1); } else { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(32); Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1); } textaxis->PaintLatex(gPad->GetX1() + xpl1*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + ypl1*(gPad->GetY2() - gPad->GetY1()), phil=(kPI+phil)*180/kPI, GetTitleSize(), GetTitle()); } else { if (x1 >= x0) { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(32); Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1); } else { if (TestBit(TAxis::kCenterTitle)) textaxis->SetTextAlign(22); else textaxis->SetTextAlign(12); Rotate(axispos,ylabel,cosphi,sinphi,x0,y0,xpl1,ypl1); } textaxis->PaintLatex(gPad->GetX1() + xpl1*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + ypl1*(gPad->GetY2() - gPad->GetY1()), phil*180/kPI, GetTitleSize(), GetTitle()); } } // 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); Double_t s = -3; if (ymin == gPad->GetUymax()) { if (angle == 0) textaxis->SetTextAlign(21); s = 3; } textaxis->PaintLatex(fAxis->GetBinCenter(i), ymin + s*fAxis->GetLabelOffset()*(gPad->GetUymax()-gPad->GetUymin()), angle, textaxis->GetTextSize(), fAxis->GetBinLabel(i)); } 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; } 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; } 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++; } coded = &chcoded[0]; if (if1 > 14) if1=14; if (if2 > 14) if2=14; if (if2>0) snprintf(coded,8,"%%%d.%df",if1,if2); else snprintf(coded,8,"%%%d.%df",if1+1,1); } // 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[0],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"); } strftime(label, 256, timeformattmp.Data(), utctis); 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], 256); typolabel = chtemp; if (!optionTime) typolabel.ReplaceAll("-", "#minus"); textaxis->PaintLatex(gPad->GetX1() + xx*(gPad->GetX2() - gPad->GetX1()), gPad->GetY1() + yy*(gPad->GetY2() - gPad->GetY1()), 0, textaxis->GetTextSize(), typolabel.Data()); } 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 = x1-x0+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++; 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) { textaxis->PaintTextNDC(xx,yy,"1"); } else if (labelnumber == 1) { textaxis->PaintTextNDC(xx,yy,"10"); } else { if (noExponent) { textaxis->PaintTextNDC(xx,yy,&label[first]); } else { snprintf(chtemp,256, "10^{%d}", labelnumber); 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()); } } } 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) 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(); } } //////////////////////////////////////////////////////////////////////////////// /// 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); strftime(tmp, 20,"%Y-%m-%d %H:%M:%S",utctis); fTimeFormat.Append(tmp); // 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); } }