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/visualisation/graphs/gr106_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(1)->SetLineColor(kBlue);
464 gme->GetAttFill(1)->SetFillStyle(0);
465
466 gme->Draw("a p s ; ; 5 s=0.5");
467}
468End_Macro
469
470
471\anchor GrP4
472### TGraphPolar options
473
474The drawing options for the polar graphs are the following:
475
476| Option | Description |
477|----------|-------------------------------------------------------------------|
478| "P" | Polymarker are drawn at each point position. |
479| "E" | Draw error bars. |
480| "F" | Draw fill area (closed polygon). |
481| "L" | Draw line. |
482| "C" | Draw curve. |
483| "A" | Force axis redrawing even if a polargram already exists. |
484| "R" | Use radians for angle coordinates. |
485| "D" | Use degrees for angle coordinates. |
486| "G" | Use grads for angle coordinates. |
487| "O" | Polar labels are drawn orthogonally to the polargram radius. |
488| "N" | Disable the display of the polar labels. |
489
490
491Begin_Macro(source)
492{
493 auto c46 = new TCanvas("c46","c46",500,500);
494 auto grP1 = new TGraphPolar();
495 grP1->SetTitle("TGraphPolar example");
496
497 grP1->SetPoint(0, (1*TMath::Pi())/4., 0.05);
498 grP1->SetPoint(1, (2*TMath::Pi())/4., 0.10);
499 grP1->SetPoint(2, (3*TMath::Pi())/4., 0.15);
500 grP1->SetPoint(3, (4*TMath::Pi())/4., 0.20);
501 grP1->SetPoint(4, (5*TMath::Pi())/4., 0.25);
502 grP1->SetPoint(5, (6*TMath::Pi())/4., 0.30);
503 grP1->SetPoint(6, (7*TMath::Pi())/4., 0.35);
504 grP1->SetPoint(7, (8*TMath::Pi())/4., 0.40);
505
506 grP1->SetMarkerStyle(20);
507 grP1->SetMarkerSize(1.);
508 grP1->SetMarkerColor(4);
509 grP1->SetLineColor(4);
510 grP1->Draw("ARLP");
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/visualisation/graphs/gr104_palettecolor.C
531End_Macro
532
533Begin_Macro(source)
534../../../tutorials/visualisation/graphs/gr105_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/visualisation/graphs/gr*_highlight*.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/visualisation/graphs/gr003_errors2.C
641 root [1] // try SetHighlight() interactively from TGraph context menu
642~~~
643
644\image html hl_gr003_errors2.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/// Default constructor
665
669
670
671////////////////////////////////////////////////////////////////////////////////
672/// Destructor.
673
677
678
679////////////////////////////////////////////////////////////////////////////////
680/// Compute the logarithm of variables `gxwork` and `gywork`
681/// according to the value of Options and put the results
682/// in the variables `gxworkl` and `gyworkl`.
683///
684/// npoints : Number of points in gxwork and in gywork.
685///
686/// - opt = 1 ComputeLogs is called from PaintGrapHist
687/// - opt = 0 ComputeLogs is called from PaintGraph
688
690{
691 if (gPad->GetLogx()) {
692 for (Int_t i = 0; i < npoints; i++) {
693 gxworkl[i] = (gxwork[i] > 0.) ? TMath::Log10(gxwork[i]) : gPad->GetX1();
694 }
695 } else {
696 for (Int_t i = 0; i < npoints; i++)
697 gxworkl[i] = gxwork[i];
698 }
699 if (!opt && gPad->GetLogy()) {
700 for (Int_t i = 0; i < npoints; i++) {
701 gyworkl[i] = (gywork[i] > 0.) ? TMath::Log10(gywork[i]) : gPad->GetY1();
702 }
703 } else {
704 for (Int_t i = 0; i < npoints; i++)
705 gyworkl[i] = gywork[i];
706 }
707}
708
709
710////////////////////////////////////////////////////////////////////////////////
711/// Compute distance from point px,py to a graph.
712///
713/// Compute the closest distance of approach from point px,py to this line.
714/// The distance is computed in pixels units.
715
717{
718
719 // Are we on the axis?
721 if (theGraph->GetHistogram()) {
722 distance = theGraph->GetHistogram()->DistancetoPrimitive(px,py);
723 if (distance <= 5) return distance;
724 }
725
726 // Somewhere on the graph points?
727 const Int_t big = 9999;
728 const Int_t kMaxDiff = 10;
729
730 // check if point is near one of the graph points
731 Int_t i, pxp, pyp, d;
732 distance = big;
733
734 Int_t theNpoints = theGraph->GetN();
735 Double_t *theX, *theY;
736 if (theGraph->InheritsFrom(TGraphPolar::Class())) {
738 theX = theGraphPolar->GetXpol();
739 theY = theGraphPolar->GetYpol();
740 } else {
741 theX = theGraph->GetX();
742 theY = theGraph->GetY();
743 }
744
745 Int_t hpoint = -1;
746 for (i=0;i<theNpoints;i++) {
747 pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
748 pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
749 d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
750 if (d < distance) {
751 distance = d;
752 hpoint = i;
753 }
754 }
755
756 if (theGraph->IsHighlight()) // only if highlight is enable
758 if (distance < kMaxDiff) return distance;
759
760 for (i=0;i<theNpoints-1;i++) {
761 TAttLine l;
762 d = l.DistancetoLine(px, py, gPad->XtoPad(theX[i]), gPad->YtoPad(theY[i]), gPad->XtoPad(theX[i+1]), gPad->YtoPad(theY[i+1]));
763 if (d < distance) distance = d;
764 }
765
766 // If graph has been drawn with the fill area option, check if we are inside
767 TString drawOption = theGraph->GetDrawOption();
768 drawOption.ToLower();
769 if (drawOption.Contains("f")) {
770 Double_t xp = gPad->AbsPixeltoX(px); xp = gPad->PadtoX(xp);
771 Double_t yp = gPad->AbsPixeltoY(py); yp = gPad->PadtoY(yp);
773 }
774
775 // Loop on the list of associated functions and user objects
776 TObject *f;
777 TList *functions = theGraph->GetListOfFunctions();
778 TIter next(functions);
779 while ((f = (TObject*) next())) {
780 if (f->InheritsFrom(TF1::Class())) distance = f->DistancetoPrimitive(-px,py);
781 else distance = f->DistancetoPrimitive(px,py);
782 if (distance < kMaxDiff) {
783 gPad->SetSelected(f);
784 return 0; //must be o and not dist in case of TMultiGraph
785 }
786 }
787
788 return distance;
789}
790
791
792////////////////////////////////////////////////////////////////////////////////
793/// Display a panel with all histogram drawing options.
794
796{
797
798 if (!gPad) {
799 Error("DrawPanel", "need to draw graph first");
800 return;
801 }
803 editor->Show();
804 gROOT->ProcessLine(TString::Format("((TCanvas*)0x%zx)->Selected((TVirtualPad*)0x%zx,(TObject*)0x%zx,1)",
805 (size_t)gPad->GetCanvas(), (size_t)gPad, (size_t)theGraph));
806}
807
808
809////////////////////////////////////////////////////////////////////////////////
810/// Execute action corresponding to one event.
811///
812/// This member function is called when a graph is clicked with the locator.
813///
814/// If the left mouse button is clicked on one of the line end points, this point
815/// follows the cursor until button is released.
816///
817/// If the middle mouse button clicked, the line is moved parallel to itself
818/// until the button is released.
819
821{
822
823 if (!gPad) return;
824
825 Int_t i, d;
827 const Int_t kMaxDiff = 10;//3;
828 static Bool_t middle, badcase;
829 static Int_t ipoint, pxp, pyp;
830 static Int_t px1,px2,py1,py2;
832 static Int_t dpx, dpy;
833 static std::vector<Int_t> x, y;
834 Bool_t opaque = gPad->OpaqueMoving();
835
836 if (!theGraph->IsEditable() || theGraph->InheritsFrom(TGraphPolar::Class())) {
837 gPad->SetCursor(kHand);
838 return;
839 }
840 if (!gPad->IsEditable()) return;
841 Int_t theNpoints = theGraph->GetN();
842 Double_t *theX = theGraph->GetX();
843 Double_t *theY = theGraph->GetY();
844
845 switch (event) {
846
847 case kButton1Down:
848 badcase = kFALSE;
849 gVirtualX->SetLineColor(-1);
850 theGraph->TAttLine::Modify(); //Change line attributes only if necessary
851 px1 = gPad->XtoAbsPixel(gPad->GetX1());
852 py1 = gPad->YtoAbsPixel(gPad->GetY1());
853 px2 = gPad->XtoAbsPixel(gPad->GetX2());
854 py2 = gPad->YtoAbsPixel(gPad->GetY2());
855 ipoint = -1;
856
857
858 if (!x.empty() || !y.empty()) break;
859 x.resize(theNpoints+1);
860 y.resize(theNpoints+1);
861 for (i=0;i<theNpoints;i++) {
862 pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
863 pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
866 badcase = kTRUE;
867 continue;
868 }
869 if (!opaque) {
870 gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
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 }
875 x[i] = pxp;
876 y[i] = pyp;
877 d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
878 if (d < kMaxDiff) ipoint =i;
879 }
880 dpx = 0;
881 dpy = 0;
882 pxold = px;
883 pyold = py;
884 if (ipoint < 0) return;
885 if (ipoint == 0) {
886 px1old = 0;
887 py1old = 0;
888 px2old = gPad->XtoAbsPixel(theX[1]);
889 py2old = gPad->YtoAbsPixel(theY[1]);
890 } else if (ipoint == theNpoints-1) {
891 px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[theNpoints-2]));
892 py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[theNpoints-2]));
893 px2old = 0;
894 py2old = 0;
895 } else {
896 px1old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint-1]));
897 py1old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint-1]));
898 px2old = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint+1]));
899 py2old = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint+1]));
900 }
901 pxold = gPad->XtoAbsPixel(gPad->XtoPad(theX[ipoint]));
902 pyold = gPad->YtoAbsPixel(gPad->YtoPad(theY[ipoint]));
903
904 break;
905
906
907 case kMouseMotion:
908
909 middle = kTRUE;
910 for (i=0;i<theNpoints;i++) {
911 pxp = gPad->XtoAbsPixel(gPad->XtoPad(theX[i]));
912 pyp = gPad->YtoAbsPixel(gPad->YtoPad(theY[i]));
913 d = TMath::Abs(pxp-px) + TMath::Abs(pyp-py);
914 if (d < kMaxDiff) middle = kFALSE;
915 }
916
917
918 // check if point is close to an axis
919 if (middle) gPad->SetCursor(kMove);
920 else gPad->SetCursor(kHand);
921 break;
922
923 case kButton1Motion:
924 if (!opaque) {
925 if (middle) {
926 for(i=0;i<theNpoints-1;i++) {
927 gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
928 pxp = x[i]+dpx;
929 pyp = y[i]+dpy;
932 gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
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 }
937 pxp = x[theNpoints-1]+dpx;
938 pyp = y[theNpoints-1]+dpy;
939 gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
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 dpx += px - pxold;
944 dpy += py - pyold;
945 pxold = px;
946 pyold = py;
947 for(i=0;i<theNpoints-1;i++) {
948 gVirtualX->DrawLine(x[i]+dpx, y[i]+dpy, x[i+1]+dpx, y[i+1]+dpy);
949 pxp = x[i]+dpx;
950 pyp = y[i]+dpy;
953 gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
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 }
958 pxp = x[theNpoints-1]+dpx;
959 pyp = y[theNpoints-1]+dpy;
960 gVirtualX->DrawLine(pxp-4, pyp-4, pxp+4, pyp-4);
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 } else {
965 if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
966 if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
967 gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4, pyold-4);
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 pxold = px;
972 pxold = TMath::Max(pxold, px1);
973 pxold = TMath::Min(pxold, px2);
974 pyold = py;
975 pyold = TMath::Max(pyold, py2);
976 pyold = TMath::Min(pyold, py1);
977 if (px1old) gVirtualX->DrawLine(px1old, py1old, pxold, pyold);
978 if (px2old) gVirtualX->DrawLine(pxold, pyold, px2old, py2old);
979 gVirtualX->DrawLine(pxold-4, pyold-4, pxold+4, pyold-4);
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 }
984 } else {
985 xmin = gPad->GetUxmin();
986 xmax = gPad->GetUxmax();
987 ymin = gPad->GetUymin();
988 ymax = gPad->GetUymax();
989 dx = xmax-xmin;
990 dy = ymax-ymin;
991 dxr = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
992 dyr = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
993
994 if (theGraph->GetHistogram()) {
995 // Range() could change the size of the pad pixmap and therefore should
996 // be called before the other paint routines
997 gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
998 ymin - dyr*gPad->GetBottomMargin(),
999 xmax + dxr*gPad->GetRightMargin(),
1000 ymax + dyr*gPad->GetTopMargin());
1001 gPad->RangeAxis(xmin, ymin, xmax, ymax);
1002 }
1003 if (middle) {
1004 dpx += px - pxold;
1005 dpy += py - pyold;
1006 pxold = px;
1007 pyold = py;
1008 for(i=0;i<theNpoints;i++) {
1009 if (badcase) continue; //do not update if big zoom and points moved
1010 if (!x.empty()) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
1011 if (!y.empty()) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
1012 }
1013 } else {
1014 pxold = px;
1015 pxold = TMath::Max(pxold, px1);
1016 pxold = TMath::Min(pxold, px2);
1017 pyold = py;
1018 pyold = TMath::Max(pyold, py2);
1019 pyold = TMath::Min(pyold, py1);
1020 theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
1021 theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
1022 if (theGraph->InheritsFrom("TCutG")) {
1023 //make sure first and last point are the same
1024 if (ipoint == 0) {
1025 theX[theNpoints-1] = theX[0];
1026 theY[theNpoints-1] = theY[0];
1027 }
1028 if (ipoint == theNpoints-1) {
1029 theX[0] = theX[theNpoints-1];
1030 theY[0] = theY[theNpoints-1];
1031 }
1032 }
1033 }
1034 badcase = kFALSE;
1035 gPad->Modified(kTRUE);
1036 //gPad->Update();
1037 }
1038 break;
1039
1040 case kButton1Up:
1041
1042 if (gROOT->IsEscaped()) {
1043 gROOT->SetEscape(kFALSE);
1044 x.clear();
1045 y.clear();
1046 break;
1047 }
1048
1049 // Compute x,y range
1050 xmin = gPad->GetUxmin();
1051 xmax = gPad->GetUxmax();
1052 ymin = gPad->GetUymin();
1053 ymax = gPad->GetUymax();
1054 dx = xmax-xmin;
1055 dy = ymax-ymin;
1056 dxr = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
1057 dyr = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
1058
1059 if (theGraph->GetHistogram()) {
1060 // Range() could change the size of the pad pixmap and therefore should
1061 // be called before the other paint routines
1062 gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
1063 ymin - dyr*gPad->GetBottomMargin(),
1064 xmax + dxr*gPad->GetRightMargin(),
1065 ymax + dyr*gPad->GetTopMargin());
1066 gPad->RangeAxis(xmin, ymin, xmax, ymax);
1067 }
1068 if (middle) {
1069 for(i=0;i<theNpoints;i++) {
1070 if (badcase) continue; //do not update if big zoom and points moved
1071 if (!x.empty()) theX[i] = gPad->PadtoX(gPad->AbsPixeltoX(x[i]+dpx));
1072 if (!y.empty()) theY[i] = gPad->PadtoY(gPad->AbsPixeltoY(y[i]+dpy));
1073 }
1074 } else {
1075 theX[ipoint] = gPad->PadtoX(gPad->AbsPixeltoX(pxold));
1076 theY[ipoint] = gPad->PadtoY(gPad->AbsPixeltoY(pyold));
1077 if (theGraph->InheritsFrom("TCutG")) {
1078 //make sure first and last point are the same
1079 if (ipoint == 0) {
1080 theX[theNpoints-1] = theX[0];
1081 theY[theNpoints-1] = theY[0];
1082 }
1083 if (ipoint == theNpoints-1) {
1084 theX[0] = theX[theNpoints-1];
1085 theY[0] = theY[theNpoints-1];
1086 }
1087 }
1088 }
1089 badcase = kFALSE;
1090 x.clear();
1091 y.clear();
1092 gPad->Modified(kTRUE);
1093 gVirtualX->SetLineColor(-1);
1094 }
1095}
1096
1097
1098////////////////////////////////////////////////////////////////////////////////
1099
1100char *TGraphPainter::GetObjectInfoHelper(TGraph * /*theGraph*/, Int_t /*px*/, Int_t /*py*/) const
1101{
1102 return (char*)"";
1103}
1104
1105
1106////////////////////////////////////////////////////////////////////////////////
1107/// Return the highlighted point for theGraph
1108
1110{
1112 else return -1;
1113}
1114
1115
1116////////////////////////////////////////////////////////////////////////////////
1117/// Set highlight (enable/disable) mode for theGraph
1118
1120{
1121 gHighlightPoint = -1; // must be -1
1122 gHighlightGraph = nullptr;
1123 if (theGraph->IsHighlight()) return;
1124
1125 // delete previous highlight marker
1126 if (gHighlightMarker) gHighlightMarker.reset(nullptr);
1127 // emit Highlighted() signal (user can check on disabled)
1128 if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, theGraph, gHighlightPoint, -1);
1129}
1130
1131
1132////////////////////////////////////////////////////////////////////////////////
1133/// Check on highlight point
1134
1136{
1137 // call from DistancetoPrimitiveHelper (only if highlight is enable)
1138
1139 const Int_t kHighlightRange = 50; // maybe as fgHighlightRange and Set/Get
1141 if (gHighlightPoint == -1) distanceOld = kHighlightRange; // reset
1142
1143 if ((distance < kHighlightRange) && (distance < distanceOld)) { // closest point
1144 if ((gHighlightPoint != hpoint) || (gHighlightGraph != theGraph)) { // was changed
1145 // Info("HighlightPoint", "graph: %p\tpoint: %d", (void *)theGraph, hpoint);
1148
1149 // paint highlight point as marker (recursive calls PaintHighlightPoint)
1150 gPad->Modified(kTRUE);
1151 gPad->Update();
1152
1153 // emit Highlighted() signal
1154 if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, theGraph, gHighlightPoint, -1);
1155 }
1156 }
1158}
1159
1160
1161////////////////////////////////////////////////////////////////////////////////
1162/// Paint highlight point as TMarker object (open circle)
1163
1165{
1166 // call from PaintGraphSimple
1167
1168 if ((!theGraph->IsHighlight()) || (gHighlightGraph != theGraph)) return;
1169
1170 Double_t hx, hy;
1171 if (theGraph->GetPoint(gHighlightPoint, hx, hy) == -1) {
1172 // special case, e.g. after interactive remove last point
1173 if (gHighlightMarker) gHighlightMarker.reset(nullptr);
1174 return;
1175 }
1176 // testing specific possibility (after zoom, draw with "same", log, etc.)
1177 Double_t uxmin = gPad->GetUxmin();
1178 Double_t uxmax = gPad->GetUxmax();
1179 Double_t uymin = gPad->GetUymin();
1180 Double_t uymax = gPad->GetUymax();
1181 if (gPad->GetLogx()) {
1182 uxmin = TMath::Power(10.0, uxmin);
1183 uxmax = TMath::Power(10.0, uxmax);
1184 }
1185 if (gPad->GetLogy()) {
1186 uymin = TMath::Power(10.0, uymin);
1187 uymax = TMath::Power(10.0, uymax);
1188 }
1189 if ((hx < uxmin) || (hx > uxmax)) return;
1190 if ((hy < uymin) || (hy > uymax)) return;
1191
1192 if (!gHighlightMarker) {
1193 gHighlightMarker = std::make_unique<TMarker>(hx, hy, 24);
1195 }
1196 gHighlightMarker->SetX(hx);
1197 gHighlightMarker->SetY(hy);
1198 gHighlightMarker->SetMarkerSize(theGraph->GetMarkerSize()*2.0);
1199 if (gHighlightMarker->GetMarkerSize() < 1.0) gHighlightMarker->SetMarkerSize(1.0); // always visible
1200 gHighlightMarker->SetMarkerColor(theGraph->GetMarkerColor());
1201 gHighlightMarker->Paint();
1202 // Info("PaintHighlightPoint", "graph: %p\tpoint: %d",
1203 // (void *)gHighlightGraph, gHighlightPoint);
1204}
1205
1206
1207////////////////////////////////////////////////////////////////////////////////
1208/// Paint a any kind of TGraph
1209
1211{
1212
1213 char chopt[80];
1214 strlcpy(chopt,option,80);
1215
1216 if (theGraph) {
1217 char *l1 = strstr(chopt,"pfc"); // Automatic Fill Color
1218 char *l2 = strstr(chopt,"plc"); // Automatic Line Color
1219 char *l3 = strstr(chopt,"pmc"); // Automatic Marker Color
1220 if (l1 || l2 || l3) {
1221 Int_t i = gPad->NextPaletteColor();
1222 if (l1) {memcpy(l1," ",3); theGraph->SetFillColor(i);}
1223 if (l2) {memcpy(l2," ",3); theGraph->SetLineColor(i);}
1224 if (l3) {memcpy(l3," ",3); theGraph->SetMarkerColor(i);}
1225 }
1226
1228
1229 char *l4 = strstr(chopt,"rx"); // Reverse graph along X axis
1230 char *l5 = strstr(chopt,"ry"); // Reverse graph along Y axis
1231
1232 if (l4 || l5) {
1234 return;
1235 }
1236
1237 if (theGraph->InheritsFrom(TGraphBentErrors::Class())) {
1239 } else if (theGraph->InheritsFrom(TGraphQQ::Class())) {
1241 } else if (theGraph->InheritsFrom(TGraphAsymmErrors::Class())) {
1243 } else if (theGraph->InheritsFrom(TGraphMultiErrors::Class())) {
1245 } else if (theGraph->InheritsFrom(TGraphErrors::Class())) {
1246 if (theGraph->InheritsFrom(TGraphPolar::Class())) {
1248 } else {
1250 }
1251 } else {
1253 }
1254
1255 // Paint the fit parameters if needed.
1256 TF1 *fit = nullptr;
1257 TList *functions = theGraph->GetListOfFunctions();
1258 TObject *f;
1259 if (functions) {
1260 f = (TF1*)functions->First();
1261 if (f) {
1262 if (f->InheritsFrom(TF1::Class())) fit = (TF1*)f;
1263 }
1264 TIter next(functions);
1265 while ((f = (TObject*) next())) {
1266 if (f->InheritsFrom(TF1::Class())) {
1267 fit = (TF1*)f;
1268 break;
1269 }
1270 }
1271 TPaletteAxis *palette = (TPaletteAxis*)functions->FindObject("palette");
1272 if (palette) palette->Paint();
1273 }
1274 if (fit && !theGraph->TestBit(TGraph::kNoStats)) PaintStats(theGraph, fit);
1275 }
1276}
1277
1278
1279////////////////////////////////////////////////////////////////////////////////
1280/// [Control function to draw a graph.](\ref GrP1)
1281
1283{
1284
1285 if (theGraph->InheritsFrom("TGraphPolar"))
1286 gPad->PushSelectableObject(theGraph);
1287
1291 Int_t i, npt, nloop;
1292 Int_t drawtype=0;
1293 Double_t xlow, xhigh, ylow, yhigh;
1296 Double_t x1, xn, y1, yn;
1298 Int_t theNpoints = theGraph->GetN();
1299
1300 if (npoints <= 0) {
1301 Error("PaintGraph", "illegal number of points (%d)", npoints);
1302 return;
1303 }
1304 TString opt = chopt;
1305 opt.ToUpper();
1306 opt.ReplaceAll("SAME","");
1307
1308 if (opt.Contains("L")) optionLine = 1; else optionLine = 0;
1309 if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0;
1310 if (opt.Contains("C")) optionCurve = 1; else optionCurve = 0;
1311 if (opt.Contains("*")) optionStar = 1; else optionStar = 0;
1312 if (opt.Contains("P")) optionMark = 1; else optionMark = 0;
1313 if (opt.Contains("B")) optionBar = 1; else optionBar = 0;
1314 if (opt.Contains("R")) optionR = 1; else optionR = 0;
1315 if (opt.Contains("1")) optionOne = 1; else optionOne = 0;
1316 if (opt.Contains("F")) optionFill = 1; else optionFill = 0;
1317 if (opt.Contains("I")) optionIAxis = 1; else optionIAxis = 0;
1318 if (opt.Contains("2") || opt.Contains("3") ||
1319 opt.Contains("4") || opt.Contains("5")) optionE = 1; else optionE = 0;
1320 optionZ = 0;
1321
1322 // If no "drawing" option is selected and if chopt<>' ' nothing is done.
1324 if (!chopt[0]) optionLine=1;
1325 else return;
1326 }
1327
1328 if (optionStar) theGraph->SetMarkerStyle(3);
1329
1330 optionCurveFill = 0;
1331 if (optionCurve && optionFill) {
1332 optionCurveFill = 1;
1333 optionFill = 0;
1334 }
1335
1336 // Draw the Axis.
1338 if (optionAxis) {
1339 if (theGraph->GetHistogram()) {
1340 rwxmin = gPad->GetUxmin();
1341 rwxmax = gPad->GetUxmax();
1342 rwymin = gPad->GetUymin();
1343 rwymax = gPad->GetUymax();
1344 minimum = theGraph->GetHistogram()->GetMinimumStored();
1345 maximum = theGraph->GetHistogram()->GetMaximumStored();
1346 if (minimum == -1111) { //this can happen after unzooming
1347 minimum = theGraph->GetHistogram()->GetYaxis()->GetXmin();
1348 theGraph->GetHistogram()->SetMinimum(minimum);
1349 }
1350 if (maximum == -1111) {
1351 maximum = theGraph->GetHistogram()->GetYaxis()->GetXmax();
1352 theGraph->GetHistogram()->SetMaximum(maximum);
1353 }
1354 uxmin = gPad->PadtoX(rwxmin);
1355 uxmax = gPad->PadtoX(rwxmax);
1356 } else {
1357
1358 theGraph->ComputeRange(rwxmin, rwymin, rwxmax, rwymax); //this is redefined in TGraphErrors
1359
1360 if (rwxmin == rwxmax) rwxmax += 1.;
1361 if (rwymin == rwymax) rwymax += 1.;
1362 dx = 0.1*(rwxmax-rwxmin);
1363 dy = 0.1*(rwymax-rwymin);
1364 uxmin = rwxmin - dx;
1365 uxmax = rwxmax + dx;
1366 minimum = rwymin - dy;
1367 maximum = rwymax + dy;
1368 }
1369 if (theGraph->GetMinimum() != -1111) rwymin = minimum = theGraph->GetMinimum();
1370 if (theGraph->GetMaximum() != -1111) rwymax = maximum = theGraph->GetMaximum();
1371 if (uxmin < 0 && rwxmin >= 0) uxmin = 0.9*rwxmin;
1372 if (uxmax > 0 && rwxmax <= 0) {
1373 if (gPad->GetLogx()) uxmax = 1.1*rwxmax;
1374 else uxmax = 0;
1375 }
1377 if (maximum > 0 && rwymax <= 0) {
1378 //if(gPad->GetLogy()) maximum = 1.1*rwymax;
1379 //else maximum = 0;
1380 }
1381 if (minimum <= 0 && gPad->GetLogy()) minimum = 0.001*maximum;
1382 if (uxmin <= 0 && gPad->GetLogx()) {
1383 if (uxmax > 1000) uxmin = 1;
1384 else uxmin = 0.001*uxmax;
1385 }
1386 rwymin = minimum;
1387 rwymax = maximum;
1388
1389 // Create a temporary histogram and fill each bin with the
1390 // function value.
1391 char chopth[8] = " ";
1392 if (strstr(chopt,"x+")) strncat(chopth, "x+",3);
1393 if (strstr(chopt,"y+")) strncat(chopth, "y+",3);
1394 if (optionIAxis) strncat(chopth, "A",2);
1395 if (!theGraph->GetHistogram()) {
1396 // the graph is created with at least as many bins as there are
1397 // points to permit zooming on the full range.
1398 rwxmin = uxmin;
1399 rwxmax = uxmax;
1400 npt = 100;
1401 if (theNpoints > npt) npt = theNpoints;
1403 theGraph->SetHistogram(h);
1404 if (!theGraph->GetHistogram()) return;
1405 theGraph->GetHistogram()->SetMinimum(rwymin);
1406 theGraph->GetHistogram()->SetMaximum(rwymax);
1407 theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
1408 theGraph->GetHistogram()->SetBit(TH1::kNoStats);
1409 theGraph->GetHistogram()->SetDirectory(nullptr);
1410 theGraph->GetHistogram()->Sumw2(kFALSE);
1411 theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
1412 } else {
1413 if (gPad->GetLogy()) {
1414 theGraph->GetHistogram()->SetMinimum(rwymin);
1415 theGraph->GetHistogram()->SetMaximum(rwymax);
1416 theGraph->GetHistogram()->GetYaxis()->SetLimits(rwymin,rwymax);
1417 }
1418 theGraph->GetHistogram()->Sumw2(kFALSE);
1419 theGraph->GetHistogram()->Paint(chopth); // Draw histogram axis, title and grid
1420 }
1421 }
1422
1423 // Set Clipping option
1425
1426 rwxmin = gPad->GetUxmin();
1427 rwxmax = gPad->GetUxmax();
1428 rwymin = gPad->GetUymin();
1429 rwymax = gPad->GetUymax();
1430 uxmin = gPad->PadtoX(rwxmin);
1431 uxmax = gPad->PadtoX(rwxmax);
1432 if (theGraph->GetHistogram() && !theGraph->InheritsFrom("TGraphPolar")) {
1433 maximum = theGraph->GetHistogram()->GetMaximum();
1434 minimum = theGraph->GetHistogram()->GetMinimum();
1435 } else {
1436 maximum = gPad->PadtoY(rwymax);
1437 minimum = gPad->PadtoY(rwymin);
1438 }
1439
1440 // Set attributes
1441 theGraph->TAttLine::Modify();
1442 theGraph->TAttFill::Modify();
1443 theGraph->TAttMarker::Modify();
1444
1445 // Draw the graph with a polyline or a fill area
1446 gxwork.resize(2*npoints+10);
1447 gywork.resize(2*npoints+10);
1448 gxworkl.resize(2*npoints+10);
1449 gyworkl.resize(2*npoints+10);
1450
1451 if (optionLine || optionFill) {
1452 x1 = x[0];
1453 xn = x[npoints-1];
1454 y1 = y[0];
1455 yn = y[npoints-1];
1456 nloop = npoints;
1457 if (optionFill && (xn != x1 || yn != y1)) nloop++;
1458 npt = 0;
1459 for (i=1;i<=nloop;i++) {
1460 if (i > npoints) {
1461 gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1462 } else {
1463 gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1464 npt++;
1465 }
1466 if (i == nloop) {
1468 else ComputeLogs(npt, optionZ);
1470 if (optionR) {
1471 if (optionFill) {
1472 gPad->PaintFillArea(npt,gyworkl.data(),gxworkl.data());
1473 if (bord) gPad->PaintPolyLine(nloop,gyworkl.data(),gxworkl.data());
1474 }
1475 if (optionLine) {
1476 if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gyworkl.data(), gxworkl.data());
1477 gPad->PaintPolyLine(npt,gyworkl.data(),gxworkl.data());
1478 }
1479 } else {
1480 if (optionFill) {
1481 gPad->PaintFillArea(npt,gxworkl.data(),gyworkl.data());
1482 if (bord) gPad->PaintPolyLine(nloop,gxworkl.data(),gyworkl.data());
1483 }
1484 if (optionLine) {
1485 if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, gxworkl.data(), gyworkl.data());
1486 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data());
1487 }
1488 }
1489 gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1490 npt = 1;
1491 }
1492 }
1493 }
1494
1495 // Draw the graph with a smooth Curve. Smoothing via Smooth
1496 if (optionCurve) {
1497 x1 = x[0];
1498 xn = x[npoints-1];
1499 y1 = y[0];
1500 yn = y[npoints-1];
1501 drawtype = 1;
1502 nloop = npoints;
1503 if (optionCurveFill) {
1504 drawtype += 1000;
1505 if (xn != x1 || yn != y1) nloop++;
1506 }
1507 if (!optionR) {
1508 npt = 0;
1509 for (i=1;i<=nloop;i++) {
1510 if (i > npoints) {
1511 gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1512 } else {
1513 gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1514 npt++;
1515 }
1517 if (gyworkl[npt-1] < rwymin || gyworkl[npt-1] > rwymax) {
1518 if (npt > 2) {
1520 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
1521 }
1522 gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1523 npt=1;
1524 continue;
1525 }
1526 }
1527 if (npt > 1) {
1529 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
1530 }
1531 } else {
1532 drawtype += 10;
1533 npt = 0;
1534 for (i=1;i<=nloop;i++) {
1535 if (i > npoints) {
1536 gxwork[npt] = gxwork[0]; gywork[npt] = gywork[0];
1537 } else {
1538 if (y[i-1] < minimum || y[i-1] > maximum) continue;
1539 if (x[i-1] < uxmin || x[i-1] > uxmax) continue;
1540 gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1541 npt++;
1542 }
1544 if (gxworkl[npt-1] < rwxmin || gxworkl[npt-1] > rwxmax) {
1545 if (npt > 2) {
1547 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
1548 }
1549 gxwork[0] = gxwork[npt-1]; gywork[0] = gywork[npt-1];
1550 npt=1;
1551 continue;
1552 }
1553 }
1554 if (npt > 1) {
1556 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
1557 }
1558 }
1559 }
1560
1561 // Draw the graph with a '*' on every points
1562 if (optionStar) {
1563 theGraph->SetMarkerStyle(3);
1564 npt = 0;
1565 for (i=1;i<=npoints;i++) {
1566 gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1567 npt++;
1568 if (i == npoints) {
1570 if (optionR) gPad->PaintPolyMarker(npt,gyworkl.data(),gxworkl.data());
1571 else gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
1572 npt = 0;
1573 }
1574 }
1575 }
1576
1577 // Draw the graph with the current polymarker on every points
1578 if (optionMark) {
1579 npt = 0;
1580 for (i=1;i<=npoints;i++) {
1581 gxwork[npt] = x[i-1]; gywork[npt] = y[i-1];
1582 npt++;
1583 if (i == npoints) {
1585 if (optionR) gPad->PaintPolyMarker(npt,gyworkl.data(),gxworkl.data());
1586 else gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
1587 npt = 0;
1588 }
1589 }
1590 }
1591
1592 // Draw the graph as a bar chart
1593 if (optionBar) {
1594 Int_t FillSave = theGraph->GetFillColor();
1595 if(FillSave == gPad->GetFrameFillColor()) {
1596 // make sure the bars' color is different from the frame background
1597 if (gPad->GetFrameFillColor()==1) {
1598 theGraph->SetFillColor(0);
1599 theGraph->TAttFill::Modify();
1600 } else {
1601 theGraph->SetFillColor(1);
1602 theGraph->TAttFill::Modify();
1603 }
1604 }
1605 if (!optionR) {
1606 barxmin = x[0];
1607 barxmax = x[0];
1608 for (i=1;i<npoints;i++) {
1609 if (x[i] < barxmin) barxmin = x[i];
1610 if (x[i] > barxmax) barxmax = x[i];
1611 }
1613 } else {
1614 barymin = y[0];
1615 barymax = y[0];
1616 for (i=1;i<npoints;i++) {
1617 if (y[i] < barymin) barymin = y[i];
1618 if (y[i] > barymax) barymax = y[i];
1619 }
1621 }
1622 dbar = 0.5*bdelta*gStyle->GetBarWidth();
1623 if (!optionR) {
1624 for (i=1;i<=npoints;i++) {
1625 xlow = x[i-1] - dbar;
1626 xhigh = x[i-1] + dbar;
1627 yhigh = y[i-1];
1628 if (xlow < uxmin && xhigh < uxmin) continue;
1629 if (xhigh > uxmax && xlow > uxmax) continue;
1630 if (xlow < uxmin) xlow = uxmin;
1631 if (xhigh > uxmax) xhigh = uxmax;
1632 if (!optionOne) ylow = TMath::Max((Double_t)0,gPad->GetUymin());
1633 else ylow = gPad->GetUymin();
1634 gxwork[0] = xlow;
1635 gywork[0] = ylow;
1636 gxwork[1] = xhigh;
1637 gywork[1] = yhigh;
1638 ComputeLogs(2, optionZ);
1639 if (gyworkl[0] < gPad->GetUymin()) gyworkl[0] = gPad->GetUymin();
1640 if (gyworkl[1] < gPad->GetUymin()) continue;
1641 if (gyworkl[1] > gPad->GetUymax()) gyworkl[1] = gPad->GetUymax();
1642 if (gyworkl[0] > gPad->GetUymax()) continue;
1643
1644 gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
1645 }
1646 } else {
1647 for (i=1;i<=npoints;i++) {
1648 xhigh = x[i-1];
1649 ylow = y[i-1] - dbar;
1650 yhigh = y[i-1] + dbar;
1651 xlow = TMath::Max((Double_t)0, gPad->GetUxmin());
1652 gxwork[0] = xlow;
1653 gywork[0] = ylow;
1654 gxwork[1] = xhigh;
1655 gywork[1] = yhigh;
1656 ComputeLogs(2, optionZ);
1657 gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
1658 }
1659 }
1660 theGraph->SetFillColor(FillSave);
1661 theGraph->TAttFill::Modify();
1662 }
1663 gPad->ResetBit(TGraph::kClipFrame);
1664
1665 gxwork.clear();
1666 gywork.clear();
1667 gxworkl.clear();
1668 gyworkl.clear();
1669}
1670
1671
1672////////////////////////////////////////////////////////////////////////////////
1673/// This is a service method used by `THistPainter`
1674/// to paint 1D histograms. It is not used to paint TGraph.
1675///
1676/// Input parameters:
1677///
1678/// - npoints : Number of points in X or in Y.
1679/// - x[npoints] or x[0] : x coordinates or (xmin,xmax).
1680/// - y[npoints] or y[0] : y coordinates or (ymin,ymax).
1681/// - chopt : Option.
1682///
1683/// The aspect of the histogram is done according to the value of the chopt.
1684///
1685/// | Option | Description |
1686/// |--------|-----------------------------------------------------------------|
1687/// |"R" | Graph is drawn horizontally, parallel to X axis. (default is vertically, parallel to Y axis).If option R is selected the user must give 2 values for Y (y[0]=YMIN and y[1]=YMAX) or N values for X, one for each channel. Otherwise the user must give, N values for Y, one for each channel or 2 values for X (x[0]=XMIN and x[1]=XMAX) |
1688/// |"L" | A simple polyline between every points is drawn.|
1689/// |"H" | An Histogram with equidistant bins is drawn as a polyline.|
1690/// |"F" | An histogram with equidistant bins is drawn as a fill area. Contour is not drawn unless chopt='H' is also selected..|
1691/// |"N" | Non equidistant bins (default is equidistant). If N is the number of channels array X and Y must be dimensioned as follow: If option R is not selected (default) then the user must give (N+1) values for X (limits of channels) or N values for Y, one for each channel. Otherwise the user must give (N+1) values for Y (limits of channels). or N values for X, one for each channel |
1692/// |"F1" | Idem as 'F' except that fill area base line is the minimum of the pad instead of Y=0.|
1693/// |"F2" | Draw a Fill area polyline connecting the center of bins|
1694/// |"C" | A smooth Curve is drawn.|
1695/// |"*" | A Star is plotted at the center of each bin.|
1696/// |"P" | Idem with the current marker.|
1697/// |"P0" | Idem with the current marker. Empty bins also drawn.|
1698/// |"B" | A Bar chart with equidistant bins is drawn as fill areas (Contours are drawn).|
1699/// |"][" | "Cutoff" style. When this option is selected together with H option, the first and last vertical lines of the histogram are not drawn.|
1700
1702 const Double_t *y, Option_t *chopt)
1703{
1704
1705 const char *where = "PaintGrapHist";
1706
1711 Int_t i, j, npt;
1713 Double_t xlow, xhigh, ylow, yhigh;
1716 Double_t delta = 0;
1717 Double_t ylast = 0;
1718 Double_t xi, xi1, xj, xj1, yi1, yi, yj, yj1, xwmin, ywmin;
1719 Int_t first, last, nbins;
1721
1722 char choptaxis[10] = " ";
1723
1724 if (npoints <= 0) {
1725 Error(where, "illegal number of points (%d)", npoints);
1726 return;
1727 }
1728 TString opt = chopt;
1729 opt.ToUpper();
1730 if (opt.Contains("H")) optionHist = 1; else optionHist = 0;
1731 if (opt.Contains("F")) optionFill = 1; else optionFill = 0;
1732 if (opt.Contains("C")) optionCurve= 1; else optionCurve= 0;
1733 if (opt.Contains("*")) optionStar = 1; else optionStar = 0;
1734 if (opt.Contains("R")) optionRot = 1; else optionRot = 0;
1735 if (opt.Contains("1")) optionOne = 1; else optionOne = 0;
1736 if (opt.Contains("B")) optionBar = 1; else optionBar = 0;
1737 if (opt.Contains("N")) optionBins = 1; else optionBins = 0;
1738 if (opt.Contains("L")) optionLine = 1; else optionLine = 0;
1739 if (opt.Contains("P")) optionMark = 1; else optionMark = 0;
1740 if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0;
1741 if (opt.Contains("][")) optionOff = 1; else optionOff = 0;
1742 if (opt.Contains("P0")) optionMark = 10;
1743
1744 Int_t optionFill2 = 0;
1745 if (opt.Contains("F") && opt.Contains("2")) {
1746 optionFill = 0; optionFill2 = 1;
1747 }
1748
1749 // Set Clipping option
1751 if (theGraph->TestBit(TGraph::kClipFrame)) noClip = "";
1752 else noClip = "C";
1754
1755 optionZ = 1;
1756
1757 if (optionStar) theGraph->SetMarkerStyle(3);
1758
1759 first = 1;
1760 last = npoints;
1761 nbins = last - first + 1;
1762
1763 // Draw the Axis with a fixed number of division: 510
1764
1765 Double_t baroffset = gStyle->GetBarOffset();
1766 Double_t barwidth = gStyle->GetBarWidth();
1767 Double_t rwxmin = gPad->GetUxmin();
1768 Double_t rwxmax = gPad->GetUxmax();
1769 Double_t rwymin = gPad->GetUymin();
1770 Double_t rwymax = gPad->GetUymax();
1771 Double_t uxmin = gPad->PadtoX(rwxmin);
1772 Double_t uxmax = gPad->PadtoX(rwxmax);
1773 Double_t rounding = (uxmax-uxmin)*1.e-5;
1775 if (optionAxis) {
1776 Int_t nx1, nx2, ndivx, ndivy, ndiv;
1777 choptaxis[0] = 0;
1780 ndivx = gStyle->GetNdivisions("X");
1781 ndivy = gStyle->GetNdivisions("Y");
1782 if (ndivx > 1000) {
1783 nx2 = ndivx/100;
1784 nx1 = TMath::Max(1, ndivx%100);
1785 ndivx = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsWNDC());
1786 }
1787 ndiv =TMath::Abs(ndivx);
1788 // coverity [Calling risky function]
1789 if (ndivx < 0) strlcat(choptaxis, "N",10);
1790 if (gPad->GetGridx()) {
1791 // coverity [Calling risky function]
1792 strlcat(choptaxis, "W",10);
1793 }
1794 if (gPad->GetLogx()) {
1797 // coverity [Calling risky function]
1798 strlcat(choptaxis, "G",10);
1799 }
1800 TGaxis axis;
1801 axis.SetLineColor(gStyle->GetAxisColor("X"));
1802 axis.SetTextColor(gStyle->GetLabelColor("X"));
1803 axis.SetTextFont(gStyle->GetLabelFont("X"));
1804 axis.SetLabelSize(gStyle->GetLabelSize("X"));
1806 axis.SetTickSize(gStyle->GetTickLength("X"));
1807
1809
1810 choptaxis[0] = 0;
1811 rwmin = rwymin;
1812 rwmax = rwymax;
1813 if (ndivy < 0) {
1814 nx2 = ndivy/100;
1815 nx1 = TMath::Max(1, ndivy%100);
1816 ndivy = 100*nx2 + Int_t(Double_t(nx1)*gPad->GetAbsHNDC());
1817 // coverity [Calling risky function]
1818 strlcat(choptaxis, "N",10);
1819 }
1820 ndiv =TMath::Abs(ndivy);
1821 if (gPad->GetGridy()) {
1822 // coverity [Calling risky function]
1823 strlcat(choptaxis, "W",10);
1824 }
1825 if (gPad->GetLogy()) {
1828 // coverity [Calling risky function]
1829 strlcat(choptaxis,"G",10);
1830 }
1831 axis.SetLineColor(gStyle->GetAxisColor("Y"));
1832 axis.SetTextColor(gStyle->GetLabelColor("Y"));
1833 axis.SetTextFont(gStyle->GetLabelFont("Y"));
1834 axis.SetLabelSize(gStyle->GetLabelSize("Y"));
1836 axis.SetTickSize(gStyle->GetTickLength("Y"));
1837
1839 }
1840
1841
1842 // Set attributes
1843 theGraph->TAttLine::Modify();
1844 theGraph->TAttFill::Modify();
1845 theGraph->TAttMarker::Modify();
1846
1847 // Min-Max scope
1848
1849 if (!optionRot) {wmin = x[0]; wmax = x[1];}
1850 else {wmin = y[0]; wmax = y[1];}
1851
1852 if (!optionBins) delta = (wmax - wmin)/ Double_t(nbins);
1853
1854 Int_t fwidth = gPad->GetFrameLineWidth();
1855 TFrame *frame = gPad->GetFrame();
1856 if (frame) fwidth = frame->GetLineWidth();
1857 if (optionOff) fwidth = 1;
1858 Double_t dxframe = gPad->AbsPixeltoX(fwidth/2) - gPad->AbsPixeltoX(0);
1859 Double_t vxmin = gPad->PadtoX(gPad->GetUxmin() + dxframe);
1860 Double_t vxmax = gPad->PadtoX(gPad->GetUxmax() - dxframe);
1861 Double_t dyframe = -gPad->AbsPixeltoY(fwidth/2) + gPad->AbsPixeltoY(0);
1862 Double_t vymin = gPad->GetUymin() + dyframe; //y already in log scale
1865
1866 // Draw the histogram with a fill area
1867
1868 gxwork.resize(2*npoints+10);
1869 gywork.resize(2*npoints+10);
1870 gxworkl.resize(2*npoints+10);
1871 gyworkl.resize(2*npoints+10);
1872
1873 if (optionFill && !optionCurve) {
1874 fillarea = kTRUE;
1875 if (!optionRot) {
1876 gxwork[0] = vxmin;
1877 if (!optionOne) gywork[0] = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
1878 ,gPad->GetUymax());
1879 else gywork[0] = gPad->GetUymin();
1880 npt = 2;
1881 for (j=first; j<=last;j++) {
1882 if (!optionBins) {
1883 gxwork[npt-1] = gxwork[npt-2];
1884 gxwork[npt] = wmin+((j-first+1)*delta);
1885 if (gxwork[npt] < gxwork[0]) gxwork[npt] = gxwork[0];
1886
1887 } else {
1888 xj1 = x[j]; xj = x[j-1];
1889 if (xj1 < xj) {
1890 if (j != last) Error(where, "X must be in increasing order");
1891 else Error(where, "X must have N+1 values with option N");
1892 goto do_cleanup;
1893 }
1894 gxwork[npt-1] = x[j-1]; gxwork[npt] = x[j];
1895 }
1896 gywork[npt-1] = y[j-1];
1897 gywork[npt] = y[j-1];
1898 if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
1899 if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1900 (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1901 if (j == last) {
1902 gxwork[npt-1] = gxwork[npt-2];
1903 gywork[npt-1] = gywork[0];
1904 //make sure that the fill area does not overwrite the frame
1905 //take into account the frame line width
1906 if (gxwork[0 ] < vxmin) {gxwork[0 ] = vxmin; gxwork[1 ] = vxmin;}
1907 if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}
1908
1909 //transform to log ?
1911 gPad->PaintFillArea(npt,gxworkl.data(),gyworkl.data());
1912 if (drawborder) {
1913 if (!fillarea) gyworkl[0] = ylast;
1914 gPad->PaintPolyLine(npt-1,gxworkl.data(),gyworkl.data(),noClip);
1915 }
1916 continue;
1917 }
1918 } //endfor (j=first; j<=last;j++) {
1919 } else {
1920 gywork[0] = wmin;
1921 if (!optionOne) gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
1922 else gxwork[0] = gPad->GetUxmin();
1923 npt = 2;
1924 for (j=first; j<=last;j++) {
1925 if (!optionBins) {
1926 gywork[npt-1] = gywork[npt-2];
1927 gywork[npt] = wmin+((j-first+1)*delta);
1928 } else {
1929 yj1 = y[j]; yj = y[j-1];
1930 if (yj1 < yj) {
1931 if (j != last) Error(where, "Y must be in increasing order");
1932 else Error(where, "Y must have N+1 values with option N");
1933 return;
1934 }
1935 gywork[npt-1] = y[j-1]; gywork[npt] = y[j];
1936 }
1937 gxwork[npt-1] = x[j-1]; gxwork[npt] = x[j-1];
1938 if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1939 (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1940 if (j == last) {
1941 gywork[npt-1] = gywork[npt-2];
1942 gxwork[npt-1] = gxwork[0];
1944 gPad->PaintFillArea(npt,gxworkl.data(),gyworkl.data());
1945 if (drawborder) {
1946 if (!fillarea) gyworkl[0] = ylast;
1947 gPad->PaintPolyLine(npt-1,gxworkl.data(),gyworkl.data(),noClip);
1948 }
1949 continue;
1950 }
1951 } //endfor (j=first; j<=last;j++)
1952 }
1953 theGraph->TAttLine::Modify();
1954 theGraph->TAttFill::Modify();
1955 }
1956
1957 // Draw a standard Histogram (default)
1958
1959 if ((optionHist) || !chopt[0]) {
1960 if (!optionRot) {
1961 gxwork[0] = wmin;
1962 if (!optionOne) gywork[0] = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
1963 ,gPad->GetUymax());
1964 else gywork[0] = gPad->GetUymin();
1965 ywmin = gywork[0];
1966 npt = 2;
1967 for (i=first; i<=last;i++) {
1968 if (!optionBins) {
1969 gxwork[npt-1] = gxwork[npt-2];
1970 gxwork[npt] = wmin+((i-first+1)*delta);
1971 } else {
1972 xi1 = x[i]; xi = x[i-1];
1973 if (xi1 < xi) {
1974 if (i != last) Error(where, "X must be in increasing order");
1975 else Error(where, "X must have N+1 values with option N");
1976 goto do_cleanup;
1977 }
1978 gxwork[npt-1] = x[i-1]; gxwork[npt] = x[i];
1979 }
1980 gywork[npt-1] = y[i-1];
1981 gywork[npt] = y[i-1];
1982 if (gywork[npt] < vymin) {gywork[npt] = vymin; gywork[npt-1] = vymin;}
1983 if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
1984 (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
1985 if (i == last) {
1986 gxwork[npt-1] = gxwork[npt-2];
1987 gywork[npt-1] = gywork[0];
1988 //make sure that the fill area does not overwrite the frame
1989 //take into account the frame line width
1990 if (gxwork[0] < vxmin) {gxwork[0] = vxmin; gxwork[1 ] = vxmin;}
1991 if (gywork[0] < vymin) {gywork[0] = vymin; gywork[npt-1] = vymin;}
1992
1994
1995 // do not draw the two vertical lines on the edges
1996 Int_t nbpoints = npt-2;
1997 Int_t point1 = 1;
1998
1999 if (optionOff) {
2000 // remove points before the low cutoff
2001 Int_t ip;
2002 for (ip=point1; ip<=nbpoints; ip++) {
2003 if (gyworkl[ip] != ywmin) {
2004 point1 = ip;
2005 break;
2006 }
2007 }
2008 // remove points after the high cutoff
2010 for (ip=point2; ip>=point1; ip--) {
2011 if (gyworkl[ip] != ywmin) {
2012 point2 = ip;
2013 break;
2014 }
2015 }
2017 } else {
2018 // if the 1st or last bin are not on the pad limits the
2019 // the two vertical lines on the edges are added.
2020 if (gxwork[0] > gPad->GetUxmin()) { nbpoints++; point1 = 0; }
2021 if (gxwork[nbpoints] < gPad->GetUxmax()) nbpoints++;
2022 }
2023
2024 gPad->PaintPolyLine(nbpoints,gxworkl.data() + point1, gyworkl.data() + point1, noClip);
2025 continue;
2026 }
2027 } //endfor (i=first; i<=last;i++)
2028 } else {
2029 gywork[0] = wmin;
2030 if (!optionOne) gxwork[0] = TMath::Max((Double_t)0,gPad->GetUxmin());
2031 else gxwork[0] = gPad->GetUxmin();
2032 xwmin = gxwork[0];
2033 npt = 2;
2034 for (i=first; i<=last;i++) {
2035 if (!optionBins) {
2036 gywork[npt-1] = gywork[npt-2];
2037 gywork[npt] = wmin+((i-first+1)*delta);
2038 } else {
2039 yi1 = y[i]; yi = y[i-1];
2040 if (yi1 < yi) {
2041 if (i != last) Error(where, "Y must be in increasing order");
2042 else Error(where, "Y must have N+1 values with option N");
2043 goto do_cleanup;
2044 }
2045 gywork[npt-1] = y[i-1]; gywork[npt] = y[i];
2046 }
2047 gxwork[npt-1] = x[i-1]; gxwork[npt] = x[i-1];
2048 if ((gxwork[npt-1] >= uxmin-rounding && gxwork[npt-1] <= uxmax+rounding) ||
2049 (gxwork[npt] >= uxmin-rounding && gxwork[npt] <= uxmax+rounding)) npt += 2;
2050 if (i == last) {
2051 gywork[npt-1] = gywork[npt-2];
2052 gxwork[npt-1] = xwmin;
2054 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data(),noClip);
2055 continue;
2056 }
2057 } //endfor (i=first; i<=last;i++)
2058 }
2059 }
2060
2061 // Draw the histogram with a smooth Curve.
2062 // The smoothing is done by the method Smooth()
2063
2064 if (optionCurve) {
2065 if (!optionFill) {
2066 drawtype = 1;
2067 } else {
2068 if (!optionOne) drawtype = 2;
2069 else drawtype = 3;
2070 }
2071 if (!optionRot) {
2072 npt = 0;
2073 for (i=first; i<=last;i++) {
2074 npt++;
2075 if (!optionBins) {
2076 gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2077 } else {
2078 xi1 = x[i]; xi = x[i-1];
2079 if (xi1 < xi) {
2080 if (i != last) Error(where, "X must be in increasing order");
2081 else Error(where, "X must have N+1 values with option N");
2082 goto do_cleanup;
2083 }
2084 gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
2085 }
2086 if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) {
2087 npt--;
2088 continue;
2089 }
2090 gywork[npt-1] = y[i-1];
2092 if ((gyworkl[npt-1] < rwymin) || (gyworkl[npt-1] > rwymax)) {
2093 if (npt > 2) {
2095 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
2096 }
2097 gxwork[0] = gxwork[npt-1];
2098 gywork[0] = gywork[npt-1];
2099 npt = 1;
2100 continue;
2101 }
2102 if (npt >= fgMaxPointsPerLine) {
2105 gxwork[0] = gxwork[npt-1];
2106 gywork[0] = gywork[npt-1];
2107 npt = 1;
2108 }
2109 } //endfor (i=first; i<=last;i++)
2110 if (npt > 1) {
2112 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
2113 }
2114 } else {
2115 drawtype = drawtype+10;
2116 npt = 0;
2117 for (i=first; i<=last;i++) {
2118 npt++;
2119 if (!optionBins) {
2120 gywork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2121 } else {
2122 yi1 = y[i]; yi = y[i-1];
2123 if (yi1 < yi) {
2124 if (i != last) Error(where, "Y must be in increasing order");
2125 else Error(where, "Y must have N+1 values with option N");
2126 return;
2127 }
2128 gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
2129 }
2130 gxwork[npt-1] = x[i-1];
2132 if ((gxworkl[npt] < uxmin) || (gxworkl[npt] > uxmax)) {
2133 if (npt > 2) {
2135 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
2136 }
2137 gxwork[0] = gxwork[npt-1];
2138 gywork[0] = gywork[npt-1];
2139 npt = 1;
2140 continue;
2141 }
2142 if (npt >= fgMaxPointsPerLine) {
2145 gxwork[0] = gxwork[npt-1];
2146 gywork[0] = gywork[npt-1];
2147 npt = 1;
2148 }
2149 } //endfor (i=first; i<=last;i++)
2150 if (npt > 1) {
2152 Smooth(theGraph, npt,gxworkl.data(),gyworkl.data(),drawtype);
2153 }
2154 }
2155 }
2156
2157 // Draw the histogram with a simple line
2158
2159 if (optionLine) {
2160 gPad->SetBit(TGraph::kClipFrame);
2161 wminstep = wmin + 0.5*delta;
2163 gPad->GetRangeAxis(ax1,ay1,ax2,ay2);
2164
2165 if (!optionRot) {
2166 npt = 0;
2167 for (i=first; i<=last;i++) {
2168 npt++;
2169 if (!optionBins) {
2170 gxwork[npt-1] = wmin+(i-first)*delta+0.5*delta;
2171 } else {
2172 xi1 = x[i]; xi = x[i-1];
2173 if (xi1 < xi) {
2174 if (i != last) Error(where, "X must be in increasing order");
2175 else Error(where, "X must have N+1 values with option N");
2176 return;
2177 }
2178 gxwork[npt-1] = x[i-1] + 0.5*(x[i]-x[i-1]);
2179 }
2180 if (gxwork[npt-1] < uxmin || gxwork[npt-1] > uxmax) { npt--; continue;}
2181 gywork[npt-1] = y[i-1];
2182 gywork[npt] = y[i-1]; //new
2183 if ((gywork[npt-1] < rwymin) || ((gywork[npt-1] > rwymax) && !optionFill2)) {
2184 if (npt > 2) {
2186 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data());
2187 }
2188 gxwork[0] = gxwork[npt-1];
2189 gywork[0] = gywork[npt-1];
2190 npt = 1;
2191 continue;
2192 }
2193
2194 if (npt >= fgMaxPointsPerLine) {
2195 if (optionLine) {
2197 if (optionFill2) {
2199 gxworkl[npt+1] = gxworkl[0]; gyworkl[npt+1] = rwymin;
2200 gPad->PaintFillArea(fgMaxPointsPerLine+2,gxworkl.data(),gyworkl.data());
2201 }
2202 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data());
2203 }
2204 gxwork[0] = gxwork[npt-1];
2205 gywork[0] = gywork[npt-1];
2206 npt = 1;
2207 }
2208 } //endfor (i=first; i<=last;i++)
2209 if (npt > 1) {
2211 if (optionFill2) {
2213 gxworkl[npt+1] = gxworkl[0]; gyworkl[npt+1] = rwymin;
2214 gPad->PaintFillArea(npt+2,gxworkl.data(),gyworkl.data());
2215 }
2216 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data());
2217 }
2218 } else {
2219 npt = 0;
2220 for (i=first; i<=last;i++) {
2221 npt++;
2222 if (!optionBins) {
2223 gywork[npt-1] = wminstep+(i-first)*delta+0.5*delta;
2224 } else {
2225 yi1 = y[i]; yi = y[i-1];
2226 if (yi1 < yi) {
2227 if (i != last) Error(where, "Y must be in increasing order");
2228 else Error(where, "Y must have N+1 values with option N");
2229 goto do_cleanup;
2230 }
2231 gywork[npt-1] = y[i-1] + 0.5*(y[i]-y[i-1]);
2232 }
2233 gxwork[npt-1] = x[i-1];
2234 if ((gxwork[npt-1] < uxmin) || (gxwork[npt-1] > uxmax)) {
2235 if (npt > 2) {
2236 if (optionLine) {
2238 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data(),noClip);
2239 }
2240 }
2241 gxwork[0] = gxwork[npt-1];
2242 gywork[0] = gywork[npt-1];
2243 npt = 1;
2244 continue;
2245 }
2246 if (npt >= fgMaxPointsPerLine) {
2247 if (optionLine) {
2249 gPad->PaintPolyLine(fgMaxPointsPerLine,gxworkl.data(),gyworkl.data());
2250 }
2251 gxwork[0] = gxwork[npt-1];
2252 gywork[0] = gywork[npt-1];
2253 npt = 1;
2254 }
2255 } //endfor (i=first; i<=last;i++)
2256 if (optionLine != 0 && npt > 1) {
2258 gPad->PaintPolyLine(npt,gxworkl.data(),gyworkl.data(),noClip);
2259 }
2260 }
2261 }
2262
2263 // Draw the histogram as a bar chart
2264
2265 if (optionBar) {
2266 if (!optionBins) {
2267 offset = delta*baroffset; dbar = delta*barwidth;
2268 } else {
2269 if (!optionRot) {
2270 offset = (x[1]-x[0])*baroffset;
2271 dbar = (x[1]-x[0])*barwidth;
2272 } else {
2273 offset = (y[1]-y[0])*baroffset;
2274 dbar = (y[1]-y[0])*barwidth;
2275 }
2276 }
2279 if (!optionRot) {
2280 xlow = wmin+offset;
2282 if (!optionOne) ylow = TMath::Min(TMath::Max((Double_t)0,gPad->GetUymin())
2283 ,gPad->GetUymax());
2284 else ylow = gPad->GetUymin();
2285
2286 for (i=first; i<=last;i++) {
2287 yhigh = y[i-1];
2288 gxwork[0] = xlow;
2289 gywork[0] = ylow;
2290 gxwork[1] = xhigh;
2291 gywork[1] = yhigh;
2292 ComputeLogs(2, optionZ);
2294 gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
2295 if (!optionBins) {
2296 xlow = xlow+delta;
2297 xhigh = xhigh+delta;
2298 } else {
2299 if (i < last) {
2300 xi1 = x[i]; xi = x[i-1];
2301 if (xi1 < xi) {
2302 Error(where, "X must be in increasing order");
2303 goto do_cleanup;
2304 }
2305 offset = (x[i+1]-x[i])*baroffset;
2306 dbar = (x[i+1]-x[i])*barwidth;
2307 xlow = x[i] + offset;
2308 xhigh = x[i] + offset + dbar;
2309 }
2310 }
2311 } //endfor (i=first; i<=last;i++)
2312 } else {
2313 ylow = wmin + offset;
2314 yhigh = wmin + offset + dbar;
2315 if (!optionOne) xlow = TMath::Max((Double_t)0,gPad->GetUxmin());
2316 else xlow = gPad->GetUxmin();
2317 for (i=first; i<=last;i++) {
2318 xhigh = x[i-1];
2319 gxwork[0] = xlow;
2320 gywork[0] = ylow;
2321 gxwork[1] = xhigh;
2322 gywork[1] = yhigh;
2323 ComputeLogs(2, optionZ);
2324 gPad->PaintBox(gxworkl[0],gyworkl[0],gxworkl[1],gyworkl[1]);
2325 gPad->PaintBox(xlow,ylow,xhigh,yhigh);
2326 if (!optionBins) {
2327 ylow = ylow + delta;
2328 yhigh = yhigh + delta;
2329 } else {
2330 if (i < last) {
2331 yi1 = y[i]; yi = y[i-1];
2332 if (yi1 < yi) {
2333 Error(where, "Y must be in increasing order");
2334 goto do_cleanup;
2335 }
2336 offset = (y[i+1]-y[i])*baroffset;
2337 dbar = (y[i+1]-y[i])*barwidth;
2338 ylow = y[i] + offset;
2339 yhigh = y[i] + offset + dbar;
2340 }
2341 }
2342 } //endfor (i=first; i<=last;i++)
2343 }
2345 }
2346
2347 // Draw the histogram with a simple marker
2348
2349 optionMarker = 0;
2350 if ((optionStar) || (optionMark)) optionMarker=1;
2351
2352 if (optionMarker) {
2353 Double_t xm,ym;
2354 npt = 0;
2355 if (!optionRot) {
2356 for (i=first; i<=last;i++) {
2357 if (!optionBins) xm = wmin+(i-first)*delta+0.5*delta;
2358 else xm = x[i-1] + 0.5*(x[i]-x[i-1]);
2359 ym = y[i-1];
2360 if (optionMark != 10) {
2362 npt++;
2363 gxwork[npt-1] = xm;
2364 gywork[npt-1] = ym;
2365 }
2366 } else {
2368 npt++;
2369 gxwork[npt-1] = xm;
2370 gywork[npt-1] = ym;
2371 }
2372 }
2373 if (npt >= fgMaxPointsPerLine) {
2375 gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
2376 npt = 0;
2377 }
2378 }
2379 if (npt > 0) {
2381 gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
2382 }
2383 } else {
2384 wminstep = wmin + 0.5*delta;
2385 for (i=first; i<=last;i++) {
2386 if (!optionBins) ym = wminstep+(i-first)*delta+0.5*delta;
2387 else ym = y[i-1] + 0.5*(y[i]-y[i-1]);
2388 xm = x[i-1];
2389 if (optionMark != 10) {
2391 npt++;
2392 gxwork[npt-1] = xm;
2393 gywork[npt-1] = ym;
2394 }
2395 } else {
2397 npt++;
2398 gxwork[npt-1] = xm;
2399 gywork[npt-1] = ym;
2400 }
2401 }
2402 if (npt >= fgMaxPointsPerLine) {
2404 gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
2405 npt = 0;
2406 }
2407 }
2408 if (npt > 0) {
2410 gPad->PaintPolyMarker(npt,gxworkl.data(),gyworkl.data());
2411 }
2412 }
2413 }
2414
2415 gPad->ResetBit(TGraph::kClipFrame);
2416
2418 gxwork.clear();
2419 gywork.clear();
2420 gxworkl.clear();
2421 gyworkl.clear();
2422}
2423
2424
2425////////////////////////////////////////////////////////////////////////////////
2426/// [Paint this TGraphAsymmErrors with its current attributes.](\ref GrP3)
2427
2429{
2430
2431 std::vector<Double_t> xline, yline;
2432 Int_t if1 = 0;
2433 Int_t if2 = 0;
2434 Double_t xb[4], yb[4];
2435
2436 const Int_t kBASEMARKER=8;
2437 static Float_t cxx[30] = {1.0,1.0,0.5,0.5,1.0,1.0,0.5,0.6,1.0,0.5,0.5,1.0,0.5,0.6,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,1.0,1.0,1.0,1.0,0.5,0.5,0.5,1.0};
2438 static Float_t cyy[30] = {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.5,0.5,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.0,0.0,1.0,1.0,1.0,1.0,0.5,0.5,0.5,1.0};
2439 Int_t theNpoints = theGraph->GetN();
2440 Double_t *theX = theGraph->GetX();
2441 Double_t *theY = theGraph->GetY();
2442 Double_t *theEXlow = theGraph->GetEXlow(); if (!theEXlow) return;
2443 Double_t *theEYlow = theGraph->GetEYlow(); if (!theEYlow) return;
2444 Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
2445 Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;
2446
2447 if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
2450 if (strstr(option,"||") || strstr(option,"[]")) {
2451 brackets = kTRUE;
2452 if (strstr(option,"[]")) braticks = kTRUE;
2453 }
2455 if (strchr(option,'z')) endLines = kFALSE;
2456 if (strchr(option,'Z')) endLines = kFALSE;
2457 const char *arrowOpt = nullptr;
2458 if (strchr(option,'>')) arrowOpt = ">";
2459 if (strstr(option,"|>")) arrowOpt = "|>";
2460
2461 Bool_t axis = kFALSE;
2462 if (strchr(option,'a')) axis = kTRUE;
2463 if (strchr(option,'A')) axis = kTRUE;
2464 if (axis) PaintGraphSimple(theGraph, option);
2465
2471 if (strchr(option,'0')) option0 = kTRUE;
2472 if (strchr(option,'2')) option2 = kTRUE;
2473 if (strchr(option,'3')) option3 = kTRUE;
2474 if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
2475 if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
2476
2477 // special flags in case of "reverse plot" and "log scale"
2480 if (strstr(option,"-N")) xrevlog = kTRUE; // along X
2481 if (strstr(option,"-M")) yrevlog = kTRUE; // along Y
2482
2483 if (option3) {
2484 xline.resize(2*theNpoints);
2485 yline.resize(2*theNpoints);
2486 if (xline.empty() || yline.empty()) {
2487 Error("PaintGraphAsymmErrors", "too many points, out of memory");
2488 return;
2489 }
2490 if1 = 1;
2491 if2 = 2*theNpoints;
2492 }
2493
2494 theGraph->TAttLine::Modify();
2495
2496 TArrow arrow;
2497 arrow.SetLineWidth(theGraph->GetLineWidth());
2498 arrow.SetLineColor(theGraph->GetLineColor());
2499 arrow.SetFillColor(theGraph->GetFillColor());
2500
2501 TBox box;
2503 box.SetLineWidth(theGraph->GetLineWidth());
2504 box.SetLineColor(theGraph->GetLineColor());
2505 box.SetFillColor(theGraph->GetFillColor());
2506 box.SetFillStyle(theGraph->GetFillStyle());
2507
2508 Double_t symbolsize = theGraph->GetMarkerSize();
2510 Int_t mark = TAttMarker::GetMarkerStyleBase(theGraph->GetMarkerStyle());
2511 Double_t cx = 0;
2512 Double_t cy = 0;
2513 if (mark >= 20 && mark <= 49) {
2514 cx = cxx[mark-20];
2515 cy = cyy[mark-20];
2516 }
2517
2518 // Define the offset of the error bars due to the symbol size
2519 Double_t s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
2520 Double_t s2y = -gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
2522 Double_t tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
2523 Double_t ty = -gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
2524 Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
2525
2527
2528 // special flags to turn off error bar drawing in case the marker cover it
2530 // loop over all the graph points
2531 Double_t x, y, exl, exh, eyl, eyh, xl1, xl2, xr1, xr2, yup, yup1, yup2, ylow, ylow1, ylow2;
2532 for (Int_t i=0;i<theNpoints;i++) {
2533 DrawXLeft = kTRUE;
2534 DrawXRight = kTRUE;
2535 DrawYUp = kTRUE;
2536 DrawYLow = kTRUE;
2537 x = gPad->XtoPad(theX[i]);
2538 y = gPad->YtoPad(theY[i]);
2539
2540 if (!option0) {
2541 if (option3) {
2542 if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
2543 if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
2544 if (y < gPad->GetUymin()) y = gPad->GetUymin();
2545 if (y > gPad->GetUymax()) y = gPad->GetUymax();
2546 } else {
2547 if (x < gPad->GetUxmin()) continue;
2548 if (x > gPad->GetUxmax()) continue;
2549 if (y < gPad->GetUymin()) continue;
2550 if (y > gPad->GetUymax()) continue;
2551 }
2552 }
2553 exl = theEXlow[i];
2554 exh = theEXhigh[i];
2555 eyl = theEYlow[i];
2556 eyh = theEYhigh[i];
2557
2558 if (xrevlog) {
2559 xl1 = x + s2x*cx;
2560 xl2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
2561 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
2562 - exh);
2563 xr1 = x - s2x*cx;
2564 xr2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
2565 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
2566 + exl);
2567 tx = -tx;
2568 } else {
2569 xl1 = x - s2x*cx;
2570 xl2 = gPad->XtoPad(theX[i] - exl);
2571 xr1 = x + s2x*cx;
2572 xr2 = gPad->XtoPad(theX[i] + exh);
2573 if (xl1 < xl2) DrawXLeft = kFALSE;
2574 if (xr1 > xr2) DrawXRight = kFALSE;
2575 }
2576
2577 if (yrevlog) {
2578 yup1 = y - s2y*cy;
2579 yup2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
2580 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
2581 + eyl);
2582 ylow1 = y + s2y*cy;
2583 ylow2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
2584 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
2585 - eyh);
2586 } else {
2587 yup1 = y + s2y*cy;
2588 yup2 = gPad->YtoPad(theY[i] + eyh);
2589 ylow1 = y - s2y*cy;
2590 ylow2 = gPad->YtoPad(theY[i] - eyl);
2591 if (yup2 < yup1) DrawYUp = kFALSE;
2592 if (ylow2 > ylow1) DrawYLow = kFALSE;
2593 }
2594 yup = yup2;
2595 ylow = ylow2;
2596 if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
2597 if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
2598
2599 // draw the error rectangles
2600 if (option2) {
2601 x1b = xl2;
2602 y1b = ylow2;
2603 x2b = xr2;
2604 y2b = yup2;
2605 if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
2606 if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
2607 if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
2608 if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
2609 if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
2610 if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
2611 if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
2612 if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
2613 if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
2614 else box.PaintBox(x1b, y1b, x2b, y2b);
2615 continue;
2616 }
2617
2618 // keep points for fill area drawing
2619 if (option3) {
2620 xline[if1-1] = x;
2621 xline[if2-1] = x;
2622 yline[if1-1] = yup2;
2623 yline[if2-1] = ylow2;
2624 if1++;
2625 if2--;
2626 continue;
2627 }
2628
2629 if (exl != 0. || exh != 0.) {
2630 if (arrowOpt) {
2631 if (exl != 0. && DrawXLeft) arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
2632 if (exh != 0. && DrawXRight) arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
2633 } else {
2634 if (!brackets) {
2635 if (exl != 0. && DrawXLeft) gPad->PaintLine(xl1,y,xl2,y);
2636 if (exh != 0. && DrawXRight) gPad->PaintLine(xr1,y,xr2,y);
2637 }
2638 if (endLines) {
2639 if (braticks) {
2640 if (exl != 0. && DrawXLeft) {
2641 xb[0] = xl2+tx; yb[0] = y-ty;
2642 xb[1] = xl2; yb[1] = y-ty;
2643 xb[2] = xl2; yb[2] = y+ty;
2644 xb[3] = xl2+tx; yb[3] = y+ty;
2645 gPad->PaintPolyLine(4, xb, yb);
2646 }
2647 if (exh != 0. && DrawXRight) {
2648 xb[0] = xr2-tx; yb[0] = y-ty;
2649 xb[1] = xr2; yb[1] = y-ty;
2650 xb[2] = xr2; yb[2] = y+ty;
2651 xb[3] = xr2-tx; yb[3] = y+ty;
2652 gPad->PaintPolyLine(4, xb, yb);
2653 }
2654 } else {
2655 if (DrawXLeft) gPad->PaintLine(xl2,y-ty,xl2,y+ty);
2656 if (DrawXRight) gPad->PaintLine(xr2,y-ty,xr2,y+ty);
2657 }
2658 }
2659 }
2660 }
2661
2662 if (eyl != 0. || eyh != 0.) {
2663 if (arrowOpt) {
2664 if (eyh != 0. && DrawYUp) {
2665 if (yup2 == yup) arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
2666 else gPad->PaintLine(x,yup1,x,yup2);
2667 }
2668 if (eyl != 0. && DrawYLow) {
2669 if (ylow2 == ylow) arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
2670 else gPad->PaintLine(x,ylow1,x,ylow2);
2671 }
2672 } else {
2673 if (!brackets) {
2674 if (eyh != 0. && DrawYUp) gPad->PaintLine(x,yup1,x,yup2);
2675 if (eyl != 0. && DrawYLow) gPad->PaintLine(x,ylow1,x,ylow2);
2676 }
2677 if (endLines) {
2678 if (braticks) {
2679 if (eyh != 0. && yup2 == yup && DrawYUp) {
2680 xb[0] = x-tx; yb[0] = yup2-ty;
2681 xb[1] = x-tx; yb[1] = yup2;
2682 xb[2] = x+tx; yb[2] = yup2;
2683 xb[3] = x+tx; yb[3] = yup2-ty;
2684 gPad->PaintPolyLine(4, xb, yb);
2685 }
2686 if (eyl != 0. && ylow2 == ylow && DrawYLow) {
2687 xb[0] = x-tx; yb[0] = ylow2+ty;
2688 xb[1] = x-tx; yb[1] = ylow2;
2689 xb[2] = x+tx; yb[2] = ylow2;
2690 xb[3] = x+tx; yb[3] = ylow2+ty;
2691 gPad->PaintPolyLine(4, xb, yb);
2692 }
2693 } else {
2694 if (eyh != 0. && yup2 == yup && DrawYUp) gPad->PaintLine(x-tx,yup2,x+tx,yup2);
2695 if (eyl != 0. && ylow2 == ylow && DrawYLow) gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
2696 }
2697 }
2698 }
2699 }
2700 }
2701 if (!brackets && !axis) PaintGraphSimple(theGraph, option);
2702 gPad->ResetBit(TGraph::kClipFrame);
2703
2704 if (option3) {
2705 Int_t logx = gPad->GetLogx();
2706 Int_t logy = gPad->GetLogy();
2707 gPad->SetLogx(0);
2708 gPad->SetLogy(0);
2709 if (option4) PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"FC");
2710 else PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"F");
2711 gPad->SetLogx(logx);
2712 gPad->SetLogy(logy);
2713 }
2714}
2715
2716////////////////////////////////////////////////////////////////////////////////
2717/// [Paint this TGraphMultiErrors with its current attributes.](\ref GrP3)
2718
2720{
2721 if (!theGraph->InheritsFrom(TGraphMultiErrors::Class())) {
2723 return;
2724 }
2725
2726 auto tg = (TGraphMultiErrors *)theGraph;
2727
2728 Int_t NYErrors = tg->GetNYErrors();
2729 if (NYErrors <= 0) {
2731 return;
2732 }
2733
2735 tsOpt.ToLower();
2736
2737 std::vector<TString> options(NYErrors + 1);
2738 Int_t filled = 0;
2739
2740 if (tsOpt.CountChar(';') < NYErrors) {
2741 options[0] = tsOpt.Contains(";") ? tsOpt(0, tsOpt.First(';')) : tsOpt.Copy();
2742 filled++;
2743 }
2744
2746 while ((firstSemicolon = tsOpt.First(';')) != kNPOS && filled <= NYErrors) {
2747 options[filled] = tsOpt(0, firstSemicolon);
2748 tsOpt = tsOpt(firstSemicolon + 1, tsOpt.Length());
2749 filled++;
2750 }
2751
2752 if (filled <= NYErrors) {
2753 options[filled] = tsOpt.Copy();
2754 filled++;
2755 }
2756
2757 for (Int_t i = filled; i <= NYErrors; i++)
2758 options[i] = "";
2759
2760 std::vector<Double_t> xline;
2761 std::vector<std::vector<Double_t>> yline(NYErrors);
2762 Int_t if1 = 0;
2763 Int_t if2 = 0;
2764 Double_t xb[4], yb[4];
2765
2766 const Int_t kBASEMARKER = 8;
2767 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};
2768 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};
2769 Int_t theNpoints = tg->GetN();
2770 Double_t *theX = tg->GetX();
2771 Double_t *theY = tg->GetY();
2772 Double_t *theExL = tg->GetEXlow();
2773 Double_t *theExH = tg->GetEXhigh();
2774 std::vector<Double_t *> theEyL(NYErrors);
2775 std::vector<Double_t *> theEyH(NYErrors);
2776
2778 for (Int_t j = 0; j < NYErrors; j++) {
2779 theEyL[j] = tg->GetEYlow(j);
2780 theEyH[j] = tg->GetEYhigh(j);
2781 theEyExists &= (theEyL[j] && theEyH[j]);
2782 }
2783
2784 if (!theX || !theY || !theExL || !theExH || !theEyExists)
2785 return;
2786
2787 std::vector<Bool_t> DrawErrors(NYErrors);
2792 std::vector<Bool_t> Braticks(NYErrors);
2793 std::vector<Bool_t> Brackets(NYErrors);
2794 std::vector<Bool_t> EndLines(NYErrors);
2795 std::vector<Char_t *> ArrowOpt(NYErrors);
2796 std::vector<Bool_t> Option5(NYErrors);
2797 std::vector<Bool_t> Option4(NYErrors);
2798 std::vector<Bool_t> Option3(NYErrors);
2800 std::vector<Bool_t> Option2(NYErrors);
2801 std::vector<Bool_t> Option0(NYErrors);
2803 std::vector<Double_t> Scale(NYErrors);
2804
2805 const TRegexp ScaleRegExp("s=*[0-9]\\.*[0-9]");
2806
2807 for (Int_t j = 0; j < NYErrors; j++) {
2808 if (options[j + 1].Contains("s=")) {
2809 sscanf(strstr(options[j + 1].Data(), "s="), "s=%lf", &Scale[j]);
2810 options[j + 1].ReplaceAll(options[j + 1](ScaleRegExp), "");
2811 } else
2812 Scale[j] = 1.;
2813
2814 DrawErrors[j] = !options[j + 1].Contains("x");
2815 AnyErrors |= DrawErrors[j];
2816 Braticks[j] = options[j + 1].Contains("[]");
2817 Brackets[j] = options[j + 1].Contains("||") || Braticks[j];
2818 EndLines[j] = !options[j + 1].Contains("z");
2819
2820 if (options[j + 1].Contains("|>"))
2821 ArrowOpt[j] = (Char_t *)"|>";
2822 else if (options[j + 1].Contains(">"))
2823 ArrowOpt[j] = (Char_t *)">";
2824 else
2825 ArrowOpt[j] = nullptr;
2826
2827 Option5[j] = options[j + 1].Contains("5");
2828 Option4[j] = options[j + 1].Contains("4");
2829 Option3[j] = options[j + 1].Contains("3") || Option4[j];
2830 AnyOption3 |= Option3[j];
2831 Option2[j] = options[j + 1].Contains("2") || Option5[j];
2832 Option0[j] = options[j + 1].Contains("0");
2833 AnyOption0 |= Option0[j];
2834
2835 NoErrorsX &= (Option3[j] || Option2[j]);
2836 Option0X |= !(Option3[j] || Option2[j]) && Option0[j];
2837 DrawMarker |= !(Brackets[j] || Option3[j] || Option2[j]);
2838 }
2839
2840 Bool_t Draw0PointsX = !options[0].Contains("x0") && (gPad->GetLogx() == 0);
2841 Bool_t Draw0PointsY = !options[0].Contains("y0") && (gPad->GetLogy() == 0);
2842 options[0].ReplaceAll("x0", "");
2843 options[0].ReplaceAll("y0", "");
2844
2845 Bool_t DrawErrorsX = !options[0].Contains("x");
2846 Bool_t BraticksX = options[0].Contains("[]");
2847 Bool_t BracketsX = options[0].Contains("||") || BraticksX;
2848 Bool_t EndLinesX = !options[0].Contains("z");
2849
2850 Char_t *ArrowOptX = nullptr;
2851 if (options[0].Contains("|>"))
2852 ArrowOptX = (Char_t *)"|>";
2853 else if (options[0].Contains(">"))
2854 ArrowOptX = (Char_t *)">";
2855
2856 Double_t ScaleX = 1.;
2857 if (options[0].Contains("s=")) {
2858 sscanf(strstr(options[0].Data(), "s="), "s=%lf", &ScaleX);
2859 options[0].ReplaceAll(options[0](ScaleRegExp), "");
2860 }
2861
2862 if (!AnyErrors && !DrawErrorsX) {
2863 PaintGraphSimple(tg, options[0].Data());
2864 return;
2865 }
2866
2867 Bool_t DrawAxis = options[0].Contains("a");
2868 Bool_t IndividualStyles = options[0].Contains("s");
2869
2870 if (DrawAxis)
2871 PaintGraphSimple(tg, options[0].Data());
2872
2874
2875 Double_t x,y;
2876 for (Int_t i = 0; i < theNpoints && !AnyOption0; i++) {
2877 x = gPad->XtoPad(theX[i]);
2878 y = gPad->YtoPad(theY[i]);
2879
2880 if ((x >= gPad->GetUxmin()) && (x <= gPad->GetUxmax()) && (y >= gPad->GetUymin()) && (y <= gPad->GetUymax()) &&
2881 (Draw0PointsX || theX[i] != 0.) && (Draw0PointsY || theY[i] != 0.))
2882 NPointsInside++;
2883 }
2884
2885 if (AnyOption3) {
2886 xline.resize(2 * NPointsInside);
2887
2888 if (xline.empty()) {
2889 Error("PaintGraphMultiErrors", "too many points, out of memory");
2890 return;
2891 }
2892
2893 if1 = 1;
2894 if2 = 2 * NPointsInside;
2895 }
2896
2897 for (Int_t j = 0; j < NYErrors; j++) {
2898 if (Option3[j] && DrawErrors[j]) {
2899 yline[j].resize(2 * NPointsInside);
2900
2901 if (yline[j].empty()) {
2902 Error("PaintGraphMultiErrors", "too many points, out of memory");
2903 return;
2904 }
2905 }
2906 }
2907
2908 tg->TAttLine::Modify();
2909
2910 TArrow arrow;
2911 arrow.SetLineWidth(tg->GetLineWidth());
2912 arrow.SetLineColor(tg->GetLineColor());
2913 arrow.SetFillColor(tg->GetFillColor());
2914
2915 TBox box;
2916 Double_t x1b, y1b, x2b, y2b;
2917 box.SetLineWidth(tg->GetLineWidth());
2918 box.SetLineColor(tg->GetLineColor());
2919 box.SetFillColor(tg->GetFillColor());
2920 box.SetFillStyle(tg->GetFillStyle());
2921
2922 Double_t symbolsize = tg->GetMarkerSize();
2924 Int_t mark = TAttMarker::GetMarkerStyleBase(tg->GetMarkerStyle());
2925 Double_t cx = 0.;
2926 Double_t cy = 0.;
2927
2928 if (mark >= 20 && mark <= 49) {
2929 cx = cxx[mark - 20];
2930 cy = cyy[mark - 20];
2931 }
2932
2933 // Define the offset of the error bars due to the symbol size
2934 Double_t s2x = gPad->PixeltoX(Int_t(0.5 * sbase)) - gPad->PixeltoX(0);
2935 Double_t s2y = -gPad->PixeltoY(Int_t(0.5 * sbase)) + gPad->PixeltoY(0);
2936 auto dxend = Int_t(gStyle->GetEndErrorSize());
2937 Double_t tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
2938 Double_t ty = -gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
2939 Float_t asize = 0.6 * symbolsize * kBASEMARKER / gPad->GetWh();
2940
2941 gPad->SetBit(TGraph::kClipFrame, tg->TestBit(TGraph::kClipFrame));
2942
2943 // loop over all the graph points
2945 for (Int_t i = 0; i < theNpoints; i++) {
2946 x = gPad->XtoPad(theX[i]);
2947 y = gPad->YtoPad(theY[i]);
2948
2950 (x < gPad->GetUxmin()) || (x > gPad->GetUxmax()) || (y < gPad->GetUymin()) || (y > gPad->GetUymax());
2951
2952 if ((isOutside && !AnyOption0) || (!Draw0PointsX && theX[i] == 0.) || (!Draw0PointsY && theY[i] == 0.))
2953 continue;
2954
2955 if (AnyOption3) {
2956 if (isOutside) {
2957 if (x < gPad->GetUxmin())
2958 x = gPad->GetUxmin();
2959 if (x > gPad->GetUxmax())
2960 x = gPad->GetUxmax();
2961 if (y < gPad->GetUymin())
2962 y = gPad->GetUymin();
2963 if (y > gPad->GetUymax())
2964 y = gPad->GetUymax();
2965 }
2966
2967 xline[if1 - 1] = x;
2968 xline[if2 - 1] = x;
2969
2970 if1++;
2971 if2--;
2972 }
2973
2974 for (Int_t j = 0; j < NYErrors; j++) {
2975 if (!DrawErrors[j])
2976 continue;
2977
2978 // draw the error rectangles
2979 if (Option2[j] && (!isOutside || Option0[j])) {
2980 if (IndividualStyles) {
2981 box.SetLineWidth(tg->GetLineWidth(j));
2982 box.SetLineColor(tg->GetLineColor(j));
2983 box.SetFillColor(tg->GetFillColor(j));
2984 box.SetFillStyle(tg->GetFillStyle(j));
2985 }
2986
2987 x1b = gPad->XtoPad(theX[i] - Scale[j] * theExL[i]);
2988 y1b = gPad->YtoPad(theY[i] - theEyL[j][i]);
2989 x2b = gPad->XtoPad(theX[i] + Scale[j] * theExH[i]);
2990 y2b = gPad->YtoPad(theY[i] + theEyH[j][i]);
2991 if (x1b < gPad->GetUxmin())
2992 x1b = gPad->GetUxmin();
2993 if (x1b > gPad->GetUxmax())
2994 x1b = gPad->GetUxmax();
2995 if (y1b < gPad->GetUymin())
2996 y1b = gPad->GetUymin();
2997 if (y1b > gPad->GetUymax())
2998 y1b = gPad->GetUymax();
2999 if (x2b < gPad->GetUxmin())
3000 x2b = gPad->GetUxmin();
3001 if (x2b > gPad->GetUxmax())
3002 x2b = gPad->GetUxmax();
3003 if (y2b < gPad->GetUymin())
3004 y2b = gPad->GetUymin();
3005 if (y2b > gPad->GetUymax())
3006 y2b = gPad->GetUymax();
3007 if (Option5[j])
3008 box.PaintBox(x1b, y1b, x2b, y2b, "l");
3009 else
3010 box.PaintBox(x1b, y1b, x2b, y2b);
3011 }
3012
3013 // keep points for fill area drawing
3014 if (Option3[j]) {
3015 if (!isOutside || Option0[j]) {
3016 yline[j][if1 - 2] = gPad->YtoPad(theY[i] + theEyH[j][i]);
3017 yline[j][if2] = gPad->YtoPad(theY[i] - theEyL[j][i]);
3018 } else {
3019 yline[j][if1 - 2] = gPad->GetUymin();
3020 yline[j][if2] = gPad->GetUymin();
3021 }
3022 }
3023
3024 if (IndividualStyles) {
3025 tg->GetAttLine(j)->Modify();
3026
3027 arrow.SetLineWidth(tg->GetLineWidth(j));
3028 arrow.SetLineColor(tg->GetLineColor(j));
3029 arrow.SetFillColor(tg->GetFillColor(j));
3030 }
3031
3032 ylow1 = y - s2y * cy;
3033 ylow2 = gPad->YtoPad(theY[i] - theEyL[j][i]);
3034 if (ylow2 < gPad->GetUymin())
3035 ylow2 = gPad->GetUymin();
3036 if (ylow2 < ylow1 && DrawErrors[j] && !Option2[j] && !Option3[j] && (!isOutside || Option0[j])) {
3037 if (ArrowOpt[j])
3038 arrow.PaintArrow(x, ylow1, x, ylow2, asize, ArrowOpt[j]);
3039 else {
3040 if (!Brackets[j])
3041 gPad->PaintLine(x, ylow1, x, ylow2);
3042 if (EndLines[j]) {
3043 if (Braticks[j]) {
3044 xb[0] = x - tx;
3045 yb[0] = ylow2 + ty;
3046 xb[1] = x - tx;
3047 yb[1] = ylow2;
3048 xb[2] = x + tx;
3049 yb[2] = ylow2;
3050 xb[3] = x + tx;
3051 yb[3] = ylow2 + ty;
3052 gPad->PaintPolyLine(4, xb, yb);
3053 } else
3054 gPad->PaintLine(x - tx, ylow2, x + tx, ylow2);
3055 }
3056 }
3057 }
3058
3059 yup1 = y + s2y * cy;
3060 yup2 = gPad->YtoPad(theY[i] + theEyH[j][i]);
3061 if (yup2 > gPad->GetUymax())
3062 yup2 = gPad->GetUymax();
3063 if (yup2 > yup1 && DrawErrors[j] && !Option2[j] && !Option3[j] && (!isOutside || Option0[j])) {
3064 if (ArrowOpt[j])
3065 arrow.PaintArrow(x, yup1, x, yup2, asize, ArrowOpt[j]);
3066 else {
3067 if (!Brackets[j])
3068 gPad->PaintLine(x, yup1, x, yup2);
3069 if (EndLines[j]) {
3070 if (Braticks[j]) {
3071 xb[0] = x - tx;
3072 yb[0] = yup2 - ty;
3073 xb[1] = x - tx;
3074 yb[1] = yup2;
3075 xb[2] = x + tx;
3076 yb[2] = yup2;
3077 xb[3] = x + tx;
3078 yb[3] = yup2 - ty;
3079 gPad->PaintPolyLine(4, xb, yb);
3080 } else
3081 gPad->PaintLine(x - tx, yup2, x + tx, yup2);
3082 }
3083 }
3084 }
3085 }
3086
3087 if (DrawErrorsX) {
3088 if (IndividualStyles) {
3089 tg->TAttLine::Modify();
3090
3091 arrow.SetLineWidth(tg->GetLineWidth());
3092 arrow.SetLineColor(tg->GetLineColor());
3093 arrow.SetFillColor(tg->GetFillColor());
3094 }
3095
3096 xl1 = x - s2x * cx;
3097 xl2 = gPad->XtoPad(theX[i] - ScaleX * theExL[i]);
3098 if (xl1 > xl2 && !NoErrorsX && (!isOutside || Option0X)) {
3099 if (ArrowOptX)
3100 arrow.PaintArrow(xl1, y, xl2, y, asize, ArrowOptX);
3101 else {
3102 if (!BracketsX)
3103 gPad->PaintLine(xl1, y, xl2, y);
3104 if (EndLinesX) {
3105 if (BraticksX) {
3106 xb[0] = xl2 + tx;
3107 yb[0] = y - ty;
3108 xb[1] = xl2;
3109 yb[1] = y - ty;
3110 xb[2] = xl2;
3111 yb[2] = y + ty;
3112 xb[3] = xl2 + tx;
3113 yb[3] = y + ty;
3114 gPad->PaintPolyLine(4, xb, yb);
3115 } else
3116 gPad->PaintLine(xl2, y - ty, xl2, y + ty);
3117 }
3118 }
3119 }
3120
3121 xr1 = x + s2x * cx;
3122 xr2 = gPad->XtoPad(theX[i] + ScaleX * theExH[i]);
3123 if (xr1 < xr2 && !NoErrorsX && (!isOutside || Option0X)) {
3124 if (ArrowOptX)
3125 arrow.PaintArrow(xr1, y, xr2, y, asize, ArrowOptX);
3126 else {
3127 if (!BracketsX)
3128 gPad->PaintLine(xr1, y, xr2, y);
3129 if (EndLinesX) {
3130 if (BraticksX) {
3131 xb[0] = xr2 - tx;
3132 yb[0] = y - ty;
3133 xb[1] = xr2;
3134 yb[1] = y - ty;
3135 xb[2] = xr2;
3136 yb[2] = y + ty;
3137 xb[3] = xr2 - tx;
3138 yb[3] = y + ty;
3139 gPad->PaintPolyLine(4, xb, yb);
3140 } else
3141 gPad->PaintLine(xr2, y - ty, xr2, y + ty);
3142 }
3143 }
3144 }
3145 }
3146 }
3147
3148 if (DrawMarker && !DrawAxis)
3149 PaintGraphSimple(tg, options[0].Data());
3150 gPad->ResetBit(TGraph::kClipFrame);
3151
3153 tg->TAttFill::Copy(tgDummy);
3154 tg->TAttLine::Copy(tgDummy);
3155 tg->TAttMarker::Copy(tgDummy);
3156
3157 for (Int_t j = 0; j < NYErrors; j++)
3158 if (Option3[j] && DrawErrors[j]) {
3159 if (IndividualStyles) {
3160 tg->GetAttFill(j)->Copy(tgDummy);
3161 tg->GetAttLine(j)->Copy(tgDummy);
3162 }
3163
3164 Int_t logx = gPad->GetLogx();
3165 Int_t logy = gPad->GetLogy();
3166 gPad->SetLogx(0);
3167 gPad->SetLogy(0);
3168 if (Option4[j])
3169 PaintGraph(&tgDummy, 2 * NPointsInside, xline.data(), yline[j].data(), "FC");
3170 else
3171 PaintGraph(&tgDummy, 2 * NPointsInside, xline.data(), yline[j].data(), "F");
3172 gPad->SetLogx(logx);
3173 gPad->SetLogy(logy);
3174 }
3175
3176}
3177
3178////////////////////////////////////////////////////////////////////////////////
3179/// [Paint this TGraphBentErrors with its current attributes.](\ref GrP3)
3180
3182{
3183
3184 std::vector<Double_t> xline, yline;
3185 Int_t if1 = 0;
3186 Int_t if2 = 0;
3187 Double_t xb[4], yb[4];
3188
3189 const Int_t kBASEMARKER=8;
3190 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};
3191 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};
3192 Int_t theNpoints = theGraph->GetN();
3193 Double_t *theX = theGraph->GetX();
3194 Double_t *theY = theGraph->GetY();
3195 Double_t *theEXlow = theGraph->GetEXlow(); if (!theEXlow) return;
3196 Double_t *theEYlow = theGraph->GetEYlow(); if (!theEYlow) return;
3197 Double_t *theEXhigh = theGraph->GetEXhigh(); if (!theEXhigh) return;
3198 Double_t *theEYhigh = theGraph->GetEYhigh(); if (!theEYhigh) return;
3199 Double_t *theEXlowd = theGraph->GetEXlowd(); if (!theEXlowd) return;
3200 Double_t *theEXhighd = theGraph->GetEXhighd(); if (!theEXhighd) return;
3201 Double_t *theEYlowd = theGraph->GetEYlowd(); if (!theEYlowd) return;
3202 Double_t *theEYhighd = theGraph->GetEYhighd(); if (!theEYhighd) return;
3203
3204 if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
3207 if (strstr(option,"||") || strstr(option,"[]")) {
3208 brackets = kTRUE;
3209 if (strstr(option,"[]")) braticks = kTRUE;
3210 }
3212 if (strchr(option,'z')) endLines = kFALSE;
3213 if (strchr(option,'Z')) endLines = kFALSE;
3214 const char *arrowOpt = nullptr;
3215 if (strchr(option,'>')) arrowOpt = ">";
3216 if (strstr(option,"|>")) arrowOpt = "|>";
3217
3218 Bool_t axis = kFALSE;
3219 if (strchr(option,'a')) axis = kTRUE;
3220 if (strchr(option,'A')) axis = kTRUE;
3221 if (axis) PaintGraphSimple(theGraph,option);
3222
3228 if (strchr(option,'0')) option0 = kTRUE;
3229 if (strchr(option,'2')) option2 = kTRUE;
3230 if (strchr(option,'3')) option3 = kTRUE;
3231 if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
3232 if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
3233
3234 // special flags in case of "reverse plot" and "log scale"
3237 if (strstr(option,"-N")) xrevlog = kTRUE; // along X
3238 if (strstr(option,"-M")) yrevlog = kTRUE; // along Y
3239
3240 if (option3) {
3241 xline.resize(2*theNpoints);
3242 yline.resize(2*theNpoints);
3243 if (xline.empty() || yline.empty()) {
3244 Error("PaintGraphBentErrors", "too many points, out of memory");
3245 return;
3246 }
3247 if1 = 1;
3248 if2 = 2*theNpoints;
3249 }
3250
3251 theGraph->TAttLine::Modify();
3252
3253 TArrow arrow;
3254 arrow.SetLineWidth(theGraph->GetLineWidth());
3255 arrow.SetLineColor(theGraph->GetLineColor());
3256 arrow.SetFillColor(theGraph->GetFillColor());
3257
3258 TBox box;
3260 box.SetLineWidth(theGraph->GetLineWidth());
3261 box.SetLineColor(theGraph->GetLineColor());
3262 box.SetFillColor(theGraph->GetFillColor());
3263 box.SetFillStyle(theGraph->GetFillStyle());
3264
3265 Double_t symbolsize = theGraph->GetMarkerSize();
3267 Int_t mark = TAttMarker::GetMarkerStyleBase(theGraph->GetMarkerStyle());
3268 Double_t cx = 0;
3269 Double_t cy = 0;
3270 if (mark >= 20 && mark <= 49) {
3271 cx = cxx[mark-20];
3272 cy = cyy[mark-20];
3273 }
3274
3275 // define the offset of the error bars due to the symbol size
3276 Double_t s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
3277 Double_t s2y = -gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
3279 Double_t tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
3280 Double_t ty = -gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
3281 Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
3282
3284
3285 // special flags to turn off error bar drawing in case the marker cover it
3287 // loop over all the graph points
3288 Double_t x, y, exl, exh, eyl, eyh, xl1, xl2, xr1, xr2, yup, yup1, yup2, ylow, ylow1, ylow2;
3289 Double_t bxl, bxh, byl, byh, bs;
3290 for (Int_t i=0;i<theNpoints;i++) {
3291 DrawXLeft = kTRUE;
3292 DrawXRight = kTRUE;
3293 DrawYUp = kTRUE;
3294 DrawYLow = kTRUE;
3295 x = gPad->XtoPad(theX[i]);
3296 y = gPad->YtoPad(theY[i]);
3297 bxl = gPad->YtoPad(theY[i]+theEXlowd[i]);
3298 bxh = gPad->YtoPad(theY[i]+theEXhighd[i]);
3299 byl = gPad->XtoPad(theX[i]+theEYlowd[i]);
3300 byh = gPad->XtoPad(theX[i]+theEYhighd[i]);
3301
3302 if (!option0) {
3303 if (option3) {
3304 if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
3305 if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
3306 if (y < gPad->GetUymin()) y = gPad->GetUymin();
3307 if (y > gPad->GetUymax()) y = gPad->GetUymax();
3308 } else {
3309 if (x < gPad->GetUxmin()) continue;
3310 if (x > gPad->GetUxmax()) continue;
3311 if (y < gPad->GetUymin()) continue;
3312 if (y > gPad->GetUymax()) continue;
3313 }
3314 }
3315 exl = theEXlow[i];
3316 exh = theEXhigh[i];
3317 eyl = theEYlow[i];
3318 eyh = theEYhigh[i];
3319
3320 if (xrevlog) {
3321 xl1 = x + s2x*cx;
3322 xl2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3323 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3324 - exh);
3325 xr1 = x - s2x*cx;
3326 xr2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3327 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3328 + exl);
3329 tx = -tx;
3330 byl = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3331 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3332 - theEYlowd[i]);
3333 byh = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3334 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3335 - theEYhighd[i]);
3336 } else {
3337 xl1 = x - s2x*cx;
3338 xl2 = gPad->XtoPad(theX[i] - exl);
3339 xr1 = x + s2x*cx;
3340 xr2 = gPad->XtoPad(theX[i] + exh);
3341 if (xl1 < xl2) DrawXLeft = kFALSE;
3342 if (xr1 > xr2) DrawXRight = kFALSE;
3343 }
3344
3345 if (yrevlog) {
3346 yup1 = y - s2y*cy;
3347 yup2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3348 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3349 + eyl);
3350 ylow1 = y + s2y*cy;
3351 ylow2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3352 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3353 - eyh);
3354 bxl = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3355 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3356 - theEXlowd[i]);
3357 bxh = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3358 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3359 - theEXhighd[i]);
3360 } else {
3361 yup1 = y + s2y*cy;
3362 yup2 = gPad->YtoPad(theY[i] + eyh);
3363 ylow1 = y - s2y*cy;
3364 ylow2 = gPad->YtoPad(theY[i] - eyl);
3365 if (yup2 < yup1) DrawYUp = kFALSE;
3366 if (ylow2 > ylow1) DrawYLow = kFALSE;
3367 }
3368 yup = yup2;
3369 ylow = ylow2;
3370 if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
3371 if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
3372
3373 if (xrevlog) {bs = bxl; bxl = bxh; bxh = bs;}
3374 if (yrevlog) {bs = byl; byl = byh; byh = bs;}
3375
3376 // draw the error rectangles
3377 if (option2) {
3378 x1b = xl2;
3379 y1b = ylow2;
3380 x2b = xr2;
3381 y2b = yup2;
3382 if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
3383 if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
3384 if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
3385 if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
3386 if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
3387 if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
3388 if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
3389 if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
3390 if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
3391 else box.PaintBox(x1b, y1b, x2b, y2b);
3392 continue;
3393 }
3394
3395 // keep points for fill area drawing
3396 if (option3) {
3397 xline[if1-1] = byh;
3398 xline[if2-1] = byl;
3399 yline[if1-1] = yup2;
3400 yline[if2-1] = ylow2;
3401 if1++;
3402 if2--;
3403 continue;
3404 }
3405
3406 if (exl != 0. || exh != 0.) {
3407 if (arrowOpt) {
3408 if (exl != 0. && DrawXLeft) arrow.PaintArrow(xl1,y,xl2,bxl,asize,arrowOpt);
3409 if (exh != 0. && DrawXRight) arrow.PaintArrow(xr1,y,xr2,bxh,asize,arrowOpt);
3410 } else {
3411 if (!brackets) {
3412 if (exl != 0. && DrawXLeft) gPad->PaintLine(xl1,y,xl2,bxl);
3413 if (exh != 0. && DrawXRight) gPad->PaintLine(xr1,y,xr2,bxh);
3414 }
3415 if (endLines) {
3416 if (braticks) {
3417 if (exl != 0. && DrawXLeft) {
3418 xb[0] = xl2+tx; yb[0] = bxl-ty;
3419 xb[1] = xl2; yb[1] = bxl-ty;
3420 xb[2] = xl2; yb[2] = bxl+ty;
3421 xb[3] = xl2+tx; yb[3] = bxl+ty;
3422 gPad->PaintPolyLine(4, xb, yb);
3423 }
3424 if (exh != 0. && DrawXRight) {
3425 xb[0] = xr2-tx; yb[0] = bxh-ty;
3426 xb[1] = xr2; yb[1] = bxh-ty;
3427 xb[2] = xr2; yb[2] = bxh+ty;
3428 xb[3] = xr2-tx; yb[3] = bxh+ty;
3429 gPad->PaintPolyLine(4, xb, yb);
3430 }
3431 } else {
3432 if (DrawXLeft) gPad->PaintLine(xl2,bxl-ty,xl2,bxl+ty);
3433 if (DrawXRight) gPad->PaintLine(xr2,bxh-ty,xr2,bxh+ty);
3434 }
3435 }
3436 }
3437 }
3438
3439 if (eyl != 0. || eyh != 0.) {
3440 if (arrowOpt) {
3441 if (eyh != 0. && DrawYUp) {
3442 if (yup2 == yup) arrow.PaintArrow(x,yup1,byh,yup2,asize,arrowOpt);
3443 else gPad->PaintLine(x,yup1,byh,yup2);
3444 }
3445 if (eyl != 0. && DrawYLow) {
3446 if (ylow2 == ylow) arrow.PaintArrow(x,ylow1,byl,ylow2,asize,arrowOpt);
3447 else gPad->PaintLine(x,ylow1,byl,ylow2);
3448 }
3449 } else {
3450 if (!brackets) {
3451 if (eyh != 0. && DrawYUp) gPad->PaintLine(x,yup1,byh,yup2);
3452 if (eyl != 0. && DrawYLow) gPad->PaintLine(x,ylow1,byl,ylow2);
3453 }
3454 if (endLines) {
3455 if (braticks) {
3456 if (eyh != 0. && yup2 == yup && DrawYUp) {
3457 xb[0] = byh-tx; yb[0] = yup2-ty;
3458 xb[1] = byh-tx; yb[1] = yup2;
3459 xb[2] = byh+tx; yb[2] = yup2;
3460 xb[3] = byh+tx; yb[3] = yup2-ty;
3461 gPad->PaintPolyLine(4, xb, yb);
3462 }
3463 if (eyl != 0. && ylow2 == ylow && DrawYLow) {
3464 xb[0] = byl-tx; yb[0] = ylow2+ty;
3465 xb[1] = byl-tx; yb[1] = ylow2;
3466 xb[2] = byl+tx; yb[2] = ylow2;
3467 xb[3] = byl+tx; yb[3] = ylow2+ty;
3468 gPad->PaintPolyLine(4, xb, yb);
3469 }
3470 } else {
3471 if (eyh != 0. && yup2 == yup && DrawYUp) gPad->PaintLine(byh-tx,yup2,byh+tx,yup2);
3472 if (eyl != 0. && ylow2 == ylow && DrawYLow) gPad->PaintLine(byl-tx,ylow2,byl+tx,ylow2);
3473 }
3474 }
3475 }
3476 }
3477 }
3478
3479 if (!brackets && !axis) PaintGraphSimple(theGraph, option);
3480 gPad->ResetBit(TGraph::kClipFrame);
3481
3482 if (option3) {
3483 Int_t logx = gPad->GetLogx();
3484 Int_t logy = gPad->GetLogy();
3485 gPad->SetLogx(0);
3486 gPad->SetLogy(0);
3487 if (option4) PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"FC");
3488 else PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"F");
3489 gPad->SetLogx(logx);
3490 gPad->SetLogy(logy);
3491 }
3492}
3493
3494
3495////////////////////////////////////////////////////////////////////////////////
3496/// [Paint this TGraphErrors with its current attributes.](\ref GrP3)
3497
3499{
3500
3501 std::vector<Double_t> xline, yline;
3502 Int_t if1 = 0;
3503 Int_t if2 = 0;
3504 Double_t xb[4], yb[4];
3505
3506 const Int_t kBASEMARKER=8;
3507 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};
3508 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};
3509 Int_t theNpoints = theGraph->GetN();
3510 Double_t *theX = theGraph->GetX();
3511 Double_t *theY = theGraph->GetY();
3512 Double_t *theEX = theGraph->GetEX(); if (!theEX) return;
3513 Double_t *theEY = theGraph->GetEY(); if (!theEY) return;
3514
3515 if (strchr(option,'X') || strchr(option,'x')) {PaintGraphSimple(theGraph, option); return;}
3518 if (strstr(option,"||") || strstr(option,"[]")) {
3519 brackets = kTRUE;
3520 if (strstr(option,"[]")) braticks = kTRUE;
3521 }
3523 if (strchr(option,'z')) endLines = kFALSE;
3524 if (strchr(option,'Z')) endLines = kFALSE;
3525 const char *arrowOpt = nullptr;
3526 if (strchr(option,'>')) arrowOpt = ">";
3527 if (strstr(option,"|>")) arrowOpt = "|>";
3528
3529 Bool_t axis = kFALSE;
3530 if (strchr(option,'a')) axis = kTRUE;
3531 if (strchr(option,'A')) axis = kTRUE;
3532 if (axis) PaintGraphSimple(theGraph, option);
3533
3539 if (strchr(option,'0')) option0 = kTRUE;
3540 if (strchr(option,'2')) option2 = kTRUE;
3541 if (strchr(option,'3')) option3 = kTRUE;
3542 if (strchr(option,'4')) {option3 = kTRUE; option4 = kTRUE;}
3543 if (strchr(option,'5')) {option2 = kTRUE; option5 = kTRUE;}
3544
3545 // special flags in case of "reverse plot" and "log scale"
3548 if (strstr(option,"-N")) xrevlog = kTRUE; // along X
3549 if (strstr(option,"-M")) yrevlog = kTRUE; // along Y
3550
3551 if (option3) {
3552 xline.resize(2*theNpoints);
3553 yline.resize(2*theNpoints);
3554 if (xline.empty() || yline.empty()) {
3555 Error("PaintGraphErrors", "too many points, out of memory");
3556 return;
3557 }
3558 if1 = 1;
3559 if2 = 2*theNpoints;
3560 }
3561
3562 theGraph->TAttLine::Modify();
3563
3564 TArrow arrow;
3565 arrow.SetLineWidth(theGraph->GetLineWidth());
3566 arrow.SetLineStyle(theGraph->GetLineStyle());
3567 arrow.SetLineColor(theGraph->GetLineColor());
3568 arrow.SetFillColor(theGraph->GetFillColor());
3569
3570 TBox box;
3572 box.SetLineWidth(theGraph->GetLineWidth());
3573 box.SetLineColor(theGraph->GetLineColor());
3574 box.SetFillColor(theGraph->GetFillColor());
3575 box.SetFillStyle(theGraph->GetFillStyle());
3576
3577 Double_t symbolsize = theGraph->GetMarkerSize();
3579 Int_t mark = TAttMarker::GetMarkerStyleBase(theGraph->GetMarkerStyle());
3580 Double_t cx = 0;
3581 Double_t cy = 0;
3582 if (mark >= 20 && mark <= 49) {
3583 cx = cxx[mark-20];
3584 cy = cyy[mark-20];
3585 }
3586
3587 // define the offset of the error bars due to the symbol size
3588 Double_t s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
3589 Double_t s2y = -gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
3591 Double_t tx = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
3592 Double_t ty = -gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
3593 Float_t asize = 0.6*symbolsize*kBASEMARKER/gPad->GetWh();
3594
3596
3597 // special flags to turn off error bar drawing in case the marker cover it
3599 // loop over all the graph points
3600 Double_t x, y, ex, ey, xl1, xl2, xr1, xr2, yup, yup1, yup2, ylow, ylow1, ylow2;
3601 for (Int_t i=0;i<theNpoints;i++) {
3602 DrawXLeft = kTRUE;
3603 DrawXRight = kTRUE;
3604 DrawYUp = kTRUE;
3605 DrawYLow = kTRUE;
3606 x = gPad->XtoPad(theX[i]);
3607 y = gPad->YtoPad(theY[i]);
3608
3609 if (!option0) {
3610 if (option3) {
3611 if (x < gPad->GetUxmin()) x = gPad->GetUxmin();
3612 if (x > gPad->GetUxmax()) x = gPad->GetUxmax();
3613 if (y < gPad->GetUymin()) y = gPad->GetUymin();
3614 if (y > gPad->GetUymax()) y = gPad->GetUymax();
3615 } else {
3616 if (x < gPad->GetUxmin()) continue;
3617 if (x > gPad->GetUxmax()) continue;
3618 if (y < gPad->GetUymin()) continue;
3619 if (y > gPad->GetUymax()) continue;
3620 }
3621 }
3622 ex = theEX[i];
3623 ey = theEY[i];
3624
3625 if (xrevlog) {
3626 xl1 = x + s2x*cx;
3627 xl2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3628 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3629 - ex);
3630 xr1 = x - s2x*cx;
3631 xr2 = gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(
3632 TMath::Power(10,-(TMath::Log10(theX[i])-gPad->GetUxmax()-gPad->GetUxmin()))
3633 + ex);
3634 tx = -tx;
3635 } else {
3636 xl1 = x - s2x*cx;
3637 xl2 = gPad->XtoPad(theX[i] - ex);
3638 xr1 = x + s2x*cx;
3639 xr2 = gPad->XtoPad(theX[i] + ex);
3640 if (xl1 < xl2) DrawXLeft = kFALSE;
3641 if (xr1 > xr2) DrawXRight = kFALSE;
3642 }
3643
3644 if (yrevlog) {
3645 yup1 = y - s2y*cy;
3646 yup2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3647 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3648 + ey);
3649 ylow1 = y + s2y*cy;
3650 ylow2 = gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(
3651 TMath::Power(10,-(TMath::Log10(theY[i])-gPad->GetUymax()-gPad->GetUymin()))
3652 - ey);
3653 } else {
3654 yup1 = y + s2y*cy;
3655 yup2 = gPad->YtoPad(theY[i] + ey);
3656 ylow1 = y - s2y*cy;
3657 ylow2 = gPad->YtoPad(theY[i] - ey);
3658 if (yup2 < yup1) DrawYUp = kFALSE;
3659 if (ylow2 > ylow1) DrawYLow = kFALSE;
3660 }
3661 yup = yup2;
3662 ylow = ylow2;
3663 if (yup2 > gPad->GetUymax()) yup2 = gPad->GetUymax();
3664 if (ylow2 < gPad->GetUymin()) ylow2 = gPad->GetUymin();
3665
3666 // draw the error rectangles
3667 if (option2) {
3668 x1b = xl2;
3669 x2b = xr2;
3670 y1b = ylow2;
3671 y2b = yup2;
3672 if (x1b < gPad->GetUxmin()) x1b = gPad->GetUxmin();
3673 if (x1b > gPad->GetUxmax()) x1b = gPad->GetUxmax();
3674 if (y1b < gPad->GetUymin()) y1b = gPad->GetUymin();
3675 if (y1b > gPad->GetUymax()) y1b = gPad->GetUymax();
3676 if (x2b < gPad->GetUxmin()) x2b = gPad->GetUxmin();
3677 if (x2b > gPad->GetUxmax()) x2b = gPad->GetUxmax();
3678 if (y2b < gPad->GetUymin()) y2b = gPad->GetUymin();
3679 if (y2b > gPad->GetUymax()) y2b = gPad->GetUymax();
3680 if (option5) box.PaintBox(x1b, y1b, x2b, y2b, "l");
3681 else box.PaintBox(x1b, y1b, x2b, y2b);
3682 continue;
3683 }
3684
3685 // keep points for fill area drawing
3686 if (option3) {
3687 xline[if1-1] = x;
3688 xline[if2-1] = x;
3689 yline[if1-1] = yup2;
3690 yline[if2-1] = ylow2;
3691 if1++;
3692 if2--;
3693 continue;
3694 }
3695
3696 if (ex != 0.) {
3697 if (arrowOpt) {
3698 if (DrawXLeft) arrow.PaintArrow(xl1,y,xl2,y,asize,arrowOpt);
3699 if (DrawXRight) arrow.PaintArrow(xr1,y,xr2,y,asize,arrowOpt);
3700 } else {
3701 if (!brackets) {
3702 if (DrawXLeft) gPad->PaintLine(xl1,y,xl2,y);
3703 if (DrawXRight) gPad->PaintLine(xr1,y,xr2,y);
3704 }
3705 if (endLines) {
3706 if (braticks) {
3707 if (DrawXLeft) {
3708 xb[0] = xl2+tx; yb[0] = y-ty;
3709 xb[1] = xl2; yb[1] = y-ty;
3710 xb[2] = xl2; yb[2] = y+ty;
3711 xb[3] = xl2+tx; yb[3] = y+ty;
3712 gPad->PaintPolyLine(4, xb, yb);
3713 }
3714 if (DrawXRight) {
3715 xb[0] = xr2-tx; yb[0] = y-ty;
3716 xb[1] = xr2; yb[1] = y-ty;
3717 xb[2] = xr2; yb[2] = y+ty;
3718 xb[3] = xr2-tx; yb[3] = y+ty;
3719 gPad->PaintPolyLine(4, xb, yb);
3720 }
3721 } else {
3722 if (DrawXLeft) gPad->PaintLine(xl2,y-ty,xl2,y+ty);
3723 if (DrawXRight) gPad->PaintLine(xr2,y-ty,xr2,y+ty);
3724 }
3725 }
3726 }
3727 }
3728
3729 if (ey != 0.) {
3730 if (arrowOpt) {
3731 if (DrawYUp) {
3732 if (yup2 == yup) arrow.PaintArrow(x,yup1,x,yup2,asize,arrowOpt);
3733 else gPad->PaintLine(x,yup1,x,yup2);
3734 }
3735 if (DrawYLow) {
3736 if (ylow2 == ylow) arrow.PaintArrow(x,ylow1,x,ylow2,asize,arrowOpt);
3737 else gPad->PaintLine(x,ylow1,x,ylow2);
3738 }
3739 } else {
3740 if (!brackets) {
3741 if (DrawYUp) gPad->PaintLine(x,yup1,x,yup2);
3742 if (DrawYLow) gPad->PaintLine(x,ylow1,x,ylow2);
3743 }
3744 if (endLines) {
3745 if (braticks) {
3746 if (yup2 == yup && DrawYUp) {
3747 xb[0] = x-tx; yb[0] = yup2-ty;
3748 xb[1] = x-tx; yb[1] = yup2;
3749 xb[2] = x+tx; yb[2] = yup2;
3750 xb[3] = x+tx; yb[3] = yup2-ty;
3751 gPad->PaintPolyLine(4, xb, yb);
3752 }
3753 if (ylow2 == ylow && DrawYLow) {
3754 xb[0] = x-tx; yb[0] = ylow2+ty;
3755 xb[1] = x-tx; yb[1] = ylow2;
3756 xb[2] = x+tx; yb[2] = ylow2;
3757 xb[3] = x+tx; yb[3] = ylow2+ty;
3758 gPad->PaintPolyLine(4, xb, yb);
3759 }
3760 } else {
3761 if (yup2 == yup && DrawYUp) gPad->PaintLine(x-tx,yup2,x+tx,yup2);
3762 if (ylow2 == ylow && DrawYLow) gPad->PaintLine(x-tx,ylow2,x+tx,ylow2);
3763 }
3764 }
3765 }
3766 }
3767 }
3768
3769 if (!brackets && !axis) PaintGraphSimple(theGraph, option);
3770 gPad->ResetBit(TGraph::kClipFrame);
3771
3772 if (option3) {
3773 Int_t logx = gPad->GetLogx();
3774 Int_t logy = gPad->GetLogy();
3775 gPad->SetLogx(0);
3776 gPad->SetLogy(0);
3777 if (option4) PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"FC");
3778 else PaintGraph(theGraph, 2*theNpoints, xline.data(), yline.data(),"F");
3779 gPad->SetLogx(logx);
3780 gPad->SetLogy(logy);
3781 }
3782}
3783
3784
3785////////////////////////////////////////////////////////////////////////////////
3786/// [Paint this TGraphPolar with its current attributes.](\ref GrP4)
3787
3789{
3791
3792 Int_t theNpoints = theGraphPolar->GetN();
3793 Double_t *theX = theGraphPolar->GetX();
3794 Double_t *theY = theGraphPolar->GetY();
3795 Double_t *theEX = theGraphPolar->GetEX();
3796 Double_t *theEY = theGraphPolar->GetEY();
3797
3798 if (theNpoints < 1)
3799 return;
3800
3801 TString opt = options;
3802 opt.ToUpper();
3803
3804 // same is ignored
3805 opt.ReplaceAll("SAME","");
3806
3808
3809 if (opt.Contains("N")) {
3810 polargram_opt.Append("N");
3811 opt.ReplaceAll("N","");
3812 }
3813
3814 if (opt.Contains("O")) {
3815 polargram_opt.Append("O");
3816 opt.ReplaceAll("O","");
3817 }
3818
3819 if (opt.Contains("A")) {
3820 opt.ReplaceAll("A","");
3821 }
3822
3823 TGraphPolargram *thePolargram = theGraphPolar->GetPolargram();
3824
3825 // Check for existing TGraphPolargram in the Pad
3826 if (gPad) {
3827 // Existing polargram
3828 if (thePolargram && !gPad->FindObject(thePolargram))
3829 thePolargram = nullptr;
3830 if (!thePolargram) {
3831 // Find any other Polargram in the Pad
3832 TIter padObjIter(gPad->GetListOfPrimitives());
3833 while (auto obj = padObjIter()) {
3834 if (obj->InheritsFrom(TGraphPolargram::Class())) {
3835 thePolargram = static_cast<TGraphPolargram*>(obj);
3836 theGraphPolar->SetPolargram(thePolargram);
3837 }
3838 }
3839 }
3840 }
3841
3842 // Create polargram when not exists
3843 if (!thePolargram) {
3844 thePolargram = theGraphPolar->CreatePolargram(opt.Data());
3845 if (!thePolargram)
3846 return;
3847 theGraphPolar->SetPolargram(thePolargram);
3848 thePolargram->Draw(polargram_opt.Data());
3849 }
3850
3851 Double_t rwrmin = thePolargram->GetRMin(),
3852 rwrmax = thePolargram->GetRMax(),
3853 rwtmin = thePolargram->GetTMin(),
3854 rwtmax = thePolargram->GetTMax();
3855
3856 // Convert points to polar.
3857 Double_t *theXpol = theGraphPolar->GetXpol();
3858 Double_t *theYpol = theGraphPolar->GetYpol();
3859
3860 // Project theta in [0,2*Pi] and radius in [0,1].
3862 Double_t thetaNDC = (rwtmax - rwtmin) / (2*TMath::Pi());
3863
3864 // Draw the error bars.
3865 // Y errors are lines, but X errors are pieces of circles.
3866 if (opt.Contains("E")) {
3867 Double_t c = 1;
3868 if (thePolargram->IsDegree())
3869 c = 180 / TMath::Pi();
3870 if (thePolargram->IsGrad())
3871 c = 100 / TMath::Pi();
3872 if (theEY) {
3873 for (Int_t i = 0; i < theNpoints; i++) {
3875 exmin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
3877 eymin = (theY[i]-theEY[i]-rwrmin)/radiusNDC*
3879 exmax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
3881 eymax = (theY[i]+theEY[i]-rwrmin)/radiusNDC*
3883 theGraphPolar->TAttLine::Modify();
3884 if (exmin != exmax || eymin != eymax) gPad->PaintLine(exmin,eymin,exmax,eymax);
3885 }
3886 }
3887 if (theEX) {
3888 for (Int_t i = 0; i < theNpoints; i++) {
3889 Double_t rad = (theY[i]-rwrmin)/radiusNDC;
3892 theGraphPolar->TAttLine::Modify();
3893 if (phimin != phimax) thePolargram->PaintCircle(0,0,rad,phimin,phimax,0);
3894 }
3895 }
3896 }
3897
3898 // Draw the graph itself.
3899 if (!gPad->GetLogx() && !gPad->GetLogy()) {
3900 Double_t a, b, c = 1, x1, x2, y1, y2, discr, norm1, norm2, xts, yts;
3902 Double_t norm = 0;
3903 Double_t xt = 0;
3904 Double_t yt = 0 ;
3905 Int_t j = -1;
3906 if (thePolargram->IsDegree())
3907 c = 180 / TMath::Pi();
3908 if (thePolargram->IsGrad())
3909 c = 100 / TMath::Pi();
3910 for (Int_t i = 0; i < theNpoints; i++) {
3911 xts = xt;
3912 yts = yt;
3915 norm = sqrt(xt*xt+yt*yt);
3916 // Check if points are in the main circle.
3917 if ( norm <= 1) {
3918 // We check that the previous point was in the circle too.
3919 // We record new point position.
3920 if (!previouspointin) {
3921 j++;
3922 theXpol[j] = xt;
3923 theYpol[j] = yt;
3924 } else {
3925 a = (yt-yts)/(xt-xts);
3926 b = yts-a*xts;
3927 discr = 4*(a*a-b*b+1);
3928 x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
3929 x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
3930 y1 = a*x1+b;
3931 y2 = a*x2+b;
3932 norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
3933 norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
3935 j = 0;
3936 if (norm1 < norm2) {
3937 theXpol[j] = x1;
3938 theYpol[j] = y1;
3939 } else {
3940 theXpol[j] = x2;
3941 theYpol[j] = y2;
3942 }
3943 j++;
3944 theXpol[j] = xt;
3945 theYpol[j] = yt;
3947 }
3948 } else {
3949 // We check that the previous point was in the circle.
3950 // We record new point position
3951 if (j>=1 && !previouspointin) {
3952 a = (yt-theYpol[j])/(xt-theXpol[j]);
3953 b = theYpol[j]-a*theXpol[j];
3955 discr = 4*(a*a-b*b+1);
3956 x1 = (-2*a*b+sqrt(discr))/(2*(a*a+1));
3957 x2 = (-2*a*b-sqrt(discr))/(2*(a*a+1));
3958 y1 = a*x1+b;
3959 y2 = a*x2+b;
3960 norm1 = sqrt((x1-xt)*(x1-xt)+(y1-yt)*(y1-yt));
3961 norm2 = sqrt((x2-xt)*(x2-xt)+(y2-yt)*(y2-yt));
3962 j++;
3963 if (norm1 < norm2) {
3964 theXpol[j] = x1;
3965 theYpol[j] = y1;
3966 } else {
3967 theXpol[j] = x2;
3968 theYpol[j] = y2;
3969 }
3971 }
3972 j=-1;
3973 }
3974 }
3975 if (j>=1) {
3976 // If the last point is in the circle, we draw the last serie of point.
3978 }
3979 } else {
3980 for (Int_t i = 0; i < theNpoints; i++) {
3983 }
3985 }
3986
3987 // Paint the title.
3988
3989 if (TestBit(TH1::kNoTitle)) return;
3990 Int_t nt = strlen(theGraph->GetTitle());
3991 TPaveText *title = nullptr;
3992 TIter next(gPad->GetListOfPrimitives());
3993 while (auto obj = next()) {
3994 if (!obj->InheritsFrom(TPaveText::Class()))
3995 continue;
3996 if (obj->GetName() && !strcmp(obj->GetName(),"title")) {
3997 title = static_cast<TPaveText *>(obj);
3998 break;
3999 }
4000 }
4001 if (nt == 0 || gStyle->GetOptTitle() <= 0) {
4002 if (title) delete title;
4003 return;
4004 }
4007 if (ht <= 0) ht = 1.1*gStyle->GetTitleFontSize();
4008 if (ht <= 0) ht = 0.05;
4009 if (wt <= 0) {
4010 TLatex l;
4011 l.SetTextSize(ht);
4012 l.SetTitle(theGraph->GetTitle());
4013 // Adjustment in case the title has several lines (#splitline)
4014 ht = TMath::Max(ht, 1.2*l.GetYsize()/(gPad->GetY2() - gPad->GetY1()));
4015 Double_t wndc = l.GetXsize()/(gPad->GetX2() - gPad->GetX1());
4016 wt = TMath::Min(0.7, 0.02+wndc);
4017 }
4018 if (title) {
4019 TText *t0 = (TText*)title->GetLine(0);
4020 if (t0) {
4021 if (!strcmp(t0->GetTitle(),theGraph->GetTitle())) return;
4022 t0->SetTitle(theGraph->GetTitle());
4023 if (wt > 0) title->SetX2NDC(title->GetX1NDC()+wt);
4024 }
4025 return;
4026 }
4027
4029 if (talh < 1) talh = 1; else if (talh > 3) talh = 3;
4031 if (talv < 1) talv = 1; else if (talv > 3) talv = 3;
4032
4034 xpos = gStyle->GetTitleX();
4035 ypos = gStyle->GetTitleY();
4036
4037 if (talh == 2) xpos = xpos-wt/2.;
4038 if (talh == 3) xpos = xpos-wt;
4039 if (talv == 2) ypos = ypos+ht/2.;
4040 if (talv == 1) ypos = ypos+ht;
4041
4042 TPaveText *ptitle = new TPaveText(xpos, ypos-ht, xpos+wt, ypos,"blNDC");
4043
4044 // Box with the histogram title.
4045 ptitle->SetFillColor(gStyle->GetTitleFillColor());
4046 ptitle->SetFillStyle(gStyle->GetTitleStyle());
4047 ptitle->SetName("title");
4048 ptitle->SetBorderSize(gStyle->GetTitleBorderSize());
4049 ptitle->SetTextColor(gStyle->GetTitleTextColor());
4050 ptitle->SetTextFont(gStyle->GetTitleFont(""));
4051 if (gStyle->GetTitleFont("")%10 > 2)
4052 ptitle->SetTextSize(gStyle->GetTitleFontSize());
4053 ptitle->AddText(theGraph->GetTitle());
4054 ptitle->SetBit(kCanDelete);
4055 ptitle->Draw();
4056 ptitle->Paint("blNDC");
4057}
4058
4059
4060////////////////////////////////////////////////////////////////////////////////
4061/// Paint this graphQQ. No options for the time being.
4062
4064{
4065
4067
4068 Double_t *theX = theGraphQQ->GetX();
4069 Double_t theXq1 = theGraphQQ->GetXq1();
4070 Double_t theXq2 = theGraphQQ->GetXq2();
4071 Double_t theYq1 = theGraphQQ->GetYq1();
4072 Double_t theYq2 = theGraphQQ->GetYq2();
4073 TF1 *theF = theGraphQQ->GetF();
4074
4075 if (!theX){
4076 Error("TGraphQQ::Paint", "2nd dataset or theoretical function not specified");
4077 return;
4078 }
4079
4080 if (theF){
4081 theGraphQQ->GetXaxis()->SetTitle("theoretical quantiles");
4082 theGraphQQ->GetYaxis()->SetTitle("data quantiles");
4083 }
4084
4086
4087 Double_t xmin = gPad->GetUxmin();
4088 Double_t xmax = gPad->GetUxmax();
4089 Double_t ymin = gPad->GetUymin();
4090 Double_t ymax = gPad->GetUymax();
4096
4097 TLine line1, line2, line3;
4098 line1.SetLineStyle(2);
4099 line3.SetLineStyle(2);
4101 if (yxmin < ymin){
4103 line1.PaintLine(xymin, ymin, xqmin, yqmin);
4104 }
4105 else
4106 line1.PaintLine(xmin, yxmin, xqmin, yqmin);
4107
4108 line2.PaintLine(xqmin, yqmin, xqmax, yqmax);
4109
4111 if (yxmax > ymax){
4113 line3.PaintLine(xqmax, yqmax, xymax, ymax);
4114 }
4115 else
4116 line3.PaintLine(xqmax, yqmax, xmax, yxmax);
4117}
4118
4119
4120////////////////////////////////////////////////////////////////////////////////
4121/// Paint theGraph reverting values along X and/or Y axis. a new graph is created.
4122
4124{
4125 TString opt = option;
4126 opt.ToLower();
4127 TH1F *theHist = (TH1F *)theGraph->GetHistogram();
4128
4129 Bool_t lrx = opt.Contains("rx");
4130 Bool_t lry = opt.Contains("ry");
4131 Bool_t lxp = opt.Contains("x+");
4132 Bool_t lyp = opt.Contains("y+");
4133 Bool_t axis = opt.Contains("a");
4134 opt.ReplaceAll("a", "");
4135
4136 Double_t LOX = theHist->GetXaxis()->GetLabelOffset();
4137 Double_t TLX = theHist->GetXaxis()->GetTickLength();
4138 Double_t LOY = theHist->GetYaxis()->GetLabelOffset();
4139 Double_t TLY = theHist->GetYaxis()->GetTickLength();
4140 Int_t XACOL = theHist->GetXaxis()->GetAxisColor();
4141 Int_t YACOL = theHist->GetYaxis()->GetAxisColor();
4142
4143 if (axis) {
4144 if (lrx) {
4145 theHist->GetXaxis()->SetTickLength(0.);
4146 theHist->GetXaxis()->SetLabelOffset(999.);
4147 theHist->GetXaxis()->SetAxisColor(gPad->GetFrameFillColor());
4148 }
4149 if (lry) {
4150 theHist->GetYaxis()->SetTickLength(0.);
4151 theHist->GetYaxis()->SetLabelOffset(999.);
4152 theHist->GetYaxis()->SetAxisColor(gPad->GetFrameFillColor());
4153 }
4154 TString opth = "0";
4155 if (lxp) opth.Append("x+");
4156 if (lyp) opth.Append("y+");
4157 theHist->Paint(opth.Data());
4158 }
4159
4160 Int_t N = theGraph->GetN();
4161
4162 Double_t *X = theGraph->GetX();
4163 Double_t *EXhigh = theGraph->GetEXhigh();
4164 Double_t *EXhighd = theGraph->GetEXhighd();
4165 Double_t *EXlow = theGraph->GetEXlow();
4166 Double_t *EXlowd = theGraph->GetEXlowd();
4167
4168 Double_t *Y = theGraph->GetY();
4169 Double_t *EYhigh = theGraph->GetEYhigh();
4170 Double_t *EYhighd = theGraph->GetEYhighd();
4171 Double_t *EYlow = theGraph->GetEYlow();
4172 Double_t *EYlowd = theGraph->GetEYlowd();
4173
4174 Double_t XA1, XA2, YA1, YA2;
4175 if (axis) {
4176 XA1 = theGraph->GetXaxis()->GetXmin();
4177 XA2 = theGraph->GetXaxis()->GetXmax();
4178 YA1 = theGraph->GetYaxis()->GetXmin();
4179 YA2 = theGraph->GetYaxis()->GetXmax();
4180 } else {
4181 XA1 = gPad->GetUxmin();
4182 XA2 = gPad->GetUxmax();
4183 YA1 = gPad->GetUymin();
4184 YA2 = gPad->GetUymax();
4185 }
4186 Double_t dX = XA1+XA2;
4187 Double_t dY = YA1+YA2;
4188
4189 // Create the new reversed graph
4190 TGraph *theReversedGraph = (TGraph*)theGraph->Clone();
4191
4192 Double_t *rX = theReversedGraph->GetX();
4193 Double_t *rEXhigh = theReversedGraph->GetEXhigh();
4194 Double_t *rEXhighd = theReversedGraph->GetEXhighd();
4195 Double_t *rEXlow = theReversedGraph->GetEXlow();
4196 Double_t *rEXlowd = theReversedGraph->GetEXlowd();
4197
4198 Double_t *rY = theReversedGraph->GetY();
4199 Double_t *rEYhigh = theReversedGraph->GetEYhigh();
4200 Double_t *rEYhighd = theReversedGraph->GetEYhighd();
4201 Double_t *rEYlow = theReversedGraph->GetEYlow();
4202 Double_t *rEYlowd = theReversedGraph->GetEYlowd();
4203
4204 theReversedGraph->SetMarkerStyle(theGraph->GetMarkerStyle());
4205 theReversedGraph->SetMarkerColor(theGraph->GetMarkerColor());
4206 theReversedGraph->SetLineStyle(theGraph->GetLineStyle());
4207 theReversedGraph->SetLineColor(theGraph->GetLineColor());
4208
4209 Int_t i; // loop index
4210
4211 // Reserve the TGraph along the X axis
4212 if (lrx) {
4213 opt.ReplaceAll("rx", "");
4214 if (axis) {
4215 // Reverse the X axis
4216 Double_t GL = 0.;
4217 theHist->GetXaxis()->SetTickLength(0.);
4218 theHist->GetXaxis()->SetLabelOffset(999.);
4219 gPad->Update();
4220 TString optax = "-SDH";
4221 if (gPad->GetGridx()) {
4222 if (gPad->GetLogy()) {
4223 GL = (TMath::Log10(YA2) - TMath::Log10(YA1)) / (gPad->GetY2() - gPad->GetY1());
4224 } else {
4225 GL = (YA2 - YA1) / (gPad->GetY2() - gPad->GetY1());
4226 }
4227 optax.Append("W");
4228 }
4229 Double_t ypos;
4230 if (lxp) ypos = gPad->GetUymax();
4231 else ypos = gPad->GetUymin();
4232 if (gPad->GetLogy()) ypos = TMath::Power(10,ypos);
4234 if (gPad->GetLogx()) {
4235 optax.Append("G");
4236 theReversedXaxis = new TGaxis(TMath::Power(10,gPad->GetUxmax()),
4237 ypos,
4238 TMath::Power(10,gPad->GetUxmin()),
4239 ypos,
4240 theGraph->GetXaxis()->GetXmin(),
4241 theGraph->GetXaxis()->GetXmax(),
4242 theHist->GetNdivisions("X"),
4243 optax.Data(), -GL);
4244 if (theHist->GetXaxis()->GetMoreLogLabels()) theReversedXaxis->SetMoreLogLabels();
4245 theReversedXaxis->SetLabelOffset(LOX + theGraph->GetXaxis()->GetLabelSize());
4246 } else {
4247 theReversedXaxis = new TGaxis(gPad->GetUxmax(),
4248 ypos,
4249 gPad->GetUxmin(),
4250 ypos,
4251 theGraph->GetXaxis()->GetXmin(),
4252 theGraph->GetXaxis()->GetXmax(),
4253 theHist->GetNdivisions("X"),
4254 optax.Data(), -GL);
4255 theReversedXaxis->SetLabelOffset(LOX - theGraph->GetXaxis()->GetLabelSize());
4256 }
4257 theReversedXaxis->SetLabelFont(theGraph->GetXaxis()->GetLabelFont());
4258 theReversedXaxis->SetLabelSize(theGraph->GetXaxis()->GetLabelSize());
4259 theReversedXaxis->SetLabelColor(theGraph->GetXaxis()->GetLabelColor());
4260 theReversedXaxis->SetTickLength(TLX);
4261 theReversedXaxis->Paint();
4262 }
4263
4264 // Reverse X coordinates
4265 if (gPad->GetLogx()) {
4266 for (i=0; i<N; i++) rX[i] = TMath::Power(10,gPad->GetUxmax()+gPad->GetUxmin()-TMath::Log10(X[i]));
4267 opt.Append("-N");
4268 } else {
4269 for (i=0; i<N; i++) rX[i] = dX-X[i];
4270 }
4271
4272 // Reverse X asymmetric errors
4273 if (rEXhigh && EXlow) for (i=0; i<N; i++) rEXhigh[i] = EXlow[i];
4274 if (rEXlow && EXhigh) for (i=0; i<N; i++) rEXlow[i] = EXhigh[i];
4275
4276 // Reverse X bent parameters
4277 if (rEXhighd && EXlowd) for (i=0; i<N; i++) rEXhighd[i] = EXlowd[i];
4278 if (rEXlowd && EXhighd) for (i=0; i<N; i++) rEXlowd[i] = EXhighd[i];
4279 }
4280
4281 // Reserve the TGraph along the Y axis
4282 if (lry) {
4283 opt.ReplaceAll("ry", "");
4284 if (axis) {
4285 // Reverse the Y axis
4286 Double_t GL = 0.;
4287 gPad->Update();
4288 TString optax = "-SDH";
4289 if (gPad->GetGridy()) {
4290 if (gPad->GetLogx()) {
4291 GL = (TMath::Log10(XA2) - TMath::Log10(XA1)) / (gPad->GetX2() - gPad->GetX1());
4292 } else {
4293 GL = (XA2 - XA1) / (gPad->GetX2() - gPad->GetX1());
4294 }
4295 optax.Append("W");
4296 }
4297 Double_t xpos;
4298 if (lyp) xpos = gPad->GetUxmax();
4299 else xpos = gPad->GetUxmin();
4300 if (gPad->GetLogx()) xpos = TMath::Power(10,xpos);
4302 if (gPad->GetLogy()) {
4303 optax.Append("G");
4305 TMath::Power(10,gPad->GetUymax()),
4306 xpos,
4307 TMath::Power(10,gPad->GetUymin()),
4308 theGraph->GetYaxis()->GetXmin(),
4309 theGraph->GetYaxis()->GetXmax(),
4310 theHist->GetNdivisions("Y"),
4311 optax.Data(), GL);
4312 if (theHist->GetYaxis()->GetMoreLogLabels()) theReversedYaxis->SetMoreLogLabels();
4313 } else {
4315 gPad->GetUymax(),
4316 xpos,
4317 gPad->GetUymin(),
4318 theGraph->GetYaxis()->GetXmin(),
4319 theGraph->GetYaxis()->GetXmax(),
4320 theHist->GetNdivisions("Y"),
4321 optax.Data(), GL);
4322 }
4323 theReversedYaxis->SetLabelFont(theGraph->GetYaxis()->GetLabelFont());
4324 theReversedYaxis->SetLabelSize(theGraph->GetYaxis()->GetLabelSize());
4325 theReversedYaxis->SetLabelColor(theGraph->GetYaxis()->GetLabelColor());
4326 theReversedYaxis->SetTickLength(-TLY);
4327 theReversedYaxis->SetLabelOffset(LOY-TLY);
4328 theReversedYaxis->Paint();
4329 }
4330
4331 // Reverse Y coordinates
4332 if (gPad->GetLogy()) {
4333 for (i=0; i<N; i++) rY[i] = TMath::Power(10,gPad->GetUymax()+gPad->GetUymin()-TMath::Log10(Y[i]));
4334 opt.Append("-M");
4335 } else {
4336 for (i=0; i<N; i++) rY[i] = dY-Y[i];
4337 }
4338
4339 // Reverse Y asymmetric errors
4340 if (rEYhigh && EYlow) for (i=0; i<N; i++) rEYhigh[i] = EYlow[i];
4341 if (rEYlow && EYhigh) for (i=0; i<N; i++) rEYlow[i] = EYhigh[i];
4342
4343 // Reverse Y bent parameters
4344 if (rEYhighd && EYlowd) for (i=0; i<N; i++) rEYhighd[i] = EYlowd[i];
4345 if (rEYlowd && EYhighd) for (i=0; i<N; i++) rEYlowd[i] = EYhighd[i];
4346 }
4347
4348 if (lrx) {
4349 if (rEYlowd) for (i=0; i<N; i++) rEYlowd[i] = -rEYlowd[i];
4350 if (rEYhighd) for (i=0; i<N; i++) rEYhighd[i] = -rEYhighd[i];
4351 }
4352 if (lry) {
4353 if (rEXlowd) for (i=0; i<N; i++) rEXlowd[i] = -rEXlowd[i];
4354 if (rEXhighd) for (i=0; i<N; i++) rEXhighd[i] = -rEXhighd[i];
4355 }
4356
4358
4359 theHist->GetXaxis()->SetLabelOffset(LOX);
4360 theHist->GetXaxis()->SetTickLength(TLX);
4361 theHist->GetYaxis()->SetLabelOffset(LOY);
4362 theHist->GetYaxis()->SetTickLength(TLY);
4363 theHist->GetXaxis()->SetAxisColor(XACOL);
4364 theHist->GetYaxis()->SetAxisColor(YACOL);
4365}
4366
4367
4368////////////////////////////////////////////////////////////////////////////////
4369/// Paint a scatter plot
4370
4372{
4373
4375
4376 TString opt = chopt;
4377 opt.ToUpper();
4378
4379 if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0;
4380
4381 double *theX = theScatter->GetGraph()->GetX();
4382 double *theY = theScatter->GetGraph()->GetY();
4383 int n = theScatter->GetGraph()->GetN();
4384 double *theColor = theScatter->GetColor();
4385 double *theSize = theScatter->GetSize();
4386 double MinMarkerSize = theScatter->GetMinMarkerSize();
4387 double MaxMarkerSize = theScatter->GetMaxMarkerSize();
4388
4389 double minx = DBL_MAX;
4390 double maxx = -DBL_MAX;
4391 double miny = DBL_MAX;
4392 double maxy = -DBL_MAX;
4393 double minc = DBL_MAX;
4394 double maxc = -DBL_MAX;
4395 double mins = DBL_MAX;
4396 double maxs = -DBL_MAX;
4397 for (int i=0; i<n; i++) {
4398 minx = TMath::Min(minx,theX[i]);
4399 maxx = TMath::Max(maxx,theX[i]);
4400 miny = TMath::Min(miny,theY[i]);
4401 maxy = TMath::Max(maxy,theY[i]);
4402 if (theColor) {
4405 }
4406 if (theSize) {
4409 }
4410 }
4411
4412 // Make sure minimum and maximum values are different
4413 Double_t d, e = 0.1;
4414 if (minx == maxx) {
4415 if (theX[0] == 0.) {
4416 minx = -e;
4417 maxx = e;
4418 } else {
4419 d = TMath::Abs(theX[0]*e);
4420 minx = theX[0] - d;
4421 maxx = theX[0] + d;
4422 }
4423 }
4424 if (miny == maxy) {
4425 if (theY[0] == 0.) {
4426 miny = -e;
4427 maxy = e;
4428 } else {
4429 d = TMath::Abs(theY[0]*e);
4430 miny = theY[0] - d;
4431 maxy = theY[0] + d;
4432 }
4433 }
4434 if (theColor) {
4435 if (minc == maxc) {
4436 if (theColor[0] == 0.) {
4437 minc = -e;
4438 maxc = e;
4439 } else {
4440 d = TMath::Abs(theColor[0]*e);
4441 minc = theColor[0] - d;
4442 maxc = theColor[0] + d;
4443 }
4444 }
4445 }
4446 if (theSize) {
4447 if (mins == maxs) {
4448 if (theSize[0] == 0.) {
4449 mins = -e;
4450 maxs = e;
4451 } else {
4452 d = TMath::Abs(theSize[0]*e);
4453 mins = theSize[0] - d;
4454 maxs = theSize[0] + d;
4455 }
4456 }
4457 }
4458
4459 TH2F *h = theScatter->GetHistogram();
4460 if (optionAxis) h->Paint(" ");
4461 if (h->GetMinimum() != h->GetMaximum()) {
4462 if (minc<h->GetMinimum()) minc = h->GetMinimum();
4463 if (maxc>h->GetMaximum()) maxc = h->GetMaximum();
4464 }
4465
4466 // Define and paint palette
4467 if (theColor) {
4469 TList *functions = theScatter->GetGraph()->GetListOfFunctions();
4470 palette = (TPaletteAxis*)functions->FindObject("palette");
4471 TView *view = gPad->GetView();
4472 if (palette) {
4473 if (view) {
4474 if (!palette->TestBit(TPaletteAxis::kHasView)) {
4475 functions->Remove(palette);
4476 delete palette; palette = nullptr;
4477 }
4478 } else {
4479 if (palette->TestBit(TPaletteAxis::kHasView)) {
4480 functions->Remove(palette);
4481 delete palette; palette = nullptr;
4482 }
4483 }
4484 }
4485 if (!palette) {
4486 Double_t xup = gPad->GetUxmax();
4487 Double_t x2 = gPad->PadtoX(gPad->GetX2());
4488 Double_t ymin = gPad->PadtoY(gPad->GetUymin());
4489 Double_t ymax = gPad->PadtoY(gPad->GetUymax());
4490 Double_t xr = 0.05*(gPad->GetX2() - gPad->GetX1());
4491 Double_t xmin = gPad->PadtoX(xup +0.1*xr);
4492 Double_t xmax = gPad->PadtoX(xup + xr);
4493 if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr);
4495 palette->SetLabelColor(h->GetZaxis()->GetLabelColor());
4496 palette->SetLabelFont(h->GetZaxis()->GetLabelFont());
4497 palette->SetLabelOffset(h->GetZaxis()->GetLabelOffset());
4498 palette->SetLabelSize(h->GetZaxis()->GetLabelSize());
4499 palette->SetTitleOffset(h->GetZaxis()->GetTitleOffset());
4500 palette->SetTitleSize(h->GetZaxis()->GetTitleSize());
4501 palette->SetNdivisions(h->GetZaxis()->GetNdivisions());
4502 palette->SetTitle(h->GetZaxis()->GetTitle());
4503 palette->SetTitleColor(h->GetZaxis()->GetTitleColor());
4504 palette->SetTitleFont(h->GetZaxis()->GetTitleFont());
4505
4506 functions->AddFirst(palette);
4507 }
4508 if (palette) palette->Paint();
4509 }
4510
4511 // Draw markers
4512 auto nbcol = gStyle->GetNumberOfColors();
4513 int logx = gPad->GetLogx();
4514 int logy = gPad->GetLogy();
4515 int logz = gPad->GetLogz();
4516 if (theColor && logz) {
4517 if (minc>0) minc = log10(minc);
4518 if (maxc>0) maxc = log10(maxc);
4519 }
4520 theScatter->SetMarkerColor(theScatter->GetMarkerColor());
4521 theScatter->TAttMarker::Modify();
4522 double x,y,c,ms;
4523 int nc;
4524 for (int i=0; i<n; i++) {
4525 if (theColor) {
4526 if (logz) {
4527 if (theColor[i]>0) c = log10(theColor[i]);
4528 else continue;
4529 } else {
4530 c = theColor[i];
4531 }
4532 if (c<minc) continue;
4533 if (c>maxc) continue;
4534 nc = TMath::Nint(((c-minc)/(maxc-minc))*(nbcol-1));
4535 if (nc > nbcol-1) nc = nbcol-1;
4536 theScatter->SetMarkerColor(gStyle->GetColorPalette(nc));
4537 }
4538 if (theSize) {
4540 theScatter->SetMarkerSize(ms);
4541 }
4542 if (theColor || theSize) theScatter->TAttMarker::Modify();
4543 if (logx) {
4544 if (theX[i]>0) x = log10(theX[i]);
4545 else break;
4546 } else {
4547 x = theX[i];
4548 }
4549 if (logy) {
4550 if (theY[i]>0) y = log10(theY[i]);
4551 else break;
4552 } else {
4553 y = theY[i];
4554 }
4555 gPad->PaintPolyMarker(1,&x,&y);
4556 }
4557}
4558
4559
4560////////////////////////////////////////////////////////////////////////////////
4561/// Paint a simple graph, without errors bars.
4562
4564{
4565 if (strstr(option,"H") || strstr(option,"h")) {
4566 PaintGrapHist(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
4567 } else {
4568 PaintGraph(theGraph, theGraph->GetN(), theGraph->GetX(), theGraph->GetY(), option);
4569 }
4570
4572
4573 // Paint associated objects in the list of functions (for instance
4574 // the fit function).
4575 TList *functions = theGraph->GetListOfFunctions();
4576 if (!functions) return;
4577 auto lnk = functions->FirstLink();
4578
4579 while (lnk) {
4580 auto obj = lnk->GetObject();
4582 if (obj->InheritsFrom(TF1::Class())) {
4583 if (obj->TestBit(TF1::kNotDraw) == 0) obj->Paint("lsame");
4584 } else {
4585 obj->Paint(lnk->GetOption());
4586 }
4587 lnk = lnk->Next();
4588 }
4589}
4590
4591
4592////////////////////////////////////////////////////////////////////////////////
4593/// Paint a polyline with hatches on one side showing an exclusion zone. x and y
4594/// are the vectors holding the polyline and n the number of points in the
4595/// polyline and `w` the width of the hatches. `w` can be negative.
4596/// This method is not meant to be used directly. It is called automatically
4597/// according to the line style convention.
4598
4600{
4601
4602 Int_t i,j,nf;
4603 Double_t w = (theGraph->GetLineWidth()/100)*0.005;
4604
4605 std::vector<Double_t> xf(2*n);
4606 std::vector<Double_t> yf(2*n);
4607 std::vector<Double_t> xt(n);
4608 std::vector<Double_t> yt(n);
4609 Double_t x1, x2, y1, y2, x3, y3, xm, ym, a, a1, a2, a3;
4610
4611 // Compute the gPad coordinates in TRUE normalized space (NDC)
4613 Int_t iw = gPad->GetWw();
4614 Int_t ih = gPad->GetWh();
4616 gPad->GetPadPar(x1p,y1p,x2p,y2p);
4617 ix1 = (Int_t)(iw*x1p);
4618 iy1 = (Int_t)(ih*y1p);
4619 ix2 = (Int_t)(iw*x2p);
4620 iy2 = (Int_t)(ih*y2p);
4629
4630 // Ratios to convert user space in TRUE normalized space (NDC)
4632 gPad->GetRange(rx1,ry1,rx2,ry2);
4633 Double_t rx = (x2ndc-x1ndc)/(rx2-rx1);
4634 Double_t ry = (y2ndc-y1ndc)/(ry2-ry1);
4635
4636 // The first part of the filled area is made of the graph points.
4637 // Make sure that two adjacent points are different.
4638 xf[0] = rx*(x[0]-rx1)+x1ndc;
4639 yf[0] = ry*(y[0]-ry1)+y1ndc;
4640 nf = 0;
4641 for (i=1; i<n; i++) {
4642 if (x[i]==x[i-1] && y[i]==y[i-1]) continue;
4643 nf++;
4644 xf[nf] = rx*(x[i]-rx1)+x1ndc;
4645 if (xf[i]==xf[i-1]) xf[i] += 0.000001; // add an epsilon to avoid exact vertical lines.
4646 yf[nf] = ry*(y[i]-ry1)+y1ndc;
4647 }
4648
4649 // For each graph points a shifted points is computed to build up
4650 // the second part of the filled area. First and last points are
4651 // treated as special cases, outside of the loop.
4652 if (xf[1]==xf[0]) {
4653 a = TMath::PiOver2();
4654 } else {
4655 a = TMath::ATan((yf[1]-yf[0])/(xf[1]-xf[0]));
4656 }
4657 if (xf[0]<=xf[1]) {
4658 xt[0] = xf[0]-w*TMath::Sin(a);
4659 yt[0] = yf[0]+w*TMath::Cos(a);
4660 } else {
4661 xt[0] = xf[0]+w*TMath::Sin(a);
4662 yt[0] = yf[0]-w*TMath::Cos(a);
4663 }
4664
4665 if (xf[nf]==xf[nf-1]) {
4666 a = TMath::PiOver2();
4667 } else {
4668 a = TMath::ATan((yf[nf]-yf[nf-1])/(xf[nf]-xf[nf-1]));
4669 }
4670 if (xf[nf]>=xf[nf-1]) {
4671 xt[nf] = xf[nf]-w*TMath::Sin(a);
4672 yt[nf] = yf[nf]+w*TMath::Cos(a);
4673 } else {
4674 xt[nf] = xf[nf]+w*TMath::Sin(a);
4675 yt[nf] = yf[nf]-w*TMath::Cos(a);
4676 }
4677
4679 for (i=1; i<nf; i++) {
4680 xi0 = xf[i];
4681 yi0 = yf[i];
4682 xi1 = xf[i+1];
4683 yi1 = yf[i+1];
4684 xi2 = xf[i-1];
4685 yi2 = yf[i-1];
4686 if (xi1==xi0) {
4687 a1 = TMath::PiOver2();
4688 } else {
4689 a1 = TMath::ATan((yi1-yi0)/(xi1-xi0));
4690 }
4691 if (xi1<xi0) a1 = a1+3.14159;
4692 if (xi2==xi0) {
4693 a2 = TMath::PiOver2();
4694 } else {
4695 a2 = TMath::ATan((yi0-yi2)/(xi0-xi2));
4696 }
4697 if (xi0<xi2) a2 = a2+3.14159;
4698 x1 = xi0-w*TMath::Sin(a1);
4699 y1 = yi0+w*TMath::Cos(a1);
4700 x2 = xi0-w*TMath::Sin(a2);
4701 y2 = yi0+w*TMath::Cos(a2);
4702 xm = (x1+x2)*0.5;
4703 ym = (y1+y2)*0.5;
4704 if (xm==xi0) {
4705 a3 = TMath::PiOver2();
4706 } else {
4707 a3 = TMath::ATan((ym-yi0)/(xm-xi0));
4708 }
4709 x3 = xi0-w*TMath::Sin(a3+1.57079);
4710 y3 = yi0+w*TMath::Cos(a3+1.57079);
4711 // Rotate (x3,y3) by PI around (xi0,yi0) if it is not on the (xm,ym) side.
4712 if ((xm-xi0)*(x3-xi0)<0 && (ym-yi0)*(y3-yi0)<0) {
4713 x3 = 2*xi0-x3;
4714 y3 = 2*yi0-y3;
4715 }
4716 if ((xm==x1) && (ym==y1)) {
4717 x3 = xm;
4718 y3 = ym;
4719 }
4720 xt[i] = x3;
4721 yt[i] = y3;
4722 }
4723
4724 // Close the polygon if the first and last points are the same
4725 if (xf[nf]==xf[0] && yf[nf]==yf[0]) {
4726 xm = (xt[nf]+xt[0])*0.5;
4727 ym = (yt[nf]+yt[0])*0.5;
4728 if (xm==xf[0]) {
4729 a3 = TMath::PiOver2();
4730 } else {
4731 a3 = TMath::ATan((ym-yf[0])/(xm-xf[0]));
4732 }
4733 x3 = xf[0]+w*TMath::Sin(a3+1.57079);
4734 y3 = yf[0]-w*TMath::Cos(a3+1.57079);
4735 if ((xm-xf[0])*(x3-xf[0])<0 && (ym-yf[0])*(y3-yf[0])<0) {
4736 x3 = 2*xf[0]-x3;
4737 y3 = 2*yf[0]-y3;
4738 }
4739 xt[nf] = x3;
4740 xt[0] = x3;
4741 yt[nf] = y3;
4742 yt[0] = y3;
4743 }
4744
4745 // Find the crossing segments and remove the useless ones
4746 Double_t xc, yc, c1, b1, c2, b2;
4747 Bool_t cross = kFALSE;
4748 Int_t nf2 = nf;
4749 for (i=nf2; i>0; i--) {
4750 for (j=i-1; j>0; j--) {
4751 if (xt[i-1]==xt[i] || xt[j-1]==xt[j]) continue;
4752 c1 = (yt[i-1]-yt[i])/(xt[i-1]-xt[i]);
4753 b1 = yt[i]-c1*xt[i];
4754 c2 = (yt[j-1]-yt[j])/(xt[j-1]-xt[j]);
4755 b2 = yt[j]-c2*xt[j];
4756 if (c1 != c2) {
4757 xc = (b2-b1)/(c1-c2);
4758 yc = c1*xc+b1;
4759 if (xc>TMath::Min(xt[i],xt[i-1]) && xc<TMath::Max(xt[i],xt[i-1]) &&
4760 xc>TMath::Min(xt[j],xt[j-1]) && xc<TMath::Max(xt[j],xt[j-1]) &&
4761 yc>TMath::Min(yt[i],yt[i-1]) && yc<TMath::Max(yt[i],yt[i-1]) &&
4762 yc>TMath::Min(yt[j],yt[j-1]) && yc<TMath::Max(yt[j],yt[j-1])) {
4763 nf++; xf[nf] = xt[i]; yf[nf] = yt[i];
4764 nf++; xf[nf] = xc ; yf[nf] = yc;
4765 i = j;
4766 cross = kTRUE;
4767 break;
4768 } else {
4769 continue;
4770 }
4771 } else {
4772 continue;
4773 }
4774 }
4775 if (!cross) {
4776 nf++;
4777 xf[nf] = xt[i];
4778 yf[nf] = yt[i];
4779 }
4780 cross = kFALSE;
4781 }
4782 nf++; xf[nf] = xt[0]; yf[nf] = yt[0];
4783
4784 // NDC to user coordinates
4785 for (i=0; i<nf+1; i++) {
4786 xf[i] = (1/rx)*(xf[i]-x1ndc)+rx1;
4787 yf[i] = (1/ry)*(yf[i]-y1ndc)+ry1;
4788 }
4789
4790 // Draw filled area
4791 gPad->PaintFillArea(nf+1,xf.data(),yf.data());
4792 theGraph->TAttLine::Modify(); // In case of PaintFillAreaHatches
4793}
4794
4795
4796////////////////////////////////////////////////////////////////////////////////
4797/// Paint the statistics box with the fit info.
4798
4800{
4801
4802 Int_t dofit;
4803 TPaveStats *stats = nullptr;
4804 TList *functions = theGraph->GetListOfFunctions();
4805 TIter next(functions);
4806 while (auto obj = next()) {
4807 if (obj->InheritsFrom(TPaveStats::Class())) {
4808 stats = (TPaveStats*)obj;
4809 break;
4810 }
4811 }
4812
4813 if (stats) dofit = stats->GetOptFit();
4814 else dofit = gStyle->GetOptFit();
4815
4816 if (!dofit) fit = nullptr;
4817 if (!fit) return;
4818 if (dofit == 1) dofit = 111;
4819 Int_t nlines = 0;
4820 Int_t print_fval = dofit%10;
4821 Int_t print_ferrors = (dofit/10)%10;
4822 Int_t print_fchi2 = (dofit/100)%10;
4823 Int_t print_fprob = (dofit/1000)%10;
4825 if (fit) {
4826 if (print_fval < 2) nlinesf += fit->GetNumberFreeParameters();
4827 else nlinesf += fit->GetNpar();
4828 }
4829 Bool_t done = kFALSE;
4830 Double_t statw = 1.8*gStyle->GetStatW();
4832 if (stats) {
4833 stats->Clear();
4834 done = kTRUE;
4835 } else {
4836 stats = new TPaveStats(
4839 gStyle->GetStatX(),
4840 gStyle->GetStatY(),"brNDC");
4841
4842 stats->SetParent(functions);
4843 stats->SetOptFit(dofit);
4844 stats->SetOptStat(0);
4845 stats->SetFillColor(gStyle->GetStatColor());
4846 stats->SetFillStyle(gStyle->GetStatStyle());
4847 stats->SetBorderSize(gStyle->GetStatBorderSize());
4848 stats->SetTextFont(gStyle->GetStatFont());
4849 if (gStyle->GetStatFont()%10 > 2)
4850 stats->SetTextSize(gStyle->GetStatFontSize());
4851 stats->SetFitFormat(gStyle->GetFitFormat());
4852 stats->SetStatFormat(gStyle->GetStatFormat());
4853 stats->SetName("stats");
4854
4855 stats->SetTextColor(gStyle->GetStatTextColor());
4856 stats->SetTextAlign(12);
4857 stats->SetBit(kCanDelete);
4858 stats->SetBit(kMustCleanup);
4859 }
4860
4861 char t[64];
4862 char textstats[50];
4863 Int_t ndf = fit->GetNDF();
4864 snprintf(textstats,50,"#chi^{2} / ndf = %s%s / %d","%",stats->GetFitFormat(),ndf);
4865 snprintf(t,64,textstats,fit->GetChisquare());
4866 if (print_fchi2) stats->AddText(t);
4867 if (print_fprob) {
4868 snprintf(textstats,50,"Prob = %s%s","%",stats->GetFitFormat());
4869 snprintf(t,64,textstats,TMath::Prob(fit->GetChisquare(),ndf));
4870 stats->AddText(t);
4871 }
4872 if (print_fval || print_ferrors) {
4874 for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
4875 fit->GetParLimits(ipar,parmin,parmax);
4877 if (print_ferrors) {
4878 snprintf(textstats,50,"%-8s = %s%s #pm %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat(),"%",stats->GetFitFormat());
4879 snprintf(t,64,textstats,fit->GetParameter(ipar)
4880 ,fit->GetParError(ipar));
4881 } else {
4882 snprintf(textstats,50,"%-8s = %s%s ",fit->GetParName(ipar),"%",stats->GetFitFormat());
4883 snprintf(t,64,textstats,fit->GetParameter(ipar));
4884 }
4885 t[63] = 0;
4886 stats->AddText(t);
4887 }
4888 }
4889
4890 if (!done) functions->Add(stats);
4891 stats->Paint(stats->GetOption());
4892}
4893
4894
4895////////////////////////////////////////////////////////////////////////////////
4896/// Smooth a curve given by N points.
4897///
4898/// The original code is from an underlaying routine for Draw based on the
4899/// CERN GD3 routine TVIPTE:
4900///
4901/// Author - Marlow etc. Modified by - P. Ward Date - 3.10.1973
4902///
4903/// This method draws a smooth tangentially continuous curve through
4904/// the sequence of data points P(I) I=1,N where P(I)=(X(I),Y(I)).
4905/// The curve is approximated by a polygonal arc of short vectors.
4906/// The data points can represent open curves, P(1) != P(N) or closed
4907/// curves P(2) == P(N). If a tangential discontinuity at P(I) is
4908/// required, then set P(I)=P(I+1). Loops are also allowed.
4909///
4910/// Reference Marlow and Powell, Harwell report No.R.7092.1972
4911/// MCCONALOGUE, Computer Journal VOL.13, NO4, NOV1970P p392 6
4912///
4913/// - npoints : Number of data points.
4914/// - x : Abscissa
4915/// - y : Ordinate
4916
4918{
4919
4920 Int_t i, k, kp, km, npointsMax, banksize, n2, npt;
4921 Int_t maxiterations, finished;
4924 Double_t delta;
4927 Int_t flgic, flgis;
4928 Int_t iw, loptx;
4929 Double_t p1, p2, p3, p4, p5, p6;
4930 Double_t w1, w2, w3;
4931 Double_t a, b, c, r, s=0.0, t, z;
4932 Double_t co, so, ct, st, ctu, stu, xnt;
4933 Double_t dx1, dy1, dx2, dy2, dk1, dk2;
4934 Double_t xo, yo, dx, dy, xt, yt;
4935 Double_t xa, xb, ya, yb;
4936 Double_t u1, u2, u3, tj;
4937 Double_t cc, err;
4938 Double_t sb, sth;
4940 c = t = co = so = ct = st = ctu = stu = dx1 = dy1 = dx2 = dy2 = 0;
4941 xt = yt = xa = xb = ya = yb = u1 = u2 = u3 = tj = sb = 0;
4942
4943 npointsMax = npoints*10;
4944 n2 = npointsMax-2;
4945 banksize = n2;
4946
4947 std::vector<Double_t> qlx(npointsMax);
4948 std::vector<Double_t> qly(npointsMax);
4949 if (qlx.empty() || qly.empty()) {
4950 Error("Smooth", "not enough space in memory");
4951 return;
4952 }
4953
4954 // Decode the type of curve (draw type).
4955
4956 loptx = kFALSE;
4957 jtype = (drawtype%1000)-10;
4958 if (jtype > 0) { ktype = jtype; loptx = kTRUE; }
4959 else ktype = drawtype%1000;
4960
4961 Double_t ruxmin = gPad->GetUxmin();
4962 Double_t ruymin = gPad->GetUymin();
4963 if (ktype == 3) {
4964 xorg = ruxmin;
4965 yorg = ruymin;
4966 } else {
4968 yorg = TMath::Min(TMath::Max((Double_t)0,ruymin),gPad->GetUymax());
4969 }
4970
4971 // delta is the accuracy required in constructing the curve.
4972 // If it is zero then the routine calculates a value otherwise
4973 // it uses this value. (default is 0.0)
4974
4975 delta = 0.00055;
4976 maxiterations = 20;
4977
4978 // Scale data to the range 0-ratio_signs in X, 0-1 in Y
4979 // where ratio_signs is the ratio between the number of changes
4980 // of sign in Y divided by the number of changes of sign in X
4981
4982 sxmin = x[0];
4983 sxmax = x[0];
4984 symin = y[0];
4985 symax = y[0];
4986 Double_t six = 1;
4987 Double_t siy = 1;
4988 for (i=1;i<npoints;i++) {
4989 if (i > 1) {
4990 if ((x[i]-x[i-1])*(x[i-1]-x[i-2]) < 0) six++;
4991 if ((y[i]-y[i-1])*(y[i-1]-y[i-2]) < 0) siy++;
4992 }
4993 if (x[i] < sxmin) sxmin = x[i];
4994 if (x[i] > sxmax) sxmax = x[i];
4995 if (y[i] < symin) symin = y[i];
4996 if (y[i] > symax) symax = y[i];
4997 }
4998 closed = 0;
4999 Double_t dx1n = TMath::Abs(x[npoints-1]-x[0]);
5000 Double_t dy1n = TMath::Abs(y[npoints-1]-y[0]);
5001 if (dx1n < 0.01*(sxmax-sxmin) && dy1n < 0.01*(symax-symin)) closed = 1;
5002 if (sxmin == sxmax) {
5003 xratio = 1;
5004 } else {
5005 if (six > 1) ratio_signs = siy/six;
5006 else ratio_signs = 20;
5008 }
5009 if (symin == symax) yratio = 1;
5010 else yratio = 1/(symax-symin);
5011
5012 qlx[0] = x[0];
5013 qly[0] = y[0];
5014 for (i=0;i<npoints;i++) {
5015 x[i] = (x[i]-sxmin)*xratio;
5016 y[i] = (y[i]-symin)*yratio;
5017 }
5018
5019 // "finished" is minus one if we must draw a straight line from P(k-1)
5020 // to P(k). "finished" is one if the last call to PaintPolyLine has < n2
5021 // points. "finished" is zero otherwise. npt counts the X and Y
5022 // coordinates in work . When npt=n2 a call to IPL is made.
5023
5024 finished = 0;
5025 npt = 1;
5026 k = 1;
5027
5028 // Convert coordinates back to original system
5029
5030 // Separate the set of data points into arcs P(k-1),P(k).
5031 // Calculate the direction cosines. first consider whether
5032 // there is a continuous tangent at the endpoints.
5033
5034 if (!closed) {
5035 if (x[0] != x[npoints-1] || y[0] != y[npoints-1]) goto L40;
5036 if (x[npoints-2] == x[npoints-1] && y[npoints-2] == y[npoints-1]) goto L40;
5037 if (x[0] == x[1] && y[0] == y[1]) goto L40;
5038 }
5039 flgic = kFALSE;
5040 flgis = kTRUE;
5041
5042 // flgic is true if the curve is open and false if it is closed.
5043 // flgis is true in the main loop, but is false if there is
5044 // a deviation from the main loop.
5045
5046 km = npoints - 1;
5047
5048 // Calculate direction cosines at P(1) using P(N-1),P(1),P(2).
5049
5050 goto L100;
5051L40:
5052 flgic = kTRUE;
5053 flgis = kFALSE;
5054
5055 // Skip excessive consecutive equal points.
5056
5057L50:
5058 if (k >= npoints) {
5059 finished = 1; // Prepare to clear out remaining short vectors before returning
5060 if (npt > 1) goto L310;
5061 goto L390;
5062 }
5063 k++;
5064 if (x[k-1] == x[k-2] && y[k-1] == y[k-2]) goto L50;
5065L60:
5066 km = k-1;
5067 if (k > npoints) {
5068 finished = 1; // Prepare to clear out remaining short vectors before returning
5069 if (npt > 1) goto L310;
5070 goto L390;
5071 }
5072 if (k < npoints) goto L90;
5073 if (!flgic) { kp = 2; goto L130;}
5074
5075L80:
5076 if (flgis) goto L150;
5077
5078 // Draw a straight line from P(k-1) to P(k).
5079
5080 finished = -1;
5081 goto L170;
5082
5083 // Test whether P(k) is a cusp.
5084
5085L90:
5086 if (x[k-1] == x[k] && y[k-1] == y[k]) goto L80;
5087L100:
5088 kp = k+1;
5089 goto L130;
5090
5091 // Branch if the next section of the curve begins at a cusp.
5092
5093L110:
5094 if (!flgis) goto L50;
5095
5096 // Carry forward the direction cosines from the previous arc.
5097
5098L120:
5099 co = ct;
5100 so = st;
5101 k++;
5102 goto L60;
5103
5104 // Calculate the direction cosines at P(k). If k=1 then
5105 // N-1 is used for k-1. If k=N then 2 is used for k+1.
5106 // direction cosines at P(k) obtained from P(k-1),P(k),P(k+1).
5107
5108L130:
5109 dx1 = x[k-1] - x[km-1];
5110 dy1 = y[k-1] - y[km-1];
5111 dk1 = dx1*dx1 + dy1*dy1;
5112 dx2 = x[kp-1] - x[k-1];
5113 dy2 = y[kp-1] - y[k-1];
5114 dk2 = dx2*dx2 + dy2*dy2;
5115 ctu = dx1*dk2 + dx2*dk1;
5116 stu = dy1*dk2 + dy2*dk1;
5117 xnt = ctu*ctu + stu*stu;
5118
5119 // If both ctu and stu are zero,then default.This can
5120 // occur when P(k)=P(k+1). I.E. A loop.
5121
5122 if (xnt < 1.E-25) {
5123 ctu = dy1;
5124 stu =-dx1;
5125 xnt = dk1;
5126 }
5127 // Normalise direction cosines.
5128
5129 ct = ctu/TMath::Sqrt(xnt);
5130 st = stu/TMath::Sqrt(xnt);
5131 if (flgis) goto L160;
5132
5133 // Direction cosines at P(k-1) obtained from P(k-1),P(k),P(k+1).
5134
5135 w3 = 2*(dx1*dy2-dx2*dy1);
5136 co = ctu+w3*dy1;
5137 so = stu-w3*dx1;
5138 xnt = 1/TMath::Sqrt(co*co+so*so);
5139 co = co*xnt;
5140 so = so*xnt;
5141 flgis = kTRUE;
5142 goto L170;
5143
5144 // Direction cosines at P(k) obtained from P(k-2),P(k-1),P(k).
5145
5146L150:
5147 w3 = 2*(dx1*dy2-dx2*dy1);
5148 ct = ctu-w3*dy2;
5149 st = stu+w3*dx2;
5150 xnt = 1/TMath::Sqrt(ct*ct+st*st);
5151 ct = ct*xnt;
5152 st = st*xnt;
5153 flgis = kFALSE;
5154 goto L170;
5155L160:
5156 if (k <= 1) goto L120;
5157
5158 // For the arc between P(k-1) and P(k) with direction cosines co,
5159 // so and ct,st respectively, calculate the coefficients of the
5160 // parametric cubic represented by X(t) and Y(t) where
5161 // X(t)=xa*t**3 + xb*t**2 + co*t + xo
5162 // Y(t)=ya*t**3 + yb*t**2 + so*t + yo
5163
5164L170:
5165 xo = x[k-2];
5166 yo = y[k-2];
5167 dx = x[k-1] - xo;
5168 dy = y[k-1] - yo;
5169
5170 // Initialise the values of X(TI),Y(TI) in xt and yt respectively.
5171
5172 xt = xo;
5173 yt = yo;
5174 if (finished < 0) { // Draw a straight line between (xo,yo) and (xt,yt)
5175 xt += dx;
5176 yt += dy;
5177 goto L300;
5178 }
5179 c = dx*dx+dy*dy;
5180 a = co+ct;
5181 b = so+st;
5182 r = dx*a+dy*b;
5183 t = c*6/(TMath::Sqrt(r*r+2*(7-co*ct-so*st)*c)+r);
5184 tsquare = t*t;
5185 tcube = t*tsquare;
5186 xa = (a*t-2*dx)/tcube;
5187 xb = (3*dx-(co+a)*t)/tsquare;
5188 ya = (b*t-2*dy)/tcube;
5189 yb = (3*dy-(so+b)*t)/tsquare;
5190
5191 // If the curve is close to a straight line then use a straight
5192 // line between (xo,yo) and (xt,yt).
5193
5194 if (.75*TMath::Max(TMath::Abs(dx*so-dy*co),TMath::Abs(dx*st-dy*ct)) <= delta) {
5195 finished = -1;
5196 xt += dx;
5197 yt += dy;
5198 goto L300;
5199 }
5200
5201 // Calculate a set of values 0 == t(0).LTCT(1) < ... < t(M)=TC
5202 // such that polygonal arc joining X(t(J)),Y(t(J)) (J=0,1,..M)
5203 // is within the required accuracy of the curve
5204
5205 tj = 0;
5206 u1 = ya*xb-yb*xa;
5207 u2 = yb*co-xb*so;
5208 u3 = so*xa-ya*co;
5209
5210 // Given t(J), calculate t(J+1). The values of X(t(J)),
5211 // Y(t(J)) t(J) are contained in xt,yt and tj respectively.
5212
5213L180:
5214 s = t - tj;
5215 iw = -2;
5216
5217 // Define iw here later.
5218
5219 p1 = (2*u1)*tj-u3;
5220 p2 = (u1*tj-u3)*3*tj+u2;
5221 p3 = 3*tj*ya+yb;
5222 p4 = (p3+yb)*tj+so;
5223 p5 = 3*tj*xa+xb;
5224 p6 = (p5+xb)*tj+co;
5225
5226 // Test D(tj,THETA). A is set to (Y(tj+s)-Y(tj))/s.b is
5227 // set to (X(tj+s)-X(tj))/s.
5228
5229 cc = 0.8209285;
5230 err = 0.1209835;
5231L190:
5232 iw -= 2;
5233L200:
5234 a = (s*ya+p3)*s+p4;
5235 b = (s*xa+p5)*s+p6;
5236
5237 // Set z to PSI(D/delta)-cc.
5238
5239 w1 = -s*(s*u1+p1);
5240 w2 = s*s*u1-p2;
5241 w3 = 1.5*w1+w2;
5242
5243 // Set the estimate of (THETA-tj)/s.Then set the numerator
5244 // of the expression (EQUATION 4.4)/s. Then set the square
5245 // of D(tj,tj+s)/delta. Then replace z by PSI(D/delta)-cc.
5246
5247 if (w3 > 0) wsign = TMath::Abs(w1);
5248 else wsign = -TMath::Abs(w1);
5249 sth = 0.5+wsign/(3.4*TMath::Abs(w1)+5.2*TMath::Abs(w3));
5250 z = s*sth*(s-s*sth)*(w1*sth+w1+w2);
5251 z = z*z/((a*a+b*b)*(delta*delta));
5252 z = (z+2.642937)*z/((.3715652*z+3.063444)*z+.2441889)-cc;
5253
5254 // Branch if z has been calculated
5255
5256 if (iw > 0) goto L250;
5257 if (z > err) goto L240;
5258 goto L220;
5259L210:
5260 iw -= 2;
5261L220:
5262 if (iw+2 == 0) goto L190;
5263 if (iw+2 > 0) goto L290;
5264
5265 // Last part of arc.
5266
5267L230:
5268 xt = x[k-1];
5269 yt = y[k-1];
5270 s = 0;
5271 goto L300;
5272
5273 // z(s). find a value of s where 0 <= s <= sb such that
5274 // TMath::Abs(z(s)) < err
5275
5276L240:
5277 kp = 0;
5278 c = z;
5279 sb = s;
5280L250:
5281 theGraph->Zero(kp,0,sb,err,s,z,maxiterations);
5282 if (kp == 2) goto L210;
5283 if (kp > 2) {
5284 Error("Smooth", "Attempt to plot outside plot limits");
5285 goto L230;
5286 }
5287 if (iw > 0) goto L200;
5288
5289 // Set z=z(s) for s=0.
5290
5291 if (iw < 0) {
5292 z = -cc;
5293 iw = 0;
5294 goto L250;
5295 }
5296
5297 // Set z=z(s) for s=sb.
5298
5299 z = c;
5300 iw = 1;
5301 goto L250;
5302
5303 // Update tj,xt and yt.
5304
5305L290:
5306 xt = xt + s*b;
5307 yt = yt + s*a;
5308 tj = s + tj;
5309
5310 // Convert coordinates to original system
5311
5312L300:
5313 qlx[npt] = sxmin + xt/xratio;
5314 qly[npt] = symin + yt/yratio;
5315 npt++;
5316
5317 // If a fill area must be drawn and if the banks LX and
5318 // LY are too small they are enlarged in order to draw
5319 // the filled area in one go.
5320
5321 if (npt < banksize) goto L320;
5322 if (drawtype >= 1000 || ktype > 1) {
5324 std::vector<Double_t> qtemp(banksize);
5325 for (i=0;i<banksize;i++) qtemp[i] = qlx[i];
5326 qlx.resize(newsize);
5327 for (i=0;i<banksize;i++) qlx[i] = qtemp[i];
5328 for (i=0;i<banksize;i++) qtemp[i] = qly[i];
5329 qly.resize(newsize);
5330 for (i=0;i<banksize;i++) qly[i] = qtemp[i];
5331 banksize = newsize;
5332 goto L320;
5333 }
5334
5335 // Draw the graph
5336
5337L310:
5338 if (drawtype >= 1000) {
5339 gPad->PaintFillArea(npt,qlx.data(),qly.data(), "B");
5340 } else {
5341 if (ktype > 1) {
5342 if (!loptx) {
5343 qlx[npt] = qlx[npt-1];
5344 qlx[npt+1] = qlx[0];
5345 qly[npt] = yorg;
5346 qly[npt+1] = yorg;
5347 } else {
5348 qlx[npt] = xorg;
5349 qlx[npt+1] = xorg;
5350 qly[npt] = qly[npt-1];
5351 qly[npt+1] = qly[0];
5352 }
5353 gPad->PaintFillArea(npt+2,qlx.data(),qly.data());
5354 }
5355 if (TMath::Abs(theGraph->GetLineWidth())>99) PaintPolyLineHatches(theGraph, npt, qlx.data(), qly.data());
5356 gPad->PaintPolyLine(npt,qlx.data(),qly.data());
5357 }
5358 npt = 1;
5359 qlx[0] = sxmin + xt/xratio;
5360 qly[0] = symin + yt/yratio;
5361L320:
5362 if (finished > 0) goto L390;
5363 if (finished < 0) { finished = 0; goto L110;}
5364 if (s > 0) goto L180;
5365 goto L110;
5366
5367 // Convert coordinates back to original system
5368
5369L390:
5370 for (i=0;i<npoints;i++) {
5371 x[i] = sxmin + x[i]/xratio;
5372 y[i] = symin + y[i]/yratio;
5373 }
5374
5375}
5376
5377////////////////////////////////////////////////////////////////////////////////
5378/// Static function to set `fgMaxPointsPerLine` for graph painting. When graphs
5379/// are painted with lines, they are split into chunks of length `fgMaxPointsPerLine`.
5380/// This allows to paint line with an "infinite" number of points. In some case
5381/// this "chunks painting" technic may create artefacts at the chunk's boundaries.
5382/// For instance when zooming deeply in a PDF file. To avoid this effect it might
5383/// be necessary to increase the chunks' size using this function:
5384/// `TGraphPainter::SetMaxPointsPerLine(20000)`.
5385
@ kMouseMotion
Definition Buttons.h:23
@ kButton1Motion
Definition Buttons.h:20
@ kButton1Up
Definition Buttons.h:19
@ kButton1Down
Definition Buttons.h:17
@ kMove
Definition GuiTypes.h:374
@ kHand
Definition GuiTypes.h:374
const Int_t kMaxPixel
Max value for an int.
Definition GuiTypes.h:369
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
int Int_t
Definition RtypesCore.h:45
char Char_t
Definition RtypesCore.h:37
float Float_t
Definition RtypesCore.h:57
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
double Double_t
Definition RtypesCore.h:59
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:374
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define N
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t wmin
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void xpos
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void ypos
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t wmax
Option_t Option_t TPoint TPoint const char y1
static Int_t gHighlightPoint
static TGraph * gHighlightGraph
static std::unique_ptr< TMarker > gHighlightMarker
float xmin
float ymin
float xmax
float ymax
#define gROOT
Definition TROOT.h:406
R__EXTERN TStyle * gStyle
Definition TStyle.h:442
#define gPad
#define gVirtualX
Definition TVirtualX.h:337
#define snprintf
Definition civetweb.c:1540
Draw all kinds of Arrows.
Definition TArrow.h:29
Line Attributes class.
Definition TAttLine.h:20
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:44
virtual Width_t GetLineWidth() const
Return the line width.
Definition TAttLine.h:37
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition TAttLine.h:42
Int_t DistancetoLine(Int_t px, Int_t py, Double_t xp1, Double_t yp1, Double_t xp2, Double_t yp2)
Compute distance from point px,py to a line.
Definition TAttLine.cxx:211
static Style_t GetMarkerStyleBase(Style_t style)
Internal helper function that returns the corresponding marker style with line width 1 for the given ...
virtual void SetTextColor(Color_t tcolor=1)
Set the text color.
Definition TAttText.h:46
virtual void SetTextFont(Font_t tfont=62)
Set the text font.
Definition TAttText.h:48
Create a Box.
Definition TBox.h:22
1-Dim function class
Definition TF1.h:233
static TClass * Class()
@ kNotDraw
Definition TF1.h:346
Define a Frame.
Definition TFrame.h:19
The axis painter class.
Definition TGaxis.h:26
virtual void PaintAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Double_t &wmin, Double_t &wmax, Int_t &ndiv, Option_t *chopt="", Double_t gridlength=0, Bool_t drawGridOnly=kFALSE)
Control function to draw an axis.
Definition TGaxis.cxx:1008
void SetLabelOffset(Float_t labeloffset)
Definition TGaxis.h:108
void SetTickSize(Float_t ticksize)
Definition TGaxis.h:124
void SetLabelSize(Float_t labelsize)
Definition TGaxis.h:109
static TClass * Class()
static TClass * Class()
static TClass * Class()
TGraph with asymmetric error bars and multiple y error dimensions.
static TClass * Class()
The graph painter class.
void PaintGraphPolar(TGraph *theGraph, Option_t *option)
Paint this TGraphPolar with its current attributes.
void PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) override
Control function to draw a graph.
void PaintGraphErrors(TGraph *theGraph, Option_t *option)
Paint this TGraphErrors with its current attributes.
void PaintGraphAsymmErrors(TGraph *theGraph, Option_t *option)
Paint this TGraphAsymmErrors with its current attributes.
void PaintGraphMultiErrors(TGraph *theGraph, Option_t *option)
Paint this TGraphMultiErrors with its current attributes.
virtual void PaintHighlightPoint(TGraph *theGraph, Option_t *option)
Paint highlight point as TMarker object (open circle)
void PaintGraphReverse(TGraph *theGraph, Option_t *option)
Paint theGraph reverting values along X and/or Y axis. a new graph is created.
void PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) override
This is a service method used by THistPainter to paint 1D histograms.
static Int_t fgMaxPointsPerLine
Number of points per chunks' line when drawing a graph.
void PaintStats(TGraph *theGraph, TF1 *fit) override
Paint the statistics box with the fit info.
void PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y)
Paint a polyline with hatches on one side showing an exclusion zone.
void DrawPanelHelper(TGraph *theGraph) override
Display a panel with all histogram drawing options.
char * GetObjectInfoHelper(TGraph *theGraph, Int_t px, Int_t py) const override
void ExecuteEventHelper(TGraph *theGraph, Int_t event, Int_t px, Int_t py) override
Execute action corresponding to one event.
virtual void HighlightPoint(TGraph *theGraph, Int_t hpoint, Int_t distance)
Check on highlight point.
void ComputeLogs(Int_t npoints, Int_t opt)
Compute the logarithm of variables gxwork and gywork according to the value of Options and put the re...
std::vector< Double_t > gxworkl
Int_t DistancetoPrimitiveHelper(TGraph *theGraph, Int_t px, Int_t py) override
Compute distance from point px,py to a graph.
std::vector< Double_t > gxwork
std::vector< Double_t > gywork
void PaintScatter(TScatter *theScatter, Option_t *option) override
Paint a scatter plot.
void Smooth(TGraph *theGraph, Int_t npoints, Double_t *x, Double_t *y, Int_t drawtype)
Smooth a curve given by N points.
std::vector< Double_t > gyworkl
Internal buffers for coordinates. Used for graphs painting.
void SetHighlight(TGraph *theGraph) override
Set highlight (enable/disable) mode for theGraph.
virtual Int_t GetHighlightPoint(TGraph *theGraph) const
Return the highlighted point for theGraph.
void PaintGraphSimple(TGraph *theGraph, Option_t *option)
Paint a simple graph, without errors bars.
void PaintGraphQQ(TGraph *theGraph, Option_t *option)
Paint this graphQQ. No options for the time being.
~TGraphPainter() override
Destructor.
static void SetMaxPointsPerLine(Int_t maxp=50)
Static function to set fgMaxPointsPerLine for graph painting.
void PaintGraphBentErrors(TGraph *theGraph, Option_t *option)
Paint this TGraphBentErrors with its current attributes.
TGraphPainter()
Default constructor.
void PaintHelper(TGraph *theGraph, Option_t *option) override
Paint a any kind of TGraph.
To draw a polar graph.
Definition TGraphPolar.h:23
static TClass * Class()
To draw polar axis.
static TClass * Class()
This class allows to draw quantile-quantile plots.
Definition TGraphQQ.h:18
static TClass * Class()
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
@ kClipFrame
Clip to the frame boundary.
Definition TGraph.h:76
@ kNoStats
Don't draw stats box.
Definition TGraph.h:75
1-D histogram with a float per channel (see TH1 documentation)
Definition TH1.h:645
@ kNoTitle
Don't draw the histogram title.
Definition TH1.h:180
@ kNoStats
Don't draw stats box.
Definition TH1.h:175
2-D histogram with a float per channel (see TH1 documentation)
Definition TH2.h:307
To draw Mathematical Formula.
Definition TLatex.h:18
Use the TLine constructor to create a simple line.
Definition TLine.h:22
virtual void PaintLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Draw this line with new coordinates.
Definition TLine.cxx:399
A doubly linked list.
Definition TList.h:38
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:456
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:798
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1005
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:500
@ kCannotPick
if object in a pad cannot be picked
Definition TObject.h:67
@ kCanDelete
if object in a list can be deleted
Definition TObject.h:62
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition TObject.h:64
The palette painting class.
The histogram statistics painter class.
Definition TPaveStats.h:18
static TClass * Class()
A Pave (see TPave) with text, lines or/and boxes inside.
Definition TPaveText.h:21
static TClass * Class()
virtual TText * GetLine(Int_t number) const
Get Pointer to line number in this pavetext.
Double_t GetX1NDC() const
Definition TPave.h:59
virtual void SetX2NDC(Double_t x2)
Definition TPave.h:83
Regular expression class.
Definition TRegexp.h:31
A TScatter is able to draw four variables scatter plot on a single plot.
Definition TScatter.h:32
Basic string class.
Definition TString.h:139
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
const char * Data() const
Definition TString.h:376
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition TString.h:704
void ToUpper()
Change string to upper case.
Definition TString.cxx:1195
TString & Append(const char *cs)
Definition TString.h:572
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2378
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
Color_t GetLabelColor(Option_t *axis="X") const
Return the label color number in the axis.
Definition TStyle.cxx:1111
Color_t GetStatTextColor() const
Definition TStyle.h:260
Float_t GetTitleX() const
Definition TStyle.h:282
Int_t GetOptTitle() const
Definition TStyle.h:248
Int_t GetNdivisions(Option_t *axis="X") const
Return number of divisions.
Definition TStyle.cxx:1079
Float_t GetStatFontSize() const
Definition TStyle.h:263
Float_t GetBarOffset() const
Definition TStyle.h:184
Float_t GetStatX() const
Definition TStyle.h:266
Float_t GetLabelSize(Option_t *axis="X") const
Return label size.
Definition TStyle.cxx:1147
Float_t GetTickLength(Option_t *axis="X") const
Return tick length.
Definition TStyle.cxx:1194
Style_t GetLabelFont(Option_t *axis="X") const
Return label font.
Definition TStyle.cxx:1123
Float_t GetTitleY() const
Definition TStyle.h:283
Style_t GetTitleFont(Option_t *axis="X") const
Return title font.
Definition TStyle.cxx:1218
Float_t GetStatY() const
Definition TStyle.h:267
Color_t GetTitleFillColor() const
Definition TStyle.h:273
Style_t GetTitleStyle() const
Definition TStyle.h:275
Float_t GetLabelOffset(Option_t *axis="X") const
Return label offset.
Definition TStyle.cxx:1135
Color_t GetStatColor() const
Definition TStyle.h:259
Float_t GetBarWidth() const
Definition TStyle.h:185
void SetDrawBorder(Int_t drawborder=1)
Definition TStyle.h:346
Float_t GetStatH() const
Definition TStyle.h:269
Width_t GetTitleBorderSize() const
Definition TStyle.h:277
Int_t GetColorPalette(Int_t i) const
Return color number i in current palette.
Definition TStyle.cxx:1103
Float_t GetEndErrorSize() const
Definition TStyle.h:187
Int_t GetDrawBorder() const
Definition TStyle.h:186
Width_t GetStatBorderSize() const
Definition TStyle.h:261
Color_t GetTitleTextColor() const
Definition TStyle.h:274
Float_t GetTitleH() const
Definition TStyle.h:285
Style_t GetStatStyle() const
Definition TStyle.h:264
Float_t GetStatW() const
Definition TStyle.h:268
const char * GetFitFormat() const
Definition TStyle.h:201
const char * GetStatFormat() const
Definition TStyle.h:265
Int_t GetNumberOfColors() const
Return number of colors in the color palette.
Definition TStyle.cxx:1177
Int_t GetOptFit() const
Definition TStyle.h:246
Style_t GetStatFont() const
Definition TStyle.h:262
Float_t GetTitleFontSize() const
Definition TStyle.h:276
Int_t GetTitleAlign() const
Definition TStyle.h:272
Color_t GetAxisColor(Option_t *axis="X") const
Return the axis color number in the axis.
Definition TStyle.cxx:1091
Float_t GetTitleW() const
Definition TStyle.h:284
Base class for several text objects.
Definition TText.h:22
See TView3D.
Definition TView.h:25
Abstract base class used by ROOT graphics editor.
static TVirtualPadEditor * GetPadEditor(Bool_t load=kTRUE)
Returns the pad editor dialog. Static method.
small helper class to store/restore gPad context in TPad methods
Definition TVirtualPad.h:61
void box(Int_t pat, Double_t x1, Double_t y1, Double_t x2, Double_t y2)
Definition fillpatterns.C:1
Double_t y[n]
Definition legend1.C:17
return c1
Definition legend1.C:41
Double_t x[n]
Definition legend1.C:17
Double_t ey[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Double_t ex[n]
Definition legend1.C:17
return c2
Definition legend2.C:14
Int_t Nint(T x)
Round to nearest integer. Rounds half integers to the nearest even integer.
Definition TMath.h:697
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:250
Double_t Prob(Double_t chi2, Int_t ndf)
Computation of the probability for a certain Chi-squared (chi2) and number of degrees of freedom (ndf...
Definition TMath.cxx:637
Bool_t IsInside(T xp, T yp, Int_t np, T *x, T *y)
Function which returns kTRUE if point xp,yp lies inside the polygon defined by the np points in array...
Definition TMath.h:1313
Double_t ATan(Double_t)
Returns the principal value of the arc tangent of x, expressed in radians.
Definition TMath.h:644
constexpr Double_t PiOver2()
Definition TMath.h:51
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:666
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:725
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:198
Double_t Cos(Double_t)
Returns the cosine of an angle of x radians.
Definition TMath.h:598
constexpr Double_t Pi()
Definition TMath.h:37
Double_t Sin(Double_t)
Returns the sine of an angle of x radians.
Definition TMath.h:592
Double_t Log10(Double_t x)
Returns the common (base-10) logarithm of x.
Definition TMath.h:766
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:123
TLine l
Definition textangle.C:4
m DrawMarker(0.1, 0.1)