Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGraphPainter.cxx
Go to the documentation of this file.
1 // @(#)root/histpainter:$Id: TGraphPainter.cxx,v 1.00
2 // Author: Olivier Couet
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TROOT.h"
13 #include "TGraphPainter.h"
14 #include "TMath.h"
15 #include "TGraph.h"
16 #include "TPolyLine.h"
17 #include "TPolyMarker.h"
18 #include "TCanvas.h"
19 #include "TView.h"
20 #include "TStyle.h"
21 #include "TH1.h"
22 #include "TF1.h"
23 #include "TPaveStats.h"
24 #include "TGaxis.h"
25 #include "TGraphAsymmErrors.h"
26 #include "TGraphMultiErrors.h"
27 #include "TGraphBentErrors.h"
28 #include "TGraphPolargram.h"
29 #include "TGraphPolar.h"
30 #include "TGraphQQ.h"
31 #include "TLatex.h"
32 #include "TArrow.h"
33 #include "TFrame.h"
34 #include "TMarker.h"
35 #include "TVirtualPadEditor.h"
36 #include "TRegexp.h"
37 
38 Double_t *gxwork, *gywork, *gxworkl, *gyworkl;
39 Int_t TGraphPainter::fgMaxPointsPerLine = 50;
40 
41 static Int_t gHighlightPoint = -1; // highlight point of graph
42 static TGraph *gHighlightGraph = 0; // pointer to graph with highlight point
43 static TMarker *gHighlightMarker = 0; // highlight marker
44 
45 ClassImp(TGraphPainter);
46 
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 
50 /*! \class TGraphPainter
51  \ingroup Histpainter
52  \brief The graph painter class. Implements all graphs' drawing's options.
53 
54 - [Introduction](#GP00)
55 - [Graphs' plotting options](#GP01)
56 - [Exclusion graphs](#GP02)
57 - [Graphs with error bars](#GP03)
58  - [TGraphErrors](#GP03a)
59  - [TGraphAsymmErrors](#GP03b)
60  - [TGraphBentErrors](#GP03c)
61  - [TGraphMultiErrors](#GP03d)
62 - [TGraphPolar options](#GP04)
63 - [Colors automatically picked in palette](#GP05)
64 - [Reverse graphs' axis](#GP06)
65 - [Graphs in logarithmic scale](#GP07)
66 - [Highlight mode for graph](#GP08)
67 
68 
69 ### <a name="GP00"></a> Introduction
70 
71 Graphs are drawn via the painter `TGraphPainter` class. This class
72 implements techniques needed to display the various kind of
73 graphs i.e.: `TGraph`, `TGraphErrors`, `TGraphBentErrors` and `TGraphAsymmErrors`.
74 
75 To draw a graph `graph` it's enough to do:
76 
77  graph->Draw("AL");
78 
79 The option `AL` in the `Draw()` method means:
80 
81 1. The axis should be drawn (option `A`),
82 2. The graph should be drawn as a simple line (option `L`).
83 
84  By default a graph is drawn in the current pad in the current coordinate system.
85 To define a suitable coordinate system and draw the axis the option
86 `A` must be specified.
87 
88 `TGraphPainter` offers many options to paint the various kind of graphs.
89 
90 It is separated from the graph classes so that one can have graphs without the
91 graphics overhead, for example in a batch program.
92 
93 When a displayed graph is modified, there is no need to call `Draw()` again; the
94 image will be refreshed the next time the pad will be updated. A pad is updated
95 after one of these three actions:
96 
97 1. a carriage return on the ROOT command line,
98 2. a click inside the pad,
99 3. a call to `TPad::Update`.
100 
101 ### <a name="GP01"></a> Graphs' plotting options
102 Graphs can be drawn with the following options:
103 
104 | Option | Description |
105 |----------|-------------------------------------------------------------------|
106 | "A" | Axis are drawn around the graph |
107 | "I" | Combine with option 'A' it draws invisible axis |
108 | "L" | A simple polyline is drawn |
109 | "F" | A fill area is drawn ('CF' draw a smoothed fill area) |
110 | "C" | A smooth Curve is drawn |
111 | "*" | A Star is plotted at each point |
112 | "P" | The current marker is plotted at each point |
113 | "B" | A Bar chart is drawn |
114 | "1" | When a graph is drawn as a bar chart, this option makes the bars start from the bottom of the pad. By default they start at 0. |
115 | "X+" | The X-axis is drawn on the top side of the plot. |
116 | "Y+" | The Y-axis is drawn on the right side of the plot. |
117 | "PFC" | Palette Fill Color: graph's fill color is taken in the current palette. |
118 | "PLC" | Palette Line Color: graph's line color is taken in the current palette. |
119 | "PMC" | Palette Marker Color: graph's marker color is taken in the current palette. |
120 | "RX" | Reverse the X axis. |
121 | "RY" | Reverse the Y axis. |
122 
123 Drawing options can be combined. In the following example the graph
124 is drawn as a smooth curve (option "C") with markers (option "P") and
125 with axes (option "A").
126 
127 Begin_Macro(source)
128 {
129  auto c1 = new TCanvas("c1","c1",200,10,600,400);
130 
131  c1->SetFillColor(42);
132  c1->SetGrid();
133 
134  const Int_t n = 20;
135  Double_t x[n], y[n];
136  for (Int_t i=0;i<n;i++) {
137  x[i] = i*0.1;
138  y[i] = 10*sin(x[i]+0.2);
139  }
140  gr = new TGraph(n,x,y);
141  gr->SetLineColor(2);
142  gr->SetLineWidth(4);
143  gr->SetMarkerColor(4);
144  gr->SetMarkerSize(1.5);
145  gr->SetMarkerStyle(21);
146  gr->SetTitle("Option ACP example");
147  gr->GetXaxis()->SetTitle("X title");
148  gr->GetYaxis()->SetTitle("Y title");
149  gr->Draw("ACP");
150 
151  // TCanvas::Update() draws the frame, after which one can change it
152  c1->Update();
153  c1->GetFrame()->SetFillColor(21);
154  c1->GetFrame()->SetBorderSize(12);
155  c1->Modified();
156 }
157 End_Macro
158 
159 The following macro shows the option "B" usage. It can be combined with the
160 option "1".
161 
162 Begin_Macro(source)
163 {
164  auto c47 = new TCanvas("c47","c47",200,10,600,400);
165  c47->Divide(1,2);
166  const Int_t n = 20;
167  Double_t x[n], y[n];
168  for (Int_t i=0;i<n;i++) {
169  x[i] = i*0.1;
170  y[i] = 10*sin(x[i]+0.2)-6;
171  }
172  auto gr = new TGraph(n,x,y);
173  gr->SetFillColor(38);
174  c47->cd(1); gr->Draw("AB");
175  c47->cd(2); gr->Draw("AB1");
176 }
177 End_Macro
178 
179 ### <a name="GP02"></a> Exclusion graphs
180 
181 When a graph is painted with the option `C` or `L` it is
182 possible to draw a filled area on one side of the line. This is useful to show
183 exclusion zones.
184 
185 This drawing mode is activated when the absolute value of the graph line
186 width (set by `SetLineWidth()`) is greater than 99. In that
187 case the line width number is interpreted as:
188 
189  100*ff+ll = ffll
190 
191 - The two digits number `ll` represent the normal line width
192 - The two digits number `ff` represent the filled area width.
193 - The sign of "ffll" allows to flip the filled area from one side of the line to the other.
194 
195 The current fill area attributes are used to draw the hatched zone.
196 
197 Begin_Macro(source)
198 ../../../tutorials/graphs/exclusiongraph.C
199 End_Macro
200 
201 ### <a name="GP03"></a> Graphs with error bars
202 Three classes are available to handle graphs with error bars:
203 `TGraphErrors`, `TGraphAsymmErrors` and `TGraphBentErrors`.
204 The following drawing options are specific to graphs with error bars:
205 
206 | Option | Description |
207 |----------|-------------------------------------------------------------------|
208 | "Z" | Do not draw small horizontal and vertical lines the end of the error bars. Without "Z", the default is to draw these. |
209 | ">" | An arrow is drawn at the end of the error bars. The size of the arrow is set to 2/3 of the marker size. |
210 | \"\|>\" | A filled arrow is drawn at the end of the error bars. The size of the arrow is set to 2/3 of the marker size. |
211 | "X" | Do not draw error bars. By default, graph classes that have errors are drawn with the errors (TGraph itself has no errors, and so this option has no effect.) |
212 | \"\|\|\" | Draw only the small vertical/horizontal lines at the ends of the error bars, without drawing the bars themselves. This option is interesting to superimpose statistical-only errors on top of a graph with statistical+systematic errors. |
213 | "[]" | Does the same as option \"\|\|\" except that it draws additional marks at the ends of the small vertical/horizontal lines. It makes plots less ambiguous in case several graphs are drawn on the same picture. |
214 | "0" | By default, when a data point is outside the visible range along the Y axis, the error bars are not drawn. This option forces error bars' drawing for the data points outside the visible range along the Y axis (see example below). |
215 | "2" | Error rectangles are drawn. |
216 | "3" | A filled area is drawn through the end points of the vertical error bars. |
217 | "4" | A smoothed filled area is drawn through the end points of the vertical error bars. |
218 | "5" | Error rectangles are drawn like option "2". In addition the contour line around the boxes is drawn. This can be useful when boxes' fill colors are very light or in gray scale mode. |
219 
220 
221 `gStyle->SetErrorX(dx)` controls the size of the error along x.
222 `dx = 0` removes the error along x.
223 
224 `gStyle->SetEndErrorSize(np)` controls the size of the lines
225 at the end of the error bars (when option 1 is used).
226 By default `np=1`. (np represents the number of pixels).
227 
228 #### <a name="GP03a"></a> TGraphErrors
229 
230 A `TGraphErrors` is a `TGraph` with error bars. The errors are
231 defined along X and Y and are symmetric: The left and right errors are the same
232 along X and the bottom and up errors are the same along Y.
233 
234 Begin_Macro(source)
235 {
236  auto c4 = new TCanvas("c4","c4",200,10,600,400);
237  double x[] = {0, 1, 2, 3, 4};
238  double y[] = {0, 2, 4, 1, 3};
239  double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
240  double ey[] = {1, 0.5, 1, 0.5, 1};
241  auto ge = new TGraphErrors(5, x, y, ex, ey);
242  ge->Draw("ap");
243 }
244 End_Macro
245 
246 The option "0" shows the error bars for data points outside range.
247 
248 Begin_Macro(source)
249 {
250  auto c48 = new TCanvas("c48","c48",200,10,600,400);
251  float x[] = {1,2,3};
252  float err_x[] = {0,0,0};
253  float err_y[] = {5,5,5};
254  float y[] = {1,4,9};
255  auto tg = new TGraphErrors(3,x,y,err_x,err_y);
256  c48->Divide(2,1);
257  c48->cd(1); gPad->DrawFrame(0,0,4,8); tg->Draw("PC");
258  c48->cd(2); gPad->DrawFrame(0,0,4,8); tg->Draw("0PC");
259 }
260 End_Macro
261 
262 The option "3" shows the errors as a band.
263 
264 Begin_Macro(source)
265 {
266  auto c41 = new TCanvas("c41","c41",200,10,600,400);
267  double x[] = {0, 1, 2, 3, 4};
268  double y[] = {0, 2, 4, 1, 3};
269  double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
270  double ey[] = {1, 0.5, 1, 0.5, 1};
271  auto ge = new TGraphErrors(5, x, y, ex, ey);
272  ge->SetFillColor(4);
273  ge->SetFillStyle(3010);
274  ge->Draw("a3");
275 }
276 End_Macro
277 
278 The option "4" is similar to the option "3" except that the band
279 is smoothed. As the following picture shows, this option should be
280 used carefully because the smoothing algorithm may show some (huge)
281 "bouncing" effects. In some cases it looks nicer than option "3"
282 (because it is smooth) but it can be misleading.
283 
284 Begin_Macro(source)
285 {
286  auto c42 = new TCanvas("c42","c42",200,10,600,400);
287  double x[] = {0, 1, 2, 3, 4};
288  double y[] = {0, 2, 4, 1, 3};
289  double ex[] = {0.1, 0.2, 0.3, 0.4, 0.5};
290  double ey[] = {1, 0.5, 1, 0.5, 1};
291  auto ge = new TGraphErrors(5, x, y, ex, ey);
292  ge->SetFillColor(6);
293  ge->SetFillStyle(3005);
294  ge->Draw("a4");
295 }
296 End_Macro
297 
298 The following example shows how the option "[]" can be used to superimpose
299 systematic errors on top of a graph with statistical errors.
300 
301 Begin_Macro(source)
302 {
303  auto c43 = new TCanvas("c43","c43",200,10,600,400);
304  c43->DrawFrame(0., -0.5, 6., 2);
305 
306  double x[5] = {1, 2, 3, 4, 5};
307  double zero[5] = {0, 0, 0, 0, 0};
308 
309  // data set (1) with stat and sys errors
310  double py1[5] = {1.2, 1.15, 1.19, 0.9, 1.4};
311  double ey_stat1[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
312  double ey_sys1[5] = {0.5, 0.71, 0.76, 0.5, 0.45};
313 
314  // data set (2) with stat and sys errors
315  double y2[5] = {0.25, 0.18, 0.29, 0.2, 0.21};
316  double ey_stat2[5] = {0.2, 0.18, 0.17, 0.2, 0.4};
317  double ey_sys2[5] = {0.63, 0.19, 0.7, 0.2, 0.7};
318 
319  // Now draw data set (1)
320 
321  // We first have to draw it only with the stat errors
322  auto graph1 = new TGraphErrors(5, x, py1, zero, ey_stat1);
323  graph1->SetMarkerStyle(20);
324  graph1->Draw("P");
325 
326  // Now we have to somehow depict the sys errors
327 
328  auto graph1_sys = new TGraphErrors(5, x, py1, zero, ey_sys1);
329  graph1_sys->Draw("[]");
330 
331  // Now draw data set (2)
332 
333  // We first have to draw it only with the stat errors
334  auto graph2 = new TGraphErrors(5, x, y2, zero, ey_stat2);
335  graph2->SetMarkerStyle(24);
336  graph2->Draw("P");
337 
338  // Now we have to somehow depict the sys errors
339 
340  auto graph2_sys = new TGraphErrors(5, x, y2, zero, ey_sys2);
341  graph2_sys->Draw("[]");
342 }
343 End_Macro
344 
345 #### <a name="GP03b"></a> TGraphAsymmErrors
346 A `TGraphAsymmErrors` is like a `TGraphErrors` but the errors
347 defined along X and Y are not symmetric: The left and right errors are
348 different along X and the bottom and up errors are different along Y.
349 
350 Begin_Macro(source)
351 {
352  auto c44 = new TCanvas("c44","c44",200,10,600,400);
353  double ax[] = {0, 1, 2, 3, 4};
354  double ay[] = {0, 2, 4, 1, 3};
355  double aexl[] = {0.1, 0.2, 0.3, 0.4, 0.5};
356  double aexh[] = {0.5, 0.4, 0.3, 0.2, 0.1};
357  double aeyl[] = {1, 0.5, 1, 0.5, 1};
358  double aeyh[] = {0.5, 1, 0.5, 1, 0.5};
359  auto gae = new TGraphAsymmErrors(5, ax, ay, aexl, aexh, aeyl, aeyh);
360  gae->SetFillColor(2);
361  gae->SetFillStyle(3001);
362  gae->Draw("a2");
363  gae->Draw("p");
364 }
365 End_Macro
366 
367 
368 #### <a name="GP03c"></a> TGraphBentErrors
369 A `TGraphBentErrors` is like a `TGraphAsymmErrors`.
370 An extra parameter allows to bend the error bars to better see them
371 when several graphs are drawn on the same plot.
372 
373 Begin_Macro(source)
374 {
375  auto c45 = new TCanvas("c45","c45",200,10,600,400);
376  const Int_t n = 10;
377  Double_t x[n] = {-0.22, 0.05, 0.25, 0.35, 0.5, 0.61,0.7,0.85,0.89,0.95};
378  Double_t y[n] = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};
379  Double_t exl[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
380  Double_t eyl[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
381  Double_t exh[n] = {.02,.08,.05,.05,.03,.03,.04,.05,.06,.03};
382  Double_t eyh[n] = {.6,.5,.4,.3,.2,.2,.3,.4,.5,.6};
383  Double_t exld[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
384  Double_t eyld[n] = {.0,.0,.05,.0,.0,.0,.0,.0,.0,.0};
385  Double_t exhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.0,.0};
386  Double_t eyhd[n] = {.0,.0,.0,.0,.0,.0,.0,.0,.05,.0};
387  auto gr = new TGraphBentErrors(n,x,y,exl,exh,eyl,eyh,exld,exhd,eyld,eyhd);
388  gr->SetTitle("TGraphBentErrors Example");
389  gr->SetMarkerColor(4);
390  gr->SetMarkerStyle(21);
391  gr->Draw("ALP");
392 }
393 End_Macro
394 
395 
396 #### <a name="GP03d"></a> TGraphMultiErrors
397 A `TGraphMultiErrors` works basically the same way like a `TGraphAsymmErrors`.
398 It has the possibility to define more than one type / dimension of y-Errors.
399 This is useful if you want to plot statistic and systematic errors at once.
400 
401 To be able to define different drawing options for the multiple error dimensions
402 the option string can consist of multiple blocks separated by semicolons.
403 The painting method assigns these blocks to the error dimensions. The first block
404 is always used for the general draw options and options concerning the x-Errors.
405 In case there are less than NErrorDimensions + 1 blocks in the option string
406 the first block is also used for the first error dimension which is reserved for
407 statistical errors. The remaining blocks are assigned to the remaining dimensions.
408 
409 In addition to the draw options of options of `TGraphAsymmErrors` the following are possible:
410 
411 | Option | Block | Description |
412 |----------|----------------|-------------------------------------------------------------------|
413 | "X0" | First one only | Do not draw errors for points with x = 0 |
414 | "Y0" | First one only | Do not draw errors for points with y = 0 |
415 | "s=%f" | Any | Scales the x-Errors with %f similar to `gStyle->SetErrorX(dx)` but does not affect them directly (Useful when used in addition with box errors to make the box only half as wide as the x-Errors e.g. s=0.5) |
416 | "S" | First one only | Use individual TAttFill and TAttLine attributes for the different error dimensions instead of the global ones. |
417 
418 
419 Per default the Fill and Line Styles of the Graph are being used for all error
420 dimensions. To use the specific ones add the draw option "S" to the first block.
421 
422 Begin_Macro(source)
423 {
424  auto c47 = new TCanvas("c47","c47",200,10,600,400);
425  double ax[] = {0, 1, 2, 3, 4};
426  double ay[] = {0, 2, 4, 1, 3};
427  double aexl[] = {0.3, 0.3, 0.3, 0.3, 0.3};
428  double aexh[] = {0.3, 0.3, 0.3, 0.3, 0.3};
429  double* aeylstat = new double[5] {1, 0.5, 1, 0.5, 1};
430  double* aeyhstat = new double[5] {0.5, 1, 0.5, 1, 0.5};
431  double* aeylsys = new double[5] {0.5, 0.4, 0.8, 0.3, 1.2};
432  double* aeyhsys = new double[5] {0.6, 0.7, 0.6, 0.4, 0.8};
433 
434  TGraphMultiErrors* gme = new TGraphMultiErrors("gme", "TGraphMultiErrors Example", 5, ax, ay, aexl, aexh, aeylstat, aeyhstat);
435  gme->AddYError(5, aeylsys, aeyhsys);
436  gme->SetMarkerStyle(20);
437  gme->SetLineColor(kRed);
438  gme->GetAttLine(0)->SetLineColor(kRed);
439  gme->GetAttLine(1)->SetLineColor(kBlue);
440  gme->GetAttFill(1)->SetFillStyle(0);
441 
442  gme->Draw("a p s ; ; 5 s=0.5");
443 }
444 End_Macro
445 
446 
447 ### <a name="GP04"></a> TGraphPolar options
448 
449 The drawing options for the polar graphs are the following:
450 
451 | Option | Description |
452 |----------|-------------------------------------------------------------------|
453 | "O" | Polar labels are drawn orthogonally to the polargram radius. |
454 | "P" | Polymarker are drawn at each point position. |
455 | "E" | Draw error bars. |
456 | "F" | Draw fill area (closed polygon). |
457 | "A" | Force axis redrawing even if a polargram already exists. |
458 | "N" | Disable the display of the polar labels. |
459 
460 
461 Begin_Macro(source)
462 {
463  auto c46 = new TCanvas("c46","c46",500,500);
464  auto grP1 = new TGraphPolar();
465  grP1->SetTitle("TGraphPolar example");
466 
467  grP1->SetPoint(0, (1*TMath::Pi())/4., 0.05);
468  grP1->SetPoint(1, (2*TMath::Pi())/4., 0.10);
469  grP1->SetPoint(2, (3*TMath::Pi())/4., 0.15);
470  grP1->SetPoint(3, (4*TMath::Pi())/4., 0.20);
471  grP1->SetPoint(4, (5*TMath::Pi())/4., 0.25);
472  grP1->SetPoint(5, (6*TMath::Pi())/4., 0.30);
473  grP1->SetPoint(6, (7*TMath::Pi())/4., 0.35);
474  grP1->SetPoint(7, (8*TMath::Pi())/4., 0.40);
475 
476  grP1->SetMarkerStyle(20);
477  grP1->SetMarkerSize(1.);
478  grP1->SetMarkerColor(4);
479  grP1->SetLineColor(4);
480  grP1->Draw("ALP");
481 
482  // Update, otherwise GetPolargram returns 0
483  c46->Update();
484  grP1->GetPolargram()->SetToRadian();
485 }
486 End_Macro
487 
488 ### <a name="GP05"></a> Colors automatically picked in palette
489 
490 \since **ROOT version 6.09/01**
491 
492 When several graphs are painted in the same canvas or when a multi-graph is drawn,
493 it might be useful to have an easy and automatic way to choose
494 their color. The simplest way is to pick colors in the current active color
495 palette. Palette coloring for histogram is activated thanks to the options `PFC`
496 (Palette Fill Color), `PLC` (Palette Line Color) and `PMC` (Palette Marker Color).
497 When one of these options is given to `TGraph::Draw` the graph get its color
498 from the current color palette defined by `gStyle->SetPalette(…)`. The color
499 is determined according to the number of objects having palette coloring in
500 the current pad.
501 
502 Begin_Macro(source)
503 ../../../tutorials/graphs/graphpalettecolor.C
504 End_Macro
505 
506 Begin_Macro(source)
507 ../../../tutorials/graphs/multigraphpalettecolor.C
508 End_Macro
509 
510 ### <a name="GP06"></a> Reverse graphs' axis
511 
512 \since **ROOT version 6.09/03**
513 
514 When a TGraph is drawn, the X-axis is drawn with increasing values from left to
515 right and the Y-axis from bottom to top. The two options `RX` and `RY` allow to
516 change this order. The option `RX` allows to draw the X-axis with increasing values
517 from right to left and the `RY` option allows to draw the Y-axis with increasing
518 values from top to bottom. The following example illustrate how to use these options.
519 
520 Begin_Macro(source)
521 {
522  auto c = new TCanvas();
523  c->Divide(2,1);
524  auto g = new TGraphErrors();
525  g->SetTitle("Simple Graph");
526 
527  g->SetPoint(0,-4,-3);
528  g->SetPoint(1,1,1);
529  g->SetPoint(2,2,1);
530  g->SetPoint(3,3,4);
531  g->SetPoint(4,5,5);
532 
533  g->SetPointError(0,1.,2.);
534  g->SetPointError(1,2,1);
535  g->SetPointError(2,2,3);
536  g->SetPointError(3,3,2);
537  g->SetPointError(4,4,5);
538 
539  g->GetXaxis()->SetNdivisions(520);
540 
541  g->SetMarkerStyle(21);
542  c->cd(1); gPad->SetGrid(1,1);
543  g->Draw("APL");
544 
545  c->cd(2); gPad->SetGrid(1,1);
546  g->Draw("A RX RY PL");
547 }
548 End_Macro
549 
550 ### <a name="GP07"></a> Graphs in logarithmic scale
551 
552 Like histograms, graphs can be drawn in logarithmic scale along X and Y. When
553 a pad is set to logarithmic scale with TPad::SetLogx() and/or with TPad::SetLogy()
554 the points building the graph are converted into logarithmic scale. But **only** the
555 points not the lines connecting them which stay linear. This can be clearly seen
556 on the following example:
557 
558 Begin_Macro(source)
559 {
560  // A graph with 3 points
561  Double_t xmin = 750.;
562  Double_t xmax = 1000;
563  auto g = new TGraph(3);
564  g->SetPoint(0,xmin,0.1);
565  g->SetPoint(1,845,0.06504);
566  g->SetPoint(2,xmax,0.008);
567 
568  // The same graph with n points
569  Int_t n = 10000;
570  Double_t dx = (xmax-xmin)/n;
571  Double_t x = xmin;
572  auto g2 = new TGraph();
573  for (Int_t i=0; i<n; i++) {
574  g2->SetPoint(i, x, g->Eval(x));
575  x = x + dx;
576  }
577 
578  auto cv = new TCanvas("cv","cv",800,600);
579  cv->SetLogy();
580  cv->SetGridx();
581  cv->SetGridy();
582  g->Draw("AL*");
583 
584  g2->SetMarkerColor(kRed);
585  g2->SetMarkerStyle(1);
586  g2->Draw("P");
587 }
588 
589 End_Macro
590 
591 #### <a name="GP08"></a> Highlight mode for graph
592 
593 \since **ROOT version 6.15/01**
594 
595 \image html hlGraph1.gif "Highlight mode"
596 
597 Highlight mode is implemented for `TGraph` (and for `TH1`) class. When
598 highlight mode is on, mouse movement over the point will be represented
599 graphically. Point will be highlighted as "point circle" (presented by
600 marker object). Moreover, any highlight (change of point) emits signal
601 `TCanvas::Highlighted()` which allows the user to react and call their own
602 function. For a better understanding please see also the tutorials
603 `$ROOTSYS/tutorials/graphs/hlGraph*.C` files.
604 
605 Highlight mode is switched on/off by `TGraph::SetHighlight()` function
606 or interactively from `TGraph` context menu. `TGraph::IsHighlight()` to verify
607 whether the highlight mode enabled or disabled, default it is disabled.
608 
609 ~~~ {.cpp}
610  root [0] .x $ROOTSYS/tutorials/graphs/gerrors2.C
611  root [1] // try SetHighlight() interactively from TGraph context menu
612 ~~~
613 
614 \image html hlgerrors2.gif "Highlight mode for graph"
615 
616 See how it is used
617 <a href="classTHistPainter.html#HP30a">highlight mode and user function</a>
618 (is fully equivalent as for histogram).
619 
620 NOTE all parameters of user function are taken from
621 
622  void TCanvas::Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
623 
624  - `pad` is pointer to pad with highlighted graph
625  - `obj` is pointer to highlighted graph
626  - `x` is highlighted x-th (i-th) point for graph
627  - `y` not in use (only for 2D histogram)
628 
629 For more complex demo please see for example `$ROOTSYS/tutorials/math/hlquantiles.C` file.
630 
631 */
632 
633 
634 ////////////////////////////////////////////////////////////////////////////////
635 /// Default constructor
636 
637 TGraphPainter::TGraphPainter()
638 {
639 }
640 
641 
642 ////////////////////////////////////////////////////////////////////////////////
643 /// Destructor.
644 
645 TGraphPainter::~TGraphPainter()
646 {
647 }
648 
649 
650 ////////////////////////////////////////////////////////////////////////////////
651 /// Compute the logarithm of global variables `gxwork` and `gywork`
652 /// according to the value of Options and put the results in the global
653 /// variables `gxworkl` and `gyworkl`.
654 ///
655 /// npoints : Number of points in gxwork and in gywork.
656 ///
657 /// - opt = 1 ComputeLogs is called from PaintGrapHist
658 /// - opt = 0 ComputeLogs is called from PaintGraph
659 
660 void TGraphPainter::ComputeLogs(Int_t npoints, Int_t opt)
661 {
662 
663 
664  Int_t i;
665  memcpy(gxworkl,gxwork,npoints*8);
666  memcpy(gyworkl,gywork,npoints*8);
667  if (gPad->GetLogx()) {
668  for (i=0;i<npoints;i++) {
669  if (gxworkl[i] > 0) gxworkl[i] = TMath::Log10(gxworkl[i]);
670  else gxworkl[i] = gPad->GetX1();
671  }
672  }
673  if (!opt && gPad->GetLogy()) {
674  for (i=0;i<npoints;i++) {
675  if (gyworkl[i] > 0) gyworkl[i] = TMath::Log10(gyworkl[i]);
676  else gyworkl[i] = gPad->GetY1();
677  }
678  }
679 }
680 
681 
682 ////////////////////////////////////////////////////////////////////////////////
683 /// Compute distance from point px,py to a graph.
684 ///
685 /// Compute the closest distance of approach from point px,py to this line.
686 /// The distance is computed in pixels units.
687 
688 Int_t TGraphPainter::DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py)
689 {
690 
691  // Are we on the axis?
692  Int_t distance;
693  if (theGraph->GetHistogram()) {
694  distance = theGraph->GetHistogram()->DistancetoPrimitive(px,py);
695  if (distance <= 5) return distance;
696  }
697 
698  // Somewhere on the graph points?
699  const Int_t big = 9999;
700  const Int_t kMaxDiff = 10;
701  Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
702  Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
703  Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
704  Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());
705 
706  // return if point is not in the graph area
707  if (px <= puxmin) return big;
708  if (py >= puymin) return big;
709  if (px >= puxmax) return big;
710  if (py <= puymax) return big;
711 
712  // check if point is near one of the graph points
713  Int_t i, pxp, pyp, d;
714  distance = big;
715 
716  Int_t theNpoints = theGraph->GetN();
717  Double_t *theX, *theY;
718  if (theGraph->InheritsFrom(TGraphPolar::Class())) {
719  TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;
720  theX = theGraphPolar->GetXpol();
721  theY = theGraphPolar->GetYpol();
722  } else {
723  theX = theGraph->GetX();
724  theY = theGraph->GetY();
725  }
726 
727  Int_t hpoint = -1;
728  for (i=0;i<theNpoints;i++) {
729  pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
730  pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
731  d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
732  if (d < distance) {
733  distance = d;
734  hpoint = i;
735  }
736  }
737 
738  if (theGraph->IsHighlight()) // only if highlight is enable
739  HighlightPoint(theGraph, hpoint, distance);
740  if (distance < kMaxDiff) return distance;
741 
742  for (i=0;i<theNpoints-1;i++) {
743  TAttLine l;
744  d = l.DistancetoLine(px, py, gPad->XtoPad(theX[i]), gPad->YtoPad(theY[i]), gPad->XtoPad(theX[i+1]), gPad->YtoPad(theY[i+1]));
745  if (d < distance) distance = d;
746  }
747 
748  // If graph has been drawn with the fill area option, check if we are inside
749  TString drawOption = theGraph->GetDrawOption();
750  drawOption.ToLower();
751  if (drawOption.Contains("f")) {
752  Double_t xp = gPad->AbsPixeltoX(px); xp = gPad->PadtoX(xp);
753  Double_t yp = gPad->AbsPixeltoY(py); yp = gPad->PadtoY(yp);
754  if (TMath::IsInside(xp,yp,theNpoints,theX,theY) != 0) distance = 1;
755  }
756 
757  // Loop on the list of associated functions and user objects
758  TObject *f;
759  TList *functions = theGraph->GetListOfFunctions();
760  TIter next(functions);
761  while ((f = (TObject*) next())) {
762  Int_t dist;
763  if (f->InheritsFrom(TF1::Class())) dist = f->DistancetoPrimitive(-px,py);
764  else dist = f->DistancetoPrimitive(px,py);
765  if (dist < kMaxDiff) {
766  gPad->SetSelected(f);
767  return 0; //must be o and not dist in case of TMultiGraph
768  }
769  }
770 
771  return distance;
772 }
773 
774 
775 ////////////////////////////////////////////////////////////////////////////////
776 /// Display a panel with all histogram drawing options.
777 
778 void TGraphPainter::DrawPanelHelper(TGraph *theGraph)
779 {
780 
781  if (!gPad) {
782  Error("DrawPanel", "need to draw graph first");
783  return;
784  }
785  TVirtualPadEditor *editor = TVirtualPadEditor::GetPadEditor();
786  editor->Show();
787  gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->Selected((TVirtualPad*)0x%lx,(TObject*)0x%lx,1)",
788  (ULong_t)gPad->GetCanvas(), (ULong_t)gPad, (ULong_t)theGraph));
789 }
790 
791 
792 ////////////////////////////////////////////////////////////////////////////////
793 /// Execute action corresponding to one event.
794 ///
795 /// This member function is called when a graph is clicked with the locator.
796 ///
797 /// If the left mouse button is clicked on one of the line end points, this point
798 /// follows the cursor until button is released.
799 ///
800 /// If the middle mouse button clicked, the line is moved parallel to itself
801 /// until the button is released.
802 
803 void TGraphPainter::ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py)
804 {
805 
806  if (!gPad) return;
807 
808  Int_t i, d;
809  Double_t xmin, xmax, ymin, ymax, dx, dy, dxr, dyr;
810  const Int_t kMaxDiff = 10;//3;
811  static Bool_t middle, badcase;
812  static Int_t ipoint, pxp, pyp;
813  static Int_t px1,px2,py1,py2;
814  static Int_t pxold, pyold, px1old, py1old, px2old, py2old;
815  static Int_t dpx, dpy;
816  static Int_t *x=0, *y=0;
817  Bool_t opaque = gPad->OpaqueMoving();
818 
819  if (!theGraph->IsEditable() || theGraph->InheritsFrom(TGraphPolar::Class())) {
820  gPad->SetCursor(kHand);
821  return;
822  }
823  if (!gPad->IsEditable()) return;
824  Int_t theNpoints = theGraph->GetN();
825  Double_t *theX = theGraph->GetX();
826  Double_t *theY = theGraph->GetY();
827 
828  switch (event) {
829 
830  case kButton1Down:
831  badcase = kFALSE;
832  gVirtualX->SetLineColor(-1);
833  theGraph->TAttLine::Modify(); //Change line attributes only if necessary
834  px1 = gPad->XtoAbsPixel(gPad->GetX1());
835  py1 = gPad->YtoAbsPixel(gPad->GetY1());
836  px2 = gPad->XtoAbsPixel(gPad->GetX2());
837  py2 = gPad->YtoAbsPixel(gPad->GetY2());
838  ipoint = -1;
839 
840 
841  if (x || y) break;
842  x = new Int_t[theNpoints+1];
843  y = new Int_t[theNpoints+1];
844  for (i=0;i<theNpoints;i++) {
845  pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
846  pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
847  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
848  pyp < -kMaxPixel || pyp >= kMaxPixel) {
849  badcase = kTRUE;
850  continue;
851  }
852  if (!opaque) {
853  gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
854  gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4, pyp+4);
855  gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4, pyp+4);
856  gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4, pyp-4);
857  }
858  x[i] = pxp;
859  y[i] = pyp;
860  d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
861  if (d < kMaxDiff) ipoint =i;
862  }
863  dpx = 0;
864  dpy = 0;
865  pxold = px;
866  pyold = py;
867  if (ipoint < 0) return;
868  if (ipoint == 0) {
869  px1old = 0;
870  py1old = 0;
871  px2old = gPad->XtoAbsPixel(theX[1]);
872  py2old = gPad->YtoAbsPixel(theY[1]);
873  } else if (ipoint == theNpoints-1) {
874  px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[theNpoints-2]));
875  py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[theNpoints-2]));
876  px2old = 0;
877  py2old = 0;
878  } else {
879  px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint-1]));
880  py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint-1]));
881  px2old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint+1]));
882  py2old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint+1]));
883  }
884  pxold = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint]));
885  pyold = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint]));
886 
887  break;
888 
889 
890  case kMouseMotion:
891 
892  middle = kTRUE;
893  for (i=0;i<theNpoints;i++) {
894  pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
895  pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
896  d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
897  if (d < kMaxDiff) middle = kFALSE;
898  }
899 
900 
901  // check if point is close to an axis
902  if (middle) gPad->SetCursor(kMove);
903  else gPad->SetCursor(kHand);
904  break;
905 
906  case kButton1Motion:
907  if (!opaque) {
908  if (middle) {
909  for(i=0;i<theNpoints-1;i++) {
910  gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
911  pxp = x[i]+dpx;
912  pyp = y[i]+dpy;
913  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
914  pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
915  gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
916  gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4, pyp+4);
917  gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4, pyp+4);
918  gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4, pyp-4);
919  }
920  pxp = x[theNpoints-1]+dpx;
921  pyp = y[theNpoints-1]+dpy;
922  gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
923  gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4, pyp+4);
924  gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4, pyp+4);
925  gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4, pyp-4);
926  dpx += px - pxold;
927  dpy += py - pyold;
928  pxold = px;
929  pyold = py;
930  for(i=0;i<theNpoints-1;i++) {
931  gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
932  pxp = x[i]+dpx;
933  pyp = y[i]+dpy;
934  if (pxp < -kMaxPixel || pxp >= kMaxPixel ||
935  pyp < -kMaxPixel || pyp >= kMaxPixel) continue;
936  gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
937  gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4, pyp+4);
938  gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4, pyp+4);
939  gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4, pyp-4);
940  }
941  pxp = x[theNpoints-1]+dpx;
942  pyp = y[theNpoints-1]+dpy;
943  gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
944  gVirtualX->DrawLine(pxp+4, pyp-4, pxp+4, pyp+4);
945  gVirtualX->DrawLine(pxp+4, pyp+4, pxp-4, pyp+4);
946  gVirtualX->DrawLine(pxp-4, pyp+4, pxp-4, pyp-4);
947  } else {
948  if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
949  if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
950  gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4, pyold-4);
951  gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4, pyold+4);
952  gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4, pyold+4);
953  gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4, pyold-4);
954  pxold = px;
955  pxold = TMath::Max(pxold, px1);
956  pxold = TMath::Min(pxold, px2);
957  pyold = py;
958  pyold = TMath::Max(pyold, py2);
959  pyold = TMath::Min(pyold, py1);
960  if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
961  if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
962  gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4, pyold-4);
963  gVirtualX->DrawLine(pxold+4, pyold-4, pxold+4, pyold+4);
964  gVirtualX->DrawLine(pxold+4, pyold+4, pxold-4, pyold+4);
965  gVirtualX->DrawLine(pxold-4, pyold+4, pxold-4, pyold-4);
966  }
967  } else {
968  xmin = gPad->GetUxmin();
969  xmax = gPad->GetUxmax();
970  ymin = gPad->GetUymin();
971  ymax = gPad->GetUymax();
972  dx = xmax-xmin;
973  dy = ymax-ymin;
974  dxr = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
975  dyr = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
976 
977  if (theGraph->GetHistogram()) {
978  // Range() could change the size of the pad pixmap and therefore should
979  // be called before the other paint routines
980  gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
981  ymin - dyr*gPad->GetBottomMargin(),
982  xmax + dxr*gPad->GetRightMargin(),
983  ymax + dyr*gPad->GetTopMargin());
984  gPad->RangeAxis(xmin, ymin, xmax, ymax);
985  }
986  if (middle) {
987  dpx += px - pxold;
988  dpy += py - pyold;
989  pxold = px;
990  pyold = py;
991  for(i=0;i<theNpoints;i++) {
992  if (badcase) continue; //do not update if big zoom and points moved
993  if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
994  if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
995  }
996  } else {
997  pxold = px;
998  pxold = TMath::Max(pxold, px1);
999  pxold = TMath::Min(pxold, px2);
1000  pyold = py;
1001  pyold = TMath::Max(pyold, py2);
1002  pyold = TMath::Min(pyold, py1);
1003  theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
1004  theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
1005  if (theGraph->InheritsFrom("TCutG")) {
1006  //make sure first and last point are the same
1007  if (ipoint == 0) {
1008  theX[theNpoints-1] = theX[0];
1009  theY[theNpoints-1] = theY[0];
1010  }
1011  if (ipoint == theNpoints-1) {
1012  theX[0] = theX[theNpoints-1];
1013  theY[0] = theY[theNpoints-1];
1014  }
1015  }
1016  }
1017  badcase = kFALSE;
1018  gPad->Modified(kTRUE);
1019  //gPad->Update();
1020  }
1021  break;
1022 
1023  case kButton1Up:
1024 
1025  if (gROOT->IsEscaped()) {
1026  gROOT->SetEscape(kFALSE);
1027  delete [] x; x = 0;
1028  delete [] y; y = 0;
1029  break;
1030  }
1031 
1032  // Compute x,y range
1033  xmin = gPad->GetUxmin();
1034  xmax = gPad->GetUxmax();
1035  ymin = gPad->GetUymin();
1036  ymax = gPad->GetUymax();
1037  dx = xmax-xmin;
1038  dy = ymax-ymin;
1039  dxr = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
1040  dyr = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
1041 
1042  if (theGraph->GetHistogram()) {
1043  // Range() could change the size of the pad pixmap and therefore should
1044  // be called before the other paint routines
1045  gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
1046  ymin - dyr*gPad->GetBottomMargin(),
1047  xmax + dxr*gPad->GetRightMargin(),
1048  ymax + dyr*gPad->GetTopMargin());
1049  gPad->RangeAxis(xmin, ymin, xmax, ymax);
1050  }
1051  if (middle) {
1052  for(i=0;i<theNpoints;i++) {
1053  if (badcase) continue; //do not update if big zoom and points moved
1054  if (x) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
1055  if (y) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
1056  }
1057  } else {
1058  theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
1059  theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
1060  if (theGraph->InheritsFrom("TCutG")) {
1061  //make sure first and last point are the same
1062  if (ipoint == 0) {
1063  theX[theNpoints-1] = theX[0];
1064  theY[theNpoints-1] = theY[0];
1065  }
1066  if (ipoint == theNpoints-1) {
1067  theX[0] = theX[theNpoints-1];
1068  theY[0] = theY[theNpoints-1];
1069  }
1070  }
1071  }
1072  badcase = kFALSE;
1073  delete [] x; x = 0;
1074  delete [] y; y = 0;
1075  gPad->Modified(kTRUE);
1076  gVirtualX->SetLineColor(-1);
1077  }
1078 }
1079 
1080 
1081 ////////////////////////////////////////////////////////////////////////////////
1082 
1083 char *TGraphPainter::GetObjectInfoHelper(TGraph * /*theGraph*/, Int_t /*px*/, Int_t /*py*/) const
1084 {
1085  return (char*)"";
1086 }
1087 
1088 
1089 ////////////////////////////////////////////////////////////////////////////////
1090 /// Return the highlighted point for theGraph
1091 
1092 Int_t TGraphPainter::GetHighlightPoint(TGraph *theGraph) const
1093 {
1094  if (theGraph == gHighlightGraph) return gHighlightPoint;
1095  else return -1;
1096 }
1097 
1098 
1099 ////////////////////////////////////////////////////////////////////////////////
1100 /// Set highlight (enable/disable) mode for theGraph
1101 
1102 void TGraphPainter::SetHighlight(TGraph *theGraph)
1103 {
1104  gHighlightPoint = -1; // must be -1
1105  gHighlightGraph = 0;
1106  if (theGraph->IsHighlight()) return;
1107 
1108  // delete previous highlight marker
1109  if (gHighlightMarker) { gHighlightMarker->Delete(); gHighlightMarker = 0; }
1110  // emit Highlighted() signal (user can check on disabled)
1111  if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, theGraph, gHighlightPoint, -1);
1112 }
1113 
1114 
1115 ////////////////////////////////////////////////////////////////////////////////
1116 /// Check on highlight point
1117 
1118 void TGraphPainter::HighlightPoint(TGraph *theGraph, Int_t hpoint, Int_t distance)
1119 {
1120  // call from DistancetoPrimitiveHelper (only if highlight is enable)
1121 
1122  const Int_t kHighlightRange = 50; // maybe as fgHighlightRange and Set/Get
1123  static Int_t distanceOld = kHighlightRange;
1124  if (gHighlightPoint == -1) distanceOld = kHighlightRange; // reset
1125 
1126  if ((distance < kHighlightRange) && (distance < distanceOld)) { // closest point
1127  if ((gHighlightPoint != hpoint) || (gHighlightGraph != theGraph)) { // was changed
1128  // Info("HighlightPoint", "graph: %p\tpoint: %d", (void *)theGraph, hpoint);
1129  gHighlightPoint = hpoint;
1130  gHighlightGraph = theGraph;
1131 
1132  // paint highlight point as marker (recursive calls PaintHighlightPoint)
1133  gPad->Modified(kTRUE);
1134  gPad->Update();
1135 
1136  // emit Highlighted() signal
1137  if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, theGraph, gHighlightPoint, -1);
1138  }
1139  }
1140  if (gHighlightGraph == theGraph) distanceOld = distance;
1141 }
1142 
1143 
1144 ////////////////////////////////////////////////////////////////////////////////
1145 /// Paint highlight point as TMarker object (open circle)
1146 
1147 void TGraphPainter::PaintHighlightPoint(TGraph *theGraph, Option_t * /*option*/)
1148 {
1149  // call from PaintGraphSimple
1150 
1151  if ((!theGraph->IsHighlight()) || (gHighlightGraph != theGraph)) return;
1152 
1153  Double_t hx, hy;
1154  if (theGraph->GetPoint(gHighlightPoint, hx, hy) == -1) {
1155  // special case, e.g. after interactive remove last point
1156  if (gHighlightMarker) { gHighlightMarker->Delete(); gHighlightMarker = 0; }
1157  return;
1158  }
1159  // testing specific possibility (after zoom, draw with "same", log, etc.)
1160  Double_t uxmin = gPad->GetUxmin();
1161  Double_t uxmax = gPad->GetUxmax();
1162  Double_t uymin = gPad->GetUymin();
1163  Double_t uymax = gPad->GetUymax();
1164  if (gPad->GetLogx()) {
1165  uxmin = TMath::Power(10.0, uxmin);
1166  uxmax = TMath::Power(10.0, uxmax);
1167  }
1168  if (gPad->GetLogy()) {
1169  uymin = TMath::Power(10.0, uymin);
1170  uymax = TMath::Power(10.0, uymax);
1171  }
1172  if ((hx < uxmin) || (hx > uxmax)) return;
1173  if ((hy < uymin) || (hy > uymax)) return;
1174 
1175  if (!gHighlightMarker) {
1176  gHighlightMarker = new TMarker(hx, hy, 24);
1177  gHighlightMarker->SetBit(kCannotPick);
1178  }
1179  gHighlightMarker->SetX(hx);
1180  gHighlightMarker->SetY(hy);
1181  gHighlightMarker->SetMarkerSize(theGraph->GetMarkerSize()*2.0);
1182  if (gHighlightMarker->GetMarkerSize() < 1.0) gHighlightMarker->SetMarkerSize(1.0); // always visible
1183  gHighlightMarker->SetMarkerColor(theGraph->GetMarkerColor());
1184  gHighlightMarker->Paint();
1185  // Info("PaintHighlightPoint", "graph: %p\tpoint: %d",
1186  // (void *)gHighlightGraph, gHighlightPoint);
1187 }
1188 
1189 
1190 ////////////////////////////////////////////////////////////////////////////////
1191 /// Paint a any kind of TGraph
1192 
1193 void TGraphPainter::PaintHelper(TGraph *theGraph, Option_t *option)
1194 {
1195 
1196  char chopt[80];
1197  strlcpy(chopt,option,80);
1198 
1199  if (theGraph) {
1200  char *l1 = strstr(chopt,"pfc"); // Automatic Fill Color
1201  char *l2 = strstr(chopt,"plc"); // Automatic Line Color
1202  char *l3 = strstr(chopt,"pmc"); // Automatic Marker Color
1203  if (l1 || l2 || l3) {
1204  Int_t i = gPad->NextPaletteColor();
1205  if (l1) {memcpy(l1," ",3); theGraph->SetFillColor(i);}
1206  if (l2) {memcpy(l2," ",3); theGraph->SetLineColor(i);}
1207  if (l3) {memcpy(l3," ",3); theGraph->SetMarkerColor(i);}
1208  }
1209 
1210  SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
1211 
1212  char *l4 = strstr(chopt,"rx"); // Reverse graph along X axis
1213  char *l5 = strstr(chopt,"ry"); // Reverse graph along Y axis
1214 
1215  if (l4 || l5) {
1216  PaintGraphReverse(theGraph,chopt);
1217  return;
1218  }
1219 
1220  if (theGraph->InheritsFrom(TGraphBentErrors::Class())) {
1221  PaintGraphBentErrors(theGraph,chopt);
1222  } else if (theGraph->InheritsFrom(TGraphQQ::Class())) {
1223  PaintGraphQQ(theGraph,chopt);
1224  } else if (theGraph->InheritsFrom(TGraphAsymmErrors::Class())) {
1225  PaintGraphAsymmErrors(theGraph,chopt);
1226  } else if (theGraph->InheritsFrom(TGraphMultiErrors::Class())) {
1227  PaintGraphMultiErrors(theGraph,chopt);
1228  } else if (theGraph->InheritsFrom(TGraphErrors::Class())) {
1229  if (theGraph->InheritsFrom(TGraphPolar::Class())) {
1230  PaintGraphPolar(theGraph,chopt);
1231  } else {
1232  PaintGraphErrors(theGraph,chopt);
1233  }
1234  } else {
1235  PaintGraphSimple(theGraph,chopt);
1236  }
1237 
1238  // Paint the fit parameters if needed.
1239  TF1 *fit = 0;
1240  TList *functions = theGraph->GetListOfFunctions();
1241  TObject *f;
1242  if (functions) {
1243  f = (TF1*)functions->First();
1244  if (f) {
1245  if (f->InheritsFrom(TF1::Class())) fit = (TF1*)f;
1246  }
1247  TIter next(functions);
1248  while ((f = (TObject*) next())) {
1249  if (f->InheritsFrom(TF1::Class())) {
1250  fit = (TF1*)f;
1251  break;
1252  }
1253  }
1254  }
1255  if (fit) PaintStats(theGraph, fit);
1256 
1257  }
1258 }
1259 
1260 
1261 ////////////////////////////////////////////////////////////////////////////////
1262 /// [Control function to draw a graph.]($GP01)
1263 
1264 void TGraphPainter::PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt)
1265 {
1266 
1267  if (theGraph->InheritsFrom("TGraphPolar"))
1268  gPad->PushSelectableObject(theGraph);
1269 
1270  Int_t optionLine , optionAxis , optionCurve , optionStar , optionMark;
1271  Int_t optionBar , optionR , optionOne , optionE;
1272  Int_t optionFill , optionZ , optionCurveFill, optionIAxis;
1273  Int_t i, npt, nloop;
1274  Int_t drawtype=0;
1275  Double_t xlow, xhigh, ylow, yhigh;
1276  Double_t barxmin, barxmax, barymin, barymax;
1277  Double_t uxmin, uxmax;
1278  Double_t x1, xn, y1, yn;
1279  Double_t dbar, bdelta;
1280  Int_t theNpoints = theGraph->GetN();
1281 
1282  if (npoints <= 0) {
1283  Error("PaintGraph", "illegal number of points (%d)", npoints);
1284  return;
1285  }
1286  TString opt = chopt;
1287  opt.ToUpper();
1288  opt.ReplaceAll("SAME","");
1289 
1290  if (opt.Contains("L")) optionLine = 1; else optionLine = 0;
1291  if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0;
1292  if (opt.Contains("C")) optionCurve = 1; else optionCurve = 0;
1293  if (opt.Contains("*")) optionStar = 1; else optionStar = 0;
1294  if (opt.Contains("P")) optionMark = 1; else optionMark = 0;
1295  if (opt.Contains("B")) optionBar = 1; else optionBar = 0;
1296  if (opt.Contains("R")) optionR = 1; else optionR = 0;
1297  if (opt.Contains("1")) optionOne = 1; else optionOne = 0;
1298  if (opt.Contains("F")) optionFill = 1; else optionFill = 0;
1299  if (opt.Contains("I")) optionIAxis = 1; else optionIAxis = 0;
1300  if (opt.Contains("2") || opt.Contains("3") ||
1301  opt.Contains("4") || opt.Contains("5")) optionE = 1; else optionE = 0;
1302  optionZ = 0;
1303 
1304  // If no "drawing" option is selected and if chopt<>' ' nothing is done.
1305  if (optionLine+optionFill+optionCurve+optionStar+optionMark+optionBar+optionE == 0) {
1306  if (!chopt[0]) optionLine=1;
1307  else return;
1308  }
1309 
1310  if (optionStar) theGraph->SetMarkerStyle(3);
1311 
1312  optionCurveFill = 0;
1313  if (optionCurve && optionFill) {
1314  optionCurveFill = 1;
1315  optionFill = 0;
1316  }
1317 
1318  // Draw the Axis.
1319  Double_t rwxmin,rwxmax, rwymin, rwymax, maximum, minimum, dx, dy;
1320  if (optionAxis) {
1321  if (theGraph->GetHistogram()) {
1322  rwxmin = gPad->GetUxmin();
1323  rwxmax = gPad->GetUxmax();
1324  rwymin = gPad->GetUymin();
1325  rwymax = gPad->GetUymax();
1326  minimum = theGraph->GetHistogram()->GetMinimumStored();
1327  maximum = theGraph->GetHistogram()->GetMaximumStored();
1328  if (minimum == -1111) { //this can happen after unzooming
1329  minimum = theGraph->GetHistogram()->GetYaxis()->GetXmin();
1330  theGraph->GetHistogram()->SetMinimum(minimum);
1331  }
1332  if (maximum == -1111) {
1333  maximum = theGraph->GetHistogram()->GetYaxis()->GetXmax();
1334  theGraph->GetHistogram()->SetMaximum(maximum);
1335  }
1336  uxmin = gPad->PadtoX(rwxmin);
1337  uxmax = gPad->PadtoX(rwxmax);
1338  } else {
1339 
1340  theGraph->ComputeRange(rwxmin, rwymin, rwxmax, rwymax); //this is redefined in TGraphErrors
1341 
1342  if (rwxmin == rwxmax) rwxmax += 1.;
1343  if (rwymin == rwymax) rwymax += 1.;
1344  dx = 0.1*(rwxmax-rwxmin);
1345  dy = 0.1*(rwymax-rwymin);
1346  uxmin = rwxmin - dx;
1347  uxmax = rwxmax + dx;
1348  minimum = rwymin - dy;
1349  maximum = rwymax + dy;
1350  }
1351  if (theGraph->GetMinimum() != -1111) rwymin = minimum = theGraph->GetMinimum();
1352  if (theGraph->GetMaximum() != -1111) rwymax = maximum = theGraph->GetMaximum();
1353  if (uxmin < 0 && rwxmin >= 0) uxmin = 0.9*rwxmin;
1354  if (uxmax > 0 && rwxmax <= 0) {
1355  if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
1356  else uxmax = 0;
1357  }
1358  if (minimum < 0 && rwymin >= 0) minimum = 0.9*rwymin;
1359  if (maximum > 0 && rwymax <= 0) {
1360  //if(gPad->GetLogy()) maximum = 1.1*rwymax;
1361  //else maximum = 0;
1362  }
1363  if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
1364  if (uxmin <= 0 && gPad->GetLogx()) {
1365  if (uxmax > 1000) uxmin = 1;
1366  else uxmin = 0.001*uxmax;
1367  }
1368  rwymin = minimum;
1369  rwymax = maximum;
1370 
1371  // Create a temporary histogram and fill each bin with the
1372  // function value.
1373  char chopth[8] = " ";
1374  if (strstr(chopt,"x+")) strncat(chopth, "x+",3);
1375  if (strstr(chopt,"y+")) strncat(chopth, "y+",3);
1376  if (optionIAxis) strncat(chopth, "A",2);
1377  if (!theGraph->GetHistogram()) {
1378  // the graph is created with at least as many bins as there are
1379  // points to permit zooming on the full range.
1380  rwxmin = uxmin;
1381  rwxmax = uxmax;
1382  npt = 100;
1383  if (theNpoints > npt) npt = theNpoints;
1384  TH1F *h = new TH1F(Form("%s_h",GetName()),GetTitle(),npt,rwxmin,rwxmax);
1385  theGraph->SetHistogram(h);
1386  if (!theGraph->GetHistogram()) return;
1387  theGraph->GetHistogram()->SetMinimum(rwymin);
1388  theGraph->GetHistogram()->SetMaximum(rwymax);
1389  theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
1390  theGraph->GetHistogram()->SetBit(TH1::kNoStats);
1391  theGraph->GetHistogram()->SetDirectory(0);
1392  theGraph->GetHistogram()->Sumw2(kFALSE);
1393  theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
1394  } else {
1395  if (gPad->GetLogy()) {
1396  theGraph->GetHistogram()->SetMinimum(rwymin);
1397  theGraph->GetHistogram()->SetMaximum(rwymax);
1398  theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
1399  }
1400  theGraph->GetHistogram()->Sumw2(kFALSE);
1401  theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
1402  }
1403  }
1404 
1405  // Set Clipping option
1406  gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
1407 
1408  rwxmin = gPad->GetUxmin();
1409  rwxmax = gPad->GetUxmax();
1410  rwymin = gPad->GetUymin();
1411  rwymax = gPad->GetUymax();
1412  uxmin = gPad->PadtoX(rwxmin);
1413  uxmax = gPad->PadtoX(rwxmax);
1414  if (theGraph->GetHistogram() && !theGraph->InheritsFrom("TGraphPolar")) {
1415  maximum = theGraph->GetHistogram()->GetMaximum();
1416  minimum = theGraph->GetHistogram()->GetMinimum();
1417  } else {
1418  maximum = gPad->PadtoY(rwymax);
1419  minimum = gPad->PadtoY(rwymin);
1420  }
1421 
1422  // Set attributes
1423  theGraph->TAttLine::Modify();
1424  theGraph->TAttFill::Modify();
1425  theGraph->TAttMarker::Modify();
1426 
1427  // Draw the graph with a polyline or a fill area
1428  gxwork = new Double_t[2*npoints+10];
1429  gywork = new Double_t[2*npoints+10];
1430  gxworkl = new Double_t[2*npoints+10];
1431  gyworkl = new Double_t[2*npoints+10];
1432 
1433  if (optionLine || optionFill) {
1434  x1 = x[0];
1435  xn = x[npoints-1];
1436  y1 = y[0];
1437  yn = y[npoints-1];
1438  nloop = npoints;
1439  if (optionFill && (xn != x1 || yn != y1)) nloop++;
1440  npt = 0;
1441  for (i=1;i<=nloop;i++) {
1442  if (i > npoints) {
1443  gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1444  } else {
1445  gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1446  npt++;
1447  }
1448  if (i == nloop) {
1449  ComputeLogs(npt, optionZ);
1450  Int_t bord = gStyle->GetDrawBorder();
1451  if (optionR) {
1452  if (optionFill) {
1453  gPad->PaintFillArea(npt,gyworkl,gxworkl);
1454  if (bord) gPad->PaintPolyLine(npt,gyworkl,gxworkl);
1455  }
1456  if (optionLine) {
1457  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gyworkl, gxworkl);
1458  gPad->PaintPolyLine(npt,gyworkl,gxworkl);
1459  }
1460  } else {
1461  if (optionFill) {
1462  gPad->PaintFillArea(npt,gxworkl,gyworkl);
1463  if (bord) gPad->PaintPolyLine(npt,gxworkl,gyworkl);
1464  }
1465  if (optionLine) {
1466  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gxworkl, gyworkl);
1467  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
1468  }
1469  }
1470  gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1471  npt = 1;
1472  }
1473  }
1474  }
1475 
1476  // Draw the graph with a smooth Curve. Smoothing via Smooth
1477  if (optionCurve) {
1478  x1 = x[0];
1479  xn = x[npoints-1];
1480  y1 = y[0];
1481  yn = y[npoints-1];
1482  drawtype = 1;
1483  nloop = npoints;
1484  if (optionCurveFill) {
1485  drawtype += 1000;
1486  if (xn != x1 || yn != y1) nloop++;
1487  }
1488  if (!optionR) {
1489  npt = 0;
1490  for (i=1;i<=nloop;i++) {
1491  if (i > npoints) {
1492  gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1493  } else {
1494  gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1495  npt++;
1496  }
1497  ComputeLogs(npt, optionZ);
1498  if (gyworkl[npt-1] < rwymin || gyworkl[npt-1] > rwymax) {
1499  if (npt > 2) {
1500  ComputeLogs(npt, optionZ);
1501  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
1502  }
1503  gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1504  npt=1;
1505  continue;
1506  }
1507  }
1508  if (npt > 1) {
1509  ComputeLogs(npt, optionZ);
1510  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
1511  }
1512  } else {
1513  drawtype += 10;
1514  npt = 0;
1515  for (i=1;i<=nloop;i++) {
1516  if (i > npoints) {
1517  gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1518  } else {
1519  if (y[i-1] < minimum || y[i-1] > maximum) continue;
1520  if (x[i-1] < uxmin || x[i-1] > uxmax) continue;
1521  gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1522  npt++;
1523  }
1524  ComputeLogs(npt, optionZ);
1525  if (gxworkl[npt-1] < rwxmin || gxworkl[npt-1] > rwxmax) {
1526  if (npt > 2) {
1527  ComputeLogs(npt, optionZ);
1528  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
1529  }
1530  gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1531  npt=1;
1532  continue;
1533  }
1534  }
1535  if (npt > 1) {
1536  ComputeLogs(npt, optionZ);
1537  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
1538  }
1539  }
1540  }
1541 
1542  // Draw the graph with a '*' on every points
1543  if (optionStar) {
1544  theGraph->SetMarkerStyle(3);
1545  npt = 0;
1546  for (i=1;i<=npoints;i++) {
1547  gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1548  npt++;
1549  if (i == npoints) {
1550  ComputeLogs(npt, optionZ);
1551  if (optionR) gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
1552  else gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
1553  npt = 0;
1554  }
1555  }
1556  }
1557 
1558  // Draw the graph with the current polymarker on every points
1559  if (optionMark) {
1560  npt = 0;
1561  for (i=1;i<=npoints;i++) {
1562  gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1563  npt++;
1564  if (i == npoints) {
1565  ComputeLogs(npt, optionZ);
1566  if (optionR) gPad->PaintPolyMarker(npt,gyworkl,gxworkl);
1567  else gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
1568  npt = 0;
1569  }
1570  }
1571  }
1572 
1573  // Draw the graph as a bar chart
1574  if (optionBar) {
1575  if (!optionR) {
1576  barxmin = x[0];
1577  barxmax = x[0];
1578  for (i=1;i<npoints;i++) {
1579  if (x[i] < barxmin) barxmin = x[i];
1580  if (x[i] > barxmax) barxmax = x[i];
1581  }
1582  bdelta = (barxmax-barxmin)/Double_t(npoints);
1583  } else {
1584  barymin = y[0];
1585  barymax = y[0];
1586  for (i=1;i<npoints;i++) {
1587  if (y[i] < barymin) barymin = y[i];
1588  if (y[i] > barymax) barymax = y[i];
1589  }
1590  bdelta = (barymax-barymin)/Double_t(npoints);
1591  }
1592  dbar = 0.5*bdelta*gStyle->GetBarWidth();
1593  if (!optionR) {
1594  for (i=1;i<=npoints;i++) {
1595  xlow = x[i-1] - dbar;
1596  xhigh = x[i-1] + dbar;
1597  yhigh = y[i-1];
1598  if (xlow < uxmin && xhigh < uxmin) continue;
1599  if (xhigh > uxmax && xlow > uxmax) continue;
1600  if (xlow < uxmin) xlow = uxmin;
1601  if (xhigh > uxmax) xhigh = uxmax;
1602  if (!optionOne) ylow = TMath::Max((Double_t)0,gPad->GetUymin());
1603  else ylow = gPad->GetUymin();
1604  gxwork[0] = xlow;
1605  gywork[0] = ylow;
1606  gxwork[1] = xhigh;
1607  gywork[1] = yhigh;
1608  ComputeLogs(2, optionZ);
1609  if (gyworkl[0] < gPad->GetUymin()) gyworkl[0] = gPad->GetUymin();
1610  if (gyworkl[1] < gPad->GetUymin()) continue;
1611  if (gyworkl[1] > gPad->GetUymax()) gyworkl[1] = gPad->GetUymax();
1612  if (gyworkl[0] > gPad->GetUymax()) continue;
1613 
1614  gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
1615  }
1616  } else {
1617  for (i=1;i<=npoints;i++) {
1618  xhigh = x[i-1];
1619  ylow = y[i-1] - dbar;
1620  yhigh = y[i-1] + dbar;
1621  xlow = TMath::Max((Double_t)0, gPad->GetUxmin());
1622  gxwork[0] = xlow;
1623  gywork[0] = ylow;
1624  gxwork[1] = xhigh;
1625  gywork[1] = yhigh;
1626  ComputeLogs(2, optionZ);
1627  gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
1628  }
1629  }
1630  }
1631  gPad->ResetBit(TGraph::kClipFrame);
1632 
1633  delete [] gxwork;
1634  delete [] gywork;
1635  delete [] gxworkl;
1636  delete [] gyworkl;
1637 }
1638 
1639 
1640 ////////////////////////////////////////////////////////////////////////////////
1641 /// This is a service method used by `THistPainter`
1642 /// to paint 1D histograms. It is not used to paint TGraph.
1643 ///
1644 /// Input parameters:
1645 ///
1646 /// - npoints : Number of points in X or in Y.
1647 /// - x[npoints] or x[0] : x coordinates or (xmin,xmax).
1648 /// - y[npoints] or y[0] : y coordinates or (ymin,ymax).
1649 /// - chopt : Option.
1650 ///
1651 /// The aspect of the histogram is done according to the value of the chopt.
1652 ///
1653 /// | Option | Description |
1654 /// |--------|-----------------------------------------------------------------|
1655 /// |"R" | Graph is drawn horizontally, parallel to X axis. (default is vertically, parallel to Y axis).If option R is selected the user must give 2 values for Y (y[0]=YMIN and y[1]=YMAX) or N values for X, one for each channel. Otherwise the user must give, N values for Y, one for each channel or 2 values for X (x[0]=XMIN and x[1]=XMAX) |
1656 /// |"L" | A simple polyline between every points is drawn.|
1657 /// |"H" | An Histogram with equidistant bins is drawn as a polyline.|
1658 /// |"F" | An histogram with equidistant bins is drawn as a fill area. Contour is not drawn unless chopt='H' is also selected..|
1659 /// |"N" | Non equidistant bins (default is equidistant). If N is the number of channels array X and Y must be dimensioned as follow: If option R is not selected (default) then the user must give (N+1) values for X (limits of channels) or N values for Y, one for each channel. Otherwise the user must give (N+1) values for Y (limits of channels). or N values for X, one for each channel |
1660 /// |"F1" | Idem as 'F' except that fill area base line is the minimum of the pad instead of Y=0.|
1661 /// |"F2" | Draw a Fill area polyline connecting the center of bins|
1662 /// |"C" | A smooth Curve is drawn.|
1663 /// |"*" | A Star is plotted at the center of each bin.|
1664 /// |"P" | Idem with the current marker.|
1665 /// |"P0" | Idem with the current marker. Empty bins also drawn.|
1666 /// |"B" | A Bar chart with equidistant bins is drawn as fill areas (Contours are drawn).|
1667 /// |"][" | "Cutoff" style. When this option is selected together with H option, the first and last vertical lines of the histogram are not drawn.|
1668 
1669 void TGraphPainter::PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x,
1670  const Double_t *y, Option_t *chopt)
1671 {
1672 
1673  const char *where = "PaintGrapHist";
1674 
1675  Int_t optionLine , optionAxis , optionCurve, optionStar, optionMark;
1676  Int_t optionBar , optionRot , optionOne , optionOff ;
1677  Int_t optionFill , optionZ;
1678  Int_t optionHist , optionBins , optionMarker;
1679  Int_t i, j, npt;
1680  Int_t drawtype=0, drawborder, drawbordersav;
1681  Double_t xlow, xhigh, ylow, yhigh;
1682  Double_t wmin, wmax;
1683  Double_t dbar, offset, wminstep;
1684  Double_t delta = 0;
1685  Double_t ylast = 0;
1686  Double_t xi, xi1, xj, xj1, yi1, yi, yj, yj1, xwmin, ywmin;
1687  Int_t first, last, nbins;
1688  Int_t fillarea;
1689 
1690  char choptaxis[10] = " ";
1691 
1692  if (npoints <= 0) {
1693  Error(where, "illegal number of points (%d)", npoints);
1694  return;
1695  }
1696  TString opt = chopt;
1697  opt.ToUpper();
1698  if (opt.Contains("H")) optionHist = 1; else optionHist = 0;
1699  if (opt.Contains("F")) optionFill = 1; else optionFill = 0;
1700  if (opt.Contains("C")) optionCurve= 1; else optionCurve= 0;
1701  if (opt.Contains("*")) optionStar = 1; else optionStar = 0;
1702  if (opt.Contains("R")) optionRot = 1; else optionRot = 0;
1703  if (opt.Contains("1")) optionOne = 1; else optionOne = 0;
1704  if (opt.Contains("B")) optionBar = 1; else optionBar = 0;
1705  if (opt.Contains("N")) optionBins = 1; else optionBins = 0;
1706  if (opt.Contains("L")) optionLine = 1; else optionLine = 0;
1707  if (opt.Contains("P")) optionMark = 1; else optionMark = 0;
1708  if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0;
1709  if (opt.Contains("][")) optionOff = 1; else optionOff = 0;
1710  if (opt.Contains("P0")) optionMark = 10;
1711 
1712  Int_t optionFill2 = 0;
1713  if (opt.Contains("F") && opt.Contains("2")) {
1714  optionFill = 0; optionFill2 = 1;
1715  }
1716 
1717  // Set Clipping option
1718  Option_t *noClip;
1719  if (theGraph->TestBit(TGraph::kClipFrame)) noClip = "";
1720  else noClip = "C";
1721  gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
1722 
1723  optionZ = 1;
1724 
1725  if (optionStar) theGraph->SetMarkerStyle(3);
1726 
1727  first = 1;
1728  last = npoints;
1729  nbins = last - first + 1;
1730 
1731  // Draw the Axis with a fixed number of division: 510
1732 
1733  Double_t baroffset = gStyle->GetBarOffset();
1734  Double_t barwidth = gStyle->GetBarWidth();
1735  Double_t rwxmin = gPad->GetUxmin();
1736  Double_t rwxmax = gPad->GetUxmax();
1737  Double_t rwymin = gPad->GetUymin();
1738  Double_t rwymax = gPad->GetUymax();
1739  Double_t uxmin = gPad->PadtoX(rwxmin);
1740  Double_t uxmax = gPad->PadtoX(rwxmax);
1741  Double_t rounding = (uxmax-uxmin)*1.e-5;
1742  drawborder = gStyle->GetDrawBorder();
1743  if (optionAxis) {
1744  Int_t nx1, nx2, ndivx, ndivy, ndiv;
1745  choptaxis[0] = 0;
1746  Double_t rwmin = rwxmin;
1747  Double_t rwmax = rwxmax;
1748  ndivx = gStyle->GetNdivisions("X");
1749  ndivy = gStyle->GetNdivisions("Y");
1750  if (ndivx > 1000) {
1751  nx2 = ndivx/100;
1752  nx1 = TMath::Max(1, ndivx%100);
1753  ndivx = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsWNDC());
1754  }
1755  ndiv =TMath::Abs(ndivx);
1756  // coverity [Calling risky function]
1757  if (ndivx < 0) strlcat(choptaxis, "N",10);
1758  if (gPad->GetGridx()) {
1759  // coverity [Calling risky function]
1760  strlcat(choptaxis, "W",10);
1761  }
1762  if (gPad->GetLogx()) {
1763  rwmin = TMath::Power(10,rwxmin);
1764  rwmax = TMath::Power(10,rwxmax);
1765  // coverity [Calling risky function]
1766  strlcat(choptaxis, "G",10);
1767  }
1768  TGaxis *axis = new TGaxis();
1769  axis->SetLineColor(gStyle->GetAxisColor("X"));
1770  axis->SetTextColor(gStyle->GetLabelColor("X"));
1771  axis->SetTextFont(gStyle->GetLabelFont("X"));
1772  axis->SetLabelSize(gStyle->GetLabelSize("X"));
1773  axis->SetLabelOffset(gStyle->GetLabelOffset("X"));
1774  axis->SetTickSize(gStyle->GetTickLength("X"));
1775 
1776  axis->PaintAxis(rwxmin,rwymin,rwxmax,rwymin,rwmin,rwmax,ndiv,choptaxis);
1777 
1778  choptaxis[0] = 0;
1779  rwmin = rwymin;
1780  rwmax = rwymax;
1781  if (ndivy < 0) {
1782  nx2 = ndivy/100;
1783  nx1 = TMath::Max(1, ndivy%100);
1784  ndivy = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsHNDC());
1785  // coverity [Calling risky function]
1786  strlcat(choptaxis, "N",10);
1787  }
1788  ndiv =TMath::Abs(ndivy);
1789  if (gPad->GetGridy()) {
1790  // coverity [Calling risky function]
1791  strlcat(choptaxis, "W",10);
1792  }
1793  if (gPad->GetLogy()) {
1794  rwmin = TMath::Power(10,rwymin);
1795  rwmax = TMath::Power(10,rwymax);
1796  // coverity [Calling risky function]
1797  strlcat(choptaxis,"G",10);
1798  }
1799  axis->SetLineColor(gStyle->GetAxisColor("Y"));
1800  axis->SetTextColor(gStyle->GetLabelColor("Y"));
1801  axis->SetTextFont(gStyle->GetLabelFont("Y"));
1802  axis->SetLabelSize(gStyle->GetLabelSize("Y"));
1803  axis->SetLabelOffset(gStyle->GetLabelOffset("Y"));
1804  axis->SetTickSize(gStyle->GetTickLength("Y"));
1805 
1806  axis->PaintAxis(rwxmin,rwymin,rwxmin,rwymax,rwmin,rwmax,ndiv,choptaxis);
1807  delete axis;
1808  }
1809 
1810 
1811  // Set attributes
1812  theGraph->TAttLine::Modify();
1813  theGraph->TAttFill::Modify();
1814  theGraph->TAttMarker::Modify();
1815 
1816  // Min-Max scope
1817 
1818  if (!optionRot) {wmin = x[0]; wmax = x[1];}
1819  else {wmin = y[0]; wmax = y[1];}
1820 
1821  if (!optionBins) delta = (wmax - wmin)/ Double_t(nbins);
1822 
1823  Int_t fwidth = gPad->GetFrameLineWidth();
1824  TFrame *frame = gPad->GetFrame();
1825  if (frame) fwidth = frame->GetLineWidth();
1826  if (optionOff) fwidth = 1;
1827  Double_t dxframe = gPad->AbsPixeltoX(fwidth/2) - gPad->AbsPixeltoX(0);
1828  Double_t vxmin = gPad->PadtoX(gPad->GetUxmin() + dxframe);
1829  Double_t vxmax = gPad->PadtoX(gPad->GetUxmax() - dxframe);
1830  Double_t dyframe = -gPad->AbsPixeltoY(fwidth/2) + gPad->AbsPixeltoY(0);
1831  Double_t vymin = gPad->GetUymin() + dyframe; //y already in log scale
1832  vxmin = TMath::Max(vxmin,wmin);
1833  vxmax = TMath::Min(vxmax,wmax);
1834 
1835  // Draw the histogram with a fill area
1836 
1837  gxwork = new Double_t[2*npoints+10];
1838  gywork = new Double_t[2*npoints+10];
1839  gxworkl = new Double_t[2*npoints+10];
1840  gyworkl = new Double_t[2*npoints+10];
1841 
1842  if (optionFill && !optionCurve) {
1843  fillarea = kTRUE;
1844  if (!optionRot) {
1845  gxwork[0] = vxmin;
1846  if (!optionOne) gywork[0] = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
1847  ,gPad->GetUymax());
1848  else gywork[0] = gPad->GetUymin();
1849  npt = 2;
1850  for (j=first; j<=last;j++) {
1851  if (!optionBins) {
1852  gxwork[npt-1] = gxwork[npt-2];
1853  gxwork[npt] = wmin+((j-first+1)*delta);
1854  if (gxwork[npt] < gxwork[0]) gxwork[npt] = gxwork[0];
1855 
1856  } else {
1857  xj1 = x[j]; xj = x[j-1];
1858  if (xj1 < xj) {
1859  if (j != last) Error(where, "X must be in increasing order");
1860  else Error(where, "X must have N+1 values with option N");
1861  return;
1862  }
1863  gxwork[npt-1] = x[j-1]; gxwork[npt] = x[j];
1864  }
1865  gywork[npt-1] = y[j-1];
1866  gywork[npt] = y[j-1];
1867  if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
1868  if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1869  (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1870  if (j == last) {
1871  gxwork[npt-1] = gxwork[npt-2];
1872  gywork[npt-1] = gywork[0];
1873  //make sure that the fill area does not overwrite the frame
1874  //take into account the frame line width
1875  if (gxwork[0 ] < vxmin) {gxwork[0 ] = vxmin; gxwork[1 ] = vxmin;}
1876  if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}
1877 
1878  //transform to log ?
1879  ComputeLogs(npt, optionZ);
1880  gPad->PaintFillArea(npt,gxworkl,gyworkl);
1881  if (drawborder) {
1882  if (!fillarea) gyworkl[0] = ylast;
1883  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
1884  }
1885  continue;
1886  }
1887  } //endfor (j=first; j<=last;j++) {
1888  } else {
1889  gywork[0] = wmin;
1890  if (!optionOne) gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
1891  else gxwork[0] = gPad->GetUxmin();
1892  npt = 2;
1893  for (j=first; j<=last;j++) {
1894  if (!optionBins) {
1895  gywork[npt-1] = gywork[npt-2];
1896  gywork[npt] = wmin+((j-first+1)*delta);
1897  } else {
1898  yj1 = y[j]; yj = y[j-1];
1899  if (yj1 < yj) {
1900  if (j != last) Error(where, "Y must be in increasing order");
1901  else Error(where, "Y must have N+1 values with option N");
1902  return;
1903  }
1904  gywork[npt-1] = y[j-1]; gywork[npt] = y[j];
1905  }
1906  gxwork[npt-1] = x[j-1]; gxwork[npt] = x[j-1];
1907  if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1908  (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1909  if (j == last) {
1910  gywork[npt-1] = gywork[npt-2];
1911  gxwork[npt-1] = gxwork[0];
1912  ComputeLogs(npt, optionZ);
1913  gPad->PaintFillArea(npt,gxworkl,gyworkl);
1914  if (drawborder) {
1915  if (!fillarea) gyworkl[0] = ylast;
1916  gPad->PaintPolyLine(npt-1,gxworkl,gyworkl,noClip);
1917  }
1918  continue;
1919  }
1920  } //endfor (j=first; j<=last;j++)
1921  }
1922  theGraph->TAttLine::Modify();
1923  theGraph->TAttFill::Modify();
1924  }
1925 
1926  // Draw a standard Histogram (default)
1927 
1928  if ((optionHist) || !chopt[0]) {
1929  if (!optionRot) {
1930  gxwork[0] = wmin;
1931  gywork[0] = gPad->GetUymin();
1932  ywmin = gywork[0];
1933  npt = 2;
1934  for (i=first; i<=last;i++) {
1935  if (!optionBins) {
1936  gxwork[npt-1] = gxwork[npt-2];
1937  gxwork[npt] = wmin+((i-first+1)*delta);
1938  } else {
1939  xi1 = x[i]; xi = x[i-1];
1940  if (xi1 < xi) {
1941  if (i != last) Error(where, "X must be in increasing order");
1942  else Error(where, "X must have N+1 values with option N");
1943  return;
1944  }
1945  gxwork[npt-1] = x[i-1]; gxwork[npt] = x[i];
1946  }
1947  gywork[npt-1] = y[i-1];
1948  gywork[npt] = y[i-1];
1949  if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
1950  if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1951  (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1952  if (i == last) {
1953  gxwork[npt-1] = gxwork[npt-2];
1954  gywork[npt-1] = gywork[0];
1955  //make sure that the fill area does not overwrite the frame
1956  //take into account the frame line width
1957  if (gxwork[0] < vxmin) {gxwork[0] = vxmin; gxwork[1 ] = vxmin;}
1958  if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}
1959 
1960  ComputeLogs(npt, optionZ);
1961 
1962  // do not draw the two vertical lines on the edges
1963  Int_t nbpoints = npt-2;
1964  Int_t point1 = 1;
1965 
1966  if (optionOff) {
1967  // remove points before the low cutoff
1968  Int_t ip;
1969  for (ip=point1; ip<=nbpoints; ip++) {
1970  if (gyworkl[ip] != ywmin) {
1971  point1 = ip;
1972  break;
1973  }
1974  }
1975  // remove points after the high cutoff
1976  Int_t point2 = nbpoints;
1977  for (ip=point2; ip>=point1; ip--) {
1978  if (gyworkl[ip] != ywmin) {
1979  point2 = ip;
1980  break;
1981  }
1982  }
1983  nbpoints = point2-point1+1;
1984  } else {
1985  // if the 1st or last bin are not on the pad limits the
1986  // the two vertical lines on the edges are added.
1987  if (gxwork[0] > gPad->GetUxmin()) { nbpoints++; point1 = 0; }
1988  if (gxwork[nbpoints] < gPad->GetUxmax()) nbpoints++;
1989  }
1990 
1991  gPad->PaintPolyLine(nbpoints,&gxworkl[point1],&gyworkl[point1],noClip);
1992  continue;
1993  }
1994  } //endfor (i=first; i<=last;i++)
1995  } else {
1996  gywork[0] = wmin;
1997  gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
1998  xwmin = gxwork[0];
1999  npt = 2;
2000  for (i=first; i<=last;i++) {
2001  if (!optionBins) {
2002  gywork[npt-1] = gywork[npt-2];
2003  gywork[npt] = wmin+((i-first+1)*delta);
2004  } else {
2005  yi1 = y[i]; yi = y[i-1];
2006  if (yi1 < yi) {
2007  if (i != last) Error(where, "Y must be in increasing order");
2008  else Error(where, "Y must have N+1 values with option N");
2009  return;
2010  }
2011  gywork[npt-1] = y[i-1]; gywork[npt] = y[i];
2012  }
2013  gxwork[npt-1] = x[i-1]; gxwork[npt] = x[i-1];
2014  if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
2015  (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
2016  if (i == last) {
2017  gywork[npt-1] = gywork[npt-2];
2018  gxwork[npt-1] = xwmin;
2019  ComputeLogs(npt, optionZ);
2020  gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
2021  continue;
2022  }
2023  } //endfor (i=first; i<=last;i++)
2024  }
2025  }
2026 
2027  // Draw the histogram with a smooth Curve.
2028  // The smoothing is done by the method Smooth()
2029 
2030  if (optionCurve) {
2031  if (!optionFill) {
2032  drawtype = 1;
2033  } else {
2034  if (!optionOne) drawtype = 2;
2035  else drawtype = 3;
2036  }
2037  if (!optionRot) {
2038  npt = 0;
2039  for (i=first; i<=last;i++) {
2040  npt++;
2041  if (!optionBins) {
2042  gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2043  } else {
2044  xi1 = x[i]; xi = x[i-1];
2045  if (xi1 < xi) {
2046  if (i != last) Error(where, "X must be in increasing order");
2047  else Error(where, "X must have N+1 values with option N");
2048  return;
2049  }
2050  gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
2051  }
2052  if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) {
2053  npt--;
2054  continue;
2055  }
2056  gywork[npt-1] = y[i-1];
2057  ComputeLogs(npt, optionZ);
2058  if ((gyworkl[npt-1] < rwymin) || (gyworkl[npt-1] > rwymax)) {
2059  if (npt > 2) {
2060  ComputeLogs(npt, optionZ);
2061  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
2062  }
2063  gxwork[0] = gxwork[npt-1];
2064  gywork[0] = gywork[npt-1];
2065  npt = 1;
2066  continue;
2067  }
2068  if (npt >= fgMaxPointsPerLine) {
2069  ComputeLogs(fgMaxPointsPerLine, optionZ);
2070  Smooth(theGraph, fgMaxPointsPerLine,gxworkl,gyworkl,drawtype);
2071  gxwork[0] = gxwork[npt-1];
2072  gywork[0] = gywork[npt-1];
2073  npt = 1;
2074  }
2075  } //endfor (i=first; i<=last;i++)
2076  if (npt > 1) {
2077  ComputeLogs(npt, optionZ);
2078  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
2079  }
2080  } else {
2081  drawtype = drawtype+10;
2082  npt = 0;
2083  for (i=first; i<=last;i++) {
2084  npt++;
2085  if (!optionBins) {
2086  gywork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2087  } else {
2088  yi1 = y[i]; yi = y[i-1];
2089  if (yi1 < yi) {
2090  if (i != last) Error(where, "Y must be in increasing order");
2091  else Error(where, "Y must have N+1 values with option N");
2092  return;
2093  }
2094  gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
2095  }
2096  gxwork[npt-1] = x[i-1];
2097  ComputeLogs(npt, optionZ);
2098  if ((gxworkl[npt] < uxmin) || (gxworkl[npt] > uxmax)) {
2099  if (npt > 2) {
2100  ComputeLogs(npt, optionZ);
2101  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
2102  }
2103  gxwork[0] = gxwork[npt-1];
2104  gywork[0] = gywork[npt-1];
2105  npt = 1;
2106  continue;
2107  }
2108  if (npt >= fgMaxPointsPerLine) {
2109  ComputeLogs(fgMaxPointsPerLine, optionZ);
2110  Smooth(theGraph, fgMaxPointsPerLine,gxworkl,gyworkl,drawtype);
2111  gxwork[0] = gxwork[npt-1];
2112  gywork[0] = gywork[npt-1];
2113  npt = 1;
2114  }
2115  } //endfor (i=first; i<=last;i++)
2116  if (npt > 1) {
2117  ComputeLogs(npt, optionZ);
2118  Smooth(theGraph, npt,gxworkl,gyworkl,drawtype);
2119  }
2120  }
2121  }
2122 
2123  // Draw the histogram with a simple line
2124 
2125  if (optionLine) {
2126  gPad->SetBit(TGraph::kClipFrame);
2127  wminstep = wmin + 0.5*delta;
2128  Axis_t ax1,ax2,ay1,ay2;
2129  gPad->GetRangeAxis(ax1,ay1,ax2,ay2);
2130 
2131  if (!optionRot) {
2132  npt = 0;
2133  for (i=first; i<=last;i++) {
2134  npt++;
2135  if (!optionBins) {
2136  gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2137  } else {
2138  xi1 = x[i]; xi = x[i-1];
2139  if (xi1 < xi) {
2140  if (i != last) Error(where, "X must be in increasing order");
2141  else Error(where, "X must have N+1 values with option N");
2142  return;
2143  }
2144  gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
2145  }
2146  if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) { npt--; continue;}
2147  gywork[npt-1] = y[i-1];
2148  gywork[npt] = y[i-1]; //new
2149  if ((gywork[npt-1] < rwymin) || ((gywork[npt-1] > rwymax) && !optionFill2)) {
2150  if (npt > 2) {
2151  ComputeLogs(npt, optionZ);
2152  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
2153  }
2154  gxwork[0] = gxwork[npt-1];
2155  gywork[0] = gywork[npt-1];
2156  npt = 1;
2157  continue;
2158  }
2159 
2160  if (npt >= fgMaxPointsPerLine) {
2161  if (optionLine) {
2162  ComputeLogs(fgMaxPointsPerLine, optionZ);
2163  if (optionFill2) {
2164  gxworkl[npt] = gxworkl[npt-1]; gyworkl[npt] = rwymin;
2165  gxworkl[npt+1] = gxworkl[0]; gyworkl[npt+1] = rwymin;
2166  gPad->PaintFillArea(fgMaxPointsPerLine+2,gxworkl,gyworkl);
2167  }
2168  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
2169  }
2170  gxwork[0] = gxwork[npt-1];
2171  gywork[0] = gywork[npt-1];
2172  npt = 1;
2173  }
2174  } //endfor (i=first; i<=last;i++)
2175  if (npt > 1) {
2176  ComputeLogs(npt, optionZ);
2177  if (optionFill2) {
2178  gxworkl[npt] = gxworkl[npt-1]; gyworkl[npt] = rwymin;
2179  gxworkl[npt+1] = gxworkl[0]; gyworkl[npt+1] = rwymin;
2180  gPad->PaintFillArea(npt+2,gxworkl,gyworkl);
2181  }
2182  gPad->PaintPolyLine(npt,gxworkl,gyworkl);
2183  }
2184  } else {
2185  npt = 0;
2186  for (i=first; i<=last;i++) {
2187  npt++;
2188  if (!optionBins) {
2189  gywork[npt-1] = wminstep+(i-first)*delta+0.5*delta;
2190  } else {
2191  yi1 = y[i]; yi = y[i-1];
2192  if (yi1 < yi) {
2193  if (i != last) Error(where, "Y must be in increasing order");
2194  else Error(where, "Y must have N+1 values with option N");
2195  return;
2196  }
2197  gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
2198  }
2199  gxwork[npt-1] = x[i-1];
2200  if ((gxwork[npt-1] < uxmin) || (gxwork[npt-1] > uxmax)) {
2201  if (npt > 2) {
2202  if (optionLine) {
2203  ComputeLogs(npt, optionZ);
2204  gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
2205  }
2206  }
2207  gxwork[0] = gxwork[npt-1];
2208  gywork[0] = gywork[npt-1];
2209  npt = 1;
2210  continue;
2211  }
2212  if (npt >= fgMaxPointsPerLine) {
2213  if (optionLine) {
2214  ComputeLogs(fgMaxPointsPerLine, optionZ);
2215  gPad->PaintPolyLine(fgMaxPointsPerLine,gxworkl,gyworkl);
2216  }
2217  gxwork[0] = gxwork[npt-1];
2218  gywork[0] = gywork[npt-1];
2219  npt = 1;
2220  }
2221  } //endfor (i=first; i<=last;i++)
2222  if (optionLine != 0 && npt > 1) {
2223  ComputeLogs(npt, optionZ);
2224  gPad->PaintPolyLine(npt,gxworkl,gyworkl,noClip);
2225  }
2226  }
2227  }
2228 
2229  // Draw the histogram as a bar chart
2230 
2231  if (optionBar) {
2232  if (!optionBins) {
2233  offset = delta*baroffset; dbar = delta*barwidth;
2234  } else {
2235  if (!optionRot) {
2236  offset = (x[1]-x[0])*baroffset;
2237  dbar = (x[1]-x[0])*barwidth;
2238  } else {
2239  offset = (y[1]-y[0])*baroffset;
2240  dbar = (y[1]-y[0])*barwidth;
2241  }
2242  }
2243  drawbordersav = drawborder;
2244  gStyle->SetDrawBorder(1);
2245  if (!optionRot) {
2246  xlow = wmin+offset;
2247  xhigh = wmin+offset+dbar;
2248  if (!optionOne) ylow = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
2249  ,gPad->GetUymax());
2250  else ylow = gPad->GetUymin();
2251 
2252  for (i=first; i<=last;i++) {
2253  yhigh = y[i-1];
2254  gxwork[0] = xlow;
2255  gywork[0] = ylow;
2256  gxwork[1] = xhigh;
2257  gywork[1] = yhigh;
2258  ComputeLogs(2, optionZ);
2259  if (xlow < rwxmax && xhigh > rwxmin)
2260  gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
2261  if (!optionBins) {
2262  xlow = xlow+delta;
2263  xhigh = xhigh+delta;
2264  } else {
2265  if (i < last) {
2266  xi1 = x[i]; xi = x[i-1];
2267  if (xi1 < xi) {
2268  Error(where, "X must be in increasing order");
2269  return;
2270  }
2271  offset = (x[i+1]-x[i])*baroffset;
2272  dbar = (x[i+1]-x[i])*barwidth;
2273  xlow = x[i] + offset;
2274  xhigh = x[i] + offset + dbar;
2275  }
2276  }
2277  } //endfor (i=first; i<=last;i++)
2278  } else {
2279  ylow = wmin + offset;
2280  yhigh = wmin + offset + dbar;
2281  if (!optionOne) xlow = TMath::Max((Double_t)0,gPad->GetUxmin());
2282  else xlow = gPad->GetUxmin();
2283  for (i=first; i<=last;i++) {
2284  xhigh = x[i-1];
2285  gxwork[0] = xlow;
2286  gywork[0] = ylow;
2287  gxwork[1] = xhigh;
2288  gywork[1] = yhigh;
2289  ComputeLogs(2, optionZ);
2290  gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
2291  gPad->PaintBox(xlow,ylow,xhigh,yhigh);
2292  if (!optionBins) {
2293  ylow = ylow + delta;
2294  yhigh = yhigh + delta;
2295  } else {
2296  if (i < last) {
2297  yi1 = y[i]; yi = y[i-1];
2298  if (yi1 < yi) {
2299  Error(where, "Y must be in increasing order");
2300  return;
2301  }
2302  offset = (y[i+1]-y[i])*baroffset;
2303  dbar = (y[i+1]-y[i])*barwidth;
2304  ylow = y[i] + offset;
2305  yhigh = y[i] + offset + dbar;
2306  }
2307  }
2308  } //endfor (i=first; i<=last;i++)
2309  }
2310  gStyle->SetDrawBorder(drawbordersav);
2311  }
2312 
2313  // Draw the histogram with a simple marker
2314 
2315  optionMarker = 0;
2316  if ((optionStar) || (optionMark)) optionMarker=1;
2317 
2318  if (optionMarker) {
2319  Double_t xm,ym;
2320  npt = 0;
2321  if (!optionRot) {
2322  for (i=first; i<=last;i++) {
2323  if (!optionBins) xm = wmin+(i-first)*delta+0.5*delta;
2324  else xm = x[i-1] + 0.5*(x[i]-x[i-1]);
2325  ym = y[i-1];
2326  if (optionMark != 10) {
2327  if (ym<rwymax && ym > rwymin) {
2328  npt++;
2329  gxwork[npt-1] = xm;
2330  gywork[npt-1] = ym;
2331  }
2332  } else {
2333  if (ym<rwymax && ym >= rwymin) {
2334  npt++;
2335  gxwork[npt-1] = xm;
2336  gywork[npt-1] = ym;
2337  }
2338  }
2339  if (npt >= fgMaxPointsPerLine) {
2340  ComputeLogs(npt, optionZ);
2341  gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
2342  npt = 0;
2343  }
2344  }
2345  if (npt > 0) {
2346  ComputeLogs(npt, optionZ);
2347  gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
2348  }
2349  } else {
2350  wminstep = wmin + 0.5*delta;
2351  for (i=first; i<=last;i++) {
2352  if (!optionBins) ym = wminstep+(i-first)*delta+0.5*delta;
2353  else ym = y[i-1] + 0.5*(y[i]-y[i-1]);
2354  xm = x[i-1];
2355  if (optionMark != 10) {
2356  if (xm<rwxmax && xm > rwxmin) {
2357  npt++;
2358  gxwork[npt-1] = xm;
2359  gywork[npt-1] = ym;
2360  }
2361  } else {
2362  if (xm<rwxmax && xm >= rwxmin) {
2363  npt++;
2364  gxwork[npt-1] = xm;
2365  gywork[npt-1] = ym;
2366  }
2367  }
2368  if (npt >= fgMaxPointsPerLine) {
2369  ComputeLogs(npt, optionZ);
2370  gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
2371  npt = 0;
2372  }
2373  }
2374  if (npt > 0) {
2375  ComputeLogs(npt, optionZ);
2376  gPad->PaintPolyMarker(npt,gxworkl,gyworkl);
2377  }
2378  }
2379  }
2380 
2381  gPad->ResetBit(TGraph::kClipFrame);
2382 
2383  delete [] gxwork;
2384  delete [] gywork;
2385  delete [] gxworkl;
2386  delete [] gyworkl;
2387 }
2388 
2389 
2390 ////////////////////////////////////////////////////////////////////////////////
2391 /// [Paint this TGraphAsymmErrors with its current attributes.](#GP03)
2392 
2393 void TGraphPainter::PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option)
2394 {
2395 
2396  Double_t *xline = 0;
2397  Double_t *yline = 0;
2398  Int_t if1 = 0;
2399  Int_t if2 = 0;
2400  Double_t xb[4], yb[4];
2401 
2402  const Int_t kBASEMARKER=8;
2403  Double_t s2x, s2y, symbolsize, sbase;
2404  Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
2405  static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
2406  static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
2407  Int_t theNpoints = theGraph->GetN();
2408  Double_t *theX = theGraph->GetX();
2409  Double_t *theY = theGraph->GetY();
2410  Double_t *theEXlow = theGraph->GetEXlow(); if (!theEXlow) return;
2411  Double_t *theEYlow = theGraph->GetEYlow(); if (!theEYlow) return;
2412  Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
2413  Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;
2414 
2415  if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
2416  Bool_t brackets = kFALSE;
2417  Bool_t braticks = kFALSE;
2418  if (strstr(option,"||") || strstr(option,"[]")) {
2419  brackets = kTRUE;
2420  if (strstr(option,"[]")) braticks = kTRUE;
2421  }
2422  Bool_t endLines = kTRUE;
2423  if (strchr(option,'z')) endLines = kFALSE;
2424  if (strchr(option,'Z')) endLines = kFALSE;
2425  const char *arrowOpt = 0;
2426  if (strchr(option,'>')) arrowOpt = ">";
2427  if (strstr(option,"|>")) arrowOpt = "|>";
2428 
2429  Bool_t axis = kFALSE;
2430  if (strchr(option,'a')) axis = kTRUE;
2431  if (strchr(option,'A')) axis = kTRUE;
2432  if (axis) PaintGraphSimple(theGraph, option);
2433 
2434  Bool_t option0 = kFALSE;
2435  Bool_t option2 = kFALSE;
2436  Bool_t option3 = kFALSE;
2437  Bool_t option4 = kFALSE;
2438  Bool_t option5 = kFALSE;
2439  if (strchr(option,'0')) option0 = kTRUE;
2440  if (strchr(option,'2')) option2 = kTRUE;
2441  if (strchr(option,'3')) option3 = kTRUE;
2442  if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
2443  if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
2444 
2445  if (option3) {
2446  xline = new Double_t[2*theNpoints];
2447  yline = new Double_t[2*theNpoints];
2448  if (!xline || !yline) {
2449  Error("Paint", "too many points, out of memory");
2450  return;
2451  }
2452  if1 = 1;
2453  if2 = 2*theNpoints;
2454  }
2455 
2456  theGraph->TAttLine::Modify();
2457 
2458  TArrow arrow;
2459  arrow.SetLineWidth(theGraph->GetLineWidth());
2460  arrow.SetLineColor(theGraph->GetLineColor());
2461  arrow.SetFillColor(theGraph->GetFillColor());
2462 
2463  TBox box;
2464  Double_t x1b,y1b,x2b,y2b;
2465  box.SetLineWidth(theGraph->GetLineWidth());
2466  box.SetLineColor(theGraph->GetLineColor());
2467  box.SetFillColor(theGraph->GetFillColor());
2468  box.SetFillStyle(theGraph->GetFillStyle());
2469 
2470  symbolsize = theGraph->GetMarkerSize();
2471  sbase = symbolsize*kBASEMARKER;
2472  Int_t mark = theGraph->GetMarkerStyle();
2473  Double_t cx = 0;
2474  Double_t cy = 0;
2475  if (mark >= 20 && mark <= 34) {
2476  cx = cxx[mark-20];
2477  cy = cyy[mark-20];
2478  }
2479 
2480  // Define the offset of the error bars due to the symbol size
2481  s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
2482  s2y =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
2483  Int_t dxend = Int_t(gStyle->GetEndErrorSize());
2484  tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
2485  ty =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
2486  Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
2487 
2488  gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
2489  for (Int_t i=0;i<theNpoints;i++) {
2490  x = gPad->XtoPad(theX[i]);
2491  y = gPad->YtoPad(theY[i]);
2492  if (!option0) {
2493  if (option3) {
2494  if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
2495  if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
2496  if (y < gPad->GetUymin()) y = gPad->GetUymin();
2497  if (y > gPad->GetUymax()) y = gPad->GetUymax();
2498  } else {
2499  if (x < gPad->GetUxmin()) continue;
2500  if (x > gPad->GetUxmax()) continue;
2501  if (y < gPad->GetUymin()) continue;
2502  if (y > gPad->GetUymax()) continue;
2503  }
2504  }
2505  xl1 = x - s2x*cx;
2506  xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);
2507 
2508  // draw the error rectangles
2509  if (option2) {
2510  x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
2511  y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
2512  x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
2513  y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
2514  if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
2515  if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
2516  if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
2517  if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
2518  if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
2519  if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
2520  if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
2521  if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
2522  if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
2523  else box.PaintBox(x1b, y1b, x2b, y2b);
2524  continue;
2525  }
2526 
2527  // keep points for fill area drawing
2528  if (option3) {
2529  xline[if1-1] = x;
2530  xline[if2-1] = x;
2531  yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
2532  yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
2533  if1++;
2534  if2--;
2535  continue;
2536  }
2537 
2538  if (xl1 > xl2) {
2539  if (arrowOpt) {
2540  arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
2541  } else {
2542  if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
2543  if (endLines) {
2544  if (braticks) {
2545  xb[0] = xl2+tx; yb[0] = y-ty;
2546  xb[1] = xl2; yb[1] = y-ty;
2547  xb[2] = xl2; yb[2] = y+ty;
2548  xb[3] = xl2+tx; yb[3] = y+ty;
2549  gPad->PaintPolyLine(4, xb, yb);
2550  } else {
2551  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
2552  }
2553  }
2554  }
2555  }
2556  xr1 = x + s2x*cx;
2557  xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
2558  if (xr1 < xr2) {
2559  if (arrowOpt) {
2560  arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
2561  } else {
2562  if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
2563  if (endLines) {
2564  if (braticks) {
2565  xb[0] = xr2-tx; yb[0] = y-ty;
2566  xb[1] = xr2; yb[1] = y-ty;
2567  xb[2] = xr2; yb[2] = y+ty;
2568  xb[3] = xr2-tx; yb[3] = y+ty;
2569  gPad->PaintPolyLine(4, xb, yb);
2570  } else {
2571  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
2572  }
2573  }
2574  }
2575  }
2576  yup1 = y + s2y*cy;
2577  yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
2578  if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
2579  if (yup2 > yup1) {
2580  if (arrowOpt) {
2581  arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
2582  } else {
2583  if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
2584  if (endLines) {
2585  if (braticks) {
2586  xb[0] = x-tx; yb[0] = yup2-ty;
2587  xb[1] = x-tx; yb[1] = yup2;
2588  xb[2] = x+tx; yb[2] = yup2;
2589  xb[3] = x+tx; yb[3] = yup2-ty;
2590  gPad->PaintPolyLine(4, xb, yb);
2591  } else {
2592  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
2593  }
2594  }
2595  }
2596  }
2597  ylow1 = y - s2y*cy;
2598  ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
2599  if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
2600  if (ylow2 < ylow1) {
2601  if (arrowOpt) {
2602  arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
2603  } else {
2604  if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
2605  if (endLines) {
2606  if (braticks) {
2607  xb[0] = x-tx; yb[0] = ylow2+ty;
2608  xb[1] = x-tx; yb[1] = ylow2;
2609  xb[2] = x+tx; yb[2] = ylow2;
2610  xb[3] = x+tx; yb[3] = ylow2+ty;
2611  gPad->PaintPolyLine(4, xb, yb);
2612  } else {
2613  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
2614  }
2615  }
2616  }
2617  }
2618  }
2619  if (!brackets && !axis) PaintGraphSimple(theGraph, option);
2620  gPad->ResetBit(TGraph::kClipFrame);
2621 
2622  if (option3) {
2623  Int_t logx = gPad->GetLogx();
2624  Int_t logy = gPad->GetLogy();
2625  gPad->SetLogx(0);
2626  gPad->SetLogy(0);
2627  if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
2628  else PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
2629  gPad->SetLogx(logx);
2630  gPad->SetLogy(logy);
2631  delete [] xline;
2632  delete [] yline;
2633  }
2634 }
2635 
2636 ////////////////////////////////////////////////////////////////////////////////
2637 /// [Paint this TGraphMultiErrors with its current attributes.]($GP03)
2638 
2639 void TGraphPainter::PaintGraphMultiErrors(TGraph *theGraph, Option_t *option)
2640 {
2641  if (!theGraph->InheritsFrom(TGraphMultiErrors::Class())) {
2642  PaintHelper(theGraph, option);
2643  return;
2644  }
2645 
2646  auto tg = (TGraphMultiErrors *)theGraph;
2647 
2648  Int_t NYErrors = tg->GetNYErrors();
2649  if (NYErrors <= 0) {
2650  PaintGraphSimple(tg, option);
2651  return;
2652  }
2653 
2654  TString tsOpt = option;
2655  tsOpt.ToLower();
2656 
2657  std::vector<TString> options(NYErrors + 1);
2658  Int_t filled = 0;
2659 
2660  if (tsOpt.CountChar(';') < NYErrors) {
2661  options[0] = tsOpt.Contains(";") ? tsOpt(0, tsOpt.First(';')) : tsOpt.Copy();
2662  filled++;
2663  }
2664 
2665  Ssiz_t firstSemicolon;
2666  while ((firstSemicolon = tsOpt.First(';')) != kNPOS && filled <= NYErrors) {
2667  options[filled] = tsOpt(0, firstSemicolon);
2668  tsOpt = tsOpt(firstSemicolon + 1, tsOpt.Length());
2669  filled++;
2670  }
2671 
2672  if (filled <= NYErrors) {
2673  options[filled] = tsOpt.Copy();
2674  filled++;
2675  }
2676 
2677  for (Int_t i = filled; i <= NYErrors; i++)
2678  options[i] = "";
2679 
2680  Double_t *xline = nullptr;
2681  std::vector<Double_t *> yline(NYErrors);
2682  Int_t if1 = 0;
2683  Int_t if2 = 0;
2684  Double_t xb[4], yb[4];
2685 
2686  const Int_t kBASEMARKER = 8;
2687  Double_t s2x, s2y, symbolsize, sbase;
2688  Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
2689  static Float_t cxx[15] = {1., 1., 0.6, 0.6, 1., 1., 0.6, 0.5, 1., 0.6, 0.6, 1., 0.6, 1., 1.};
2690  static Float_t cyy[15] = {1., 1., 1., 1., 1., 1., 1., 1., 1., 0.5, 0.6, 1., 1., 1., 1.};
2691  Int_t theNpoints = tg->GetN();
2692  Double_t *theX = tg->GetX();
2693  Double_t *theY = tg->GetY();
2694  Double_t *theExL = tg->GetEXlow();
2695  Double_t *theExH = tg->GetEXhigh();
2696  std::vector<Double_t *> theEyL(NYErrors);
2697  std::vector<Double_t *> theEyH(NYErrors);
2698 
2699  Bool_t theEyExists = kTRUE;
2700  for (Int_t j = 0; j < NYErrors; j++) {
2701  theEyL[j] = tg->GetEYlow(j);
2702  theEyH[j] = tg->GetEYhigh(j);
2703  theEyExists &= (theEyL[j] && theEyH[j]);
2704  }
2705 
2706  if (!theX || !theY || !theExL || !theExH || !theEyExists)
2707  return;
2708 
2709  std::vector<Bool_t> DrawErrors(NYErrors);
2710  Bool_t AnyErrors = kFALSE;
2711  Bool_t NoErrorsX = kTRUE;
2712  Bool_t Option0X = kFALSE;
2713  Bool_t DrawMarker = kFALSE;
2714  std::vector<Bool_t> Braticks(NYErrors);
2715  std::vector<Bool_t> Brackets(NYErrors);
2716  std::vector<Bool_t> EndLines(NYErrors);
2717  std::vector<Char_t *> ArrowOpt(NYErrors);
2718  std::vector<Bool_t> Option5(NYErrors);
2719  std::vector<Bool_t> Option4(NYErrors);
2720  std::vector<Bool_t> Option3(NYErrors);
2721  Bool_t AnyOption3 = kFALSE;
2722  std::vector<Bool_t> Option2(NYErrors);
2723  std::vector<Bool_t> Option0(NYErrors);
2724  Bool_t AnyOption0 = kFALSE;
2725  std::vector<Double_t> Scale(NYErrors);
2726 
2727  const TRegexp ScaleRegExp("s=*[0-9]\\.*[0-9]");
2728 
2729  for (Int_t j = 0; j < NYErrors; j++) {
2730  if (options[j + 1].Contains("s=")) {
2731  sscanf(strstr(options[j + 1].Data(), "s="), "s=%lf", &Scale[j]);
2732  options[j + 1].ReplaceAll(options[j + 1](ScaleRegExp), "");
2733  } else
2734  Scale[j] = 1.;
2735 
2736  DrawErrors[j] = !options[j + 1].Contains("x");
2737  AnyErrors |= DrawErrors[j];
2738  Braticks[j] = options[j + 1].Contains("[]");
2739  Brackets[j] = options[j + 1].Contains("||") || Braticks[j];
2740  EndLines[j] = !options[j + 1].Contains("z");
2741 
2742  if (options[j + 1].Contains("|>"))
2743  ArrowOpt[j] = (Char_t *)"|>";
2744  else if (options[j + 1].Contains(">"))
2745  ArrowOpt[j] = (Char_t *)">";
2746  else
2747  ArrowOpt[j] = nullptr;
2748 
2749  Option5[j] = options[j + 1].Contains("5");
2750  Option4[j] = options[j + 1].Contains("4");
2751  Option3[j] = options[j + 1].Contains("3") || Option4[j];
2752  AnyOption3 |= Option3[j];
2753  Option2[j] = options[j + 1].Contains("2") || Option5[j];
2754  Option0[j] = options[j + 1].Contains("0");
2755  AnyOption0 |= Option0[j];
2756 
2757  NoErrorsX &= (Option3[j] || Option2[j]);
2758  Option0X |= !(Option3[j] || Option2[j]) && Option0[j];
2759  DrawMarker |= !(Brackets[j] || Option3[j] || Option2[j]);
2760  }
2761 
2762  Bool_t Draw0PointsX = !options[0].Contains("x0") && (gPad->GetLogx() == 0);
2763  Bool_t Draw0PointsY = !options[0].Contains("y0") && (gPad->GetLogy() == 0);
2764  options[0].ReplaceAll("x0", "");
2765  options[0].ReplaceAll("y0", "");
2766 
2767  Bool_t DrawErrorsX = !options[0].Contains("x");
2768  Bool_t BraticksX = options[0].Contains("[]");
2769  Bool_t BracketsX = options[0].Contains("||") || BraticksX;
2770  Bool_t EndLinesX = !options[0].Contains("z");
2771 
2772  Char_t *ArrowOptX = nullptr;
2773  if (options[0].Contains("|>"))
2774  ArrowOptX = (Char_t *)"|>";
2775  else if (options[0].Contains(">"))
2776  ArrowOptX = (Char_t *)">";
2777 
2778  Double_t ScaleX = 1.;
2779  if (options[0].Contains("s=")) {
2780  sscanf(strstr(options[0].Data(), "s="), "s=%lf", &ScaleX);
2781  options[0].ReplaceAll(options[0](ScaleRegExp), "");
2782  }
2783 
2784  if (!AnyErrors && !DrawErrorsX) {
2785  PaintGraphSimple(tg, options[0].Data());
2786  return;
2787  }
2788 
2789  Bool_t DrawAxis = options[0].Contains("a");
2790  Bool_t IndividualStyles = options[0].Contains("s");
2791 
2792  if (DrawAxis)
2793  PaintGraphSimple(tg, options[0].Data());
2794 
2795  Int_t NPointsInside = AnyOption0 ? theNpoints : 0;
2796 
2797  for (Int_t i = 0; i < theNpoints && !AnyOption0; i++) {
2798  x = gPad->XtoPad(theX[i]);
2799  y = gPad->YtoPad(theY[i]);
2800 
2801  if ((x >= gPad->GetUxmin()) && (x <= gPad->GetUxmax()) && (y >= gPad->GetUymin()) && (y <= gPad->GetUymax()) &&
2802  (Draw0PointsX || theX[i] != 0.) && (Draw0PointsY || theY[i] != 0.))
2803  NPointsInside++;
2804  }
2805 
2806  if (AnyOption3) {
2807  xline = new Double_t[2 * NPointsInside];
2808 
2809  if (!xline) {
2810  Error("Paint", "too many points, out of memory");
2811  return;
2812  }
2813 
2814  if1 = 1;
2815  if2 = 2 * NPointsInside;
2816  }
2817 
2818  for (Int_t j = 0; j < NYErrors; j++) {
2819  if (Option3[j] && DrawErrors[j]) {
2820  yline[j] = new Double_t[2 * NPointsInside];
2821 
2822  if (!yline[j]) {
2823  Error("Paint", "too many points, out of memory");
2824  delete[] xline;
2825  for (Int_t k = 0; k < j; k++)
2826  if (yline[k])
2827  delete[] yline[k];
2828  return;
2829  }
2830  }
2831  }
2832 
2833  tg->TAttLine::Modify();
2834 
2835  TArrow arrow;
2836  arrow.SetLineWidth(tg->GetLineWidth());
2837  arrow.SetLineColor(tg->GetLineColor());
2838  arrow.SetFillColor(tg->GetFillColor());
2839 
2840  TBox box;
2841  Double_t x1b, y1b, x2b, y2b;
2842  box.SetLineWidth(tg->GetLineWidth());
2843  box.SetLineColor(tg->GetLineColor());
2844  box.SetFillColor(tg->GetFillColor());
2845  box.SetFillStyle(tg->GetFillStyle());
2846 
2847  symbolsize = tg->GetMarkerSize();
2848  sbase = symbolsize * kBASEMARKER;
2849  Int_t mark = tg->GetMarkerStyle();
2850  Double_t cx = 0.;
2851  Double_t cy = 0.;
2852 
2853  if (mark >= 20 && mark <= 34) {
2854  cx = cxx[mark - 20];
2855  cy = cyy[mark - 20];
2856  }
2857 
2858  // Define the offset of the error bars due to the symbol size
2859  s2x = gPad->PixeltoX(Int_t(0.5 * sbase)) - gPad->PixeltoX(0);
2860  s2y = -gPad->PixeltoY(Int_t(0.5 * sbase)) + gPad->PixeltoY(0);
2861  auto dxend = Int_t(gStyle->GetEndErrorSize());
2862  tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
2863  ty = -gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
2864  Float_t asize = 0.6 * symbolsize * kBASEMARKER / gPad->GetWh();
2865 
2866  gPad->SetBit(TGraph::kClipFrame, tg->TestBit(TGraph::kClipFrame));
2867 
2868  for (Int_t i = 0; i < theNpoints; i++) {
2869  x = gPad->XtoPad(theX[i]);
2870  y = gPad->YtoPad(theY[i]);
2871 
2872  Bool_t isOutside =
2873  (x < gPad->GetUxmin()) || (x > gPad->GetUxmax()) || (y < gPad->GetUymin()) || (y > gPad->GetUymax());
2874 
2875  if ((isOutside && !AnyOption0) || (!Draw0PointsX && theX[i] == 0.) || (!Draw0PointsY && theY[i] == 0.))
2876  continue;
2877 
2878  if (AnyOption3) {
2879  if (isOutside) {
2880  if (x < gPad->GetUxmin())
2881  x = gPad->GetUxmin();
2882  if (x > gPad->GetUxmax())
2883  x = gPad->GetUxmax();
2884  if (y < gPad->GetUymin())
2885  y = gPad->GetUymin();
2886  if (y > gPad->GetUymax())
2887  y = gPad->GetUymax();
2888  }
2889 
2890  xline[if1 - 1] = x;
2891  xline[if2 - 1] = x;
2892 
2893  if1++;
2894  if2--;
2895  }
2896 
2897  for (Int_t j = 0; j < NYErrors; j++) {
2898  if (!DrawErrors[j])
2899  continue;
2900 
2901  // draw the error rectangles
2902  if (Option2[j] && (!isOutside || Option0[j])) {
2903  if (IndividualStyles) {
2904  box.SetLineWidth(tg->GetLineWidth(j));
2905  box.SetLineColor(tg->GetLineColor(j));
2906  box.SetFillColor(tg->GetFillColor(j));
2907  box.SetFillStyle(tg->GetFillStyle(j));
2908  }
2909 
2910  x1b = gPad->XtoPad(theX[i] - Scale[j] * theExL[i]);
2911  y1b = gPad->YtoPad(theY[i] - theEyL[j][i]);
2912  x2b = gPad->XtoPad(theX[i] + Scale[j] * theExH[i]);
2913  y2b = gPad->YtoPad(theY[i] + theEyH[j][i]);
2914  if (x1b < gPad->GetUxmin())
2915  x1b = gPad->GetUxmin();
2916  if (x1b > gPad->GetUxmax())
2917  x1b = gPad->GetUxmax();
2918  if (y1b < gPad->GetUymin())
2919  y1b = gPad->GetUymin();
2920  if (y1b > gPad->GetUymax())
2921  y1b = gPad->GetUymax();
2922  if (x2b < gPad->GetUxmin())
2923  x2b = gPad->GetUxmin();
2924  if (x2b > gPad->GetUxmax())
2925  x2b = gPad->GetUxmax();
2926  if (y2b < gPad->GetUymin())
2927  y2b = gPad->GetUymin();
2928  if (y2b > gPad->GetUymax())
2929  y2b = gPad->GetUymax();
2930  if (Option5[j])
2931  box.PaintBox(x1b, y1b, x2b, y2b, "l");
2932  else
2933  box.PaintBox(x1b, y1b, x2b, y2b);
2934  }
2935 
2936  // keep points for fill area drawing
2937  if (Option3[j]) {
2938  if (!isOutside || Option0[j]) {
2939  yline[j][if1 - 2] = gPad->YtoPad(theY[i] + theEyH[j][i]);
2940  yline[j][if2] = gPad->YtoPad(theY[i] - theEyL[j][i]);
2941  } else {
2942  yline[j][if1 - 2] = gPad->GetUymin();
2943  yline[j][if2] = gPad->GetUymin();
2944  }
2945  }
2946 
2947  if (IndividualStyles) {
2948  tg->GetAttLine(j)->Modify();
2949 
2950  arrow.SetLineWidth(tg->GetLineWidth(j));
2951  arrow.SetLineColor(tg->GetLineColor(j));
2952  arrow.SetFillColor(tg->GetFillColor(j));
2953  }
2954 
2955  ylow1 = y - s2y * cy;
2956  ylow2 = gPad->YtoPad(theY[i] - theEyL[j][i]);
2957  if (ylow2 < gPad->GetUymin())
2958  ylow2 = gPad->GetUymin();
2959  if (ylow2 < ylow1 && DrawErrors[j] && !Option2[j] && !Option3[j] && (!isOutside || Option0[j])) {
2960  if (ArrowOpt[j])
2961  arrow.PaintArrow(x, ylow1, x, ylow2, asize, ArrowOpt[j]);
2962  else {
2963  if (!Brackets[j])
2964  gPad->PaintLine(x, ylow1, x, ylow2);
2965  if (EndLines[j]) {
2966  if (Braticks[j]) {
2967  xb[0] = x - tx;
2968  yb[0] = ylow2 + ty;
2969  xb[1] = x - tx;
2970  yb[1] = ylow2;
2971  xb[2] = x + tx;
2972  yb[2] = ylow2;
2973  xb[3] = x + tx;
2974  yb[3] = ylow2 + ty;
2975  gPad->PaintPolyLine(4, xb, yb);
2976  } else
2977  gPad->PaintLine(x - tx, ylow2, x + tx, ylow2);
2978  }
2979  }
2980  }
2981 
2982  yup1 = y + s2y * cy;
2983  yup2 = gPad->YtoPad(theY[i] + theEyH[j][i]);
2984  if (yup2 > gPad->GetUymax())
2985  yup2 = gPad->GetUymax();
2986  if (yup2 > yup1 && DrawErrors[j] && !Option2[j] && !Option3[j] && (!isOutside || Option0[j])) {
2987  if (ArrowOpt[j])
2988  arrow.PaintArrow(x, yup1, x, yup2, asize, ArrowOpt[j]);
2989  else {
2990  if (!Brackets[j])
2991  gPad->PaintLine(x, yup1, x, yup2);
2992  if (EndLines[j]) {
2993  if (Braticks[j]) {
2994  xb[0] = x - tx;
2995  yb[0] = yup2 - ty;
2996  xb[1] = x - tx;
2997  yb[1] = yup2;
2998  xb[2] = x + tx;
2999  yb[2] = yup2;
3000  xb[3] = x + tx;
3001  yb[3] = yup2 - ty;
3002  gPad->PaintPolyLine(4, xb, yb);
3003  } else
3004  gPad->PaintLine(x - tx, yup2, x + tx, yup2);
3005  }
3006  }
3007  }
3008  }
3009 
3010  if (DrawErrorsX) {
3011  if (IndividualStyles) {
3012  tg->TAttLine::Modify();
3013 
3014  arrow.SetLineWidth(tg->GetLineWidth());
3015  arrow.SetLineColor(tg->GetLineColor());
3016  arrow.SetFillColor(tg->GetFillColor());
3017  }
3018 
3019  xl1 = x - s2x * cx;
3020  xl2 = gPad->XtoPad(theX[i] - ScaleX * theExL[i]);
3021  if (xl1 > xl2 && !NoErrorsX && (!isOutside || Option0X)) {
3022  if (ArrowOptX)
3023  arrow.PaintArrow(xl1, y, xl2, y, asize, ArrowOptX);
3024  else {
3025  if (!BracketsX)
3026  gPad->PaintLine(xl1, y, xl2, y);
3027  if (EndLinesX) {
3028  if (BraticksX) {
3029  xb[0] = xl2 + tx;
3030  yb[0] = y - ty;
3031  xb[1] = xl2;
3032  yb[1] = y - ty;
3033  xb[2] = xl2;
3034  yb[2] = y + ty;
3035  xb[3] = xl2 + tx;
3036  yb[3] = y + ty;
3037  gPad->PaintPolyLine(4, xb, yb);
3038  } else
3039  gPad->PaintLine(xl2, y - ty, xl2, y + ty);
3040  }
3041  }
3042  }
3043 
3044  xr1 = x + s2x * cx;
3045  xr2 = gPad->XtoPad(theX[i] + ScaleX * theExH[i]);
3046  if (xr1 < xr2 && !NoErrorsX && (!isOutside || Option0X)) {
3047  if (ArrowOptX)
3048  arrow.PaintArrow(xr1, y, xr2, y, asize, ArrowOptX);
3049  else {
3050  if (!BracketsX)
3051  gPad->PaintLine(xr1, y, xr2, y);
3052  if (EndLinesX) {
3053  if (BraticksX) {
3054  xb[0] = xr2 - tx;
3055  yb[0] = y - ty;
3056  xb[1] = xr2;
3057  yb[1] = y - ty;
3058  xb[2] = xr2;
3059  yb[2] = y + ty;
3060  xb[3] = xr2 - tx;
3061  yb[3] = y + ty;
3062  gPad->PaintPolyLine(4, xb, yb);
3063  } else
3064  gPad->PaintLine(xr2, y - ty, xr2, y + ty);
3065  }
3066  }
3067  }
3068  }
3069  }
3070 
3071  if (DrawMarker && !DrawAxis)
3072  PaintGraphSimple(tg, options[0].Data());
3073  gPad->ResetBit(TGraph::kClipFrame);
3074 
3075  auto tgDummy = new TGraph();
3076  tg->TAttFill::Copy(*tgDummy);
3077  tg->TAttLine::Copy(*tgDummy);
3078  tg->TAttMarker::Copy(*tgDummy);
3079 
3080  for (Int_t j = 0; j < NYErrors; j++) {
3081  if (Option3[j] && DrawErrors[j]) {
3082  if (IndividualStyles) {
3083  tg->GetAttFill(j)->Copy(*tgDummy);
3084  tg->GetAttLine(j)->Copy(*tgDummy);
3085  }
3086 
3087  Int_t logx = gPad->GetLogx();
3088  Int_t logy = gPad->GetLogy();
3089  gPad->SetLogx(0);
3090  gPad->SetLogy(0);
3091  if (Option4[j])
3092  PaintGraph(tgDummy, 2 * NPointsInside, xline, yline[j], "FC");
3093  else
3094  PaintGraph(tgDummy, 2 * NPointsInside, xline, yline[j], "F");
3095  gPad->SetLogx(logx);
3096  gPad->SetLogy(logy);
3097  delete[] yline[j];
3098  }
3099  }
3100 
3101  delete tgDummy;
3102 
3103  if (AnyOption3)
3104  delete[] xline;
3105 }
3106 
3107 ////////////////////////////////////////////////////////////////////////////////
3108 /// [Paint this TGraphBentErrors with its current attributes.]($GP03)
3109 
3110 void TGraphPainter::PaintGraphBentErrors(TGraph *theGraph, Option_t *option)
3111 {
3112 
3113  Double_t *xline = 0;
3114  Double_t *yline = 0;
3115  Int_t if1 = 0;
3116  Int_t if2 = 0;
3117  Double_t xb[4], yb[4];
3118 
3119  const Int_t kBASEMARKER=8;
3120  Double_t s2x, s2y, symbolsize, sbase;
3121  Double_t x, y, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
3122  Double_t bxl, bxh, byl, byh;
3123  static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
3124  static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
3125  Int_t theNpoints = theGraph->GetN();
3126  Double_t *theX = theGraph->GetX();
3127  Double_t *theY = theGraph->GetY();
3128  Double_t *theEXlow = theGraph->GetEXlow(); if (!theEXlow) return;
3129  Double_t *theEYlow = theGraph->GetEYlow(); if (!theEYlow) return;
3130  Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
3131  Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;
3132  Double_t *theEXlowd = theGraph->GetEXlowd(); if (!theEXlowd) return;
3133  Double_t *theEXhighd = theGraph->GetEXhighd(); if (!theEXhighd) return;
3134  Double_t *theEYlowd = theGraph->GetEYlowd(); if (!theEYlowd) return;
3135  Double_t *theEYhighd = theGraph->GetEYhighd(); if (!theEYhighd) return;
3136 
3137  if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
3138  Bool_t brackets = kFALSE;
3139  Bool_t braticks = kFALSE;
3140  if (strstr(option,"||") || strstr(option,"[]")) {
3141  brackets = kTRUE;
3142  if (strstr(option,"[]")) braticks = kTRUE;
3143  }
3144  Bool_t endLines = kTRUE;
3145  if (strchr(option,'z')) endLines = kFALSE;
3146  if (strchr(option,'Z')) endLines = kFALSE;
3147  const char *arrowOpt = 0;
3148  if (strchr(option,'>')) arrowOpt = ">";
3149  if (strstr(option,"|>")) arrowOpt = "|>";
3150 
3151  Bool_t axis = kFALSE;
3152  if (strchr(option,'a')) axis = kTRUE;
3153  if (strchr(option,'A')) axis = kTRUE;
3154  if (axis) PaintGraphSimple(theGraph,option);
3155 
3156  Bool_t option0 = kFALSE;
3157  Bool_t option2 = kFALSE;
3158  Bool_t option3 = kFALSE;
3159  Bool_t option4 = kFALSE;
3160  Bool_t option5 = kFALSE;
3161  if (strchr(option,'0')) option0 = kTRUE;
3162  if (strchr(option,'2')) option2 = kTRUE;
3163  if (strchr(option,'3')) option3 = kTRUE;
3164  if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
3165  if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
3166 
3167  if (option3) {
3168  xline = new Double_t[2*theNpoints];
3169  yline = new Double_t[2*theNpoints];
3170  if (!xline || !yline) {
3171  Error("Paint", "too many points, out of memory");
3172  return;
3173  }
3174  if1 = 1;
3175  if2 = 2*theNpoints;
3176  }
3177 
3178  theGraph->TAttLine::Modify();
3179 
3180  TArrow arrow;
3181  arrow.SetLineWidth(theGraph->GetLineWidth());
3182  arrow.SetLineColor(theGraph->GetLineColor());
3183  arrow.SetFillColor(theGraph->GetFillColor());
3184 
3185  TBox box;
3186  Double_t x1b,y1b,x2b,y2b;
3187  box.SetLineWidth(theGraph->GetLineWidth());
3188  box.SetLineColor(theGraph->GetLineColor());
3189  box.SetFillColor(theGraph->GetFillColor());
3190  box.SetFillStyle(theGraph->GetFillStyle());
3191 
3192  symbolsize = theGraph->GetMarkerSize();
3193  sbase = symbolsize*kBASEMARKER;
3194  Int_t mark = theGraph->GetMarkerStyle();
3195  Double_t cx = 0;
3196  Double_t cy = 0;
3197  if (mark >= 20 && mark <= 34) {
3198  cx = cxx[mark-20];
3199  cy = cyy[mark-20];
3200  }
3201 
3202  // define the offset of the error bars due to the symbol size
3203  s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
3204  s2y =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
3205  Int_t dxend = Int_t(gStyle->GetEndErrorSize());
3206  tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
3207  ty =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
3208  Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
3209 
3210  gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
3211  for (Int_t i=0;i<theNpoints;i++) {
3212  x = gPad->XtoPad(theX[i]);
3213  y = gPad->YtoPad(theY[i]);
3214  bxl = gPad->YtoPad(theY[i]+theEXlowd[i]);
3215  bxh = gPad->YtoPad(theY[i]+theEXhighd[i]);
3216  byl = gPad->XtoPad(theX[i]+theEYlowd[i]);
3217  byh = gPad->XtoPad(theX[i]+theEYhighd[i]);
3218  if (!option0) {
3219  if (option3) {
3220  if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
3221  if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
3222  if (y < gPad->GetUymin()) y = gPad->GetUymin();
3223  if (y > gPad->GetUymax()) y = gPad->GetUymax();
3224  } else {
3225  if (x < gPad->GetUxmin()) continue;
3226  if (x > gPad->GetUxmax()) continue;
3227  if (y < gPad->GetUymin()) continue;
3228  if (y > gPad->GetUymax()) continue;
3229  }
3230  }
3231 
3232  // draw the error rectangles
3233  if (option2) {
3234  x1b = gPad->XtoPad(theX[i] - theEXlow[i]);
3235  y1b = gPad->YtoPad(theY[i] - theEYlow[i]);
3236  x2b = gPad->XtoPad(theX[i] + theEXhigh[i]);
3237  y2b = gPad->YtoPad(theY[i] + theEYhigh[i]);
3238  if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
3239  if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
3240  if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
3241  if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
3242  if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
3243  if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
3244  if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
3245  if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
3246  if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
3247  else box.PaintBox(x1b, y1b, x2b, y2b);
3248  continue;
3249  }
3250 
3251  // keep points for fill area drawing
3252  if (option3) {
3253  xline[if1-1] = byh;
3254  xline[if2-1] = byl;
3255  yline[if1-1] = gPad->YtoPad(theY[i] + theEYhigh[i]);
3256  yline[if2-1] = gPad->YtoPad(theY[i] - theEYlow[i]);
3257  if1++;
3258  if2--;
3259  continue;
3260  }
3261 
3262  xl1 = x - s2x*cx;
3263  xl2 = gPad->XtoPad(theX[i] - theEXlow[i]);
3264  if (xl1 > xl2) {
3265  if (arrowOpt) {
3266  arrow.PaintArrow(xl1,y,xl2,bxl,asize,arrowOpt);
3267  } else {
3268  if (!brackets) gPad->PaintLine(xl1,y,xl2,bxl);
3269  if (endLines) {
3270  if (braticks) {
3271  xb[0] = xl2+tx; yb[0] = bxl-ty;
3272  xb[1] = xl2; yb[1] = bxl-ty;
3273  xb[2] = xl2; yb[2] = bxl+ty;
3274  xb[3] = xl2+tx; yb[3] = bxl+ty;
3275  gPad->PaintPolyLine(4, xb, yb);
3276  } else {
3277  gPad->PaintLine(xl2,bxl-ty,xl2,bxl+ty);
3278  }
3279  }
3280  }
3281  }
3282  xr1 = x + s2x*cx;
3283  xr2 = gPad->XtoPad(theX[i] + theEXhigh[i]);
3284  if (xr1 < xr2) {
3285  if (arrowOpt) {
3286  arrow.PaintArrow(xr1,y,xr2,bxh,asize,arrowOpt);
3287  } else {
3288  if (!brackets) gPad->PaintLine(xr1,y,xr2,bxh);
3289  if (endLines) {
3290  if (braticks) {
3291  xb[0] = xr2-tx; yb[0] = bxh-ty;
3292  xb[1] = xr2; yb[1] = bxh-ty;
3293  xb[2] = xr2; yb[2] = bxh+ty;
3294  xb[3] = xr2-tx; yb[3] = bxh+ty;
3295  gPad->PaintPolyLine(4, xb, yb);
3296  } else {
3297  gPad->PaintLine(xr2,bxh-ty,xr2,bxh+ty);
3298  }
3299  }
3300  }
3301  }
3302  yup1 = y + s2y*cy;
3303  yup2 = gPad->YtoPad(theY[i] + theEYhigh[i]);
3304  if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
3305  if (yup2 > yup1) {
3306  if (arrowOpt) {
3307  arrow.PaintArrow(x,yup1,byh,yup2,asize,arrowOpt);
3308  } else {
3309  if (!brackets) gPad->PaintLine(x,yup1,byh,yup2);
3310  if (endLines) {
3311  if (braticks) {
3312  xb[0] = byh-tx; yb[0] = yup2-ty;
3313  xb[1] = byh-tx; yb[1] = yup2;
3314  xb[2] = byh+tx; yb[2] = yup2;
3315  xb[3] = byh+tx; yb[3] = yup2-ty;
3316  gPad->PaintPolyLine(4, xb, yb);
3317  } else {
3318  gPad->PaintLine(byh-tx,yup2,byh+tx,yup2);
3319  }
3320  }
3321  }
3322  }
3323  ylow1 = y - s2y*cy;
3324  ylow2 = gPad->YtoPad(theY[i] - theEYlow[i]);
3325  if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
3326  if (ylow2 < ylow1) {
3327  if (arrowOpt) {
3328  arrow.PaintArrow(x,ylow1,byl,ylow2,asize,arrowOpt);
3329  } else {
3330  if (!brackets) gPad->PaintLine(x,ylow1,byl,ylow2);
3331  if (endLines) {
3332  if (braticks) {
3333  xb[0] = byl-tx; yb[0] = ylow2+ty;
3334  xb[1] = byl-tx; yb[1] = ylow2;
3335  xb[2] = byl+tx; yb[2] = ylow2;
3336  xb[3] = byl+tx; yb[3] = ylow2+ty;
3337  gPad->PaintPolyLine(4, xb, yb);
3338  } else {
3339  gPad->PaintLine(byl-tx,ylow2,byl+tx,ylow2);
3340  }
3341  }
3342  }
3343  }
3344  }
3345  if (!brackets && !axis) PaintGraphSimple(theGraph, option);
3346  gPad->ResetBit(TGraph::kClipFrame);
3347 
3348  if (option3) {
3349  Int_t logx = gPad->GetLogx();
3350  Int_t logy = gPad->GetLogy();
3351  gPad->SetLogx(0);
3352  gPad->SetLogy(0);
3353  if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
3354  else PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
3355  gPad->SetLogx(logx);
3356  gPad->SetLogy(logy);
3357  delete [] xline;
3358  delete [] yline;
3359  }
3360 }
3361 
3362 
3363 ////////////////////////////////////////////////////////////////////////////////
3364 /// [Paint this TGraphErrors with its current attributes.]($GP03)
3365 
3366 void TGraphPainter::PaintGraphErrors(TGraph *theGraph, Option_t *option)
3367 {
3368 
3369  Double_t *xline = 0;
3370  Double_t *yline = 0;
3371  Int_t if1 = 0;
3372  Int_t if2 = 0;
3373  Double_t xb[4], yb[4];
3374 
3375  const Int_t kBASEMARKER=8;
3376  Double_t s2x, s2y, symbolsize, sbase;
3377  Double_t x, y, ex, ey, xl1, xl2, xr1, xr2, yup1, yup2, ylow1, ylow2, tx, ty;
3378  static Float_t cxx[15] = {1,1,0.6,0.6,1,1,0.6,0.5,1,0.6,0.6,1,0.6,1,1};
3379  static Float_t cyy[15] = {1,1,1,1,1,1,1,1,1,0.5,0.6,1,1,1,1};
3380  Int_t theNpoints = theGraph->GetN();
3381  Double_t *theX = theGraph->GetX();
3382  Double_t *theY = theGraph->GetY();
3383  Double_t *theEX = theGraph->GetEX(); if (!theEX) return;
3384  Double_t *theEY = theGraph->GetEY(); if (!theEY) return;
3385 
3386  if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
3387  Bool_t brackets = kFALSE;
3388  Bool_t braticks = kFALSE;
3389  if (strstr(option,"||") || strstr(option,"[]")) {
3390  brackets = kTRUE;
3391  if (strstr(option,"[]")) braticks = kTRUE;
3392  }
3393  Bool_t endLines = kTRUE;
3394  if (strchr(option,'z')) endLines = kFALSE;
3395  if (strchr(option,'Z')) endLines = kFALSE;
3396  const char *arrowOpt = 0;
3397  if (strchr(option,'>')) arrowOpt = ">";
3398  if (strstr(option,"|>")) arrowOpt = "|>";
3399 
3400  Bool_t axis = kFALSE;
3401  if (strchr(option,'a')) axis = kTRUE;
3402  if (strchr(option,'A')) axis = kTRUE;
3403  if (axis) PaintGraphSimple(theGraph, option);
3404 
3405  Bool_t option0 = kFALSE;
3406  Bool_t option2 = kFALSE;
3407  Bool_t option3 = kFALSE;
3408  Bool_t option4 = kFALSE;
3409  Bool_t option5 = kFALSE;
3410  if (strchr(option,'0')) option0 = kTRUE;
3411  if (strchr(option,'2')) option2 = kTRUE;
3412  if (strchr(option,'3')) option3 = kTRUE;
3413  if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
3414  if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
3415 
3416  if (option3) {
3417  xline = new Double_t[2*theNpoints];
3418  yline = new Double_t[2*theNpoints];
3419  if (!xline || !yline) {
3420  Error("Paint", "too many points, out of memory");
3421  return;
3422  }
3423  if1 = 1;
3424  if2 = 2*theNpoints;
3425  }
3426 
3427  theGraph->TAttLine::Modify();
3428 
3429  TArrow arrow;
3430  arrow.SetLineWidth(theGraph->GetLineWidth());
3431  arrow.SetLineColor(theGraph->GetLineColor());
3432  arrow.SetFillColor(theGraph->GetFillColor());
3433 
3434  TBox box;
3435  Double_t x1b,y1b,x2b,y2b;
3436  box.SetLineWidth(theGraph->GetLineWidth());
3437  box.SetLineColor(theGraph->GetLineColor());
3438  box.SetFillColor(theGraph->GetFillColor());
3439  box.SetFillStyle(theGraph->GetFillStyle());
3440 
3441  symbolsize = theGraph->GetMarkerSize();
3442  sbase = symbolsize*kBASEMARKER;
3443  Int_t mark = theGraph->GetMarkerStyle();
3444  Double_t cx = 0;
3445  Double_t cy = 0;
3446  if (mark >= 20 && mark <= 34) {
3447  cx = cxx[mark-20];
3448  cy = cyy[mark-20];
3449  }
3450 
3451  // define the offset of the error bars due to the symbol size
3452  s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
3453  s2y =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
3454  Int_t dxend = Int_t(gStyle->GetEndErrorSize());
3455  tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
3456  ty =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
3457  Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
3458 
3459  gPad->SetBit(TGraph::kClipFrame, theGraph->TestBit(TGraph::kClipFrame));
3460  for (Int_t i=0;i<theNpoints;i++) {
3461  x = gPad->XtoPad(theX[i]);
3462  y = gPad->YtoPad(theY[i]);
3463  if (!option0) {
3464  if (option3) {
3465  if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
3466  if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
3467  if (y < gPad->GetUymin()) y = gPad->GetUymin();
3468  if (y > gPad->GetUymax()) y = gPad->GetUymax();
3469  } else {
3470  if (x < gPad->GetUxmin()) continue;
3471  if (x > gPad->GetUxmax()) continue;
3472  if (y < gPad->GetUymin()) continue;
3473  if (y > gPad->GetUymax()) continue;
3474  }
3475  }
3476  ex = theEX[i];
3477  ey = theEY[i];
3478 
3479  // draw the error rectangles
3480  if (option2) {
3481  x1b = gPad->XtoPad(theX[i] - ex);
3482  y1b = gPad->YtoPad(theY[i] - ey);
3483  x2b = gPad->XtoPad(theX[i] + ex);
3484  y2b = gPad->YtoPad(theY[i] + ey);
3485  if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
3486  if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
3487  if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
3488  if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
3489  if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
3490  if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
3491  if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
3492  if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
3493  if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
3494  else box.PaintBox(x1b, y1b, x2b, y2b);
3495  continue;
3496  }
3497 
3498  // keep points for fill area drawing
3499  if (option3) {
3500  xline[if1-1] = x;
3501  xline[if2-1] = x;
3502  yline[if1-1] = gPad->YtoPad(theY[i] + ey);
3503  yline[if2-1] = gPad->YtoPad(theY[i] - ey);
3504  if1++;
3505  if2--;
3506  continue;
3507  }
3508 
3509  xl1 = x - s2x*cx;
3510  xl2 = gPad->XtoPad(theX[i] - ex);
3511  if (xl1 > xl2) {
3512  if (arrowOpt) {
3513  arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
3514  } else {
3515  if (!brackets) gPad->PaintLine(xl1,y,xl2,y);
3516  if (endLines) {
3517  if (braticks) {
3518  xb[0] = xl2+tx; yb[0] = y-ty;
3519  xb[1] = xl2; yb[1] = y-ty;
3520  xb[2] = xl2; yb[2] = y+ty;
3521  xb[3] = xl2+tx; yb[3] = y+ty;
3522  gPad->PaintPolyLine(4, xb, yb);
3523  } else {
3524  gPad->PaintLine(xl2,y-ty,xl2,y+ty);
3525  }
3526  }
3527  }
3528  }
3529  xr1 = x + s2x*cx;
3530  xr2 = gPad->XtoPad(theX[i] + ex);
3531  if (xr1 < xr2) {
3532  if (arrowOpt) {
3533  arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
3534  } else {
3535  if (!brackets) gPad->PaintLine(xr1,y,xr2,y);
3536  if (endLines) {
3537  if (braticks) {
3538  xb[0] = xr2-tx; yb[0] = y-ty;
3539  xb[1] = xr2; yb[1] = y-ty;
3540  xb[2] = xr2; yb[2] = y+ty;
3541  xb[3] = xr2-tx; yb[3] = y+ty;
3542  gPad->PaintPolyLine(4, xb, yb);
3543  } else {
3544  gPad->PaintLine(xr2,y-ty,xr2,y+ty);
3545  }
3546  }
3547  }
3548  }
3549  yup1 = y + s2y*cy;
3550  yup2 = gPad->YtoPad(theY[i] + ey);
3551  if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
3552  if (yup2 > yup1) {
3553  if (arrowOpt) {
3554  arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
3555  } else {
3556  if (!brackets) gPad->PaintLine(x,yup1,x,yup2);
3557  if (endLines) {
3558  if (braticks) {
3559  xb[0] = x-tx; yb[0] = yup2-ty;
3560  xb[1] = x-tx; yb[1] = yup2;
3561  xb[2] = x+tx; yb[2] = yup2;
3562  xb[3] = x+tx; yb[3] = yup2-ty;
3563  gPad->PaintPolyLine(4, xb, yb);
3564  } else {
3565  gPad->PaintLine(x-tx,yup2,x+tx,yup2);
3566  }
3567  }
3568  }
3569  }
3570  ylow1 = y - s2y*cy;
3571  ylow2 = gPad->YtoPad(theY[i] - ey);
3572  if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
3573  if (ylow2 < ylow1) {
3574  if (arrowOpt) {
3575  arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
3576  } else {
3577  if (!brackets) gPad->PaintLine(x,ylow1,x,ylow2);
3578  if (endLines) {
3579  if (braticks) {
3580  xb[0] = x-tx; yb[0] = ylow2+ty;
3581  xb[1] = x-tx; yb[1] = ylow2;
3582  xb[2] = x+tx; yb[2] = ylow2;
3583  xb[3] = x+tx; yb[3] = ylow2+ty;
3584  gPad->PaintPolyLine(4, xb, yb);
3585  } else {
3586  gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
3587  }
3588  }
3589  }
3590  }
3591  }
3592  if (!brackets && !axis) PaintGraphSimple(theGraph, option);
3593  gPad->ResetBit(TGraph::kClipFrame);
3594 
3595  if (option3) {
3596  Int_t logx = gPad->GetLogx();
3597  Int_t logy = gPad->GetLogy();
3598  gPad->SetLogx(0);
3599  gPad->SetLogy(0);
3600  if (option4) PaintGraph(theGraph, 2*theNpoints, xline, yline,"FC");
3601  else PaintGraph(theGraph, 2*theNpoints, xline, yline,"F");
3602  gPad->SetLogx(logx);
3603  gPad->SetLogy(logy);
3604  delete [] xline;
3605  delete [] yline;
3606  }
3607 }
3608 
3609 
3610 ////////////////////////////////////////////////////////////////////////////////
3611 /// [Paint this TGraphPolar with its current attributes.]($GP04)
3612 
3613 void TGraphPainter::PaintGraphPolar(TGraph *theGraph, Option_t* options)
3614 {
3615 
3616  Int_t ipt, i;
3617  Double_t rwrmin, rwrmax, rwtmin, rwtmax;
3618 
3619  TGraphPolar *theGraphPolar = (TGraphPolar*) theGraph;
3620 
3621  Int_t theNpoints = theGraphPolar->GetN();
3622  Double_t *theX = theGraphPolar->GetX();
3623  Double_t *theY = theGraphPolar->GetY();
3624  Double_t *theEX = theGraphPolar->GetEX();
3625  Double_t *theEY = theGraphPolar->GetEY();
3626 
3627  if (theNpoints<1) return;
3628  TString opt = options;
3629  opt.ToUpper();
3630 
3631  Bool_t nolabel = kFALSE;
3632  if (opt.Contains("N")){
3633  nolabel = kTRUE;
3634  opt.ReplaceAll("N","");
3635  }
3636 
3637  TGraphPolargram *thePolargram = theGraphPolar->GetPolargram();
3638 
3639  // Check for existing TGraphPolargram in the Pad
3640  if (gPad) {
3641  // Existing polargram
3642  if (thePolargram) if (!gPad->FindObject(thePolargram->GetName())) thePolargram=0;
3643  if (!thePolargram) {
3644  // Find any other Polargram in the Pad
3645  TListIter padObjIter(gPad->GetListOfPrimitives());
3646  while (TObject* AnyObj = padObjIter.Next()) {
3647  if (TString(AnyObj->ClassName()).CompareTo("TGraphPolargram",
3648  TString::kExact)==0)
3649  thePolargram = (TGraphPolargram*)AnyObj;
3650  theGraphPolar->SetPolargram(thePolargram);
3651  }
3652  }
3653  }
3654 
3655  // Get new polargram range if necessary.
3656  if (!thePolargram) {
3657  // Get range, initialize with first/last value
3658  rwrmin = theY[0]; rwrmax = theY[theNpoints-1];
3659  rwtmin = theX[0]; rwtmax = theX[theNpoints-1];
3660 
3661  for (ipt = 0; ipt < theNpoints; ipt++) {
3662  // Check for errors if available
3663  if (theEX) {
3664  if (theX[ipt] -theEX[ipt] < rwtmin) rwtmin = theX[ipt]-theEX[ipt];
3665  if (theX[ipt] +theEX[ipt] > rwtmax) rwtmax = theX[ipt]+theEX[ipt];
3666  } else {
3667  if (theX[ipt] < rwtmin) rwtmin=theX[ipt];
3668  if (theX[ipt] > rwtmax) rwtmax=theX[ipt];
3669  }
3670  if (theEY) {
3671  if (theY[ipt] -theEY[ipt] < rwrmin) rwrmin = theY[ipt]-theEY[ipt];
3672  if (theY[ipt] +theEY[ipt] > rwrmax) rwrmax = theY[ipt]+theEY[ipt];
3673  } else {
3674  if (theY[ipt] < rwrmin) rwrmin=theY[ipt];
3675  if (theY[ipt] > rwrmax) rwrmax=theY[ipt];
3676  }
3677  }
3678  // Add radial and Polar margins.
3679  if (rwrmin == rwrmax) rwrmax += 1.;
3680  if (rwtmin == rwtmax) rwtmax += 1.;
3681  Double_t dr = (rwrmax-rwrmin);
3682  Double_t dt = (rwtmax-rwtmin);
3683  rwrmax += 0.1*dr;
3684  rwrmin -= 0.1*dr;
3685 
3686  // Assume equally spaced points for full 2*Pi.
3687  rwtmax += dt/theNpoints;
3688  } else {
3689  rwrmin = thePolargram->GetRMin();
3690  rwrmax = thePolargram->GetRMax();
3691  rwtmin = thePolargram->GetTMin();
3692  rwtmax = thePolargram->GetTMax();
3693  }
3694 
3695  if ((!thePolargram) || theGraphPolar->GetOptionAxis()) {
3696  // Draw Polar coord system
3697  thePolargram = new TGraphPolargram("Polargram",rwrmin,rwrmax,rwtmin,rwtmax);
3698  theGraphPolar->SetPolargram(thePolargram);
3699  if (opt.Contains("O")) thePolargram->SetBit(TGraphPolargram::kLabelOrtho);
3700  else thePolargram->ResetBit(TGraphPolargram::kLabelOrtho);
3701  if (nolabel) thePolargram->Draw("N");
3702  else thePolargram->Draw("");
3703  theGraphPolar->SetOptionAxis(kFALSE); //Prevent redrawing
3704  }
3705 
3706  // Convert points to polar.
3707  Double_t *theXpol = theGraphPolar->GetXpol();
3708  Double_t *theYpol = theGraphPolar->GetYpol();
3709 
3710  // Project theta in [0,2*Pi] and radius in [0,1].
3711  Double_t radiusNDC = rwrmax-rwrmin;
3712  Double_t thetaNDC = (rwtmax-rwtmin)/(2*TMath::Pi());
3713 
3714  // Draw the error bars.
3715  // Y errors are lines, but X errors are pieces of circles.
3716  if (opt.Contains("E")) {
3717  Double_t c=1;
3718  if (thePolargram->IsDegree()) {c=180/TMath::Pi();}
3719  if (thePolargram->IsGrad()) {c=100/TMath::Pi();}
3720  if (theEY) {
3721  for (i=0; i<theNpoints; i++) {
3722  Double_t eymin, eymax, exmin,exmax;
3723  exmin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
3724  TMath::Cos(c*(theX[i]-rwtmin)/thetaNDC);
3725  eymin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
3726  TMath::Sin(c*(theX[i]-rwtmin)/thetaNDC);
3727  exmax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
3728  TMath::Cos(c*(theX[i]-rwtmin)/thetaNDC);
3729  eymax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
3730  TMath::Sin(c*(theX[i]-rwtmin)/thetaNDC);
3731  theGraphPolar->TAttLine::Modify();
3732  if (exmin != exmax || eymin != eymax) gPad->PaintLine(exmin,eymin,exmax,eymax);
3733  }
3734  }
3735  if (theEX) {
3736  for (i=0; i<theNpoints; i++) {
3737  Double_t rad = (theY[i]-rwrmin)/radiusNDC;
3738  Double_t phimin = c*(theX[i]-theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
3739  Double_t phimax = c*(theX[i]+theEX[i]-rwtmin)/thetaNDC*180/TMath::Pi();
3740  theGraphPolar->TAttLine::Modify();
3741  if (phimin != phimax) thePolargram->PaintCircle(0,0,rad,phimin,phimax,0);
3742  }
3743  }
3744  }
3745 
3746  // Draw the graph itself.
3747  if (!(gPad->GetLogx()) && !(gPad->GetLogy())) {
3748  Double_t a, b, c=1, x1, x2, y1, y2, discr, norm1, norm2, xts, yts;
3749  Bool_t previouspointin = kFALSE;
3750  Double_t norm = 0;
3751  Double_t xt = 0;
3752  Double_t yt = 0 ;
3753  Int_t j = -1;
3754  if (thePolargram->IsDegree()) {c=180/TMath::Pi();}
3755  if (thePolargram->IsGrad()) {c=100/TMath::Pi();}
3756  for (i=0; i<theNpoints; i++) {
3757  xts = xt;
3758  yts = yt;
3759  xt = (theY[i]-rwrmin)/radiusNDC*TMath::Cos(c*(theX[i]-rwtmin)/thetaNDC);
3760  yt = (theY[i]-rwrmin)/radiusNDC*TMath::Sin(c*(theX[i]-rwtmin)/thetaNDC);
3761  norm = sqrt(xt*xt+yt*yt);
3762  // Check if points are in the main circle.
3763  if ( norm <= 1) {
3764  // We check that the previous point was in the circle too.
3765  // We record new point position.
3766  if (!previouspointin) {
3767  j++;
3768  theXpol[j] = xt;
3769  theYpol[j] = yt;
3770  } else {
3771  a = (yt-yts)/(xt-xts);
3772  b = yts-a*xts;
3773  discr = 4*(a*a-b*b+1);
3774  x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
3775  x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
3776  y1 = a*x1+b;
3777  y2 = a*x2+b;
3778  norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
3779  norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
3780  previouspointin = kFALSE;
3781  j = 0;
3782  if (norm1 < norm2) {
3783  theXpol[j] = x1;
3784  theYpol[j] = y1;
3785  } else {
3786  theXpol[j] = x2;
3787  theYpol[j] = y2;
3788  }
3789  j++;
3790  theXpol[j] = xt;
3791  theYpol[j] = yt;
3792  PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
3793  }
3794  } else {
3795  // We check that the previous point was in the circle.
3796  // We record new point position
3797  if (j>=1 && !previouspointin) {
3798  a = (yt-theYpol[j])/(xt-theXpol[j]);
3799  b = theYpol[j]-a*theXpol[j];
3800  previouspointin = kTRUE;
3801  discr = 4*(a*a-b*b+1);
3802  x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
3803  x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
3804  y1 = a*x1+b;
3805  y2 = a*x2+b;
3806  norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
3807  norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
3808  j++;
3809  if (norm1 < norm2) {
3810  theXpol[j] = x1;
3811  theYpol[j] = y1;
3812  } else {
3813  theXpol[j] = x2;
3814  theYpol[j] = y2;
3815  }
3816  PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
3817  }
3818  j=-1;
3819  }
3820  }
3821  if (j>=1) {
3822  // If the last point is in the circle, we draw the last serie of point.
3823  PaintGraph(theGraphPolar, j+1, theXpol, theYpol, opt);
3824  }
3825  } else {
3826  for (i=0; i<theNpoints; i++) {
3827  theXpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Cos((theX[i]-rwtmin)/thetaNDC)+1);
3828  theYpol[i] = TMath::Abs((theY[i]-rwrmin)/radiusNDC*TMath::Sin((theX[i]-rwtmin)/thetaNDC)+1);
3829  }
3830  PaintGraph(theGraphPolar, theNpoints, theXpol, theYpol,opt);
3831  }
3832 
3833  // Paint the title.
3834 
3835  if (TestBit(TH1::kNoTitle)) return;
3836  Int_t nt = strlen(theGraph->GetTitle());
3837  TPaveText *title = 0;
3838  TObject *obj;
3839  TIter next(gPad->GetListOfPrimitives());
3840  while ((obj = next())) {
3841  if (!obj->InheritsFrom(TPaveText::Class())) continue;
3842  title = (TPaveText*)obj;
3843  if (title->GetName())
3844  if (strcmp(title->GetName(),"title")) {title = 0; continue;}
3845  break;
3846  }
3847  if (nt == 0 || gStyle->GetOptTitle() <= 0) {
3848  if (title) delete title;
3849  return;
3850  }
3851  Double_t ht = gStyle->GetTitleH();
3852  Double_t wt = gStyle->GetTitleW();
3853  if (ht <= 0) ht = 1.1*gStyle->GetTitleFontSize();
3854  if (ht <= 0) ht = 0.05;
3855  if (wt <= 0) {
3856  TLatex l;
3857  l.SetTextSize(ht);
3858  l.SetTitle(theGraph->GetTitle());
3859  // Adjustment in case the title has several lines (#splitline)
3860  ht = TMath::Max(ht, 1.2*l.GetYsize()/(gPad->GetY2() - gPad->GetY1()));
3861  Double_t wndc = l.GetXsize()/(gPad->GetX2() - gPad->GetX1());
3862  wt = TMath::Min(0.7, 0.02+wndc);
3863  }
3864  if (title) {
3865  TText *t0 = (TText*)title->GetLine(0);
3866  if (t0) {
3867  if (!strcmp(t0->GetTitle(),theGraph->GetTitle())) return;
3868  t0->SetTitle(theGraph->GetTitle());
3869  if (wt > 0) title->SetX2NDC(title->GetX1NDC()+wt);
3870  }
3871  return;
3872  }
3873 
3874  Int_t talh = gStyle->GetTitleAlign()/10;
3875  if (talh < 1) talh = 1; else if (talh > 3) talh = 3;
3876  Int_t talv = gStyle->GetTitleAlign()%10;
3877  if (talv < 1) talv = 1; else if (talv > 3) talv = 3;
3878 
3879  Double_t xpos, ypos;
3880  xpos = gStyle->GetTitleX();
3881  ypos = gStyle->GetTitleY();
3882 
3883  if (talh == 2) xpos = xpos-wt/2.;
3884  if (talh == 3) xpos = xpos-wt;
3885  if (talv == 2) ypos = ypos+ht/2.;
3886  if (talv == 1) ypos = ypos+ht;
3887 
3888  TPaveText *ptitle = new TPaveText(xpos, ypos-ht, xpos+wt, ypos,"blNDC");
3889 
3890  // Box with the histogram title.
3891  ptitle->SetFillColor(gStyle->GetTitleFillColor());
3892  ptitle->SetFillStyle(gStyle->GetTitleStyle());
3893  ptitle->SetName("title");
3894  ptitle->SetBorderSize(gStyle->GetTitleBorderSize());
3895  ptitle->SetTextColor(gStyle->GetTitleTextColor());
3896  ptitle->SetTextFont(gStyle->GetTitleFont(""));
3897  if (gStyle->GetTitleFont("")%10 > 2)
3898  ptitle->SetTextSize(gStyle->GetTitleFontSize());
3899  ptitle->AddText(theGraph->GetTitle());
3900  ptitle->SetBit(kCanDelete);
3901  ptitle->Draw();
3902  ptitle->Paint();
3903 }
3904 
3905 
3906 ////////////////////////////////////////////////////////////////////////////////
3907 /// Paint this graphQQ. No options for the time being.
3908 
3909 void TGraphPainter::PaintGraphQQ(TGraph *theGraph, Option_t *option)
3910 {
3911 
3912  TGraphQQ *theGraphQQ = (TGraphQQ*) theGraph;
3913 
3914  Double_t *theX = theGraphQQ->GetX();
3915  Double_t theXq1 = theGraphQQ->GetXq1();
3916  Double_t theXq2 = theGraphQQ->GetXq2();
3917  Double_t theYq1 = theGraphQQ->GetYq1();
3918  Double_t theYq2 = theGraphQQ->GetYq2();
3919  TF1 *theF = theGraphQQ->GetF();
3920 
3921  if (!theX){
3922  Error("TGraphQQ::Paint", "2nd dataset or theoretical function not specified");
3923  return;
3924  }
3925 
3926  if (theF){
3927  theGraphQQ->GetXaxis()->SetTitle("theoretical quantiles");
3928  theGraphQQ->GetYaxis()->SetTitle("data quantiles");
3929  }
3930 
3931  PaintGraphSimple(theGraph,option);
3932 
3933  Double_t xmin = gPad->GetUxmin();
3934  Double_t xmax = gPad->GetUxmax();
3935  Double_t ymin = gPad->GetUymin();
3936  Double_t ymax = gPad->GetUymax();
3937  Double_t yxmin, xymin, yxmax, xymax;
3938  Double_t xqmin = TMath::Max(xmin, theXq1);
3939  Double_t xqmax = TMath::Min(xmax, theXq2);
3940  Double_t yqmin = TMath::Max(ymin, theYq1);
3941  Double_t yqmax = TMath::Min(ymax, theYq2);
3942 
3943  TLine line1, line2, line3;
3944  line1.SetLineStyle(2);
3945  line3.SetLineStyle(2);
3946  yxmin = (theYq2-theYq1)*(xmin-theXq1)/(theXq2-theXq1) + theYq1;
3947  if (yxmin < ymin){
3948  xymin = (theXq2-theXq1)*(ymin-theYq1)/(theYq2-theYq1) + theXq1;
3949  line1.PaintLine(xymin, ymin, xqmin, yqmin);
3950  }
3951  else
3952  line1.PaintLine(xmin, yxmin, xqmin, yqmin);
3953 
3954  line2.PaintLine(xqmin, yqmin, xqmax, yqmax);
3955 
3956  yxmax = (theYq2-theYq1)*(xmax-theXq1)/(theXq2-theXq1) + theYq1;
3957  if (yxmax > ymax){
3958  xymax = (theXq2-theXq1)*(ymax-theYq1)/(theYq2-theYq1) + theXq1;
3959  line3.PaintLine(xqmax, yqmax, xymax, ymax);
3960  }
3961  else
3962  line3.PaintLine(xqmax, yqmax, xmax, yxmax);
3963 }
3964 
3965 
3966 ////////////////////////////////////////////////////////////////////////////////
3967 /// Paint theGraph reverting values along X and/or Y axis. a new graph is created.
3968 
3969 void TGraphPainter::PaintGraphReverse(TGraph *theGraph, Option_t *option)
3970 {
3971  TString opt = option;
3972  opt.ToLower();
3973  TH1F *theHist = (TH1F *)theGraph->GetHistogram();
3974 
3975  Bool_t lrx = opt.Contains("rx");
3976  Bool_t lry = opt.Contains("ry");
3977  Bool_t axis = opt.Contains("a");
3978  opt.ReplaceAll("a", "");
3979 
3980  Double_t LOX = theHist->GetXaxis()->GetLabelOffset();
3981  Double_t TLX = theHist->GetXaxis()->GetTickLength();
3982  Double_t LOY = theHist->GetYaxis()->GetLabelOffset();
3983  Double_t TLY = theHist->GetYaxis()->GetTickLength();
3984  Int_t XACOL = theHist->GetXaxis()->GetAxisColor();
3985  Int_t YACOL = theHist->GetYaxis()->GetAxisColor();
3986 
3987  if (axis) {
3988  if (lrx) {
3989  theHist->GetXaxis()->SetTickLength(0.);
3990  theHist->GetXaxis()->SetLabelOffset(999.);
3991  theHist->GetXaxis()->SetAxisColor(gPad->GetFrameFillColor());
3992  }
3993  if (lry) {
3994  theHist->GetYaxis()->SetTickLength(0.);
3995  theHist->GetYaxis()->SetLabelOffset(999.);
3996  theHist->GetYaxis()->SetAxisColor(gPad->GetFrameFillColor());
3997  }
3998  theHist->Paint("0");
3999  }
4000 
4001  Int_t N = theGraph->GetN();
4002  Double_t *X = theGraph->GetX();
4003  Double_t *Y = theGraph->GetY();
4004  Double_t XA1, XA2, YA1, YA2;
4005  if (axis) {
4006  XA1 = theGraph->GetXaxis()->GetXmin();
4007  XA2 = theGraph->GetXaxis()->GetXmax();
4008  YA1 = theGraph->GetYaxis()->GetXmin();
4009  YA2 = theGraph->GetYaxis()->GetXmax();
4010  } else {
4011  XA1 = gPad->GetUxmin();
4012  XA2 = gPad->GetUxmax();
4013  YA1 = gPad->GetUymin();
4014  YA2 = gPad->GetUymax();
4015  }
4016  Double_t dX = XA1+XA2;
4017  Double_t dY = YA1+YA2;
4018 
4019  std::vector<Double_t> newX(N);
4020  std::vector<Double_t> newY(N);
4021 
4022  if (lrx) {
4023  opt.ReplaceAll("rx", "");
4024  if (axis) {
4025  Double_t GL = 0.;
4026  theHist->GetXaxis()->SetTickLength(0.);
4027  theHist->GetXaxis()->SetLabelOffset(999.);
4028 
4029  // Redraw the new X axis
4030  gPad->Update();
4031  TString optax = "-SDH";
4032  if (gPad->GetGridx()) {
4033  GL = (YA2 - YA1) / (gPad->GetY2() - gPad->GetY1());
4034  optax.Append("W");
4035  }
4036  auto *theNewAxis = new TGaxis(gPad->GetUxmax(),
4037  gPad->GetUymin(),
4038  gPad->GetUxmin(),
4039  gPad->GetUymin(),
4040  theGraph->GetXaxis()->GetXmin(),
4041  theGraph->GetXaxis()->GetXmax(),
4042  theHist->GetNdivisions("X"),
4043  optax.Data(), -GL);
4044  theNewAxis->SetLabelFont(theGraph->GetXaxis()->GetLabelFont());
4045  theNewAxis->SetLabelSize(theGraph->GetXaxis()->GetLabelSize());
4046  theNewAxis->SetLabelColor(theGraph->GetXaxis()->GetLabelColor());
4047  theNewAxis->SetTickLength(TLX);
4048  theNewAxis->SetLabelOffset(LOX - theGraph->GetXaxis()->GetLabelSize());
4049  theNewAxis->Paint();
4050  }
4051  // Reverse X coordinates
4052  for (Int_t i=0; i<N; i++) newX[i] = dX-X[i];
4053  } else {
4054  for (Int_t i=0; i<N; i++) newX[i] = X[i];
4055  }
4056 
4057  if (lry) {
4058  opt.ReplaceAll("ry", "");
4059  if (axis) {
4060  Double_t GL = 0.;
4061  // Redraw the new Y axis
4062  gPad->Update();
4063  TString optax = "-SDH";
4064 
4065  if (gPad->GetGridy()) {
4066  GL = (XA2 - XA1) / (gPad->GetX2() - gPad->GetX1());
4067  optax.Append("W");
4068  }
4069  auto *theNewAxis = new TGaxis(gPad->GetUxmin(),
4070  gPad->GetUymax(),
4071  gPad->GetUxmin(),
4072  gPad->GetUymin(),
4073  theGraph->GetYaxis()->GetXmin(),
4074  theGraph->GetYaxis()->GetXmax(),
4075  theHist->GetNdivisions("Y"),
4076  optax.Data(), GL);
4077  theNewAxis->SetLabelFont(theGraph->GetYaxis()->GetLabelFont());
4078  theNewAxis->SetLabelSize(theGraph->GetYaxis()->GetLabelSize());
4079  theNewAxis->SetLabelColor(theGraph->GetYaxis()->GetLabelColor());
4080  theNewAxis->SetTickLength(-TLY);
4081  theNewAxis->SetLabelOffset(LOY-TLY);
4082  theNewAxis->Paint();
4083  }
4084  // Reverse Y coordinates
4085  for (Int_t i=0; i<N; i++) newY[i] = dY-Y[i];
4086  } else {
4087  for (Int_t i=0; i<N; i++) newY[i] = Y[i];
4088  }
4089 
4090  // Create the new reversed graph
4091  TGraph *theNewGraph = (TGraph*)theGraph->Clone();
4092  for (Int_t i=0; i<N; i++) theNewGraph->SetPoint(i, newX[i], newY[i]);
4093  theNewGraph->SetMarkerStyle(theGraph->GetMarkerStyle());
4094  theNewGraph->SetMarkerColor(theGraph->GetMarkerColor());
4095  theNewGraph->SetLineStyle(theGraph->GetLineStyle());
4096  theNewGraph->SetLineColor(theGraph->GetLineColor());
4097 
4098  PaintHelper(theNewGraph,opt.Data());
4099 
4100  theHist->GetXaxis()->SetLabelOffset(LOX);
4101  theHist->GetXaxis()->SetTickLength(TLX);
4102  theHist->GetYaxis()->SetLabelOffset(LOY);
4103  theHist->GetYaxis()->SetTickLength(TLY);
4104  theHist->GetXaxis()->SetAxisColor(XACOL);
4105  theHist->GetYaxis()->SetAxisColor(YACOL);
4106 }
4107 
4108 
4109 ////////////////////////////////////////////////////////////////////////////////
4110 /// Paint a simple graph, without errors bars.
4111 
4112 void TGraphPainter::PaintGraphSimple(TGraph *theGraph, Option_t *option)
4113 {
4114 
4115  if (strstr(option,"H") || strstr(option,"h")) {
4116  PaintGrapHist(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
4117  } else {
4118  PaintGraph(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
4119  }
4120 
4121  PaintHighlightPoint(theGraph, option);
4122 
4123  // Paint associated objects in the list of functions (for instance
4124  // the fit function).
4125  TList *functions = theGraph->GetListOfFunctions();
4126  if (!functions) return;
4127  TObjOptLink *lnk = (TObjOptLink*)functions->FirstLink();
4128  TObject *obj;
4129 
4130  while (lnk) {
4131  obj = lnk->GetObject();
4132  TVirtualPad *padsave = gPad;
4133  if (obj->InheritsFrom(TF1::Class())) {
4134  if (obj->TestBit(TF1::kNotDraw) == 0) obj->Paint("lsame");
4135  } else {
4136  obj->Paint(lnk->GetOption());
4137  }
4138  lnk = (TObjOptLink*)lnk->Next();
4139  padsave->cd();
4140  }
4141  return;
4142 }
4143 
4144 
4145 ////////////////////////////////////////////////////////////////////////////////
4146 /// Paint a polyline with hatches on one side showing an exclusion zone. x and y
4147 /// are the the vectors holding the polyline and n the number of points in the
4148 /// polyline and `w` the width of the hatches. `w` can be negative.
4149 /// This method is not meant to be used directly. It is called automatically
4150 /// according to the line style convention.
4151 
4152 void TGraphPainter::PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y)
4153 {
4154 
4155  Int_t i,j,nf;
4156  Double_t w = (theGraph->GetLineWidth()/100)*0.005;
4157 
4158  Double_t *xf = new Double_t[2*n];
4159  Double_t *yf = new Double_t[2*n];
4160  Double_t *xt = new Double_t[n];
4161  Double_t *yt = new Double_t[n];
4162  Double_t x1, x2, y1, y2, x3, y3, xm, ym, a, a1, a2, a3;
4163 
4164  // Compute the gPad coordinates in TRUE normalized space (NDC)
4165  Int_t ix1,iy1,ix2,iy2;
4166  Int_t iw = gPad->GetWw();
4167  Int_t ih = gPad->GetWh();
4168  Double_t x1p,y1p,x2p,y2p;
4169  gPad->GetPadPar(x1p,y1p,x2p,y2p);
4170  ix1 = (Int_t)(iw*x1p);
4171  iy1 = (Int_t)(ih*y1p);
4172  ix2 = (Int_t)(iw*x2p);
4173  iy2 = (Int_t)(ih*y2p);
4174  Double_t wndc = TMath::Min(1.,(Double_t)iw/(Double_t)ih);
4175  Double_t hndc = TMath::Min(1.,(Double_t)ih/(Double_t)iw);
4176  Double_t rh = hndc/(Double_t)ih;
4177  Double_t rw = wndc/(Double_t)iw;
4178  Double_t x1ndc = (Double_t)ix1*rw;
4179  Double_t y1ndc = (Double_t)iy1*rh;
4180  Double_t x2ndc = (Double_t)ix2*rw;
4181  Double_t y2ndc = (Double_t)iy2*rh;
4182 
4183  // Ratios to convert user space in TRUE normalized space (NDC)
4184  Double_t rx1,ry1,rx2,ry2;
4185  gPad->GetRange(rx1,ry1,rx2,ry2);
4186  Double_t rx = (x2ndc-x1ndc)/(rx2-rx1);
4187  Double_t ry = (y2ndc-y1ndc)/(ry2-ry1);
4188 
4189  // The first part of the filled area is made of the graph points.
4190  // Make sure that two adjacent points are different.
4191  xf[0] = rx*(x[0]-rx1)+x1ndc;
4192  yf[0] = ry*(y[0]-ry1)+y1ndc;
4193  nf = 0;
4194  for (i=1; i<n; i++) {
4195  if (x[i]==x[i-1] && y[i]==y[i-1]) continue;
4196  nf++;
4197  xf[nf] = rx*(x[i]-rx1)+x1ndc;
4198  if (xf[i]==xf[i-1]) xf[i] += 0.000001; // add an epsilon to avoid exact vertical lines.
4199  yf[nf] = ry*(y[i]-ry1)+y1ndc;
4200  }
4201 
4202  // For each graph points a shifted points is computed to build up
4203  // the second part of the filled area. First and last points are
4204  // treated as special cases, outside of the loop.
4205  if (xf[1]==xf[0]) {
4206  a = TMath::PiOver2();
4207  } else {
4208  a = TMath::ATan((yf[1]-yf[0])/(xf[1]-xf[0]));
4209  }
4210  if (xf[0]<=xf[1]) {
4211  xt[0] = xf[0]-w*TMath::Sin(a);
4212  yt[0] = yf[0]+w*TMath::Cos(a);
4213  } else {
4214  xt[0] = xf[0]+w*TMath::Sin(a);
4215  yt[0] = yf[0]-w*TMath::Cos(a);
4216  }
4217 
4218  if (xf[nf]==xf[nf-1]) {
4219  a = TMath::PiOver2();
4220  } else {
4221  a = TMath::ATan((yf[nf]-yf[nf-1])/(xf[nf]-xf[nf-1]));
4222  }
4223  if (xf[nf]>=xf[nf-1]) {
4224  xt[nf] = xf[nf]-w*TMath::Sin(a);
4225  yt[nf] = yf[nf]+w*TMath::Cos(a);
4226  } else {
4227  xt[nf] = xf[nf]+w*TMath::Sin(a);
4228  yt[nf] = yf[nf]-w*TMath::Cos(a);
4229  }
4230 
4231  Double_t xi0,yi0,xi1,yi1,xi2,yi2;
4232  for (i=1; i<nf; i++) {
4233  xi0 = xf[i];
4234  yi0 = yf[i];
4235  xi1 = xf[i+1];
4236  yi1 = yf[i+1];
4237  xi2 = xf[i-1];
4238  yi2 = yf[i-1];
4239  if (xi1==xi0) {
4240  a1 = TMath::PiOver2();
4241  } else {
4242  a1 = TMath::ATan((yi1-yi0)/(xi1-xi0));
4243  }
4244  if (xi1<xi0) a1 = a1+3.14159;
4245  if (xi2==xi0) {
4246  a2 = TMath::PiOver2();
4247  } else {
4248  a2 = TMath::ATan((yi0-yi2)/(xi0-xi2));
4249  }
4250  if (xi0<xi2) a2 = a2+3.14159;
4251  x1 = xi0-w*TMath::Sin(a1);
4252  y1 = yi0+w*TMath::Cos(a1);
4253  x2 = xi0-w*TMath::Sin(a2);
4254  y2 = yi0+w*TMath::Cos(a2);
4255  xm = (x1+x2)*0.5;
4256  ym = (y1+y2)*0.5;
4257  if (xm==xi0) {
4258  a3 = TMath::PiOver2();
4259  } else {
4260  a3 = TMath::ATan((ym-yi0)/(xm-xi0));
4261  }
4262  x3 = xi0-w*TMath::Sin(a3+1.57079);
4263  y3 = yi0+w*TMath::Cos(a3+1.57079);
4264  // Rotate (x3,y3) by PI around (xi0,yi0) if it is not on the (xm,ym) side.
4265  if ((xm-xi0)*(x3-xi0)<0 && (ym-yi0)*(y3-yi0)<0) {
4266  x3 = 2*xi0-x3;
4267  y3 = 2*yi0-y3;
4268  }
4269  if ((xm==x1) && (ym==y1)) {
4270  x3 = xm;
4271  y3 = ym;
4272  }
4273  xt[i] = x3;
4274  yt[i] = y3;
4275  }
4276 
4277  // Close the polygon if the first and last points are the same
4278  if (xf[nf]==xf[0] && yf[nf]==yf[0]) {
4279  xm = (xt[nf]+xt[0])*0.5;
4280  ym = (yt[nf]+yt[0])*0.5;
4281  if (xm==xf[0]) {
4282  a3 = TMath::PiOver2();
4283  } else {
4284  a3 = TMath::ATan((ym-yf[0])/(xm-xf[0]));
4285  }
4286  x3 = xf[0]+w*TMath::Sin(a3+1.57079);
4287  y3 = yf[0]-w*TMath::Cos(a3+1.57079);
4288  if ((xm-xf[0])*(x3-xf[0])<0 && (ym-yf[0])*(y3-yf[0])<0) {
4289  x3 = 2*xf[0]-x3;
4290  y3 = 2*yf[0]-y3;
4291  }
4292  xt[nf] = x3;
4293  xt[0] = x3;
4294  yt[nf] = y3;
4295  yt[0] = y3;
4296  }
4297 
4298  // Find the crossing segments and remove the useless ones
4299  Double_t xc, yc, c1, b1, c2, b2;
4300  Bool_t cross = kFALSE;
4301  Int_t nf2 = nf;
4302  for (i=nf2; i>0; i--) {
4303  for (j=i-1; j>0; j--) {
4304  if (xt[i-1]==xt[i] || xt[j-1]==xt[j]) continue;
4305  c1 = (yt[i-1]-yt[i])/(xt[i-1]-xt[i]);
4306  b1 = yt[i]-c1*xt[i];
4307  c2 = (yt[j-1]-yt[j])/(xt[j-1]-xt[j]);
4308  b2 = yt[j]-c2*xt[j];
4309  if (c1 != c2) {
4310  xc = (b2-b1)/(c1-c2);
4311  yc = c1*xc+b1;
4312  if (xc>TMath::Min(xt[i],xt[i-1]) && xc<TMath::Max(xt[i],xt[i-1]) &&
4313  xc>TMath::Min(xt[j],xt[j-1]) && xc<TMath::Max(xt[j],xt[j-1]) &&
4314  yc>TMath::Min(yt[i],yt[i-1]) && yc<TMath::Max(yt[i],yt[i-1]) &&
4315  yc>TMath::Min(yt[j],yt[j-1]) && yc<TMath::Max(yt[j],yt[j-1])) {
4316  nf++; xf[nf] = xt[i]; yf[nf] = yt[i];
4317  nf++; xf[nf] = xc ; yf[nf] = yc;
4318  i = j;
4319  cross = kTRUE;
4320  break;
4321  } else {
4322  continue;
4323  }
4324  } else {
4325  continue;
4326  }
4327  }
4328  if (!cross) {
4329  nf++;
4330  xf[nf] = xt[i];
4331  yf[nf] = yt[i];
4332  }
4333  cross = kFALSE;
4334  }
4335  nf++; xf[nf] = xt[0]; yf[nf] = yt[0];
4336 
4337  // NDC to user coordinates
4338  for (i=0; i<nf+1; i++) {
4339  xf[i] = (1/rx)*(xf[i]-x1ndc)+rx1;
4340  yf[i] = (1/ry)*(yf[i]-y1ndc)+ry1;
4341  }
4342 
4343  // Draw filled area
4344  gPad->PaintFillArea(nf+1,xf,yf);
4345  theGraph->TAttLine::Modify(); // In case of PaintFillAreaHatches
4346 
4347  delete [] xf;
4348  delete [] yf;
4349  delete [] xt;
4350  delete [] yt;
4351 }
4352 
4353 
4354 ////////////////////////////////////////////////////////////////////////////////
4355 /// Paint the statistics box with the fit info.
4356 
4357 void TGraphPainter::PaintStats(TGraph *theGraph, TF1 *fit)
4358 {
4359 
4360  Int_t dofit;
4361  TPaveStats *stats = 0;
4362  TList *functions = theGraph->GetListOfFunctions();
4363  TIter next(functions);
4364  TObject *obj;
4365  while ((obj = next())) {
4366  if (obj->InheritsFrom(TPaveStats::Class())) {
4367  stats = (TPaveStats*)obj;
4368  break;
4369  }
4370  }
4371 
4372  if (stats) dofit = stats->GetOptFit();
4373  else dofit = gStyle->GetOptFit();
4374 
4375  if (!dofit) fit = 0;
4376  if (!fit) return;
4377  if (dofit == 1) dofit = 111;
4378  Int_t nlines = 0;
4379  Int_t print_fval = dofit%10;
4380  Int_t print_ferrors = (dofit/10)%10;
4381  Int_t print_fchi2 = (dofit/100)%10;
4382  Int_t print_fprob = (dofit/1000)%10;
4383  Int_t nlinesf = print_fval + print_fchi2 + print_fprob;
4384  if (fit) nlinesf += fit->GetNpar();
4385  Bool_t done = kFALSE;
4386  Double_t statw = 1.8*gStyle->GetStatW();
4387  Double_t stath = 0.25*(nlines+nlinesf)*gStyle->GetStatH();
4388  if (stats) {
4389  stats->Clear();
4390  done = kTRUE;
4391  } else {
4392  stats = new TPaveStats(
4393  gStyle->GetStatX()-statw,
4394  gStyle->GetStatY()-stath,
4395  gStyle->GetStatX(),
4396  gStyle->GetStatY(),"brNDC");
4397 
4398  stats->SetParent(functions);
4399  stats->SetOptFit(dofit);
4400  stats->SetOptStat(0);
4401  stats->SetFillColor(gStyle->GetStatColor());
4402  stats->SetFillStyle(gStyle->GetStatStyle());
4403  stats->SetBorderSize(gStyle->GetStatBorderSize());
4404  stats->SetTextFont(gStyle->GetStatFont());
4405  if (gStyle->GetStatFont()%10 > 2)
4406  stats->SetTextSize(gStyle->GetStatFontSize());
4407  stats->SetFitFormat(gStyle->GetFitFormat());
4408  stats->SetStatFormat(gStyle->GetStatFormat());
4409  stats->SetName("stats");
4410 
4411  stats->SetTextColor(gStyle->GetStatTextColor());
4412  stats->SetTextAlign(12);
4413  stats->SetBit(kCanDelete);
4414  stats->SetBit(kMustCleanup);
4415  }
4416 
4417  char t[64];
4418  char textstats[50];
4419  Int_t ndf = fit->GetNDF();
4420  snprintf(textstats,50,"#chi^{2} / ndf = %s%s / %d","%",stats->GetFitFormat(),ndf);
4421  snprintf(t,64,textstats,(Float_t)fit->GetChisquare());
4422  if (print_fchi2) stats->AddText(t);
4423  if (print_fprob) {
4424  snprintf(textstats,50,"Prob = %s%s","%",stats->GetFitFormat());
4425  snprintf(t,64,textstats,(Float_t)TMath::Prob(fit->GetChisquare(),ndf));
4426  stats->AddText(t);
4427  }
4428  if (print_fval || print_ferrors) {
4429  for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
4430  if (print_ferrors) {
4431  snprintf(textstats,50,"%-8s = %s%s #pm %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat(),"%",stats->GetFitFormat());
4432  snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar)
4433  ,(Float_t)fit->GetParError(ipar));
4434  } else {
4435  snprintf(textstats,50,"%-8s = %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat());
4436  snprintf(t,64,textstats,(Float_t)fit->GetParameter(ipar));
4437  }
4438  t[63] = 0;
4439  stats->AddText(t);
4440  }
4441  }
4442 
4443  if (!done) functions->Add(stats);
4444  stats->Paint();
4445 }
4446 
4447 
4448 ////////////////////////////////////////////////////////////////////////////////
4449 /// Smooth a curve given by N points.
4450 ///
4451 /// The original code is from an underlaying routine for Draw based on the
4452 /// CERN GD3 routine TVIPTE:
4453 ///
4454 /// Author - Marlow etc. Modified by - P. Ward Date - 3.10.1973
4455 ///
4456 /// This method draws a smooth tangentially continuous curve through
4457 /// the sequence of data points P(I) I=1,N where P(I)=(X(I),Y(I)).
4458 /// The curve is approximated by a polygonal arc of short vectors.
4459 /// The data points can represent open curves, P(1) != P(N) or closed
4460 /// curves P(2) == P(N). If a tangential discontinuity at P(I) is
4461 /// required, then set P(I)=P(I+1). Loops are also allowed.
4462 ///
4463 /// Reference Marlow and Powell, Harwell report No.R.7092.1972
4464 /// MCCONALOGUE, Computer Journal VOL.13, NO4, NOV1970P p392 6
4465 ///
4466 /// - npoints : Number of data points.
4467 /// - x : Abscissa
4468 /// - y : Ordinate
4469 
4470 void TGraphPainter::Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype)
4471 {
4472 
4473  Int_t i, k, kp, km, npointsMax, banksize, n2, npt;
4474  Int_t maxiterations, finished;
4475  Int_t jtype, ktype, closed;
4476  Double_t sxmin, sxmax, symin, symax;
4477  Double_t delta;
4478  Double_t xorg, yorg;
4479  Double_t ratio_signs, xratio, yratio;
4480  Int_t flgic, flgis;
4481  Int_t iw, loptx;
4482  Double_t p1, p2, p3, p4, p5, p6;
4483  Double_t w1, w2, w3;
4484  Double_t a, b, c, r, s=0.0, t, z;
4485  Double_t co, so, ct, st, ctu, stu, xnt;
4486  Double_t dx1, dy1, dx2, dy2, dk1, dk2;
4487  Double_t xo, yo, dx, dy, xt, yt;
4488  Double_t xa, xb, ya, yb;
4489  Double_t u1, u2, u3, tj;
4490  Double_t cc, err;
4491  Double_t sb, sth;
4492  Double_t wsign, tsquare, tcube;
4493  c = t = co = so = ct = st = ctu = stu = dx1 = dy1 = dx2 = dy2 = 0;
4494  xt = yt = xa = xb = ya = yb = u1 = u2 = u3 = tj = sb = 0;
4495 
4496  npointsMax = npoints*10;
4497  n2 = npointsMax-2;
4498  banksize = n2;
4499 
4500  Double_t *qlx = new Double_t[npointsMax];
4501  Double_t *qly = new Double_t[npointsMax];
4502  if (!qlx || !qly) {
4503  Error("Smooth", "not enough space in memory");
4504  return;
4505  }
4506 
4507  // Decode the type of curve (draw type).
4508 
4509  loptx = kFALSE;
4510  jtype = (drawtype%1000)-10;
4511  if (jtype > 0) { ktype = jtype; loptx = kTRUE; }
4512  else ktype = drawtype%1000;
4513 
4514  Double_t ruxmin = gPad->GetUxmin();
4515  Double_t ruymin = gPad->GetUymin();
4516  if (ktype == 3) {
4517  xorg = ruxmin;
4518  yorg = ruymin;
4519  } else {
4520  xorg = TMath::Max((Double_t)0,ruxmin);
4521  yorg = TMath::Min(TMath::Max((Double_t)0,ruymin),gPad->GetUymax());
4522  }
4523 
4524  // delta is the accuracy required in constructing the curve.
4525  // If it is zero then the routine calculates a value otherwise
4526  // it uses this value. (default is 0.0)
4527 
4528  delta = 0.00055;
4529  maxiterations = 20;
4530 
4531  // Scale data to the range 0-ratio_signs in X, 0-1 in Y
4532  // where ratio_signs is the ratio between the number of changes
4533  // of sign in Y divided by the number of changes of sign in X
4534 
4535  sxmin = x[0];
4536  sxmax = x[0];
4537  symin = y[0];
4538  symax = y[0];
4539  Double_t six = 1;
4540  Double_t siy = 1;
4541  for (i=1;i<npoints;i++) {
4542  if (i > 1) {
4543  if ((x[i]-x[i-1])*(x[i-1]-x[i-2]) < 0) six++;
4544  if ((y[i]-y[i-1])*(y[i-1]-y[i-2]) < 0) siy++;
4545  }
4546  if (x[i] < sxmin) sxmin = x[i];
4547  if (x[i] > sxmax) sxmax = x[i];
4548  if (y[i] < symin) symin = y[i];
4549  if (y[i] > symax) symax = y[i];
4550  }
4551  closed = 0;
4552  Double_t dx1n = TMath::Abs(x[npoints-1]-x[0]);
4553  Double_t dy1n = TMath::Abs(y[npoints-1]-y[0]);
4554  if (dx1n < 0.01*(sxmax-sxmin) && dy1n < 0.01*(symax-symin)) closed = 1;
4555  if (sxmin == sxmax) {
4556  xratio = 1;
4557  } else {
4558  if (six > 1) ratio_signs = siy/six;
4559  else ratio_signs = 20;
4560  xratio = ratio_signs/(sxmax-sxmin);
4561  }
4562  if (symin == symax) yratio = 1;
4563  else yratio = 1/(symax-symin);
4564 
4565  qlx[0] = x[0];
4566  qly[0] = y[0];
4567  for (i=0;i<npoints;i++) {
4568  x[i] = (x[i]-sxmin)*xratio;
4569  y[i] = (y[i]-symin)*yratio;
4570  }
4571 
4572  // "finished" is minus one if we must draw a straight line from P(k-1)
4573  // to P(k). "finished" is one if the last call to PaintPolyLine has < n2
4574  // points. "finished" is zero otherwise. npt counts the X and Y
4575  // coordinates in work . When npt=n2 a call to IPL is made.
4576 
4577  finished = 0;
4578  npt = 1;
4579  k = 1;
4580 
4581  // Convert coordinates back to original system
4582 
4583  // Separate the set of data points into arcs P(k-1),P(k).
4584  // Calculate the direction cosines. first consider whether
4585  // there is a continuous tangent at the endpoints.
4586 
4587  if (!closed) {
4588  if (x[0] != x[npoints-1] || y[0] != y[npoints-1]) goto L40;
4589  if (x[npoints-2] == x[npoints-1] && y[npoints-2] == y[npoints-1]) goto L40;
4590  if (x[0] == x[1] && y[0] == y[1]) goto L40;
4591  }
4592  flgic = kFALSE;
4593  flgis = kTRUE;
4594 
4595  // flgic is true if the curve is open and false if it is closed.
4596  // flgis is true in the main loop, but is false if there is
4597  // a deviation from the main loop.
4598 
4599  km = npoints - 1;
4600 
4601  // Calculate direction cosines at P(1) using P(N-1),P(1),P(2).
4602 
4603  goto L100;
4604 L40:
4605  flgic = kTRUE;
4606  flgis = kFALSE;
4607 
4608  // Skip excessive consecutive equal points.
4609 
4610 L50:
4611  if (k >= npoints) {
4612  finished = 1; // Prepare to clear out remaining short vectors before returning
4613  if (npt > 1) goto L310;
4614  goto L390;
4615  }
4616  k++;
4617  if (x[k-1] == x[k-2] && y[k-1] == y[k-2]) goto L50;
4618 L60:
4619  km = k-1;
4620  if (k > npoints) {
4621  finished = 1; // Prepare to clear out remaining short vectors before returning
4622  if (npt > 1) goto L310;
4623  goto L390;
4624  }
4625  if (k < npoints) goto L90;
4626  if (!flgic) { kp = 2; goto L130;}
4627 
4628 L80:
4629  if (flgis) goto L150;
4630 
4631  // Draw a straight line from P(k-1) to P(k).
4632 
4633  finished = -1;
4634  goto L170;
4635 
4636  // Test whether P(k) is a cusp.
4637 
4638 L90:
4639  if (x[k-1] == x[k] && y[k-1] == y[k]) goto L80;
4640 L100:
4641  kp = k+1;
4642  goto L130;
4643 
4644  // Branch if the next section of the curve begins at a cusp.
4645 
4646 L110:
4647  if (!flgis) goto L50;
4648 
4649  // Carry forward the direction cosines from the previous arc.
4650 
4651 L120:
4652  co = ct;
4653  so = st;
4654  k++;
4655  goto L60;
4656 
4657  // Calculate the direction cosines at P(k). If k=1 then
4658  // N-1 is used for k-1. If k=N then 2 is used for k+1.
4659  // direction cosines at P(k) obtained from P(k-1),P(k),P(k+1).
4660 
4661 L130:
4662  dx1 = x[k-1] - x[km-1];
4663  dy1 = y[k-1] - y[km-1];
4664  dk1 = dx1*dx1 + dy1*dy1;
4665  dx2 = x[kp-1] - x[k-1];
4666  dy2 = y[kp-1] - y[k-1];
4667  dk2 = dx2*dx2 + dy2*dy2;
4668  ctu = dx1*dk2 + dx2*dk1;
4669  stu = dy1*dk2 + dy2*dk1;
4670  xnt = ctu*ctu + stu*stu;
4671 
4672  // If both ctu and stu are zero,then default.This can
4673  // occur when P(k)=P(k+1). I.E. A loop.
4674 
4675  if (xnt < 1.E-25) {
4676  ctu = dy1;
4677  stu =-dx1;
4678  xnt = dk1;
4679  }
4680  // Normalise direction cosines.
4681 
4682  ct = ctu/TMath::Sqrt(xnt);
4683  st = stu/TMath::Sqrt(xnt);
4684  if (flgis) goto L160;
4685 
4686  // Direction cosines at P(k-1) obtained from P(k-1),P(k),P(k+1).
4687 
4688  w3 = 2*(dx1*dy2-dx2*dy1);
4689  co = ctu+w3*dy1;
4690  so = stu-w3*dx1;
4691  xnt = 1/TMath::Sqrt(co*co+so*so);
4692  co = co*xnt;
4693  so = so*xnt;
4694  flgis = kTRUE;
4695  goto L170;
4696 
4697  // Direction cosines at P(k) obtained from P(k-2),P(k-1),P(k).
4698 
4699 L150:
4700  w3 = 2*(dx1*dy2-dx2*dy1);
4701  ct = ctu-w3*dy2;
4702  st = stu+w3*dx2;
4703  xnt = 1/TMath::Sqrt(ct*ct+st*st);
4704  ct = ct*xnt;
4705  st = st*xnt;
4706  flgis = kFALSE;
4707  goto L170;
4708 L160:
4709  if (k <= 1) goto L120;
4710 
4711  // For the arc between P(k-1) and P(k) with direction cosines co,
4712  // so and ct,st respectively, calculate the coefficients of the
4713  // parametric cubic represented by X(t) and Y(t) where
4714  // X(t)=xa*t**3 + xb*t**2 + co*t + xo
4715  // Y(t)=ya*t**3 + yb*t**2 + so*t + yo
4716 
4717 L170:
4718  xo = x[k-2];
4719  yo = y[k-2];
4720  dx = x[k-1] - xo;
4721  dy = y[k-1] - yo;
4722 
4723  // Initialise the values of X(TI),Y(TI) in xt and yt respectively.
4724 
4725  xt = xo;
4726  yt = yo;
4727  if (finished < 0) { // Draw a straight line between (xo,yo) and (xt,yt)
4728  xt += dx;
4729  yt += dy;
4730  goto L300;
4731  }
4732  c = dx*dx+dy*dy;
4733  a = co+ct;
4734  b = so+st;
4735  r = dx*a+dy*b;
4736  t = c*6/(TMath::Sqrt(r*r+2*(7-co*ct-so*st)*c)+r);
4737  tsquare = t*t;
4738  tcube = t*tsquare;
4739  xa = (a*t-2*dx)/tcube;
4740  xb = (3*dx-(co+a)*t)/tsquare;
4741  ya = (b*t-2*dy)/tcube;
4742  yb = (3*dy-(so+b)*t)/tsquare;
4743 
4744  // If the curve is close to a straight line then use a straight
4745  // line between (xo,yo) and (xt,yt).
4746 
4747  if (.75*TMath::Max(TMath::Abs(dx*so-dy*co),TMath::Abs(dx*st-dy*ct)) <= delta) {
4748  finished = -1;
4749  xt += dx;
4750  yt += dy;
4751  goto L300;
4752  }
4753 
4754  // Calculate a set of values 0 == t(0).LTCT(1) < ... < t(M)=TC
4755  // such that polygonal arc joining X(t(J)),Y(t(J)) (J=0,1,..M)
4756  // is within the required accuracy of the curve
4757 
4758  tj = 0;
4759  u1 = ya*xb-yb*xa;
4760  u2 = yb*co-xb*so;
4761  u3 = so*xa-ya*co;
4762 
4763  // Given t(J), calculate t(J+1). The values of X(t(J)),
4764  // Y(t(J)) t(J) are contained in xt,yt and tj respectively.
4765 
4766 L180:
4767  s = t - tj;
4768  iw = -2;
4769 
4770  // Define iw here later.
4771 
4772  p1 = (2*u1)*tj-u3;
4773  p2 = (u1*tj-u3)*3*tj+u2;
4774  p3 = 3*tj*ya+yb;
4775  p4 = (p3+yb)*tj+so;
4776  p5 = 3*tj*xa+xb;
4777  p6 = (p5+xb)*tj+co;
4778 
4779  // Test D(tj,THETA). A is set to (Y(tj+s)-Y(tj))/s.b is
4780  // set to (X(tj+s)-X(tj))/s.
4781 
4782  cc = 0.8209285;
4783  err = 0.1209835;
4784 L190:
4785  iw -= 2;
4786 L200:
4787  a = (s*ya+p3)*s+p4;
4788  b = (s*xa+p5)*s+p6;
4789 
4790  // Set z to PSI(D/delta)-cc.
4791 
4792  w1 = -s*(s*u1+p1);
4793  w2 = s*s*u1-p2;
4794  w3 = 1.5*w1+w2;
4795 
4796  // Set the estimate of (THETA-tj)/s.Then set the numerator
4797  // of the expression (EQUATION 4.4)/s. Then set the square
4798  // of D(tj,tj+s)/delta. Then replace z by PSI(D/delta)-cc.
4799 
4800  if (w3 > 0) wsign = TMath::Abs(w1);
4801  else wsign = -TMath::Abs(w1);
4802  sth = 0.5+wsign/(3.4*TMath::Abs(w1)+5.2*TMath::Abs(w3));
4803  z = s*sth*(s-s*sth)*(w1*sth+w1+w2);
4804  z = z*z/((a*a+b*b)*(delta*delta));
4805  z = (z+2.642937)*z/((.3715652*z+3.063444)*z+.2441889)-cc;
4806 
4807  // Branch if z has been calculated
4808 
4809  if (iw > 0) goto L250;
4810  if (z > err) goto L240;
4811  goto L220;
4812 L210:
4813  iw -= 2;
4814 L220:
4815  if (iw+2 == 0) goto L190;
4816  if (iw+2 > 0) goto L290;
4817 
4818  // Last part of arc.
4819 
4820 L230:
4821  xt = x[k-1];
4822  yt = y[k-1];
4823  s = 0;
4824  goto L300;
4825 
4826  // z(s). find a value of s where 0 <= s <= sb such that
4827  // TMath::Abs(z(s)) < err
4828 
4829 L240:
4830  kp = 0;
4831  c = z;
4832  sb = s;
4833 L250:
4834  theGraph->Zero(kp,0,sb,err,s,z,maxiterations);
4835  if (kp == 2) goto L210;
4836  if (kp > 2) {
4837  Error("Smooth", "Attempt to plot outside plot limits");
4838  goto L230;
4839  }
4840  if (iw > 0) goto L200;
4841 
4842  // Set z=z(s) for s=0.
4843 
4844  if (iw < 0) {
4845  z = -cc;
4846  iw = 0;
4847  goto L250;
4848  }
4849 
4850  // Set z=z(s) for s=sb.
4851 
4852  z = c;
4853  iw = 1;
4854  goto L250;
4855 
4856  // Update tj,xt and yt.
4857 
4858 L290:
4859  xt = xt + s*b;
4860  yt = yt + s*a;
4861  tj = s + tj;
4862 
4863  // Convert coordinates to original system
4864 
4865 L300:
4866  qlx[npt] = sxmin + xt/xratio;
4867  qly[npt] = symin + yt/yratio;
4868  npt++;
4869 
4870  // If a fill area must be drawn and if the banks LX and
4871  // LY are too small they are enlarged in order to draw
4872  // the filled area in one go.
4873 
4874  if (npt < banksize) goto L320;
4875  if (drawtype >= 1000 || ktype > 1) {
4876  Int_t newsize = banksize + n2;
4877  Double_t *qtemp = new Double_t[banksize];
4878  for (i=0;i<banksize;i++) qtemp[i] = qlx[i];
4879  delete [] qlx;
4880  qlx = new Double_t[newsize];
4881  for (i=0;i<banksize;i++) qlx[i] = qtemp[i];
4882  for (i=0;i<banksize;i++) qtemp[i] = qly[i];
4883  delete [] qly;
4884  qly = new Double_t[newsize];
4885  for (i=0;i<banksize;i++) qly[i] = qtemp[i];
4886  delete [] qtemp;
4887  banksize = newsize;
4888  goto L320;
4889  }
4890 
4891  // Draw the graph
4892 
4893 L310:
4894  if (drawtype >= 1000) {
4895  gPad->PaintFillArea(npt,qlx,qly, "B");
4896  } else {
4897  if (ktype > 1) {
4898  if (!loptx) {
4899  qlx[npt] = qlx[npt-1];
4900  qlx[npt+1] = qlx[0];
4901  qly[npt] = yorg;
4902  qly[npt+1] = yorg;
4903  } else {
4904  qlx[npt] = xorg;
4905  qlx[npt+1] = xorg;
4906  qly[npt] = qly[npt-1];
4907  qly[npt+1] = qly[0];
4908  }
4909  gPad->PaintFillArea(npt+2,qlx,qly);
4910  }
4911  if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, qlx, qly);
4912  gPad->PaintPolyLine(npt,qlx,qly);
4913  }
4914  npt = 1;
4915  qlx[0] = sxmin + xt/xratio;
4916  qly[0] = symin + yt/yratio;
4917 L320:
4918  if (finished > 0) goto L390;
4919  if (finished < 0) { finished = 0; goto L110;}
4920  if (s > 0) goto L180;
4921  goto L110;
4922 
4923  // Convert coordinates back to original system
4924 
4925 L390:
4926  for (i=0;i<npoints;i++) {
4927  x[i] = sxmin + x[i]/xratio;
4928  y[i] = symin + y[i]/yratio;
4929  }
4930 
4931  delete [] qlx;
4932  delete [] qly;
4933 }
4934 
4935 ////////////////////////////////////////////////////////////////////////////////
4936 /// Static function to set `fgMaxPointsPerLine` for graph painting. When graphs
4937 /// are painted with lines, they are split into chunks of length `fgMaxPointsPerLine`.
4938 /// This allows to paint line with an "infinite" number of points. In some case
4939 /// this "chunks painting" technic may create artefacts at the chunk's boundaries.
4940 /// For instance when zooming deeply in a PDF file. To avoid this effect it might
4941 /// be necessary to increase the chunks' size using this function:
4942 /// `TGraphPainter::SetMaxPointsPerLine(20000)`.
4943 
4944 void TGraphPainter::SetMaxPointsPerLine(Int_t maxp)
4945 {
4946  fgMaxPointsPerLine = maxp;
4947  if (maxp < 50) fgMaxPointsPerLine = 50;
4948 }