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