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