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