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