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