Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
THistPainter.cxx
Go to the documentation of this file.
1// @(#)root/histpainter:$Id$
2// Author: Rene Brun, 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 <cstdlib>
13#include <cstring>
14#include <cstdio>
15#include <cctype>
16#include <iostream>
17
18#include "TROOT.h"
19#include "TSystem.h"
20#include "THistPainter.h"
21#include "TH2.h"
22#include "TH2Poly.h"
23#include "TH3.h"
24#include "TProfile.h"
25#include "TProfile2D.h"
26#include "THStack.h"
27#include "TF2.h"
28#include "TF3.h"
29#include "TCutG.h"
30#include "TMatrixDBase.h"
31#include "TMatrixFBase.h"
32#include "TVectorD.h"
33#include "TVectorF.h"
34#include "TCanvas.h"
35#include "TPad.h"
36#include "TPaveStats.h"
37#include "TFrame.h"
38#include "TLatex.h"
39#include "TPolyLine.h"
40#include "TPoints.h"
41#include "TStyle.h"
42#include "TGraph.h"
43#include "TMultiGraph.h"
44#include "TPie.h"
45#include "TGaxis.h"
46#include "TColor.h"
48#include "TGraph2D.h"
49#include "TGraph2DPainter.h"
50#include "TGraphDelaunay2D.h"
51#include "TView.h"
52#include "TMath.h"
53#include "TRandom2.h"
54#include "TObjArray.h"
55#include "Hoption.h"
56#include "Hparam.h"
57#include "TPluginManager.h"
58#include "TPaletteAxis.h"
59#include "TCrown.h"
60#include "TArrow.h"
61#include "TVirtualPadEditor.h"
62#include "TVirtualX.h"
63#include "TEnv.h"
64#include "TPoint.h"
65#include "TImage.h"
66#include "TCandle.h"
67#include "strlcpy.h"
68
69/*! \class THistPainter
70 \ingroup Histpainter
71 \brief The histogram painter class. Implements all histograms' drawing's options.
72
73- [Introduction](\ref HP00)
74- [Histograms' plotting options](\ref HP01)
75 - [Options supported for 1D and 2D histograms](\ref HP01a)
76 - [Options supported for 1D histograms](\ref HP01b)
77 - [Options supported for 2D histograms](\ref HP01c)
78 - [Options supported for 3D histograms](\ref HP01d)
79 - [Options supported for histograms' stacks (THStack)](\ref HP01e)
80- [Setting the Style](\ref HP02)
81- [Setting line, fill, marker, and text attributes](\ref HP03)
82- [Setting Tick marks on the histogram axis](\ref HP04)
83- [Giving titles to the X, Y and Z axis](\ref HP05)
84- [The option SAME](\ref HP060)
85 - [Limitations](\ref HP060a)
86- [Colors automatically picked in palette](\ref HP061)
87- [Superimposing two histograms with different scales in the same pad](\ref HP06)
88- [Statistics Display](\ref HP07)
89- [Fit Statistics](\ref HP08)
90- [The error bars options](\ref HP09)
91- [The bar chart option](\ref HP100)
92- [The BAR and HBAR options](\ref HP10)
93- [The SCATter plot option (legacy draw option)](\ref HP11)
94- [The ARRow option](\ref HP12)
95- [The BOX option](\ref HP13)
96- [The COLor option (default for 2D and 3D histograms)](\ref HP14)
97- [The CANDLE and VIOLIN options](\ref HP140)
98 - [The CANDLE option](\ref HP140a)
99 - [The VIOLIN option](\ref HP140b)
100- [The TEXT and TEXTnn Option](\ref HP15)
101- [The CONTour options](\ref HP16)
102 - [The LIST option](\ref HP16a)
103 - [The AITOFF, MERCATOR, SINUSOIDAL and PARABOLIC options](\ref HP16b)
104- [The LEGO options](\ref HP17)
105- [The SURFace options](\ref HP18)
106- [Cylindrical, Polar, Spherical and PseudoRapidity/Phi options](\ref HP19)
107- [Base line for bar-charts and lego plots](\ref HP20)
108- [TH2Poly Drawing](\ref HP20a)
109- [The SPEC option](\ref HP21)
110- [Option Z : Adding the color palette on the right side of the pad](\ref HP22)
111- [Setting the color palette](\ref HP23)
112- [Drawing a sub-range of a 2-D histogram; the [cutg] option](\ref HP24)
113- [Drawing options for 3D histograms](\ref HP25)
114- [Drawing option for histograms' stacks](\ref HP26)
115- [Drawing of 3D implicit functions](\ref HP27)
116- [Associated functions drawing](\ref HP28)
117- [Drawing using OpenGL](\ref HP29)
118 - [General information: plot types and supported options](\ref HP29a)
119 - [TH3 as color boxes](\ref HP290)
120 - [TH3 as boxes (spheres)](\ref HP29b)
121 - [TH3 as iso-surface(s)](\ref HP29c)
122 - [TF3 (implicit function)](\ref HP29d)
123 - [Parametric surfaces](\ref HP29e)
124 - [Interaction with the plots](\ref HP29f)
125 - [Selectable parts](\ref HP29g)
126 - [Rotation and zooming](\ref HP29h)
127 - [Panning](\ref HP29i)
128 - [Box cut](\ref HP29j)
129 - [Plot specific interactions (dynamic slicing etc.)](\ref HP29k)
130 - [Surface with option GLSURF](\ref HP29l)
131 - [TF3](\ref HP29m)
132 - [Box](\ref HP29n)
133 - [Iso](\ref HP29o)
134 - [Parametric plot](\ref HP29p)
135- [Highlight mode for histogram](\ref HP30)
136 - [Highlight mode and user function](\ref HP30a)
137
138
139\anchor HP00
140## Introduction
141
142
143Histograms are drawn via the `THistPainter` class. Each histogram has a
144pointer to its own painter (to be usable in a multithreaded program). When the
145canvas has to be redrawn, the `Paint` function of each objects in the
146pad is called. In case of histograms, `TH1::Paint` invokes directly
147`THistPainter::Paint`.
148
149To draw a histogram `h` it is enough to do:
150
151 h->Draw();
152
153`h` can be of any kind: 1D, 2D or 3D. To choose how the histogram will
154be drawn, the `Draw()` method can be invoked with an option. For instance
155to draw a 2D histogram as a lego plot it is enough to do:
156
157 h->Draw("lego");
158
159`THistPainter` offers many options to paint 1D, 2D and 3D histograms.
160
161When the `Draw()` method of a histogram is called for the first time
162(`TH1::Draw`), it creates a `THistPainter` object and saves a
163pointer to this "painter" as a data member of the histogram. The
164`THistPainter` class specializes in the drawing of histograms. It is
165separated from the histogram so that one can have histograms without the
166graphics overhead, for example in a batch program. Each histogram having its own
167painter (rather than a central singleton painter painting all histograms), allows
168two histograms to be drawn in two threads without overwriting the painter's
169values.
170
171When a displayed histogram is filled again, there is no need to call the
172`Draw()` method again; the image will be refreshed the next time the
173pad will be updated.
174
175A pad is updated after one of these three actions:
176
1771. a carriage control on the ROOT command line,
1782. a click inside the pad,
1793. a call to `TPad::Update`.
180
181
182By default a call to `TH1::Draw()` clears the pad of all objects
183before drawing the new image of the histogram. One can use the `SAME`
184option to leave the previous display intact and superimpose the new histogram.
185The same histogram can be drawn with different graphics options in different
186pads.
187
188When a displayed histogram is deleted, its image is automatically removed
189from the pad.
190
191To create a copy of the histogram when drawing it, one can use
192`TH1::DrawClone()`. This will clone the histogram and allow to change
193and delete the original one without affecting the clone.
194
195
196\anchor HP01
197### Histograms' plotting options
198
199
200Most options can be concatenated with or without spaces or commas, for example:
201
202 h->Draw("E1 SAME");
203
204The options are not case sensitive:
205
206 h->Draw("e1 same");
207
208
209The default drawing option can be set with `TH1::SetOption` and retrieve
210using `TH1::GetOption`:
211
212 root [0] h->Draw(); // Draw "h" using the standard histogram representation.
213 root [1] h->Draw("E"); // Draw "h" using error bars
214 root [3] h->SetOption("E"); // Change the default drawing option for "h"
215 root [4] h->Draw(); // Draw "h" using error bars
216 root [5] h->GetOption(); // Retrieve the default drawing option for "h"
217 (const Option_t* 0xa3ff948)"E"
218
219
220\anchor HP01a
221#### Options supported for 1D and 2D histograms
222
223| Option | Description |
224|----------|-------------------------------------------------------------------|
225| "E" | Draw error bars. |
226| "AXIS" | Draw only axis. |
227| "AXIG" | Draw only grid (if the grid is requested). |
228| \anchor OPTHIST "HIST" | When an histogram has errors it is visualized by default with error bars. To visualize it without errors use the option "HIST" together with the required option (eg "hist same c"). The "HIST" option can also be used to plot only the histogram and not the associated function(s). |
229| "FUNC" | When an histogram has a fitted function, this option allows to draw the fit result only. |
230| "SAME" | Superimpose on previous picture in the same pad. |
231| "SAMES" | Same as "SAME" and draw the statistics box|
232| "PFC" | Palette Fill Color: histogram's fill color is taken in the current palette. |
233| "PLC" | Palette Line Color: histogram's line color is taken in the current palette. |
234| "PMC" | Palette Marker Color: histogram's marker color is taken in the current palette. |
235| "LEGO" | Draw a lego plot with hidden line removal. |
236| "LEGO1" | Draw a lego plot with hidden surface removal. |
237| "LEGO2" | Draw a lego plot using colors to show the cell contents When the option "0" is used with any LEGO option, the empty bins are not drawn.|
238| "LEGO3" | Draw a lego plot with hidden surface removal, like LEGO1 but the border lines of each lego-bar are not drawn.|
239| "LEGO4" | Draw a lego plot with hidden surface removal, like LEGO1 but without the shadow effect on each lego-bar.|
240| "TEXT" | Draw bin contents as text (format set via `gStyle->SetPaintTextFormat`).|
241| "TEXTnn" | Draw bin contents as text at angle nn (0 < nn <= 90). |
242| "X+" | The X-axis is drawn on the top side of the plot. |
243| "Y+" | The Y-axis is drawn on the right side of the plot. |
244| "MIN0" | Set minimum value for the Y axis to 0, equivalent to gStyle->SetHistMinimumZero(). |
245
246
247\anchor HP01b
248#### Options supported for 1D histograms
249
250| Option | Description |
251|----------|-------------------------------------------------------------------|
252| " " | Default. |
253| "AH" | Draw histogram without axis. "A" can be combined with any drawing option. For instance, "AC" draws the histogram as a smooth Curve without axis.|
254| "][" | When this option is selected the first and last vertical lines of the histogram are not drawn.|
255| "B" | Bar chart option.|
256| "BAR" | Like option "B", but bars can be drawn with a 3D effect.|
257| "HBAR" | Like option "BAR", but bars are drawn horizontally.|
258| "C" | Draw a smooth Curve through the histogram bins.|
259| "E0" | Draw error bars. Markers are drawn for bins with 0 contents. Combined with E1 or E2 it avoids error bars clipping|
260| "E1" | Draw error bars with perpendicular lines at the edges.|
261| "E2" | Draw error bars with rectangles.|
262| "E3" | Draw a fill area through the end points of the vertical error bars.|
263| "E4" | Draw a smoothed filled area through the end points of the error bars.|
264| "E5" | Like E3 but ignore the bins with 0 contents.|
265| "E6" | Like E4 but ignore the bins with 0 contents.|
266| "X0" | When used with one of the "E" option, it suppress the error bar along X as `gStyle->SetErrorX(0)` would do.|
267| "L" | Draw a line through the bin contents.|
268| "P" | Draw current marker at each bin except empty bins.|
269| "P*" | Draw a star marker at each bin except empty bins.|
270| "P0" | Draw current marker at each bin including empty bins.|
271| "PIE" | Draw histogram as a Pie Chart.|
272| "*H" | Draw histogram with a * at each bin.|
273| "LF2" | Draw histogram like with option "L" but with a fill area. Note that "L" draws also a fill area if the hist fill color is set but the fill area corresponds to the histogram contour.|
274
275
276
277\anchor HP01c
278#### Options supported for 2D histograms
279
280| Option | Description |
281|--------------|------------------------------------------------------------------|
282| " " | Default (color plot).|
283| "ARR" | Arrow mode. Shows gradient between adjacent cells.|
284| "BOX" | A box is drawn for each cell with surface proportional to the content's absolute value. A negative content is marked with a X. |
285| "BOX1" | A button is drawn for each cell with surface proportional to content's absolute value. A sunken button is drawn for negative values a raised one for positive.|
286| "COL" | A box is drawn for each cell with a color scale varying with contents. All the none empty bins (bins with content and error equal to 0) are painted. Empty bins are not painted unless some bins have a negative content because in that case the null bins might be not empty. `TProfile2D` histograms are handled differently because, for this type of 2D histograms, it is possible to know if an empty bin has been filled or not. So even if all the bins' contents are positive some empty bins might be painted. And vice versa, if some bins have a negative content some empty bins might be not painted (default).|
287| "COL1" | Same as "COL" but in case of histogram with negative content the empty bins are not drawn.
288| "COLZ" | Same as "COL". In addition the color palette is also drawn.|
289| "COL2" | Alternative rendering algorithm to "COL". Can significantly improve rendering performance for large, non-sparse 2-D histograms.|
290| "COLZ2" | Same as "COL2". In addition the color palette is also drawn.|
291| "Z CJUST" | In combination with colored options "COL","CONT0" etc: Justify labels in the color palette at color boundaries. For more details see `TPaletteAxis`|
292| "CANDLE" | Draw a candle plot along X axis.|
293| "CANDLEX" | Same as "CANDLE".|
294| "CANDLEY" | Draw a candle plot along Y axis.|
295| "CANDLEXn" | Draw a candle plot along X axis. Different candle-styles with n from 1 to 6.|
296| "CANDLEYn" | Draw a candle plot along Y axis. Different candle-styles with n from 1 to 6.|
297| "VIOLIN" | Draw a violin plot along X axis.|
298| "VIOLINX" | Same as "VIOLIN".|
299| "VIOLINY" | Draw a violin plot along Y axis.|
300| "VIOLINXn" | Draw a violin plot along X axis. Different violin-styles with n being 1 or 2.|
301| "VIOLINYn" | Draw a violin plot along Y axis. Different violin-styles with n being 1 or 2.|
302| "CONT" | Draw a contour plot (same as CONT0).|
303| "CONT0" | Draw a contour plot using surface colors to distinguish contours.|
304| "CONT1" | Draw a contour plot using line styles to distinguish contours.|
305| "CONT2" | Draw a contour plot using the same line style for all contours.|
306| "CONT3" | Draw a contour plot using fill area colors.|
307| "CONT4" | Draw a contour plot using surface colors (SURF option at theta = 0).|
308| "LIST" | Generate a list of TGraph objects for each contour.|
309| "SAME0" | Same as "SAME" but do not use the z-axis range of the first plot. |
310| "SAMES0" | Same as "SAMES" but do not use the z-axis range of the first plot. |
311| "CYL" | Use Cylindrical coordinates. The X coordinate is mapped on the angle and the Y coordinate on the cylinder length.|
312| "POL" | Use Polar coordinates. The visible X range mapped on the angle and the visible Y coordinate on the radius.|
313| "POLF" | Fixed Polar coordinates. The histogram X coordinate mapped on the angle and the Y coordinate on the radius.|
314| "POLN" | Natural Polar coordinates. The X coordinate directly represent angle in radian and the Y coordinate is the radius.|
315| "SPH" | Use Spherical coordinates. The X coordinate is mapped on the latitude and the Y coordinate on the longitude.|
316| "PSR" | Use PseudoRapidity/Phi coordinates. The X coordinate is mapped on Phi.|
317| "SURF" | Draw a surface plot with hidden line removal.|
318| "SURF1" | Draw a surface plot with hidden surface removal.|
319| "SURF2" | Draw a surface plot using colors to show the cell contents.|
320| "SURF3" | Same as SURF with in addition a contour view drawn on the top.|
321| "SURF4" | Draw a surface using Gouraud shading.|
322| "SURF5" | Same as SURF3 but only the colored contour is drawn. Used with option CYL, SPH or PSR it allows to draw colored contours on a sphere, a cylinder or a in pseudo rapidity space. In cartesian or polar coordinates, option SURF3 is used.|
323| "AITOFF" | Draw a contour via an AITOFF projection.|
324| "MERCATOR" | Draw a contour via an Mercator projection.|
325| "SINUSOIDAL" | Draw a contour via an Sinusoidal projection.|
326| "PARABOLIC" | Draw a contour via an Parabolic projection.|
327| "MOLLWEIDE" | Draw a contour via an Mollweide projection.|
328| "LEGO9" | Draw the 3D axis only. Mainly needed for internal use |
329| "FB" | With LEGO or SURFACE, suppress the Front-Box.|
330| "BB" | With LEGO or SURFACE, suppress the Back-Box.|
331| "A" | With LEGO or SURFACE, suppress the axis.|
332| "SCAT" | Draw a scatter-plot (legacy draw option).|
333| "[cutg]" | Draw only the sub-range selected by the TCutG named "cutg".|
334
335
336
337\anchor HP01d
338#### Options supported for 3D histograms
339
340| Option | Description |
341|----------|-------------------------------------------------------------------|
342| " " | Default (color plot).|
343| "ISO" | Draw a Gouraud shaded 3d iso surface through a 3d histogram. It paints one surface at the value computed as follow: `SumOfWeights/(NbinsX*NbinsY*NbinsZ)`.|
344| "BOX" | Draw a for each cell with volume proportional to the content's absolute value. An hidden line removal algorithm is used|
345| "BOX1" | Same as BOX but an hidden surface removal algorithm is used|
346| "BOX2" | The boxes' colors are picked in the current palette according to the bins' contents|
347| "BOX2Z" | Same as "BOX2". In addition the color palette is also drawn.|
348| "BOX3" | Same as BOX1, but the border lines of each lego-bar are not drawn.|
349| "LEGO" | Same as `BOX`.|
350
351\anchor HP01e
352#### Options supported for histograms' stacks (`THStack`)
353
354| Option | Description |
355|------------|-----------------------------------------------------------------|
356| " " | Default, the histograms are drawn on top of each other (as lego plots for 2D histograms).|
357| "NOSTACK" | Histograms in the stack are all paint in the same pad as if the option `SAME` had been specified.|
358| "NOSTACKB" | Histograms are drawn next to each other as bar charts.|
359| "PADS" | The current pad/canvas is subdivided into a number of pads equal to the number of histograms in the stack and each histogram is paint into a separate pad.|
360| "PADSn" | Like PADS but the current pad/canvas is subdivided into a `n` columns, automatically calculating the number of rows.|
361| "PFC" | Palette Fill Color: stack's fill color is taken in the current palette. |
362| "PLC" | Palette Line Color: stack's line color is taken in the current palette. |
363| "PMC" | Palette Marker Color: stack's marker color is taken in the current palette. |
364
365
366
367\anchor HP02
368### Setting the Style
369
370
371Histograms use the current style (`gStyle`). When one changes the current
372style and would like to propagate the changes to the histogram,
373`TH1::UseCurrentStyle` should be called. Call `UseCurrentStyle` on
374each histogram is needed.
375
376To force all the histogram to use the current style use:
377
378 gROOT->ForceStyle();
379
380All the histograms read after this call will use the current style.
381
382
383\anchor HP03
384### Setting line, fill, marker, and text attributes
385
386
387The histogram classes inherit from the attribute classes:
388`TAttLine`, `TAttFill` and `TAttMarker`.
389See the description of these classes for the list of options.
390
391
392\anchor HP04
393### Setting Tick marks on the histogram axis
394
395
396The `TPad::SetTicks` method specifies the type of tick marks on the axis.
397If ` tx = gPad->GetTickx()` and `ty = gPad->GetTicky()` then:
398
399 tx = 1; tick marks on top side are drawn (inside)
400 tx = 2; tick marks and labels on top side are drawn
401 ty = 1; tick marks on right side are drawn (inside)
402 ty = 2; tick marks and labels on right side are drawn
403
404By default only the left Y axis and X bottom axis are drawn
405(`tx = ty = 0`)
406
407`TPad::SetTicks(tx,ty)` allows to set these options.
408See also The `TAxis` functions to set specific axis attributes.
409
410In case multiple color filled histograms are drawn on the same pad, the fill
411area may hide the axis tick marks. One can force a redraw of the axis over all
412the histograms by calling:
413
414 gPad->RedrawAxis();
415
416
417\anchor HP05
418### Giving titles to the X, Y and Z axis
419
420
421 h->GetXaxis()->SetTitle("X axis title");
422 h->GetYaxis()->SetTitle("Y axis title");
423
424The histogram title and the axis titles can be any `TLatex` string.
425The titles are part of the persistent histogram.
426
427
428\anchor HP060
429### The option "SAME"
430
431
432By default, when an histogram is drawn, the current pad is cleared before
433drawing. In order to keep the previous drawing and draw on top of it the
434option `SAME` should be use. The histogram drawn with the option
435`SAME` uses the coordinates system available in the current pad.
436
437This option can be used alone or combined with any valid drawing option but
438some combinations must be use with care.
439
440\anchor HP060a
441#### Limitations
442
443- It does not work when combined with the `LEGO` and `SURF` options unless the
444 histogram plotted with the option `SAME` has exactly the same
445 ranges on the X, Y and Z axis as the currently drawn histogram. To superimpose
446 lego plots [histograms' stacks](\ref HP26) should be used.
447
448
449\anchor HP061
450### Colors automatically picked in palette
451
452\since **ROOT version 6.09/01**
453
454When several histograms are painted in the same canvas thanks to the option "SAME"
455or via a `THStack` it might be useful to have an easy and automatic way to choose
456their color. The simplest way is to pick colors in the current active color
457palette. Palette coloring for histogram is activated thanks to the options `PFC`
458(Palette Fill Color), `PLC` (Palette Line Color) and `PMC` (Palette Marker Color).
459When one of these options is given to `TH1::Draw` the histogram get its color
460from the current color palette defined by `gStyle->SetPalette(...)`. The color
461is determined according to the number of objects having palette coloring in
462the current pad.
463
464Begin_Macro(source)
465../../../tutorials/hist/hist005_TH1_palettecolor.C
466End_Macro
467
468Begin_Macro(source)
469../../../tutorials/hist/hist027_THStack_palette_color.C
470End_Macro
471
472Begin_Macro(source)
473../../../tutorials/hist/hist025_THStack_2d_palette_color.C
474End_Macro
475
476\anchor HP06
477### Superimposing two histograms with different scales in the same pad
478
479
480The following example creates two histograms, the second histogram is the bins
481integral of the first one. It shows a procedure to draw the two histograms in
482the same pad and it draws the scale of the second histogram using a new vertical
483axis on the right side. See also the tutorial `transpad.C` for a variant
484of this example.
485
486Begin_Macro(source)
487{
488 auto c1 = new TCanvas("c1","c1",600,400);
489 // create/fill draw h1
490 gStyle->SetOptStat(kFALSE);
491 auto h1 = new TH1F("h1","Superimposing two histograms with different scales",100,-3,3);
492 Int_t i;
493 for (i=0;i<10000;i++) h1->Fill(gRandom->Gaus(0,1));
494 h1->Draw();
495 c1->Update();
496
497 // create hint1 filled with the bins integral of h1
498 auto hint1 = new TH1F("hint1","h1 bins integral",100,-3,3);
499 float sum = 0.f;
500 for (i=1;i<=100;i++) {
501 sum += h1->GetBinContent(i);
502 hint1->SetBinContent(i,sum);
503 }
504
505 // scale hint1 to the pad coordinates
506 float rightmax = 1.1*hint1->GetMaximum();
507 float scale = gPad->GetUymax()/rightmax;
508 hint1->SetLineColor(kRed);
509 hint1->Scale(scale);
510 hint1->Draw("same");
511
512 // draw an axis on the right side
513 auto axis = new TGaxis(gPad->GetUxmax(),gPad->GetUymin(),
514 gPad->GetUxmax(), gPad->GetUymax(),0,rightmax,510,"+L");
515 axis->SetLineColor(kRed);
516 axis->SetTextColor(kRed);
517 axis->Draw();
518}
519End_Macro
520
521
522\anchor HP07
523### Statistics Display
524
525
526The type of information shown in the histogram statistics box can be selected
527with:
528
529 gStyle->SetOptStat(mode);
530
531The `mode` has up to nine digits that can be set to on (1 or 2), off (0).
532
533 mode = ksiourmen (default = 000001111)
534 k = 1; kurtosis printed
535 k = 2; kurtosis and kurtosis error printed
536 s = 1; skewness printed
537 s = 2; skewness and skewness error printed
538 i = 1; integral of bins printed
539 i = 2; integral of bins with option "width" printed
540 o = 1; number of overflows printed
541 u = 1; number of underflows printed
542 r = 1; standard deviation printed
543 r = 2; standard deviation and standard deviation error printed
544 m = 1; mean value printed
545 m = 2; mean and mean error values printed
546 e = 1; number of entries printed
547 n = 1; name of histogram is printed
548
549For example:
550
551 gStyle->SetOptStat(11);
552
553displays only the name of histogram and the number of entries, whereas:
554
555 gStyle->SetOptStat(1101);
556
557displays the name of histogram, mean value and standard deviation.
558
559<b>WARNING 1:</b> never do:
560
561 gStyle->SetOptStat(0001111);
562
563but instead do:
564
565 gStyle->SetOptStat(1111);
566
567because `0001111` will be taken as an octal number!
568
569<b>WARNING 2:</b> for backward compatibility with older versions
570
571 gStyle->SetOptStat(1);
572
573is taken as:
574
575 gStyle->SetOptStat(1111)
576
577To print only the name of the histogram do:
578
579 gStyle->SetOptStat(1000000001);
580
581<b>NOTE</b> that in case of 2D histograms, when selecting only underflow
582(10000) or overflow (100000), the statistics box will show all combinations
583of underflow/overflows and not just one single number.
584
585The parameter mode can be any combination of the letters `kKsSiIourRmMen`
586
587 k : kurtosis printed
588 K : kurtosis and kurtosis error printed
589 s : skewness printed
590 S : skewness and skewness error printed
591 i : integral of bins printed
592 I : integral of bins with option "width" printed
593 o : number of overflows printed
594 u : number of underflows printed
595 r : standard deviation printed
596 R : standard deviation and standard deviation error printed
597 m : mean value printed
598 M : mean value mean error values printed
599 e : number of entries printed
600 n : name of histogram is printed
601
602For example, to print only name of histogram and number of entries do:
603
604 gStyle->SetOptStat("ne");
605
606To print only the name of the histogram do:
607
608 gStyle->SetOptStat("n");
609
610The default value is:
611
612 gStyle->SetOptStat("nemr");
613
614When a histogram is painted, a `TPaveStats` object is created and added
615to the list of functions of the histogram. If a `TPaveStats` object
616already exists in the histogram list of functions, the existing object is just
617updated with the current histogram parameters.
618
619Once a histogram is painted, the statistics box can be accessed using
620`h->FindObject("stats")`. In the command line it is enough to do:
621
622 Root > h->Draw()
623 Root > TPaveStats *st = (TPaveStats*)h->FindObject("stats")
624
625because after `h->Draw()` the histogram is automatically painted. But
626in a script file the painting should be forced using `gPad->Update()`
627in order to make sure the statistics box is created:
628
629 h->Draw();
630 gPad->Update();
631 TPaveStats *st = (TPaveStats*)h->FindObject("stats");
632
633Without `gPad->Update()` the line `h->FindObject("stats")` returns a null pointer.
634
635When a histogram is drawn with the option `SAME`, the statistics box
636is not drawn. To force the statistics box drawing with the option
637`SAME`, the option `SAMES` must be used.
638If the new statistics box hides the previous statistics box, one can change
639its position with these lines (`h` being the pointer to the histogram):
640
641 Root > TPaveStats *st = (TPaveStats*)h->FindObject("stats")
642 Root > st->SetX1NDC(newx1); //new x start position
643 Root > st->SetX2NDC(newx2); //new x end position
644
645To change the type of information for an histogram with an existing
646`TPaveStats` one should do:
647
648 st->SetOptStat(mode);
649
650Where `mode` has the same meaning than when calling `gStyle->SetOptStat(mode)`
651(see above).
652
653One can delete the statistics box for a histogram `TH1* h` with:
654
655 h->SetStats(0)
656
657and activate it again with:
658
659 h->SetStats(1).
660
661Labels used in the statistics box ("Mean", "Std Dev", ...) can be changed from
662`$ROOTSYS/etc/system.rootrc` or `.rootrc` (look for the string `Hist.Stats.`).
663
664
665\anchor HP08
666### Fit Statistics
667
668
669The type of information about fit parameters printed in the histogram statistics
670box can be selected via the parameter mode. The parameter mode can be
671`= pcev` (default `= 0111`)
672
673 p = 1; print Probability
674 c = 1; print Chisquare/Number of degrees of freedom
675 e = 1; print errors (if e=1, v must be 1)
676 v = 1; print name/values of parameters
677
678Example:
679
680 gStyle->SetOptFit(1011);
681
682print fit probability, parameter names/values and errors.
683
6841. When `v = 1` is specified, only the non-fixed parameters are shown.
6852. When `v = 2` all parameters are shown.
686
687Note: `gStyle->SetOptFit(1)` means "default value", so it is equivalent
688to `gStyle->SetOptFit(111)`
689
690
691\anchor HP09
692### The error bars options
693
694
695| Option | Description |
696|----------|-------------------------------------------------------------------|
697| "E" | Default. Shows only the error bars, not a marker.|
698| "E1" | Small lines are drawn at the end of the error bars.|
699| "E2" | Error rectangles are drawn.|
700| "E3" | A filled area is drawn through the end points of the vertical error bars.|
701| "E4" | A smoothed filled area is drawn through the end points of the vertical error bars.|
702| "E0" | Draw error bars. Markers are drawn for bins with 0 contents. Combined with E1 or E2 it avoids error bars clipping|
703| "E5" | Like E3 but ignore the bins with 0 contents.|
704| "E6" | Like E4 but ignore the bins with 0 contents.|
705| "X0" | When used with one of the "E" option, it suppress the error bar along X as `gStyle->SetErrorX(0)` would do.|
706
707Begin_Macro(source)
708{
709 auto c1 = new TCanvas("c1","c1",600,400);
710 auto he = new TH1F("he","Distribution drawn with error bars (option E1) ",100,-3,3);
711 for (int i=0; i<10000; i++) he->Fill(gRandom->Gaus(0,1));
712 gStyle->SetEndErrorSize(3);
713 gStyle->SetErrorX(1.);
714 he->SetMarkerStyle(20);
715 he->Draw("E1");
716}
717End_Macro
718
719The options "E3" and "E4" draw an error band through the end points of the
720vertical error bars. With "E4" the error band is smoothed. Because of the
721smoothing algorithm used some artefacts may appear at the end of the band
722like in the following example. In such cases "E3" should be used instead
723of "E4".
724
725Begin_Macro(source)
726{
727 auto ce4 = new TCanvas("ce4","ce4",600,400);
728 ce4->Divide(2,1);
729 auto he4 = new TH1F("he4","Distribution drawn with option E4",100,-3,3);
730 Int_t i;
731 for (i=0;i<10000;i++) he4->Fill(gRandom->Gaus(0,1));
732 he4->SetFillColor(kRed);
733 he4->GetXaxis()->SetRange(40,48);
734 ce4->cd(1);
735 he4->Draw("E4");
736 ce4->cd(2);
737 auto he3 = (TH1F*)he4->DrawClone("E3");
738 he3->SetTitle("Distribution drawn option E3");
739}
740End_Macro
741
7422D histograms can be drawn with error bars as shown is the following example:
743
744Begin_Macro(source)
745{
746 auto c2e = new TCanvas("c2e","c2e",600,400);
747 auto h2e = new TH2F("h2e","TH2 drawn with option E",40,-4,4,40,-20,20);
748 float px, py;
749 for (Int_t i = 0; i < 25000; i++) {
750 gRandom->Rannor(px,py);
751 h2e->Fill(px,5*py);
752 }
753 h2e->Draw("E");
754}
755End_Macro
756
757
758\anchor HP100
759### The bar chart option
760
761
762The option "B" allows to draw simple vertical bar charts.
763The bar width is controlled with `TH1::SetBarWidth()`,
764and the bar offset within the bin, with `TH1::SetBarOffset()`.
765These two settings are useful to draw several histograms on the
766same plot as shown in the following example:
767
768Begin_Macro(source)
769{
770 int i;
771 const Int_t nx = 8;
772 string os_X[nx] = {"8","32","128","512","2048","8192","32768","131072"};
773 float d_35_0[nx] = {0.75, -3.30, -0.92, 0.10, 0.08, -1.69, -1.29, -2.37};
774 float d_35_1[nx] = {1.01, -3.02, -0.65, 0.37, 0.34, -1.42, -1.02, -2.10};
775
776 auto cb = new TCanvas("cb","cb",600,400);
777 cb->SetGrid();
778
779 gStyle->SetHistMinimumZero();
780
781 auto h1b = new TH1F("h1b","Option B example",nx,0,nx);
782 h1b->SetFillColor(4);
783 h1b->SetBarWidth(0.4);
784 h1b->SetBarOffset(0.1);
785 h1b->SetStats(0);
786 h1b->SetMinimum(-5);
787 h1b->SetMaximum(5);
788
789 for (i=1; i<=nx; i++) {
790 h1b->SetBinContent(i, d_35_0[i-1]);
791 h1b->GetXaxis()->SetBinLabel(i,os_X[i-1].c_str());
792 }
793
794 h1b->Draw("b");
795
796 auto h2b = new TH1F("h2b","h2b",nx,0,nx);
797 h2b->SetFillColor(38);
798 h2b->SetBarWidth(0.4);
799 h2b->SetBarOffset(0.5);
800 h2b->SetStats(0);
801 for (i=1;i<=nx;i++) h2b->SetBinContent(i, d_35_1[i-1]);
802
803 h2b->Draw("b same");
804}
805End_Macro
806
807
808\anchor HP10
809### The "BAR" and "HBAR" options
810
811
812When the option `bar` or `hbar` is specified, a bar chart is drawn. A vertical
813bar-chart is drawn with the options `bar`, `bar0`, `bar1`, `bar2`, `bar3`, `bar4`.
814An horizontal bar-chart is drawn with the options `hbar`, `hbar0`, `hbar1`,
815`hbar2`, `hbar3`, `hbar4` (hist006_TH1_bar_charts.C).
816
817- The bar is filled with the histogram fill color.
818- The left side of the bar is drawn with a light fill color.
819- The right side of the bar is drawn with a dark fill color.
820- The percentage of the bar drawn with either the light or dark color is:
821 - 0% for option "(h)bar" or "(h)bar0"
822 - 10% for option "(h)bar1"
823 - 20% for option "(h)bar2"
824 - 30% for option "(h)bar3"
825 - 40% for option "(h)bar4"
826
827When an histogram has errors the option ["HIST"](\ref OPTHIST) together with the `(h)bar` option.
828
829Begin_Macro(source)
830../../../tutorials/hist/hist006_TH1_bar_charts.C
831End_Macro
832
833To control the bar width (default is the bin width) `TH1::SetBarWidth()`
834should be used.
835
836To control the bar offset (default is 0) `TH1::SetBarOffset()` should
837be used.
838
839These two parameters are useful when several histograms are plotted using
840the option `SAME`. They allow to plot the histograms next to each other.
841
842
843\anchor HP11
844### The SCATter plot option (legacy draw option)
845
846\attention
847Use of option `SCAT` has been deprecated. It was the default drawing option for 2D and
8483D histograms. The new default option is `COL` (heat-map).
849
850
851For each cell (i,j) a number of points proportional to the cell content is
852drawn. A maximum of `kNMAX` points per cell is drawn. If the maximum is above
853`kNMAX` contents are normalized to `kNMAX` (`kNMAX=2000`).
854If option is of the form `scat=ff`, (eg `scat=1.8`,
855`scat=1e-3`), then `ff` is used as a scale factor to compute the
856number of dots. `scat=1` is the default.
857
858By default the scatter plot is painted with a "dot marker" which not scalable
859(see the `TAttMarker` documentation). To change the marker size, a scalable marker
860type should be used. For instance a circle (marker style 20).
861
862Begin_Macro(source)
863{
864 auto c1 = new TCanvas("c1","c1",600,400);
865 auto hscat = new TH2F("hscat","Option SCATter example (default for 2D histograms) ",40,-4,4,40,-20,20);
866 float px, py;
867 for (Int_t i = 0; i < 25000; i++) {
868 gRandom->Rannor(px,py);
869 hscat->Fill(px,5*py);
870 hscat->Fill(3+0.5*px,2*py-10.);
871 }
872 hscat->Draw("scat=0.5"); // This a legacy draw option. Please consider using TScatter
873}
874End_Macro
875
876
877\anchor HP12
878### The ARRow option
879
880
881Shows gradient between adjacent cells. For each cell (i,j) an arrow is drawn
882The orientation of the arrow follows the cell gradient.
883
884Begin_Macro(source)
885{
886 auto c1 = new TCanvas("c1","c1",600,400);
887 auto harr = new TH2F("harr","Option ARRow example",20,-4,4,20,-20,20);
888 harr->SetLineColor(kRed);
889 float px, py;
890 for (Int_t i = 0; i < 25000; i++) {
891 gRandom->Rannor(px,py);
892 harr->Fill(px,5*py);
893 harr->Fill(3+0.5*px,2*py-10.,0.1);
894 }
895 harr->Draw("ARR");
896}
897End_Macro
898
899\since **ROOT version 6.17/01**
900
901The option `ARR` can be combined with the option `COL` or `COLZ`.
902
903Begin_Macro(source)
904{
905 auto c1 = new TCanvas("c1","c1",600,400);
906 auto harr = new TH2F("harr","Option ARR + COLZ example",20,-4,4,20,-20,20);
907 harr->SetStats(0);
908 float px, py;
909 for (Int_t i = 0; i < 25000; i++) {
910 gRandom->Rannor(px,py);
911 harr->Fill(px,5*py);
912 harr->Fill(3+0.5*px,2*py-10.,0.1);
913 }
914 harr->Draw("ARR COLZ");
915}
916End_Macro
917
918
919\anchor HP13
920### The BOX option
921
922
923For each cell (i,j) a box is drawn. The size (surface) of the box is
924proportional to the absolute value of the cell content.
925The cells with a negative content are drawn with a `X` on top of the box.
926
927Begin_Macro(source)
928{
929 auto c1 = new TCanvas("c1","c1",600,400);
930 auto hbox = new TH2F("hbox","Option BOX example",3,0,3,3,0,3);
931 hbox->SetFillColor(42);
932 hbox->Fill(0.5, 0.5, 1.);
933 hbox->Fill(0.5, 1.5, 4.);
934 hbox->Fill(0.5, 2.5, 3.);
935 hbox->Fill(1.5, 0.5, 2.);
936 hbox->Fill(1.5, 1.5, 12.);
937 hbox->Fill(1.5, 2.5, -6.);
938 hbox->Fill(2.5, 0.5, -4.);
939 hbox->Fill(2.5, 1.5, 6.);
940 hbox->Fill(2.5, 2.5, 0.5);
941 hbox->Draw("BOX");
942}
943End_Macro
944
945With option `BOX1` a button is drawn for each cell with surface
946proportional to content's absolute value. A sunken button is drawn for
947negative values a raised one for positive.
948
949Begin_Macro(source)
950{
951 auto c1 = new TCanvas("c1","c1",600,400);
952 auto hbox1 = new TH2F("hbox1","Option BOX1 example",3,0,3,3,0,3);
953 hbox1->SetFillColor(42);
954 hbox1->Fill(0.5, 0.5, 1.);
955 hbox1->Fill(0.5, 1.5, 4.);
956 hbox1->Fill(0.5, 2.5, 3.);
957 hbox1->Fill(1.5, 0.5, 2.);
958 hbox1->Fill(1.5, 1.5, 12.);
959 hbox1->Fill(1.5, 2.5, -6.);
960 hbox1->Fill(2.5, 0.5, -4.);
961 hbox1->Fill(2.5, 1.5, 6.);
962 hbox1->Fill(2.5, 2.5, 0.5);
963 hbox1->Draw("BOX1");
964}
965End_Macro
966
967When the option `SAME` (or "SAMES") is used with the option `BOX`,
968the boxes' sizes are computed taking the previous plots into account. The range
969along the Z axis is imposed by the first plot (the one without option
970`SAME`); therefore the order in which the plots are done is relevant.
971
972Begin_Macro(source)
973{
974 auto c1 = new TCanvas("c1","c1",600,400);
975 auto hb1 = new TH2F("hb1","Example of BOX plots with option SAME ",40,-3,3,40,-3,3);
976 auto hb2 = new TH2F("hb2","hb2",40,-3,3,40,-3,3);
977 auto hb3 = new TH2F("hb3","hb3",40,-3,3,40,-3,3);
978 auto hb4 = new TH2F("hb4","hb4",40,-3,3,40,-3,3);
979 for (Int_t i=0;i<1000;i++) {
980 double x,y;
981 gRandom->Rannor(x,y);
982 if (x>0 && y>0) hb1->Fill(x,y,4);
983 if (x<0 && y<0) hb2->Fill(x,y,3);
984 if (x>0 && y<0) hb3->Fill(x,y,2);
985 if (x<0 && y>0) hb4->Fill(x,y,1);
986 }
987 hb1->SetFillColor(1);
988 hb2->SetFillColor(2);
989 hb3->SetFillColor(3);
990 hb4->SetFillColor(4);
991 hb1->Draw("box");
992 hb2->Draw("box same");
993 hb3->Draw("box same");
994 hb4->Draw("box same");
995}
996End_Macro
997
998\since **ROOT version 6.17/01:**
999
1000Sometimes the change of the range of the Z axis is unwanted, in which case, one
1001can use `SAME0` (or `SAMES0`) option to opt out of this change.
1002
1003Begin_Macro(source)
1004{
1005 auto h2 = new TH2F("h2"," ",10,0,10,10,20,30);
1006 auto hf = (TH2F*)h2->Clone("hf");
1007 h2->SetBit(TH1::kNoStats);
1008 hf->SetBit(TH1::kNoStats);
1009 h2->Fill(5,22);
1010 h2->Fill(5,23);
1011 h2->Fill(6,22);
1012 h2->Fill(6,23);
1013 hf->Fill(6,23);
1014 hf->Fill(6,23);
1015 hf->Fill(6,23);
1016 hf->Fill(6,23);
1017 hf->Fill(5,23);
1018
1019 auto hf_copy1 = hf->Clone("hf_copy1");
1020 TLatex lt;
1021
1022 auto cx = new TCanvas(); cx->Divide(2,1);
1023
1024 cx->cd(1);
1025 h2->Draw("box");
1026 hf->Draw("text colz same");
1027 lt.DrawLatexNDC(0.3,0.5,"SAME");
1028
1029 cx->cd(2);
1030 h2->Draw("box");
1031 hf_copy1->Draw("text colz same0");
1032 lt.DrawLatexNDC(0.3,0.5,"SAME0");
1033}
1034End_Macro
1035
1036
1037\anchor HP14
1038### The COLor option (default for 2D histograms)
1039
1040The magnitude of individual cell (i,j) is represented as a color picked in the current color palette.
1041This data visualization technique is often called a heat map (or heat-map).
1042
1043The color table used is defined in the current style.
1044
1045If the histogram's minimum and maximum are the same (flat histogram), the
1046mapping on colors is not possible, therefore nothing is painted. To paint a
1047flat histogram it is enough to set the histogram minimum
1048(`TH1::SetMinimum()`) different from the bins' content.
1049
1050The default number of color levels used to paint the cells is 20.
1051It can be changed with `TH1::SetContour()` or
1052`TStyle::SetNumberContours()`. The higher this number is, the smoother
1053is the color change between cells.
1054
1055The color palette in TStyle can be modified via `gStyle->SetPalette()`.
1056
1057All the non-empty bins are painted. Empty bins (bins with content and error equal to 0) are
1058not painted unless some bins have a negative content because in that case the null bins
1059might be not empty.
1060
1061`TProfile2D` histograms are handled differently because, for this type of 2D
1062histograms, it is possible to know if an empty bin has been filled or not. So even
1063if all the bins' contents are positive some empty bins might be painted. And vice versa,
1064if some bins have a negative content some empty bins might be not painted.
1065
1066Combined with the option `COL`, the option `Z` allows to
1067display the color palette defined by `gStyle->SetPalette()`.
1068
1069In the following example, the histogram has only positive bins; the empty
1070bins (containing 0) are not drawn.
1071
1072Begin_Macro(source)
1073{
1074 auto c1 = new TCanvas("c1","c1",600,400);
1075 auto hcol1 = new TH2F("hcol1","Option COLor example ",40,-4,4,40,-20,20);
1076 float px, py;
1077 for (Int_t i = 0; i < 25000; i++) {
1078 gRandom->Rannor(px,py);
1079 hcol1->Fill(px,5*py);
1080 }
1081 hcol1->Draw("COLZ");
1082}
1083End_Macro
1084
1085In the first plot of following example, the histogram has some negative bins;
1086the empty bins (containing 0) are drawn. In some cases one wants to not draw
1087empty bins (containing 0) of histograms having a negative minimum. The option
1088`1`, used to produce the second plot in the following picture, allows to do that.
1089
1090Begin_Macro(source)
1091{
1092 auto c1 = new TCanvas("c1","c1",600,600);
1093 c1->Divide(1,2);
1094 auto hcol23 = new TH2F("hcol23","Option COLZ example ",40,-4,4,40,-20,20);
1095 auto hcol24 = new TH2F("hcol24","Option COLZ1 example ",40,-4,4,40,-20,20);
1096 float px, py;
1097 for (Int_t i = 0; i < 25000; i++) {
1098 gRandom->Rannor(px,py);
1099 hcol23->Fill(px,5*py);
1100 hcol24->Fill(px,5*py);
1101 }
1102 hcol23->Fill(0.,0.,-200.);
1103 hcol24->Fill(0.,0.,-200.);
1104 c1->cd(1); hcol23->Draw("COLZ");
1105 c1->cd(2); hcol24->Draw("COLZ1");
1106}
1107End_Macro
1108
1109When the maximum of the histogram is set to a smaller value than the real maximum,
1110 the bins having a content between the new maximum and the real maximum are
1111painted with the color corresponding to the new maximum.
1112
1113When the minimum of the histogram is set to a greater value than the real minimum,
1114 the bins having a value between the real minimum and the new minimum are not drawn
1115 unless the option `0` is set.
1116In other words, option `COLZ0` forces the painting of bins with content < set minimum with
1117 a color corresponding to the set minimum. In contrast, option `COLZ` would not draw values
1118 smaller than the specified minimum. Note that both `COLZ` and `COLZ0` still do not draw
1119 empty bins, ie bins with `content == error == 0`, if the set min is not negative.
1120(Note that option `COLZ0` for TH2Poly has a different behavior than for TH2.)
1121
1122The following example illustrates the option `0` combined with the option `COL`.
1123
1124Begin_Macro(source)
1125{
1126 auto c1 = new TCanvas("c1","c1",600,600);
1127 c1->Divide(1,2);
1128 auto hcol21 = new TH2F("hcol21","Option COLZ",40,-4,4,40,-20,20);
1129 auto hcol22 = new TH2F("hcol22","Option COLZ0",40,-4,4,40,-20,20);
1130 float px, py;
1131 for (Int_t i = 0; i < 25000; i++) {
1132 gRandom->Rannor(px,py);
1133 hcol21->Fill(px,5*py);
1134 hcol22->Fill(px,5*py);
1135 }
1136 hcol21->SetBit(TH1::kNoStats);
1137 hcol22->SetBit(TH1::kNoStats);
1138 c1->cd(1); hcol21->Draw("COLZ");
1139 c1->cd(2); hcol22->Draw("COLZ0");
1140 hcol21->SetMaximum(100);
1141 hcol21->SetMinimum(40);
1142 hcol22->SetMaximum(100);
1143 hcol22->SetMinimum(40);
1144}
1145End_Macro
1146
1147Note that the behavior of `COLZ` is not symmetric: it does not draw values below the specified minimum,
1148but does draw values above the specified maximum by clipping them to the maximum color. In contrast, `COLZ0`
1149clips color on both lower and upper sides. Both `COLZ0` and `COLZ` exclude drawing empty bins (`content == error == 0`),
1150if the set minimum is not negative.
1151
1152\since **ROOT version 6.09/01:**
1153
1154When the option SAME (or "SAMES") is used with the option COL, the boxes' color
1155are computed taking the previous plots into account. The range along the Z axis
1156is imposed by the first plot (the one without option SAME); therefore the order
1157in which the plots are done is relevant. Same as [in the `BOX` option](\ref HP13), one can use
1158`SAME0` (or `SAMES0`) to opt out of this imposition.
1159
1160Begin_Macro(source)
1161{
1162 auto c = new TCanvas("c","Example of col plots with option SAME",200,10,700,500);
1163 auto h1 = new TH2F("h1","h1",40,-3,3,40,-3,3);
1164 auto h2 = new TH2F("h2","h2",40,-3,3,40,-3,3);
1165 auto h3 = new TH2F("h3","h3",40,-3,3,40,-3,3);
1166 auto h4 = new TH2F("h4","h4",40,-3,3,40,-3,3);
1167 h1->SetBit(TH1::kNoStats);
1168 for (Int_t i=0;i<5000;i++) {
1169 double x,y;
1170 gRandom->Rannor(x,y);
1171 if(x>0 && y>0) h1->Fill(x,y,4);
1172 if(x<0 && y<0) h2->Fill(x,y,3);
1173 if(x>0 && y<0) h3->Fill(x,y,2);
1174 if(x<0 && y>0) h4->Fill(x,y,1);
1175 }
1176 h1->Draw("colz");
1177 h2->Draw("col same");
1178 h3->Draw("col same");
1179 h4->Draw("col same");
1180}
1181End_Macro
1182
1183The option `COL` can be combined with the option `POL`:
1184
1185Begin_Macro(source)
1186{
1187 auto c1 = new TCanvas("c1","c1",600,400);
1188 auto hcol1 = new TH2F("hcol1","Option COLor combined with POL",40,-4,4,40,-4,4);
1189 float px, py;
1190 for (Int_t i = 0; i < 25000; i++) {
1191 gRandom->Rannor(px,py);
1192 hcol1->Fill(px,py);
1193 }
1194 hcol1->Draw("COLZPOL");
1195}
1196End_Macro
1197
1198\since **ROOT version 6.07/03:**
1199
1200A second rendering technique is also available with the COL2 and COLZ2 options.
1201
1202These options provide potential performance improvements compared to the standard
1203COL option. The performance comparison of the COL2 to the COL option depends on
1204the histogram and the size of the rendering region in the current pad. In general,
1205a small (approx. less than 100 bins per axis), sparsely populated TH2 will render
1206faster with the COL option.
1207
1208However, for larger histograms (approx. more than 100 bins per axis)
1209that are not sparse, the COL2 option will provide up to 20 times performance improvements.
1210For example, a 1000x1000 bin TH2 that is not sparse will render an order of magnitude
1211faster with the COL2 option.
1212
1213The COL2 option will also scale its performance based on the size of the
1214pixmap the histogram image is being rendered into. It also is much better optimized for
1215sessions where the user is forwarding X11 windows through an `ssh` connection.
1216
1217For the most part, the COL2 and COLZ2 options are a drop in replacement to the COL
1218and COLZ options. There is one major difference and that concerns the treatment of
1219bins with zero content. The COL2 and COLZ2 options color these bins the color of zero.
1220
1221COL2 option renders the histogram as a bitmap. Therefore it cannot be saved in vector
1222graphics file format like PostScript or PDF (an empty image will be generated). It can
1223be saved only in bitmap files like PNG format for instance.
1224
1225
1226\anchor HP140
1227### The CANDLE and VIOLIN options
1228
1229The mechanism behind Candle plots and Violin plots is very similar. Because of this they are
1230implemented in the same class TCandle. The keywords CANDLE or VIOLIN will initiate the drawing of
1231the corresponding plots. Followed by the keyword the user can select a plot direction (X or V for
1232vertical projections, or Y or H for horizontal projections) and/or predefined definitions
1233(1-6 for candles, 1-2 for violins). The order doesn't matter. Default is X and 1.
1234
1235Instead of using the predefined representations, the candle and violin parameters can be
1236changed individually. In that case the option have the following form:
1237
1238 CANDLEX(<option-string>)
1239 CANDLEY(<option-string>)
1240 VIOLINX(<option-string>)
1241 VIOLINY(<option-string>).
1242
1243All zeros at the beginning of `option-string` can be omitted.
1244
1245`option-string` consists eight values, defined as follow:
1246
1247 "CANDLEX(zhpawMmb)"
1248
1249Where:
1250
1251 - `b = 0`; no box drawn
1252 - `b = 1`; the box is drawn. As the candle-plot is also called a box-plot it
1253 makes sense in the very most cases to always draw the box
1254 - `b = 2`; draw a filled box with border
1255
1256 - `m = 0`; no median drawn
1257 - `m = 1`; median is drawn as a line
1258 - `m = 2`; median is drawn with errors (notches)
1259 - `m = 3`; median is drawn as a circle
1260
1261 - `M = 0`; no mean drawn
1262 - `M = 1`; mean is drawn as a dashed line
1263 - `M = 3`; mean is drawn as a circle
1264
1265 - `w = 0`; no whisker drawn
1266 - `w = 1`; whisker is drawn to end of distribution.
1267 - `w = 2`; whisker is drawn to max 1.5*iqr
1268
1269 - `a = 0`; no anchor drawn
1270 - `a = 1`; the anchors are drawn
1271
1272 - `p = 0`; no points drawn
1273 - `p = 1`; only outliers are drawn
1274 - `p = 2`; all datapoints are drawn
1275 - `p = 3`: all datapoints are drawn scattered
1276
1277 - `h = 0`; no histogram is drawn
1278 - `h = 1`; histogram at the left or bottom side is drawn
1279 - `h = 2`; histogram at the right or top side is drawn
1280 - `h = 3`; histogram at left and right or top and bottom (violin-style) is drawn
1281
1282 - `z = 0`; no zero indicator line is drawn
1283 - `z = 1`; zero indicator line is drawn.
1284
1285As one can see all individual options for both candle and violin plots can be accessed by this
1286mechanism. In deed the keywords CANDLE(<option-string>) and VIOLIN(<option-string>) have the same
1287meaning. So you can parametrise an option-string for a candle plot and use the keywords VIOLIN and
1288vice versa, if you wish.
1289
1290Using a logarithmic x- or y-axis is possible for candle and violin charts.
1291
1292\since **ROOT version 6.11/01**
1293
1294a logarithmic z-axis is possible, too but will only affect violin charts of course.
1295
1296\anchor HP140a
1297#### The CANDLE option
1298
1299<a href="http://en.wikipedia.org/wiki/Box_plot">A Candle plot</a> (also known as
1300a "box plot" or "whisker plot") was invented in 1977 by John Tukey. It is a convenient
1301way to describe graphically a data distribution (D) with only five numbers:
1302
1303 1. The minimum value of the distribution D (bottom or left whisker).
1304 2. The lower quartile (Q1): 25% of the data points in D are less than Q1 (bottom of the box).
1305 3. The median (M): 50% of the data points in D are less than M.
1306 4. The upper quartile (Q3): 75% of the data points in D are less than Q3 (top of the box).
1307 5. The maximum value of the distribution D (top or right whisker).
1308
1309In this implementation a TH2 is considered as a collection of TH1 along
1310X (option `CANDLE` or `CANDLEX`) or Y (option `CANDLEY`).
1311Each TH1 is represented as one candle.
1312
1313Begin_Macro(source)
1314../../../tutorials/hist/hist052_Graphics_candle_plot_whiskers.C
1315End_Macro
1316
1317The candle reduces the information coming from a whole distribution into few values.
1318Independently from the number of entries or the significance of the underlying distribution
1319a candle will always look like a candle. So candle plots should be used carefully in
1320particular with unknown distributions. The definition of a candle is based on
1321__unbinned data__. Here, candles are created from binned data. Because of this, the
1322deviation is connected to the bin width used. The calculation of the quantiles
1323normally done on unbinned data also. Because data are binned, this will
1324only work the best possible way within the resolution of one bin
1325
1326Because of all these facts one should take care that:
1327
1328 - there are enough points per candle
1329 - the bin width is small enough (more bins will increase the maximum
1330 available resolution of the quantiles although there will be some
1331 bins with no entries)
1332 - never make a candle-plot if the underlying distribution is double-distributed
1333 - only create candles of distributions that are more-or-less gaussian (the
1334 MPV should be not too far away from the mean).
1335
1336#### What a candle is made of
1337
1338\since **ROOT version 6.07/05**
1339
1340##### The box
1341The box displays the position of the inter-quantile-range of the underlying
1342distribution. The box contains 25% of the distribution below the median
1343and 25% of the distribution above the median. If the underlying distribution is large
1344enough and gaussian shaped the end-points of the box represent \f$ 0.6745\times\sigma \f$
1345(Where \f$ \sigma \f$ is the standard deviation of the gaussian). The width and
1346the position of the box can be modified by SetBarWidth() and SetBarOffset().
1347The +-25% quantiles are calculated by the GetQuantiles() methods.
1348
1349\since **ROOT version 6.11/01**
1350
1351Using the static function TCandle::SetBoxRange(double) the box definition will be
1352overwritten. E.g. using a box range of 0.68 will redefine the area of the lower box edge
1353to the upper box edge in order to cover 68% of the distribution illustrated by that candle.
1354The static function will affect all candle-charts in the running program.
1355Default is 0.5.
1356
1357Using the static function TCandle::SetScaledCandle(bool) the width of the box (and the
1358whole candle) can be influenced. Deactivated, the width is constant (to be set by
1359SetBarWidth() ). Activated, the width of the boxes will be scaled to each other based on the
1360amount of data in the corresponding candle, the maximum width can be influenced by
1361SetBarWidth(). The static function will affect all candle-charts in the running program.
1362Default is false. Scaling between multiple candle-charts (using "same" or THStack) is not
1363supported, yet
1364
1365##### The Median
1366For a sorted list of numbers, the median is the value in the middle of the list.
1367E.g. if a sorted list is made of five numbers "1,2,3,6,7" 3 will be the median
1368because it is in the middle of the list. If the number of entries is even the
1369average of the two values in the middle will be used. As histograms are binned
1370data, the situation is a bit more complex. The following example shows this:
1371
1372~~~ {.cpp}
1373void quantiles() {
1374 auto h = new TH1I("h","h",10,0,10);
1375 //h->Fill(3);
1376 //h->Fill(3);
1377 h->Fill(4);
1378 h->Draw();
1379 double p = 0.;
1380 double q = 0.;
1381 h->GetQuantiles(1,&q,&p);
1382
1383 cout << "Median is: " << q << std::endl;
1384}
1385~~~
1386
1387Here the bin-width is 1.0. If the two Fill(3) are commented out, as there are currently,
1388the example will return a calculated median of 4.5, because that's the bin center
1389of the bin in which the value 4.0 has been dropped. If the two Fill(3) are not
1390commented out, it will return 3.75, because the algorithm tries to evenly distribute
1391the individual values of a bin with bin content > 0. It means the sorted list
1392would be "3.25, 3.75, 4.5".
1393
1394The consequence is a median of 3.75. This shows how important it is to use a
1395small enough bin-width when using candle-plots on binned data.
1396If the distribution is large enough and gaussian shaped the median will be exactly
1397equal to the mean.
1398The median can be shown as a line or as a circle or not shown at all.
1399
1400In order to show the significance of the median notched candle plots apply a "notch" or
1401narrowing of the box around the median. The significance is defined by
1402\f$ 1.57\times\frac{iqr}{N} \f$ and will be represented as the size of the notch
1403(where iqr is the size of the box and N is the number of entries of the whole
1404distribution). Candle plots like these are usually called "notched candle plots".
1405
1406In case the significance of the median is greater that the size of the box, the
1407box will have an unnatural shape. Usually it means the chart has not enough data,
1408or that representing this uncertainty is not useful
1409
1410##### The Mean
1411The mean can be drawn as a dashed line or as a circle or not drawn at all.
1412The mean is the arithmetic average of the values in the distribution.
1413It is calculated using GetMean(). Because histograms are
1414binned data, the mean value can differ from a calculation on the raw-data.
1415If the distribution is large enough and gaussian shaped the mean will be
1416exactly the median.
1417
1418##### The Whiskers
1419The whiskers represent the part of the distribution not covered by the box.
1420The upper 25% and the lower 25% of the distribution are located within the whiskers.
1421Two representations are available.
1422
1423 - A simple one (using w=1) defining the lower whisker from the lowest data value
1424 to the bottom of the box, and the upper whisker from the top of the box to the
1425 highest data value. In this representation the whisker-lines are dashed.
1426 - A more complex one having a further restriction. The whiskers are still connected
1427 to the box but their length cannot exceed \f$ 1.5\times iqr \f$. So it might
1428 be that the outermost part of the underlying distribution will not be covered
1429 by the whiskers. Usually these missing parts will be represented by the outliers
1430 (see points). Of course the upper and the lower whisker may differ in length.
1431 In this representation the whiskers are drawn as solid lines.
1432
1433\since **ROOT version 6.11/01**
1434
1435Using the static function TCandle::SetWhiskerRange(double) the whisker definition w=1
1436will be overwritten. E.g. using a whisker-range of 0.95 and w=1 will redefine the area of
1437the lower whisker to the upper whisker in order to cover 95% of the distribution inside
1438that candle. The static function will affect all candle-charts in the running program.
1439Default is 1.
1440
1441If the distribution is large enough and gaussian shaped, the maximum length of
1442the whisker will be located at \f$ \pm 2.698 \sigma \f$ (when using the
14431.5*iqr-definition (w=2), where \f$ \sigma \f$ is the standard deviation
1444(see picture above). In that case 99.3% of the total distribution will be covered
1445by the box and the whiskers, whereas 0.7% are represented by the outliers.
1446
1447##### The Anchors
1448The anchors have no special meaning in terms of statistical calculation. They mark
1449the end of the whiskers and they have the width of the box. Both representation
1450with and without anchors are common.
1451
1452##### The Points
1453Depending on the configuration the points can have different meanings:
1454 - If p=1 the points represent the outliers. If they are shown, it means
1455 some parts of the underlying distribution are not covered by the whiskers.
1456 This can only occur when the whiskers are set to option w=2. Here the whiskers
1457 can have a maximum length of \f$ 1.5 \times iqr \f$. So any points outside the
1458 whiskers will be drawn as outliers. The outliers will be represented by crosses.
1459 - If p=2 all points in the distribution will be painted as crosses. This is
1460 useful for small datasets only (up to 10 or 20 points per candle).
1461 The outliers are shown along the candle. Because the underlying distribution
1462 is binned, is frequently occurs that a bin contains more than one value.
1463 Because of this the points will be randomly scattered within their bin along
1464 the candle axis. If the bin content for a bin is exactly 1 (usually
1465 this happens for the outliers) if will be drawn in the middle of the bin along
1466 the candle axis. As the maximum number of points per candle is limited by kNMax/2
1467 on very large datasets scaling will be performed automatically. In that case one
1468 would loose all outliers because they have usually a bin content of 1 (and a
1469 bin content between 0 and 1 after the scaling). Because of this all bin contents
1470 between 0 and 1 - after the scaling - will be forced to be 1.
1471 - As the drawing of all values on large datasets can lead to big amounts of crosses,
1472 one can show all values as a scatter plot instead by choosing p=3. The points will be
1473 drawn as dots and will be scattered within the width of the candle. The color
1474 of the points will be the color of the candle-chart.
1475
1476##### Other Options
1477Is is possible to combine all options of candle and violin plots with each other. E.g. a box-plot
1478with a histogram.
1479
1480#### How to use the candle-plots drawing option
1481
1482There are six predefined candle-plot representations:
1483
1484 - "CANDLEX1": Standard candle (whiskers cover the whole distribution)
1485 - "CANDLEX2": Standard candle with better whisker definition + outliers.
1486 It is a good compromise
1487 - "CANDLEX3": Like candle2 but with a mean as a circle.
1488 It is easier to distinguish mean and median
1489 - "CANDLEX4": Like candle3 but showing the uncertainty of the median as well
1490 (notched candle plots).
1491 For bigger datasets per candle
1492 - "CANDLEX5": Like candle2 but showing all data points.
1493 For very small datasets
1494 - "CANDLEX6": Like candle2 but showing all datapoints scattered.
1495 For huge datasets
1496
1497
1498The following picture shows how the six predefined representations look.
1499
1500Begin_Macro
1501{
1502 auto c1 = new TCanvas("c1","c1",700,800);
1503 c1->Divide(2,3);
1504 gStyle->SetOptStat(kFALSE);
1505
1506 auto hcandle = new TH2F("hcandle"," ",10,-4,4,40,-20,20);
1507 float px, py;
1508 for (Int_t i = 0; i < 15000; i++) {
1509 gRandom->Rannor(px,py);
1510 hcandle->Fill(px,5*py);
1511 }
1512 hcandle->SetMarkerSize(0.5);
1513
1514 TH2F *h2;
1515 for (Int_t i=1; i<7; i++) {
1516 c1->cd(i);
1517 h2 = (TH2F*)hcandle->DrawClone(Form("CANDLE%d",i));
1518 h2->SetTitle(Form("CANDLE%d",i));
1519 }
1520}
1521End_Macro
1522
1523
1524#### Example 1
1525Box and improved whisker, no mean, no median, no anchor no outliers
1526
1527 h1->Draw("CANDLEX(2001)");
1528
1529#### Example 2
1530A Candle-definition like "CANDLEX2" (New standard candle with better whisker definition + outliers)
1531
1532 h1->Draw("CANDLEX(112111)");
1533
1534#### Example 3
1535The following example shows how several candle plots can be super-imposed using
1536the option SAME. Note that the bar-width and bar-offset are active on candle plots.
1537Also the color, the line width, the size of the points and so on can be changed by the
1538standard attribute setting methods such as SetLineColor() SetLineWidth().
1539
1540Begin_Macro(source)
1541../../../tutorials/hist/hist049_Graphics_candle_plot.C
1542End_Macro
1543
1544\anchor HP140b
1545#### The VIOLIN option
1546
1547<a href="http://en.wikipedia.org/wiki/Violin_plot">A violin plot</a> is a candle plot
1548that also encodes the pdf information at each point.
1549
1550
1551Quartiles and mean are also represented at each point, with a marker
1552and two lines.
1553
1554In this implementation a TH2 is considered as a collection of TH1 along
1555X (option `VIOLIN` or `VIOLINX`) or Y (option `VIOLINY`).
1556
1557#### What a violin is made of
1558
1559\since **ROOT version 6.09/02**
1560
1561##### The histogram
1562The histogram is typically drawn to both directions with respect to the middle-line of the
1563corresponding bin. This can be achieved by using h=3. It is possible to draw a histogram only to
1564one side (h=1, or h=2).
1565The maximum number of bins in the histogram is limited to 500, if the number of bins in the used
1566histogram is higher it will be rebinned automatically. The maximum height of the histogram can
1567be modified by using SetBarWidth() and the position can be changed with SetBarOffset().
1568A solid fill style is recommended.
1569
1570\since **ROOT version 6.11/01**
1571
1572Using the static function TCandle::SetScaledViolin(bool) the height of the histogram or the
1573violin can be influenced. Activated, the height of the bins of the individual violins will be
1574scaled with respect to each other, the maximum height can be influenced by SetBarWidth().
1575Deactivated, the height of the bin with the maximum content of each individual violin is
1576set to a constant value using SetBarWidth(). The static function will affect all violin-charts
1577in the running program. Default is true. Scaling between multiple violin-charts
1578(using "same" or THStack) is not supported, yet.
1579
1580##### The zero indicator line
1581Typical for violin charts is a line in the background over the whole histogram indicating
1582the bins with zero entries. The zero indicator line can be activated with z=1. The line color
1583will always be the same as the fill-color of the histogram.
1584
1585##### The Mean
1586The Mean is illustrated with the same mechanism as used for candle plots. Usually a circle is used.
1587
1588##### Whiskers
1589The whiskers are illustrated by the same mechanism as used for candle plots. There is only one
1590difference. When using the simple whisker definition (w=1) and the zero indicator line (z=1), then
1591the whiskers will be forced to be solid (usually hashed)
1592
1593##### Points
1594The points are illustrated by the same mechanism as used for candle plots. E.g. VIOLIN2 uses
1595better whisker definition (w=2) and outliers (p=1).
1596
1597##### Other options
1598It is possible to combine all options of candle or violin plots with each other. E.g. a violin plot
1599including a box-plot.
1600
1601#### How to use the violin-plots drawing option
1602
1603There are two predefined violin-plot representations:
1604 - "VIOLINX1": Standard violin (histogram, mean, whisker over full distribution,
1605 zero indicator line)
1606 - "VIOLINX2": Line VIOLINX1 both with better whisker definition + outliers.
1607
1608A solid fill style is recommended for this plot (as opposed to a hollow or
1609hashed style).
1610
1611Begin_Macro(source)
1612{
1613 auto c1 = new TCanvas("c1","c1",600,400);
1614 Int_t nx(6), ny(40);
1615 double xmin(0.0), xmax(+6.0), ymin(0.0), ymax(+4.0);
1616 auto hviolin = new TH2F("hviolin", "Option VIOLIN example", nx, xmin, xmax, ny, ymin, ymax);
1617 TF1 f1("f1", "gaus", +0,0 +4.0);
1618 double x,y;
1619 for (Int_t iBin=1; iBin<hviolin->GetNbinsX(); ++iBin) {
1620 double xc = hviolin->GetXaxis()->GetBinCenter(iBin);
1621 f1.SetParameters(1, 2.0+TMath::Sin(1.0+xc), 0.2+0.1*(xc-xmin)/xmax);
1622 for(Int_t i=0; i<10000; ++i){
1623 x = xc;
1624 y = f1.GetRandom();
1625 hviolin->Fill(x, y);
1626 }
1627 }
1628 hviolin->SetFillColor(kGray);
1629 hviolin->SetMarkerStyle(20);
1630 hviolin->SetMarkerSize(0.5);
1631 hviolin->Draw("VIOLIN");
1632 c1->Update();
1633}
1634End_Macro
1635
1636The next example illustrates a time development of a certain value:
1637
1638Begin_Macro(source)
1639../../../tutorials/hist/hist047_Graphics_candle_decay.C
1640End_Macro
1641
1642
1643\anchor HP15
1644### The TEXT and TEXTnn Option
1645
1646
1647For each bin the content is printed. The text attributes are:
1648
1649- text font = current TStyle font (`gStyle->SetTextFont()`).
1650- text size = 0.02*padheight*markersize (if `h` is the histogram drawn
1651 with the option `TEXT` the marker size can be changed with
1652 `h->SetMarkerSize(markersize)`).
1653- text color = marker color.
1654
1655By default the format `g` is used. This format can be redefined
1656by calling `gStyle->SetPaintTextFormat()`.
1657
1658It is also possible to use `TEXTnn` in order to draw the text with
1659the angle `nn` (`0 < nn <= 90`).
1660
1661For 2D histograms the text is plotted in the center of each non empty cells.
1662It is possible to plot empty cells by calling `gStyle->SetHistMinimumZero()`
1663or providing MIN0 draw option. For 1D histogram the text is plotted at a y
1664position equal to the bin content.
1665
1666For 2D histograms when the option "E" (errors) is combined with the option
1667text ("TEXTE"), the error for each bin is also printed.
1668
1669Begin_Macro(source)
1670{
1671 auto c01 = new TCanvas("c01","c01",700,400);
1672 c01->Divide(2,1);
1673 auto htext1 = new TH1F("htext1","Option TEXT on 1D histograms ",10,-4,4);
1674 auto htext2 = new TH2F("htext2","Option TEXT on 2D histograms ",10,-4,4,10,-20,20);
1675 float px, py;
1676 for (Int_t i = 0; i < 25000; i++) {
1677 gRandom->Rannor(px,py);
1678 htext1->Fill(px,0.1);
1679 htext2->Fill(px,5*py,0.1);
1680 }
1681 gStyle->SetPaintTextFormat("4.1f m");
1682 htext2->SetMarkerSize(1.8);
1683 c01->cd(1);
1684 htext2->Draw("TEXT45");
1685 c01->cd(2);
1686 htext1->Draw();
1687 htext1->Draw("HIST TEXT0 SAME");
1688}
1689End_Macro
1690
1691\since **ROOT version 6.07/07:**
1692
1693In case several histograms are drawn on top ot each other (using option `SAME`),
1694the text can be shifted using `SetBarOffset()`. It specifies an offset for the
1695text position in each cell, in percentage of the bin width.
1696
1697Begin_Macro(source)
1698{
1699 auto c03 = new TCanvas("c03","c03",700,400);
1700 gStyle->SetOptStat(0);
1701 auto htext3 = new TH2F("htext3","Several 2D histograms drawn with option TEXT",10,-4,4,10,-20,20);
1702 auto htext4 = new TH2F("htext4","htext4",10,-4,4,10,-20,20);
1703 auto htext5 = new TH2F("htext5","htext5",10,-4,4,10,-20,20);
1704 float px, py;
1705 for (Int_t i = 0; i < 25000; i++) {
1706 gRandom->Rannor(px,py);
1707 htext3->Fill(4*px,20*py,0.1);
1708 htext4->Fill(4*px,20*py,0.5);
1709 htext5->Fill(4*px,20*py,1.0);
1710 }
1711 htext4->SetMarkerSize(1.8);
1712 htext5->SetMarkerSize(1.8);
1713 htext5->SetMarkerColor(kRed);
1714 htext4->SetBarOffset(0.2);
1715 htext5->SetBarOffset(-0.2);
1716 htext3->Draw("COL");
1717 htext4->Draw("TEXT SAME");
1718 htext5->Draw("TEXT SAME");
1719}
1720End_Macro
1721
1722In the case of profile histograms it is possible to print the number
1723of entries instead of the bin content. It is enough to combine the
1724option "E" (for entries) with the option "TEXT".
1725
1726Begin_Macro(source)
1727{
1728 auto c02 = new TCanvas("c02","c02",700,400);
1729 c02->Divide(2,1);
1730 gStyle->SetPaintTextFormat("g");
1731
1732 auto profile = new TProfile("profile","profile",10,0,10);
1733 profile->SetMarkerSize(2.2);
1734 profile->Fill(0.5,1);
1735 profile->Fill(1.5,2);
1736 profile->Fill(2.5,3);
1737 profile->Fill(3.5,4);
1738 profile->Fill(4.5,5);
1739 profile->Fill(5.5,5);
1740 profile->Fill(6.5,4);
1741 profile->Fill(7.5,3);
1742 profile->Fill(8.5,2);
1743 profile->Fill(9.5,1);
1744 c02->cd(1); profile->Draw("HIST TEXT0");
1745 c02->cd(2); profile->Draw("HIST TEXT0E");
1746}
1747End_Macro
1748
1749\anchor HP16
1750### The CONTour options
1751
1752
1753The following contour options are supported:
1754
1755| Option | Description |
1756|----------|-----------------------------------------------------------------------------|
1757| "CONT" | Draw a contour plot (same as CONT0). |
1758| "CONT0" | Draw a contour plot using surface colors to distinguish contours. |
1759| "CONT1" | Draw a contour plot using the line colors to distinguish contours. |
1760| "CONT2" | Draw a contour plot using the line styles (1 to 5) to distinguish contours. |
1761| "CONT3" | Draw a contour plot using the same line style for all contours. |
1762| "CONT4" | Draw a contour plot using surface colors (`SURF` option at theta = 0). |
1763
1764
1765The following example shows a 2D histogram plotted with the option
1766`CONTZ`. The option `CONT` draws a contour plot using surface
1767colors to distinguish contours. Combined with the option `CONT` (or
1768`CONT0`), the option `Z` allows to display the color palette
1769defined by `gStyle->SetPalette()`.
1770
1771Begin_Macro(source)
1772{
1773 auto c1 = new TCanvas("c1","c1",600,400);
1774 auto hcontz = new TH2F("hcontz","Option CONTZ example ",40,-4,4,40,-20,20);
1775 float px, py;
1776 for (Int_t i = 0; i < 25000; i++) {
1777 gRandom->Rannor(px,py);
1778 hcontz->Fill(px-1,5*py);
1779 hcontz->Fill(2+0.5*px,2*py-10.,0.1);
1780 }
1781 hcontz->Draw("CONTZ");
1782}
1783End_Macro
1784
1785The following example shows a 2D histogram plotted with the option
1786`CONT1Z`. The option `CONT1` draws a contour plot using the
1787line colors to distinguish contours. Combined with the option `CONT1`,
1788the option `Z` allows to display the color palette defined by
1789`gStyle->SetPalette()`.
1790
1791Begin_Macro(source)
1792{
1793 auto c1 = new TCanvas("c1","c1",600,400);
1794 auto hcont1 = new TH2F("hcont1","Option CONT1Z example ",40,-4,4,40,-20,20);
1795 float px, py;
1796 for (Int_t i = 0; i < 25000; i++) {
1797 gRandom->Rannor(px,py);
1798 hcont1->Fill(px-1,5*py);
1799 hcont1->Fill(2+0.5*px,2*py-10.,0.1);
1800 }
1801 hcont1->Draw("CONT1Z");
1802}
1803End_Macro
1804
1805The following example shows a 2D histogram plotted with the option
1806`CONT2`. The option `CONT2` draws a contour plot using the
1807line styles (1 to 5) to distinguish contours.
1808
1809Begin_Macro(source)
1810{
1811 auto c1 = new TCanvas("c1","c1",600,400);
1812 auto hcont2 = new TH2F("hcont2","Option CONT2 example ",40,-4,4,40,-20,20);
1813 float px, py;
1814 for (Int_t i = 0; i < 25000; i++) {
1815 gRandom->Rannor(px,py);
1816 hcont2->Fill(px-1,5*py);
1817 hcont2->Fill(2+0.5*px,2*py-10.,0.1);
1818 }
1819 hcont2->Draw("CONT2");
1820}
1821End_Macro
1822
1823The following example shows a 2D histogram plotted with the option
1824`CONT3`. The option `CONT3` draws contour plot using the same line style for
1825all contours.
1826
1827Begin_Macro(source)
1828{
1829 auto c1 = new TCanvas("c1","c1",600,400);
1830 auto hcont3 = new TH2F("hcont3","Option CONT3 example ",40,-4,4,40,-20,20);
1831 float px, py;
1832 for (Int_t i = 0; i < 25000; i++) {
1833 gRandom->Rannor(px,py);
1834 hcont3->Fill(px-1,5*py);
1835 hcont3->Fill(2+0.5*px,2*py-10.,0.1);
1836 }
1837 hcont3->SetLineStyle(kDotted);
1838 hcont3->Draw("CONT3");
1839}
1840End_Macro
1841
1842The following example shows a 2D histogram plotted with the option
1843`CONT4`. The option `CONT4` draws a contour plot using surface
1844colors to distinguish contours (`SURF` option at theta = 0). Combined
1845with the option `CONT` (or `CONT0`), the option `Z`
1846allows to display the color palette defined by `gStyle->SetPalette()`.
1847
1848Begin_Macro(source)
1849{
1850 auto c1 = new TCanvas("c1","c1",600,400);
1851 auto hcont4 = new TH2F("hcont4","Option CONT4Z example ",40,-4,4,40,-20,20);
1852 float px, py;
1853 for (Int_t i = 0; i < 25000; i++) {
1854 gRandom->Rannor(px,py);
1855 hcont4->Fill(px-1,5*py);
1856 hcont4->Fill(2+0.5*px,2*py-10.,0.1);
1857 }
1858 hcont4->Draw("CONT4Z");
1859}
1860End_Macro
1861
1862The default number of contour levels is 20 equidistant levels and can be changed
1863with `TH1::SetContour()` or `TStyle::SetNumberContours()`.
1864
1865\anchor HP16a
1866#### The LIST option
1867
1868When option `LIST` is specified together with option
1869`CONT`, the points used to draw the contours are saved in
1870`TGraph` objects:
1871
1872 h->Draw("CONT LIST");
1873 gPad->Update();
1874
1875The contour are saved in `TGraph` objects once the pad is painted.
1876Therefore to use this functionality in a macro, `gPad->Update()`
1877should be performed after the histogram drawing. Once the list is
1878built, the contours are accessible in the following way:
1879
1880 TObjArray *contours = (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
1881 Int_t ncontours = contours->GetSize();
1882 TList *list = (TList*)contours->At(i);
1883
1884Where `i` is a contour number, and list contains a list of
1885`TGraph` objects.
1886For one given contour, more than one disjoint polyline may be generated.
1887The number of TGraphs per contour is given by:
1888
1889 list->GetSize();
1890
1891To access the first graph in the list one should do:
1892
1893 TGraph *gr1 = (TGraph*)list->First();
1894
1895
1896The following example (hist102_TH2_contour_list.C) shows how to use this functionality.
1897
1898Begin_Macro(source)
1899../../../tutorials/hist/hist102_TH2_contour_list.C
1900End_Macro
1901
1902\anchor HP16b
1903#### The AITOFF, MERCATOR, SINUSOIDAL and PARABOLIC options
1904
1905The following options select the `CONT4` option and are useful for
1906sky maps or exposure maps (earth.C).
1907
1908| Option | Description |
1909|--------------|---------------------------------------------------------------|
1910| "AITOFF" | Draw a contour via an AITOFF projection.|
1911| "MERCATOR" | Draw a contour via an Mercator projection.|
1912| "SINUSOIDAL" | Draw a contour via an Sinusoidal projection.|
1913| "PARABOLIC" | Draw a contour via an Parabolic projection.|
1914
1915Begin_Macro(source)
1916../../../tutorials/visualisation/graphics/earth.C
1917End_Macro
1918
1919
1920\anchor HP17
1921### The LEGO options
1922
1923
1924In a lego plot the cell contents are drawn as 3-d boxes. The height of each box
1925is proportional to the cell content. The lego aspect is control with the
1926following options:
1927
1928| Option | Description |
1929|----------|-------------------------------------------------------------------|
1930| "LEGO" | Draw a lego plot using the hidden lines removal technique.|
1931| "LEGO1" | Draw a lego plot using the hidden surface removal technique.|
1932| "LEGO2" | Draw a lego plot using colors to show the cell contents.|
1933| "LEGO3" | Draw a lego plot with hidden surface removal, like LEGO1 but the border lines of each lego-bar are not drawn.|
1934| "LEGO4" | Draw a lego plot with hidden surface removal, like LEGO1 but without the shadow effect on each lego-bar.|
1935| "0" | When used with any LEGO option, the empty bins are not drawn.|
1936
1937
1938See the limitations with [the option "SAME"](\ref HP060a).
1939
1940Line attributes can be used in lego plots to change the edges' style.
1941
1942The following example shows a 2D histogram plotted with the option
1943`LEGO`. The option `LEGO` draws a lego plot using the hidden
1944lines removal technique.
1945
1946Begin_Macro(source)
1947{
1948 auto c2 = new TCanvas("c2","c2",600,400);
1949 auto hlego = new TH2F("hlego","Option LEGO example ",40,-4,4,40,-20,20);
1950 float px, py;
1951 for (Int_t i = 0; i < 25000; i++) {
1952 gRandom->Rannor(px,py);
1953 hlego->Fill(px-1,5*py);
1954 hlego->Fill(2+0.5*px,2*py-10.,0.1);
1955 }
1956 hlego->Draw("LEGO");
1957}
1958End_Macro
1959
1960The following example shows a 2D histogram plotted with the option
1961`LEGO1`. The option `LEGO1` draws a lego plot using the
1962hidden surface removal technique. Combined with any `LEGOn` option, the
1963option `0` allows to not drawn the empty bins.
1964
1965Begin_Macro(source)
1966{
1967 auto c2 = new TCanvas("c2","c2",600,400);
1968 auto hlego1 = new TH2F("hlego1","Option LEGO1 example (with option 0) ",40,-4,4,40,-20,20);
1969 float px, py;
1970 for (Int_t i = 0; i < 25000; i++) {
1971 gRandom->Rannor(px,py);
1972 hlego1->Fill(px-1,5*py);
1973 hlego1->Fill(2+0.5*px,2*py-10.,0.1);
1974 }
1975 hlego1->SetFillColor(kYellow);
1976 hlego1->Draw("LEGO1 0");
1977}
1978End_Macro
1979
1980The following example shows a 2D histogram plotted with the option
1981`LEGO3`. Like the option `LEGO1`, the option `LEGO3`
1982draws a lego plot using the hidden surface removal technique but doesn't draw
1983the border lines of each individual lego-bar. This is very useful for histograms
1984having many bins. With such histograms the option `LEGO1` gives a black
1985image because of the border lines. This option also works with stacked legos.
1986
1987Begin_Macro(source)
1988{
1989 auto c2 = new TCanvas("c2","c2",600,400);
1990 auto hlego3 = new TH2F("hlego3","Option LEGO3 example",40,-4,4,40,-20,20);
1991 float px, py;
1992 for (Int_t i = 0; i < 25000; i++) {
1993 gRandom->Rannor(px,py);
1994 hlego3->Fill(px-1,5*py);
1995 hlego3->Fill(2+0.5*px,2*py-10.,0.1);
1996 }
1997 hlego3->SetFillColor(kRed);
1998 hlego3->Draw("LEGO3");
1999}
2000End_Macro
2001
2002The following example shows a 2D histogram plotted with the option
2003`LEGO2`. The option `LEGO2` draws a lego plot using colors to
2004show the cell contents. Combined with the option `LEGO2`, the option
2005`Z` allows to display the color palette defined by
2006`gStyle->SetPalette()`.
2007
2008Begin_Macro(source)
2009{
2010 auto c2 = new TCanvas("c2","c2",600,400);
2011 auto hlego2 = new TH2F("hlego2","Option LEGO2Z example ",40,-4,4,40,-20,20);
2012 float px, py;
2013 for (Int_t i = 0; i < 25000; i++) {
2014 gRandom->Rannor(px,py);
2015 hlego2->Fill(px-1,5*py);
2016 hlego2->Fill(2+0.5*px,2*py-10.,0.1);
2017 }
2018 hlego2->Draw("LEGO2Z");
2019}
2020End_Macro
2021
2022
2023
2024\anchor HP18
2025### The "SURFace" options
2026
2027
2028In a surface plot, cell contents are represented as a mesh.
2029The height of the mesh is proportional to the cell content.
2030
2031| Option | Description |
2032|----------|-------------------------------------------------------------------|
2033| "SURF" | Draw a surface plot using the hidden line removal technique.|
2034| "SURF1" | Draw a surface plot using the hidden surface removal technique.|
2035| "SURF2" | Draw a surface plot using colors to show the cell contents.|
2036| "SURF3" | Same as `SURF` with an additional filled contour plot on top.|
2037| "SURF4" | Draw a surface using the Gouraud shading technique.|
2038| "SURF5" | Used with one of the options CYL, PSR and CYL this option allows to draw a filled contour plot.|
2039| "SURF6" | This option should not be used directly. It is used internally when the CONT is used with option the option SAME on a 3D plot.|
2040| "SURF7" | Same as `SURF2` with an additional line contour plot on top.|
2041
2042
2043
2044See the limitations with [the option "SAME"](\ref HP060a).
2045
2046The following example shows a 2D histogram plotted with the option
2047`SURF`. The option `SURF` draws a lego plot using the hidden
2048lines removal technique.
2049
2050Begin_Macro(source)
2051{
2052 auto c2 = new TCanvas("c2","c2",600,400);
2053 auto hsurf = new TH2F("hsurf","Option SURF example ",30,-4,4,30,-20,20);
2054 float px, py;
2055 for (Int_t i = 0; i < 25000; i++) {
2056 gRandom->Rannor(px,py);
2057 hsurf->Fill(px-1,5*py);
2058 hsurf->Fill(2+0.5*px,2*py-10.,0.1);
2059 }
2060 hsurf->Draw("SURF");
2061}
2062End_Macro
2063
2064The following example shows a 2D histogram plotted with the option
2065`SURF1`. The option `SURF1` draws a surface plot using the
2066hidden surface removal technique. Combined with the option `SURF1`,
2067the option `Z` allows to display the color palette defined by
2068`gStyle->SetPalette()`.
2069
2070Begin_Macro(source)
2071{
2072 auto c2 = new TCanvas("c2","c2",600,400);
2073 auto hsurf1 = new TH2F("hsurf1","Option SURF1 example ",30,-4,4,30,-20,20);
2074 float px, py;
2075 for (Int_t i = 0; i < 25000; i++) {
2076 gRandom->Rannor(px,py);
2077 hsurf1->Fill(px-1,5*py);
2078 hsurf1->Fill(2+0.5*px,2*py-10.,0.1);
2079 }
2080 hsurf1->Draw("SURF1");
2081}
2082End_Macro
2083
2084The following example shows a 2D histogram plotted with the option
2085`SURF2`. The option `SURF2` draws a surface plot using colors
2086to show the cell contents. Combined with the option `SURF2`, the option
2087`Z` allows to display the color palette defined by
2088`gStyle->SetPalette()`.
2089
2090Begin_Macro(source)
2091{
2092 auto c2 = new TCanvas("c2","c2",600,400);
2093 auto hsurf2 = new TH2F("hsurf2","Option SURF2 example ",30,-4,4,30,-20,20);
2094 float px, py;
2095 for (Int_t i = 0; i < 25000; i++) {
2096 gRandom->Rannor(px,py);
2097 hsurf2->Fill(px-1,5*py);
2098 hsurf2->Fill(2+0.5*px,2*py-10.,0.1);
2099 }
2100 hsurf2->Draw("SURF2");
2101}
2102End_Macro
2103
2104The following example shows a 2D histogram plotted with the option
2105`SURF3`. The option `SURF3` draws a surface plot using the
2106hidden line removal technique with, in addition, a filled contour view drawn on the
2107top. Combined with the option `SURF3`, the option `Z` allows
2108to display the color palette defined by `gStyle->SetPalette()`.
2109
2110Begin_Macro(source)
2111{
2112 auto c2 = new TCanvas("c2","c2",600,400);
2113 auto hsurf3 = new TH2F("hsurf3","Option SURF3 example ",30,-4,4,30,-20,20);
2114 float px, py;
2115 for (Int_t i = 0; i < 25000; i++) {
2116 gRandom->Rannor(px,py);
2117 hsurf3->Fill(px-1,5*py);
2118 hsurf3->Fill(2+0.5*px,2*py-10.,0.1);
2119 }
2120 hsurf3->Draw("SURF3");
2121}
2122End_Macro
2123
2124The following example shows a 2D histogram plotted with the option
2125`SURF4`. The option `SURF4` draws a surface using the Gouraud
2126shading technique.
2127
2128Begin_Macro(source)
2129{
2130 auto c2 = new TCanvas("c2","c2",600,400);
2131 auto hsurf4 = new TH2F("hsurf4","Option SURF4 example ",30,-4,4,30,-20,20);
2132 float px, py;
2133 for (Int_t i = 0; i < 25000; i++) {
2134 gRandom->Rannor(px,py);
2135 hsurf4->Fill(px-1,5*py);
2136 hsurf4->Fill(2+0.5*px,2*py-10.,0.1);
2137 }
2138 hsurf4->SetFillColor(kOrange);
2139 hsurf4->Draw("SURF4");
2140}
2141End_Macro
2142
2143The following example shows a 2D histogram plotted with the option
2144`SURF5 CYL`. Combined with the option `SURF5`, the option
2145`Z` allows to display the color palette defined by `gStyle->SetPalette()`.
2146
2147Begin_Macro(source)
2148{
2149 auto c2 = new TCanvas("c2","c2",600,400);
2150 auto hsurf5 = new TH2F("hsurf4","Option SURF5 example ",30,-4,4,30,-20,20);
2151 float px, py;
2152 for (Int_t i = 0; i < 25000; i++) {
2153 gRandom->Rannor(px,py);
2154 hsurf5->Fill(px-1,5*py);
2155 hsurf5->Fill(2+0.5*px,2*py-10.,0.1);
2156 }
2157 hsurf5->Draw("SURF5 CYL");
2158}
2159End_Macro
2160
2161The following example shows a 2D histogram plotted with the option
2162`SURF7`. The option `SURF7` draws a surface plot using the
2163hidden surfaces removal technique with, in addition, a line contour view drawn on the
2164top. Combined with the option `SURF7`, the option `Z` allows
2165to display the color palette defined by `gStyle->SetPalette()`.
2166
2167Begin_Macro(source)
2168{
2169 auto c2 = new TCanvas("c2","c2",600,400);
2170 auto hsurf7 = new TH2F("hsurf3","Option SURF7 example ",30,-4,4,30,-20,20);
2171 float px, py;
2172 for (Int_t i = 0; i < 25000; i++) {
2173 gRandom->Rannor(px,py);
2174 hsurf7->Fill(px-1,5*py);
2175 hsurf7->Fill(2+0.5*px,2*py-10.,0.1);
2176 }
2177 hsurf7->Draw("SURF7");
2178}
2179End_Macro
2180
2181As shown in the following example, when a contour plot is painted on top of a
2182surface plot using the option `SAME`, the contours appear in 3D on the
2183surface.
2184
2185Begin_Macro(source)
2186{
2187 auto c20=new TCanvas("c20","c20",600,400);
2188 int NBins = 50;
2189 double d = 2;
2190 auto hsc = new TH2F("hsc", "Surface and contour with option SAME ", NBins, -d, d, NBins, -d, d);
2191 for (int bx = 1; bx <= NBins; ++bx) {
2192 for (int by = 1; by <= NBins; ++by) {
2193 double x = hsc->GetXaxis()->GetBinCenter(bx);
2194 double y = hsc->GetYaxis()->GetBinCenter(by);
2195 hsc->SetBinContent(bx, by, exp(-x*x)*exp(-y*y));
2196 }
2197 }
2198 hsc->Draw("surf2");
2199 hsc->Draw("CONT1 SAME");
2200}
2201End_Macro
2202
2203
2204\anchor HP19
2205### Cylindrical, Polar, Spherical and PseudoRapidity/Phi options
2206
2207
2208Legos and surfaces plots are represented by default in Cartesian coordinates.
2209Combined with any `LEGOn` or `SURFn` options the following
2210options allow to draw a lego or a surface in other coordinates systems.
2211
2212| Option | Description |
2213|----------|-------------------------------------------------------------------|
2214| "CYL" | Use Cylindrical coordinates. The X coordinate is mapped on the angle and the Y coordinate on the cylinder length.|
2215| "POL" | Use Polar coordinates. The X coordinate is mapped on the angle and the Y coordinate on the radius.|
2216| "SPH" | Use Spherical coordinates. The X coordinate is mapped on the latitude and the Y coordinate on the longitude.|
2217| "PSR" | Use PseudoRapidity/Phi coordinates. The X coordinate is mapped on Phi.|
2218
2219
2220
2221<b>WARNING:</b> Axis are not drawn with these options.
2222
2223The following example shows the same histogram as a lego plot is the four
2224different coordinates systems.
2225
2226Begin_Macro(source)
2227{
2228 auto c3 = new TCanvas("c3","c3",600,400);
2229 c3->Divide(2,2);
2230 auto hlcc = new TH2F("hlcc","Cylindrical coordinates",20,-4,4,20,-20,20);
2231 float px, py;
2232 for (Int_t i = 0; i < 25000; i++) {
2233 gRandom->Rannor(px,py);
2234 hlcc->Fill(px-1,5*py);
2235 hlcc->Fill(2+0.5*px,2*py-10.,0.1);
2236 }
2237 hlcc->SetFillColor(kYellow);
2238 c3->cd(1); hlcc->Draw("LEGO1 CYL");
2239 c3->cd(2); auto hlpc = (TH2F*) hlcc->DrawClone("LEGO1 POL");
2240 hlpc->SetTitle("Polar coordinates");
2241 c3->cd(3); auto hlsc = (TH2F*) hlcc->DrawClone("LEGO1 SPH");
2242 hlsc->SetTitle("Spherical coordinates");
2243 c3->cd(4); auto hlprpc = (TH2F*) hlcc->DrawClone("LEGO1 PSR");
2244 hlprpc->SetTitle("PseudoRapidity/Phi coordinates");
2245}
2246End_Macro
2247
2248The following example shows the same histogram as a surface plot is the four different coordinates systems.
2249
2250Begin_Macro(source)
2251{
2252 auto c4 = new TCanvas("c4","c4",600,400);
2253 c4->Divide(2,2);
2254 auto hscc = new TH2F("hscc","Cylindrical coordinates",20,-4,4,20,-20,20);
2255 float px, py;
2256 for (Int_t i = 0; i < 25000; i++) {
2257 gRandom->Rannor(px,py);
2258 hscc->Fill(px-1,5*py);
2259 hscc->Fill(2+0.5*px,2*py-10.,0.1);
2260 }
2261 c4->cd(1); hscc->Draw("SURF1 CYL");
2262 c4->cd(2); auto hspc = (TH2F*) hscc->DrawClone("SURF1 POL");
2263 hspc->SetTitle("Polar coordinates");
2264 c4->cd(3); auto hssc = (TH2F*) hscc->DrawClone("SURF1 SPH");
2265 hssc->SetTitle("Spherical coordinates");
2266 c4->cd(4); auto hsprpc = (TH2F*) hscc->DrawClone("SURF1 PSR");
2267 hsprpc->SetTitle("PseudoRapidity/Phi coordinates");
2268}
2269End_Macro
2270
2271
2272\anchor HP20
2273### Base line for bar-charts and lego plots
2274
2275
2276By default the base line used to draw the boxes for bar-charts and lego plots is
2277the histogram minimum. It is possible to force this base line to be 0, using MIN0 draw
2278option or with the command:
2279
2280 gStyle->SetHistMinimumZero();
2281
2282Begin_Macro(source)
2283{
2284 auto c5 = new TCanvas("c5","c5",700,400);
2285 c5->Divide(2,1);
2286 auto hz1 = new TH1F("hz1","Bar-chart drawn from 0",20,-3,3);
2287 auto hz2 = new TH2F("hz2","Lego plot drawn from 0",20,-3,3,20,-3,3);
2288 Int_t i;
2289 double x,y;
2290 hz1->SetFillColor(kBlue);
2291 hz2->SetFillColor(kBlue);
2292 for (i=0;i<10000;i++) {
2293 x = gRandom->Gaus(0,1);
2294 y = gRandom->Gaus(0,1);
2295 if (x>0) {
2296 hz1->Fill(x,1);
2297 hz2->Fill(x,y,1);
2298 } else {
2299 hz1->Fill(x,-1);
2300 hz2->Fill(x,y,-2);
2301 }
2302 }
2303 c5->cd(1); hz1->Draw("bar2 min0");
2304 c5->cd(2); hz2->Draw("lego1 min0");
2305}
2306End_Macro
2307
2308This option also works for horizontal plots. The example given in the section
2309["The bar chart option"](\ref HP100) appears as follow:
2310
2311Begin_Macro(source)
2312{
2313 int i;
2314 const Int_t nx = 8;
2315 string os_X[nx] = {"8","32","128","512","2048","8192","32768","131072"};
2316 float d_35_0[nx] = {0.75, -3.30, -0.92, 0.10, 0.08, -1.69, -1.29, -2.37};
2317 float d_35_1[nx] = {1.01, -3.02, -0.65, 0.37, 0.34, -1.42, -1.02, -2.10};
2318
2319 auto cbh = new TCanvas("cbh","cbh",400,600);
2320 cbh->SetGrid();
2321
2322 auto h1bh = new TH1F("h1bh","Option HBAR centered on 0",nx,0,nx);
2323 h1bh->SetFillColor(4);
2324 h1bh->SetBarWidth(0.4);
2325 h1bh->SetBarOffset(0.1);
2326 h1bh->SetStats(0);
2327 h1bh->SetMinimum(-5);
2328 h1bh->SetMaximum(5);
2329
2330 for (i=1; i<=nx; i++) {
2331 h1bh->Fill(os_X[i-1].c_str(), d_35_0[i-1]);
2332 h1bh->GetXaxis()->SetBinLabel(i,os_X[i-1].c_str());
2333 }
2334
2335 h1bh->Draw("hbar min0");
2336
2337 auto h2bh = new TH1F("h2bh","h2bh",nx,0,nx);
2338 h2bh->SetFillColor(38);
2339 h2bh->SetBarWidth(0.4);
2340 h2bh->SetBarOffset(0.5);
2341 h2bh->SetStats(0);
2342 for (i=1;i<=nx;i++) h2bh->Fill(os_X[i-1].c_str(), d_35_1[i-1]);
2343
2344 h2bh->Draw("hbar min0 same");
2345}
2346End_Macro
2347
2348
2349\anchor HP20a
2350### TH2Poly Drawing
2351
2352
2353The following options are supported:
2354
2355| Option | Description |
2356|----------|-------------------------------------------------------------------|
2357| "SCAT" | Draw a scatter plot (legacy draw option).|
2358| "COL" | Draw a color plot. All the bins are painted even the empty bins (default).|
2359| "COLZ" | Same as "COL". In addition the color palette is also drawn.|
2360| "0" | When used with any COL options, the empty bins are not drawn.|
2361| "TEXT" | Draw bin contents as text (format set via `gStyle->SetPaintTextFormat`).|
2362| "TEXTN" | Draw bin names as text.|
2363| "TEXTnn" | Draw bin contents as text at angle nn (0 < nn <= 90).|
2364| "L" | Draw the bins boundaries as lines. The lines attributes are the TGraphs ones.|
2365| "P" | Draw the bins boundaries as markers. The markers attributes are the TGraphs ones.|
2366| "F" | Draw the bins boundaries as filled polygons. The filled polygons attributes are the TGraphs ones.|
2367
2368
2369
2370`TH2Poly` can be drawn as a color plot (option COL). `TH2Poly` bins can have any
2371shapes. The bins are defined as graphs. The following macro is a very simple
2372example showing how to book a TH2Poly and draw it.
2373
2374Begin_Macro(source)
2375{
2376 auto ch2p1 = new TCanvas("ch2p1","ch2p1",600,400);
2377 auto h2p = new TH2Poly();
2378 h2p->SetName("h2poly_name");
2379 h2p->SetTitle("h2poly_title");
2380 double px1[] = {0, 5, 6};
2381 double py1[] = {0, 0, 5};
2382 double px2[] = {0, -1, -1, 0};
2383 double py2[] = {0, 0, -1, 3};
2384 double px3[] = {4, 3, 0, 1, 2.4};
2385 double py3[] = {4, 3.7, 1, 3.7, 2.5};
2386 h2p->AddBin(3, px1, py1);
2387 h2p->AddBin(4, px2, py2);
2388 h2p->AddBin(5, px3, py3);
2389 h2p->Fill(0.1, 0.01, 3);
2390 h2p->Fill(-0.5, -0.5, 7);
2391 h2p->Fill(-0.7, -0.5, 1);
2392 h2p->Fill(1, 3, 1.5);
2393 double fx[] = {0.1, -0.5, -0.7, 1};
2394 double fy[] = {0.01, -0.5, -0.5, 3};
2395 double fw[] = {3, 1, 1, 1.5};
2396 h2p->FillN(4, fx, fy, fw);
2397 h2p->Draw("col");
2398}
2399End_Macro
2400
2401Rectangular bins are a frequent case. The special version of
2402the `AddBin` method allows to define them more easily like
2403shown in the following example (hist037_TH2Poly_boxes.C).
2404
2405Begin_Macro(source)
2406../../../tutorials/hist/hist037_TH2Poly_boxes.C
2407End_Macro
2408
2409One `TH2Poly` bin can be a list of polygons. Such bins are defined
2410by calling `AddBin` with a `TMultiGraph`. The following example
2411shows a such case:
2412
2413Begin_Macro(source)
2414{
2415 auto ch2p2 = new TCanvas("ch2p2","ch2p2",600,400);
2416
2417 Int_t i, bin;
2418 const Int_t nx = 48;
2419 const char *states [nx] = {
2420 "alabama", "arizona", "arkansas", "california",
2421 "colorado", "connecticut", "delaware", "florida",
2422 "georgia", "idaho", "illinois", "indiana",
2423 "iowa", "kansas", "kentucky", "louisiana",
2424 "maine", "maryland", "massachusetts", "michigan",
2425 "minnesota", "mississippi", "missouri", "montana",
2426 "nebraska", "nevada", "new_hampshire", "new_jersey",
2427 "new_mexico", "new_york", "north_carolina", "north_dakota",
2428 "ohio", "oklahoma", "oregon", "pennsylvania",
2429 "rhode_island", "south_carolina", "south_dakota", "tennessee",
2430 "texas", "utah", "vermont", "virginia",
2431 "washington", "west_virginia", "wisconsin", "wyoming"
2432 };
2433 Double_t pop[nx] = {
2434 4708708, 6595778, 2889450, 36961664, 5024748, 3518288, 885122, 18537969,
2435 9829211, 1545801, 12910409, 6423113, 3007856, 2818747, 4314113, 4492076,
2436 1318301, 5699478, 6593587, 9969727, 5266214, 2951996, 5987580, 974989,
2437 1796619, 2643085, 1324575, 8707739, 2009671, 19541453, 9380884, 646844,
2438 11542645, 3687050, 3825657, 12604767, 1053209, 4561242, 812383, 6296254,
2439 24782302, 2784572, 621760, 7882590, 6664195, 1819777, 5654774, 544270
2440 };
2441
2442 Double_t lon1 = -130;
2443 Double_t lon2 = -65;
2444 Double_t lat1 = 24;
2445 Double_t lat2 = 50;
2446 auto p = new TH2Poly("USA","USA Population",lon1,lon2,lat1,lat2);
2447
2448 TFile::SetCacheFileDir(".");
2449 auto f = TFile::Open("http://root.cern/files/usa.root", "CACHEREAD");
2450
2451 TMultiGraph *mg;
2452 TKey *key;
2453 TIter nextkey(gDirectory->GetListOfKeys());
2454 while ((key = (TKey*)nextkey())) {
2455 TObject *obj = key->ReadObj();
2456 if (obj->InheritsFrom("TMultiGraph")) {
2457 mg = (TMultiGraph*)obj;
2458 bin = p->AddBin(mg);
2459 }
2460 }
2461
2462 for (i=0; i<nx; i++) p->Fill(states[i], pop[i]);
2463
2464 gStyle->SetOptStat(11);
2465 p->Draw("COLZ L");
2466}
2467End_Macro
2468
2469`TH2Poly` histograms can also be plotted using the GL interface using
2470the option "GLLEGO".
2471
2472\since **ROOT version 6.09/01**
2473
2474In some cases it can be useful to not draw the empty bins. the option "0"
2475combined with the option "COL" and "COLZ" allows to do that.
2476
2477Begin_Macro(source)
2478{
2479 auto chc = new TCanvas("chc","chc",600,400);
2480
2481 auto hc = new TH2Poly();
2482 hc->Honeycomb(0,0,.1,25,25);
2483 hc->SetName("hc");
2484 hc->SetTitle("Option COLZ 0");
2485 TRandom ran;
2486 for (int i = 0; i<300; i++) hc->Fill(ran.Gaus(2.,1), ran.Gaus(2.,1));
2487 hc->Draw("colz 0");
2488}
2489End_Macro
2490
2491\anchor HP21
2492### The SPEC option
2493
2494
2495This option allows to use the `TSpectrum2Painter` tools. See the full
2496documentation in `TSpectrum2Painter::PaintSpectrum`.
2497
2498
2499\anchor HP22
2500### Option "Z" : Adding the color palette on the right side of the pad
2501
2502
2503When this option is specified, a color palette with an axis indicating the value
2504of the corresponding color is drawn on the right side of the picture. In case,
2505not enough space is left, one can increase the size of the right margin by
2506calling `TPad::SetRightMargin()`. The attributes used to display the
2507palette axis values are taken from the Z axis of the object. For example, to
2508set the labels size on the palette axis do:
2509
2510 hist->GetZaxis()->SetLabelSize().
2511
2512<b>WARNING:</b> The palette axis is always drawn vertically.
2513
2514
2515\anchor HP23
2516### Setting the color palette
2517
2518
2519To change the color palette `TStyle::SetPalette` should be used, eg:
2520
2521 gStyle->SetPalette(ncolors,colors);
2522
2523For example the option `COL` draws a 2D histogram with cells
2524represented by a box filled with a color index which is a function
2525of the cell content.
2526If the cell content is N, the color index used will be the color number
2527in `colors[N]`, etc. If the maximum cell content is greater than
2528`ncolors`, all cell contents are scaled to `ncolors`.
2529
2530If ` ncolors <= 0`, a default palette (see below) of 50 colors is
2531defined. This palette is recommended for pads, labels ...
2532
2533`if ncolors == 1 && colors == 0`, then a Pretty Palette with a
2534Spectrum Violet->Red is created with 50 colors. That's the default rain bow
2535palette.
2536
2537Other pre-defined palettes with 255 colors are available when `colors == 0`.
2538The following value of `ncolors` give access to:
2539
2540
2541 if ncolors = 51 and colors=0, a Deep Sea palette is used.
2542 if ncolors = 52 and colors=0, a Grey Scale palette is used.
2543 if ncolors = 53 and colors=0, a Dark Body Radiator palette is used.
2544 if ncolors = 54 and colors=0, a two-color hue palette palette is used.(dark blue through neutral gray to bright
2545yellow) if ncolors = 55 and colors=0, a Rain Bow palette is used. if ncolors = 56 and colors=0, an inverted Dark Body
2546Radiator palette is used.
2547
2548
2549If `ncolors > 0 && colors == 0`, the default palette is used with a maximum of ncolors.
2550
2551The default palette defines:
2552
2553- index 0 to 9 : shades of grey
2554- index 10 to 19 : shades of brown
2555- index 20 to 29 : shades of blue
2556- index 30 to 39 : shades of red
2557- index 40 to 49 : basic colors
2558
2559The color numbers specified in the palette can be viewed by selecting
2560the item `colors` in the `VIEW` menu of the canvas tool bar.
2561The red, green, and blue components of a color can be changed thanks to
2562`TColor::SetRGB()`.
2563
2564\since **ROOT version 6.19/01**
2565
2566As default labels and ticks are drawn by `TGAxis` at equidistant (lin or log)
2567points as controlled by SetNdivisions.
2568If option "CJUST" is given labels and ticks are justified at the
2569color boundaries defined by the contour levels.
2570For more details see `TPaletteAxis`
2571
2572\anchor HP24
2573### Drawing a sub-range of a 2D histogram; the [cutg] option
2574
2575
2576Using a `TCutG` object, it is possible to draw a sub-range of a 2D
2577histogram. One must create a graphical cut (mouse or C++) and specify the name
2578of the cut between `[]` in the `Draw()` option.
2579For example (fit2a.C), with a `TCutG` named `cutg`, one can call:
2580
2581 myhist->Draw("surf1 [cutg]");
2582
2583To invert the cut, it is enough to put a `-` in front of its name:
2584
2585 myhist->Draw("surf1 [-cutg]");
2586
2587It is possible to apply several cuts (`,` means logical AND):
2588
2589 myhist->Draw("surf1 [cutg1,cutg2]");
2590
2591Begin_Macro(source)
2592../../../tutorials/fit/fit2a.C
2593End_Macro
2594
2595\anchor HP25
2596### Drawing options for 3D histograms
2597
2598
2599| Option | Description |
2600|----------|-------------------------------------------------------------------|
2601| "SCAT" | Draw a scatter plot (legacy draw option).|
2602| "ISO" | Draw a Gouraud shaded 3d iso surface through a 3d histogram. It paints one surface at the value computed as follow: `SumOfWeights/(NbinsX*NbinsY*NbinsZ)`|
2603| "BOX" | Draw a for each cell with volume proportional to the content's absolute value. An hidden line removal algorithm is used|
2604| "BOX1" | Same as BOX but an hidden surface removal algorithm is used|
2605| "BOX2" | Same as "COL". The boxes' colors are picked in the current palette according to the bins' contents (default)|
2606| "BOX2Z" | Same as "BOX2". In addition the color palette is also drawn.|
2607| "BOX3" | Same as BOX1, but the border lines of each lego-bar are not drawn.|
2608
2609Note that instead of `BOX` one can also use `LEGO`.
2610
2611By default, 3D histograms are drawn as a colored box plots.
2612
2613The following example shows a 3D histogram plotted as a scatter plot.
2614
2615Begin_Macro(source)
2616{
2617 auto c06 = new TCanvas("c06","c06",600,400);
2618 gStyle->SetOptStat(kFALSE);
2619 auto h3scat = new TH3F("h3scat","Option SCAT",15,-2,2,15,-2,2,15,0,4);
2620 double x, y, z;
2621 for (Int_t i=0;i<10000;i++) {
2622 gRandom->Rannor(x, y);
2623 z = x*x + y*y;
2624 h3scat->Fill(x,y,z);
2625 }
2626 h3scat->Draw("SCAT"); // This a legacy draw option
2627}
2628End_Macro
2629
2630The following example shows a 3D histogram plotted with the option `BOX`.
2631
2632Begin_Macro(source)
2633{
2634 auto c16 = new TCanvas("c16","c16",600,400);
2635 gStyle->SetOptStat(kFALSE);
2636 auto h3box = new TH3F("h3box","Option BOX",15,-2,2,15,-2,2,15,0,4);
2637 double x, y, z;
2638 for (Int_t i=0;i<10000;i++) {
2639 gRandom->Rannor(x, y);
2640 z = x*x + y*y;
2641 h3box->Fill(x,y,z);
2642 }
2643 h3box->Draw("BOX");
2644}
2645End_Macro
2646
2647The following example shows a 3D histogram plotted with the option `BOX1`.
2648
2649Begin_Macro(source)
2650{
2651 auto c36 = new TCanvas("c36","c36",600,400);
2652 gStyle->SetOptStat(kFALSE);
2653 auto h3box = new TH3F("h3box","Option BOX1",10,-2.,2.,10,-2.,2.,10,-0.5,2.);
2654 double x, y, z;
2655 for (Int_t i=0;i<10000;i++) {
2656 gRandom->Rannor(x, y);
2657 z = abs(sin(x)/x + cos(y)*y);
2658 h3box->Fill(x,y,z);
2659 }
2660 h3box->SetFillColor(9);
2661 h3box->Draw("BOX1");
2662}
2663End_Macro
2664
2665The following example shows a 3D histogram plotted with the option `BOX2`.
2666
2667Begin_Macro(source)
2668{
2669 auto c56 = new TCanvas("c56","c56",600,400);
2670 gStyle->SetOptStat(kFALSE);
2671 auto h3box = new TH3F("h3box","Option BOX2 (default)",10,-2.,2.,10,-2.,2.,10,-0.5,2.);
2672 double x, y, z;
2673 for (Int_t i=0;i<10000;i++) {
2674 gRandom->Rannor(x, y);
2675 z = abs(sin(x)/x + cos(y)*y);
2676 h3box->Fill(x,y,z);
2677 }
2678 h3box->Draw("BOX2 Z");
2679}
2680End_Macro
2681
2682The following example shows a 3D histogram plotted with the option `BOX3`.
2683
2684Begin_Macro(source)
2685{
2686 auto c46 = new TCanvas("c46","c46",600,400);
2687 c46->SetFillColor(38);
2688 gStyle->SetOptStat(kFALSE);
2689 auto h3box = new TH3F("h3box","Option BOX3",15,-2,2,15,-2,2,15,0,4);
2690 double x, y, z;
2691 for (Int_t i=0;i<10000;i++) {
2692 gRandom->Rannor(x, y);
2693 z = x*x + y*y;
2694 h3box->Fill(x,y,z);
2695 }
2696 h3box->Draw("BOX3");
2697}
2698End_Macro
2699
2700For all the `BOX` options each bin is drawn as a 3D box with a volume proportional
2701to the absolute value of the bin content. The bins with a negative content are
2702drawn with a X on each face of the box as shown in the following example:
2703
2704Begin_Macro(source)
2705{
2706 auto c = new TCanvas("c","c",600,400);
2707 gStyle->SetOptStat(kFALSE);
2708 auto h3box = new TH3F("h3box","Option BOX1 with negative bins",3, 0., 4., 3, 0.,4., 3, 0., 4.);
2709 h3box->Fill(0., 2., 2., 10.);
2710 h3box->Fill(2., 2., 2., 5.);
2711 h3box->Fill(2., 2., .5, 2.);
2712 h3box->Fill(2., 2., 3., -1.);
2713 h3box->Fill(3., 2., 2., -10.);
2714 h3box->SetFillColor(8);
2715 h3box->Draw("box1");
2716}
2717End_Macro
2718
2719The following example shows a 3D histogram plotted with the option `ISO`.
2720
2721Begin_Macro(source)
2722{
2723 auto c26 = new TCanvas("c26","c26",600,400);
2724 gStyle->SetOptStat(kFALSE);
2725 auto h3iso = new TH3F("h3iso","Option ISO",15,-2,2,15,-2,2,15,0,4);
2726 double x, y, z;
2727 for (Int_t i=0;i<10000;i++) {
2728 gRandom->Rannor(x, y);
2729 z = x*x + y*y;
2730 h3iso->Fill(x,y,z);
2731 }
2732 h3iso->SetFillColor(kCyan);
2733 h3iso->Draw("ISO");
2734}
2735End_Macro
2736
2737
2738\anchor HP26
2739### Drawing option for histograms' stacks
2740
2741
2742Stacks of histograms are managed with the `THStack`. A `THStack`
2743is a collection of `TH1` (or derived) objects. For painting only the
2744`THStack` containing `TH1` only or
2745`THStack` containing `TH2` only will be considered.
2746
2747By default, histograms are shown stacked:
2748
27491. The first histogram is paint.
27502. The sum of the first and second, etc...
2751
2752If the option `NOSTACK` is specified, the histograms are all paint in
2753the same pad as if the option `SAME` had been specified. This allows to
2754compute X and Y scales common to all the histograms, like
2755`TMultiGraph` does for graphs.
2756
2757If the option `PADS` is specified, the current pad/canvas is subdivided into
2758a number of pads equal to the number of histograms and each histogram is paint
2759into a separate pad. With `PADSn`, the current pad/canvas is subdivided into
2760`n` columns, automatically calculating the number of rows.
2761
2762The following example shows various types of stacks (hist023_THStack_simple.C).
2763
2764Begin_Macro(source)
2765../../../tutorials/hist/hist023_THStack_simple.C
2766End_Macro
2767
2768The option `nostackb` allows to draw the histograms next to each
2769other as bar charts:
2770
2771Begin_Macro(source)
2772{
2773 auto cst0 = new TCanvas("cst0","cst0",600,400);
2774 auto hs = new THStack("hs","Stacked 1D histograms: option #font[82]{\"nostackb\"}");
2775
2776 auto h1 = new TH1F("h1","h1",10,-4,4);
2777 h1->FillRandom("gaus",20000);
2778 h1->SetFillColor(kRed);
2779 hs->Add(h1);
2780
2781 auto h2 = new TH1F("h2","h2",10,-4,4);
2782 h2->FillRandom("gaus",15000);
2783 h2->SetFillColor(kBlue);
2784 hs->Add(h2);
2785
2786 auto h3 = new TH1F("h3","h3",10,-4,4);
2787 h3->FillRandom("gaus",10000);
2788 h3->SetFillColor(kGreen);
2789 hs->Add(h3);
2790
2791 hs->Draw("nostackb");
2792 hs->GetXaxis()->SetNdivisions(-10);
2793 cst0->SetGridx();
2794}
2795End_Macro
2796
2797If at least one of the histograms in the stack has errors, the whole stack is
2798visualized by default with error bars. To visualize it without errors the
2799option `HIST` should be used.
2800
2801Begin_Macro(source)
2802{
2803 auto cst1 = new TCanvas("cst1","cst1",700,400);
2804 cst1->Divide(2,1);
2805
2806 auto hst11 = new TH1F("hst11", "", 20, -10, 10);
2807 hst11->Sumw2();
2808 hst11->FillRandom("gaus", 1000);
2809 hst11->SetFillColor(kViolet);
2810 hst11->SetLineColor(kViolet);
2811
2812 auto hst12 = new TH1F("hst12", "", 20, -10, 10);
2813 hst12->FillRandom("gaus", 500);
2814 hst12->SetFillColor(kBlue);
2815 hst12->SetLineColor(kBlue);
2816
2817 THStack st1("st1", "st1");
2818 st1.Add(hst11);
2819 st1.Add(hst12);
2820
2821 cst1->cd(1); st1.Draw();
2822 cst1->cd(2); st1.Draw("hist");
2823}
2824End_Macro
2825
2826\anchor HP27
2827### Drawing of 3D implicit functions
2828
2829
28303D implicit functions (`TF3`) can be drawn as iso-surfaces.
2831The implicit function f(x,y,z) = 0 is drawn in cartesian coordinates.
2832In the following example the options "FB" and "BB" suppress the
2833"Front Box" and "Back Box" around the plot.
2834
2835Begin_Macro(source)
2836{
2837 auto c2 = new TCanvas("c2","c2",600,400);
2838 auto f3 = new TF3("f3","sin(x*x+y*y+z*z-36)",-2,2,-2,2,-2,2);
2839 f3->SetClippingBoxOn(0,0,0);
2840 f3->SetFillColor(30);
2841 f3->SetLineColor(15);
2842 f3->Draw("FBBB");
2843}
2844End_Macro
2845
2846
2847\anchor HP28
2848### Associated functions drawing
2849
2850
2851An associated function is created by `TH1::Fit`. More than on fitted
2852function can be associated with one histogram (see `TH1::Fit`).
2853
2854A `TF1` object `f1` can be added to the list of associated
2855functions of an histogram `h` without calling `TH1::Fit`
2856simply doing:
2857
2858 h->GetListOfFunctions()->Add(f1);
2859
2860or
2861
2862 h->GetListOfFunctions()->Add(f1,someoption);
2863
2864To retrieve a function by name from this list, do:
2865
2866 TF1 *f1 = (TF1*)h->GetListOfFunctions()->FindObject(name);
2867
2868or
2869
2870 TF1 *f1 = h->GetFunction(name);
2871
2872Associated functions are automatically painted when an histogram is drawn.
2873To avoid the painting of the associated functions the option `HIST`
2874should be added to the list of the options used to paint the histogram.
2875
2876
2877\anchor HP29
2878### Drawing using OpenGL
2879
2880
2881The class `TGLHistPainter` allows to paint data set using the OpenGL 3D
2882graphics library. The plotting options start with `GL` keyword.
2883In addition, in order to inform canvases that OpenGL should be used to render
28843D representations, the following option should be set:
2885
2886 gStyle->SetCanvasPreferGL(true);
2887
2888
2889\anchor HP29a
2890#### General information: plot types and supported options
2891
2892The following types of plots are provided:
2893
2894For lego plots the supported options are:
2895
2896| Option | Description |
2897|----------|-------------------------------------------------------------------|
2898| "GLLEGO" | Draw a lego plot. It works also for `TH2Poly`.|
2899| "GLLEGO2"| Bins with color levels.|
2900| "GLLEGO3"| Cylindrical bars.|
2901
2902
2903
2904Lego painter in cartesian supports logarithmic scales for X, Y, Z.
2905In polar only Z axis can be logarithmic, in cylindrical only Y.
2906
2907For surface plots (`TF2` and `TH2`) the supported options are:
2908
2909| Option | Description |
2910|-----------|------------------------------------------------------------------|
2911| "GLSURF" | Draw a surface.|
2912| "GLSURF1" | Surface with color levels|
2913| "GLSURF2" | The same as "GLSURF1" but without polygon outlines.|
2914| "GLSURF3" | Color level projection on top of plot (works only in cartesian coordinate system).|
2915| "GLSURF4" | Same as "GLSURF" but without polygon outlines.|
2916
2917
2918
2919The surface painting in cartesian coordinates supports logarithmic scales along
2920X, Y, Z axis. In polar coordinates only the Z axis can be logarithmic,
2921in cylindrical coordinates only the Y axis.
2922
2923Additional options to SURF and LEGO - Coordinate systems:
2924
2925| Option | Description |
2926|----------|-------------------------------------------------------------------|
2927| " " | Default, cartesian coordinates system.|
2928| "POL" | Polar coordinates system.|
2929| "CYL" | Cylindrical coordinates system.|
2930| "SPH" | Spherical coordinates system.|
2931
2932
2933
2934\anchor HP290
2935#### TH3 as color boxes
2936
2937The supported option is:
2938
2939| Option | Description |
2940|----------|-------------------------------------------------------------------|
2941| "GLCOL" | H3 is drawn using semi-transparent colored boxes. See glvox1.C .|
2942
2943
2944
2945\anchor HP29b
2946#### TH3 as boxes (spheres)
2947
2948The supported options are:
2949
2950| Option | Description |
2951|----------|-------------------------------------------------------------------|
2952| "GLBOX" | TH3 as a set of boxes, size of box is proportional to bin content.|
2953| "GLBOX1" | The same as "glbox", but spheres are drawn instead of boxes.|
2954
2955
2956
2957\anchor HP29c
2958#### TH3 as iso-surface(s)
2959
2960The supported option is:
2961
2962| Option | Description |
2963|----------|-------------------------------------------------------------------|
2964| "GLISO" | TH3 is drawn using iso-surfaces.|
2965
2966
2967
2968\anchor HP29d
2969#### TF3 (implicit function)
2970
2971The supported option is:
2972
2973| Option | Description |
2974|----------|-------------------------------------------------------------------|
2975| "GL" | Draw a TF3.|
2976
2977
2978
2979\anchor HP29e
2980#### Parametric surfaces
2981
2982glparametric.C shows how to create parametric equations and visualize the surface.
2983
2984\anchor HP29f
2985#### Interaction with the plots
2986
2987All the interactions are implemented via standard methods
2988`DistancetoPrimitive()` and `ExecuteEvent()`. That's why all the
2989interactions with the OpenGL plots are possible only when the mouse cursor is
2990in the plot's area (the plot's area is the part of a the pad occupied by
2991gl-produced picture). If the mouse cursor is not above gl-picture, the standard
2992pad interaction is performed.
2993
2994\anchor HP29g
2995#### Selectable parts
2996
2997Different parts of the plot can be selected:
2998
2999- xoz, yoz, xoy back planes: When such a plane selected, it's highlighted in green
3000 if the dynamic slicing by this plane is supported, and it's highlighted in red,
3001 if the dynamic slicing is not supported.
3002- The plot itself:
3003 On surfaces, the selected surface is outlined in red. (TF3 and
3004 ISO are not outlined). On lego plots, the selected bin is
3005 highlighted. The bin number and content are displayed in pad's
3006 status bar. In box plots, the box or sphere is highlighted and
3007 the bin info is displayed in pad's status bar.
3008
3009
3010\anchor HP29h
3011#### Rotation and zooming
3012
3013
3014- Rotation:
3015 When the plot is selected, it can be rotated by pressing and
3016 holding the left mouse button and move the cursor.
3017- Zoom/Unzoom:
3018 Mouse wheel or 'j', 'J', 'k', 'K' keys.
3019
3020
3021\anchor HP29i
3022#### Panning
3023
3024The selected plot can be moved in a pad's area by pressing and
3025holding the left mouse button and the shift key.
3026
3027\anchor HP29j
3028#### Box cut
3029
3030Surface, iso, box, TF3 and parametric painters support box cut by
3031pressing the 'c' or 'C' key when the mouse cursor is in a plot's
3032area. That will display a transparent box, cutting away part of the
3033surface (or boxes) in order to show internal part of plot. This box
3034can be moved inside the plot's area (the full size of the box is
3035equal to the plot's surrounding box) by selecting one of the box
3036cut axes and pressing the left mouse button to move it.
3037
3038\anchor HP29k
3039#### Plot specific interactions (dynamic slicing etc.)
3040
3041Currently, all gl-plots support some form of slicing. When back plane
3042is selected (and if it's highlighted in green) you can press and hold
3043left mouse button and shift key and move this back plane inside
3044plot's area, creating the slice. During this "slicing" plot becomes
3045semi-transparent. To remove all slices (and projected curves for
3046surfaces) double click with left mouse button in a plot's area.
3047
3048\anchor HP29l
3049#### Surface with option "GLSURF"
3050
3051The surface profile is displayed on the slicing plane.
3052The profile projection is drawn on the back plane
3053by pressing `'p'` or `'P'` key.
3054
3055\anchor HP29m
3056#### TF3
3057
3058The contour plot is drawn on the slicing plane. For TF3 the color
3059scheme can be changed by pressing 's' or 'S'.
3060
3061\anchor HP29n
3062#### Box
3063
3064The contour plot corresponding to slice plane position is drawn in real time.
3065
3066\anchor HP29o
3067#### Iso
3068
3069Slicing is similar to "GLBOX" option.
3070
3071\anchor HP29p
3072#### Parametric plot
3073
3074No slicing. Additional keys: 's' or 'S' to change color scheme -
3075about 20 color schemes supported ('s' for "scheme"); 'l' or 'L' to
3076increase number of polygons ('l' for "level" of details), 'w' or 'W'
3077to show outlines ('w' for "wireframe").
3078
3079\anchor HP30
3080#### Highlight mode for histogram
3081
3082\since **ROOT version 6.15/01**
3083
3084\image html hlHisto3_top.gif "Highlight mode"
3085
3086Highlight mode is implemented for `TH1` (and for `TGraph`) class. When
3087highlight mode is on, mouse movement over the bin will be represented
3088graphically. Bin will be highlighted as "bin box" (presented by box
3089object). Moreover, any highlight (change of bin) emits signal
3090`TCanvas::Highlighted()` which allows the user to react and call their own
3091function. For a better understanding see also the tutorial `hist043` to `hist046`
3092located in `$ROOTSYS/tutorials/hist/`.
3093
3094Highlight mode is switched on/off by `TH1::SetHighlight()` function
3095or interactively from `TH1` context menu. `TH1::IsHighlight()` to verify
3096whether the highlight mode enabled or disabled, default it is disabled.
3097
3098~~~ {.cpp}
3099 root [0] .x $ROOTSYS/tutorials/hsimple.C
3100 root [1] hpx->SetHighlight(kTRUE) // or interactively from TH1 context menu
3101 root [2] hpx->IsHighlight()
3102 (bool) true
3103~~~
3104
3105\image html hlsimple_nofun.gif "Highlight mode for histogram"
3106
3107\anchor HP30a
3108#### Highlight mode and user function
3109
3110The user can use (connect) `TCanvas::Highlighted()` signal, which is always
3111emitted if there is a highlight bin and call user function via signal
3112and slot communication mechanism. `TCanvas::Highlighted()` is similar
3113`TCanvas::Picked()`
3114
3115- when selected object (histogram as a whole) is different from previous
3116then emit `Picked()` signal
3117- when selected (highlighted) bin from histogram is different from previous
3118then emit `Highlighted()` signal
3119
3120Any user function (or functions) has to be defined
3121`UserFunction(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)`.
3122In example (see below) has name `PrintInfo()`. All parameters of user
3123function are taken from
3124
3125 void TCanvas::Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
3126
3127- `pad` is pointer to pad with highlighted histogram
3128- `obj` is pointer to highlighted histogram
3129- `x` is highlighted x bin for 1D histogram
3130- `y` is highlighted y bin for 2D histogram (for 1D histogram not in use)
3131
3132Example how to create a connection from any `TCanvas` object to a user
3133`UserFunction()` slot (see also `TQObject::Connect()` for additional info)
3134
3135 TQObject::Connect("TCanvas", "Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)",
3136 0, 0, "UserFunction(TVirtualPad*,TObject*,Int_t,Int_t)");
3137
3138or use non-static "simplified" function
3139`TCanvas::HighlightConnect(const char *slot)`
3140
3141 c1->HighlightConnect("UserFunction(TVirtualPad*,TObject*,Int_t,Int_t)");
3142
3143NOTE the signal and slot string must have a form
3144"(TVirtualPad*,TObject*,Int_t,Int_t)"
3145
3146 root [0] .x $ROOTSYS/tutorials/hsimple.C
3147 root [1] hpx->SetHighlight(kTRUE)
3148 root [2] .x hlprint.C
3149
3150file `hlprint.C`
3151~~~ {.cpp}
3152void PrintInfo(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
3153{
3154 auto h = (TH1F *)obj;
3155 if (!h->IsHighlight()) // after highlight disabled
3156 h->SetTitle("highlight disable");
3157 else
3158 h->SetTitle(TString::Format("bin[%03d] (%5.2f) content %g", x,
3159 h->GetBinCenter(x), h->GetBinContent(x)));
3160 pad->Update();
3161}
3162
3163void hlprint()
3164{
3165 if (!gPad) return;
3166 gPad->GetCanvas()->HighlightConnect("PrintInfo(TVirtualPad*,TObject*,Int_t,Int_t)");
3167}
3168~~~
3169
3170\image html hlsimple.gif "Highlight mode and simple user function"
3171
3172For more complex demo please see for example tree200_temperature.C file.
3173
3174*/
3175
3177
3180
3181const Int_t kNMAX = 2000;
3182
3183const Int_t kMAXCONTOUR = 104;
3185
3186static std::unique_ptr<TBox> gXHighlightBox, gYHighlightBox; // highlight X and Y box
3187
3209
3210
3211////////////////////////////////////////////////////////////////////////////////
3212/// Default constructor.
3213
3215{
3216 fH = nullptr;
3217 fXaxis = nullptr;
3218 fYaxis = nullptr;
3219 fZaxis = nullptr;
3220 fFunctions = nullptr;
3221 fNcuts = 0;
3222 fStack = nullptr;
3223 fShowProjection = 0;
3224 fShowProjection2 = 0;
3225 fShowOption = "";
3226 for (int i=0; i<kMaxCuts; i++) {
3227 fCuts[i] = nullptr;
3228 fCutsOpt[i] = 0;
3229 }
3230 fXHighlightBin = -1;
3231 fYHighlightBin = -1;
3232 fCurrentF3 = nullptr;
3233
3234 gStringEntries = gEnv->GetValue("Hist.Stats.Entries", "Entries");
3235 gStringMean = gEnv->GetValue("Hist.Stats.Mean", "Mean");
3236 gStringMeanX = gEnv->GetValue("Hist.Stats.MeanX", "Mean x");
3237 gStringMeanY = gEnv->GetValue("Hist.Stats.MeanY", "Mean y");
3238 gStringMeanZ = gEnv->GetValue("Hist.Stats.MeanZ", "Mean z");
3239 gStringStdDev = gEnv->GetValue("Hist.Stats.StdDev", "Std Dev");
3240 gStringStdDevX = gEnv->GetValue("Hist.Stats.StdDevX", "Std Dev x");
3241 gStringStdDevY = gEnv->GetValue("Hist.Stats.StdDevY", "Std Dev y");
3242 gStringStdDevZ = gEnv->GetValue("Hist.Stats.StdDevZ", "Std Dev z");
3243 gStringUnderflow = gEnv->GetValue("Hist.Stats.Underflow", "Underflow");
3244 gStringOverflow = gEnv->GetValue("Hist.Stats.Overflow", "Overflow");
3245 gStringIntegral = gEnv->GetValue("Hist.Stats.Integral", "Integral");
3246 gStringIntegralBinWidth = gEnv->GetValue("Hist.Stats.IntegralBinWidth", "Integral(w)");
3247 gStringSkewness = gEnv->GetValue("Hist.Stats.Skewness", "Skewness");
3248 gStringSkewnessX = gEnv->GetValue("Hist.Stats.SkewnessX", "Skewness x");
3249 gStringSkewnessY = gEnv->GetValue("Hist.Stats.SkewnessY", "Skewness y");
3250 gStringSkewnessZ = gEnv->GetValue("Hist.Stats.SkewnessZ", "Skewness z");
3251 gStringKurtosis = gEnv->GetValue("Hist.Stats.Kurtosis", "Kurtosis");
3252 gStringKurtosisX = gEnv->GetValue("Hist.Stats.KurtosisX", "Kurtosis x");
3253 gStringKurtosisY = gEnv->GetValue("Hist.Stats.KurtosisY", "Kurtosis y");
3254 gStringKurtosisZ = gEnv->GetValue("Hist.Stats.KurtosisZ", "Kurtosis z");
3255}
3256
3257////////////////////////////////////////////////////////////////////////////////
3258/// destructor.
3259
3263
3264////////////////////////////////////////////////////////////////////////////////
3265/// Compute the distance from the point px,py to a line.
3266///
3267/// Compute the closest distance of approach from point px,py to elements of
3268/// an histogram. The distance is computed in pixels units.
3269///
3270/// Algorithm: Currently, this simple model computes the distance from the mouse
3271/// to the histogram contour only.
3272
3274{
3275
3276 Double_t defaultLabelSize = 0.04; // See TAttAxis.h for source of this value
3277
3278 const Int_t big = 9999;
3279 const Int_t kMaxDiff = 7;
3280
3281 if (fPie)
3282 return fPie->DistancetoPrimitive(px, py);
3283
3284 Double_t x = gPad->AbsPixeltoX(px);
3285 Double_t x1 = gPad->AbsPixeltoX(px+1);
3286
3287 Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
3288 Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
3289 Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
3290 Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());
3291 Int_t curdist = big;
3293 Bool_t dsame;
3294 TObject *PadPointer = gPad->GetPadPointer();
3295 if (!PadPointer) return 0;
3296 TString doption = PadPointer->GetDrawOption();
3297 Double_t factor = 1;
3298 if (fH->GetNormFactor() != 0) {
3299 factor = fH->GetNormFactor()/fH->GetSumOfWeights();
3300 }
3301 // return if point is not in the histogram area
3302
3303 // If a 3D view exists, check distance to axis
3304 TView *view = gPad->GetView();
3305 Int_t d1,d2,d3;
3306 if (view && Hoption.Contour != 14) {
3307 Double_t ratio;
3308 d3 = view->GetDistancetoAxis(3, px, py, ratio);
3309 if (d3 <= kMaxDiff) {gPad->SetSelected(fZaxis); return 0;}
3310 d1 = view->GetDistancetoAxis(1, px, py, ratio);
3311 if (d1 <= kMaxDiff) {gPad->SetSelected(fXaxis); return 0;}
3312 d2 = view->GetDistancetoAxis(2, px, py, ratio);
3313 if (d2 <= kMaxDiff) {gPad->SetSelected(fYaxis); return 0;}
3314 if ( px > puxmin && px < puxmax && py > puymax && py < puymin) curdist = 1;
3315 goto FUNCTIONS;
3316 }
3317 // check if point is close to an axis
3318 doption.ToLower();
3319 dsame = kFALSE;
3320 if (doption.Contains("same")) dsame = kTRUE;
3321
3323 if (doption.Contains("y+")) {
3325 if (px <= xyaxis+dyaxis && px >= xyaxis && py >puymax && py < puymin) {
3326 if (!dsame) {
3327 if (gPad->IsVertical()) gPad->SetSelected(fYaxis);
3328 else gPad->SetSelected(fXaxis);
3329 return 0;
3330 }
3331 }
3332 } else {
3334 if (px >= xyaxis-dyaxis && px <= xyaxis && py >puymax && py < puymin) {
3335 if (!dsame) {
3336 if (gPad->IsVertical()) gPad->SetSelected(fYaxis);
3337 else gPad->SetSelected(fXaxis);
3338 return 0;
3339 }
3340 }
3341 }
3342
3344 if (doption.Contains("x+")) {
3346 if (py >= yxaxis-dxaxis && py <= yxaxis && px <puxmax && px > puxmin) {
3347 if (!dsame) {
3348 if (gPad->IsVertical()) gPad->SetSelected(fXaxis);
3349 else gPad->SetSelected(fYaxis);
3350 return 0;
3351 }
3352 }
3353 } else {
3355 if (yxaxis < puymin) yxaxis = puymin;
3357 if (!dsame) {
3358 if (gPad->IsVertical()) gPad->SetSelected(fXaxis);
3359 else gPad->SetSelected(fYaxis);
3360 return 0;
3361 }
3362 }
3363 }
3364
3365 if (fH->IsHighlight()) { // only if highlight is enable
3366 if ((px > puxmin) && (py < puymin) && (px < puxmax) && (py > puymax))
3367 HighlightBin(px, py);
3368 }
3369
3370 // if object is 2D or 3D return this object
3371 if (fH->GetDimension() == 2) {
3372 if (fH->InheritsFrom(TH2Poly::Class())) {
3373 TH2Poly *th2 = (TH2Poly*)fH;
3375 gPad->GetRangeAxis(xmin, ymin, xmax, ymax);
3376 Double_t pxu = gPad->AbsPixeltoX(px);
3377 Double_t pyu = gPad->AbsPixeltoY(py);
3378 if ((pxu>xmax) || (pxu < xmin) || (pyu>ymax) || (pyu < ymin)) {
3379 curdist = big;
3380 goto FUNCTIONS;
3381 } else {
3382 Int_t bin = th2->FindBin(pxu, pyu);
3383 if (bin>0) curdist = 1;
3384 else curdist = big;
3385 goto FUNCTIONS;
3386 }
3387 }
3388 Int_t delta2 = 5; //Give a margin of delta2 pixels to be in the 2-d area
3389 if ( px > puxmin + delta2
3390 && px < puxmax - delta2
3391 && py > puymax + delta2
3392 && py < puymin - delta2) {curdist =1; goto FUNCTIONS;}
3393 }
3394
3395 // point is inside histogram area. Find channel number
3396 if (gPad->IsVertical()) {
3397 Int_t bin = fXaxis->FindFixBin(gPad->PadtoX(x));
3398 Int_t binsup = fXaxis->FindFixBin(gPad->PadtoX(x1));
3399 Double_t binval = factor*fH->GetBinContent(bin);
3400 Int_t pybin = gPad->YtoAbsPixel(gPad->YtoPad(binval));
3401 if (binval == 0 && pybin < puymin) pybin = 10000;
3402 // special case if more than one bin for the pixel
3403 if (binsup-bin>1) {
3407 for (Int_t ibin=bin+1; ibin<binsup; ibin++) {
3411 }
3412 Int_t pybinmin = gPad->YtoAbsPixel(gPad->YtoPad(binvalmax));
3413 Int_t pybinmax = gPad->YtoAbsPixel(gPad->YtoPad(binvalmin));
3415 }
3416 if (bin != binsup) { // Mouse on bin border
3418 Int_t pybinsub = gPad->YtoAbsPixel(gPad->YtoPad(binsupval));
3419 if (py <= TMath::Max(pybinsub,pybin) && py >= TMath::Min(pybinsub,pybin) && pybin != 10000) return 0;
3420 }
3421 if (TMath::Abs(py - pybin) <= kMaxDiff) return TMath::Abs(py - pybin);
3422 } else {
3423 Double_t y = gPad->AbsPixeltoY(py);
3424 Double_t y1 = gPad->AbsPixeltoY(py+1);
3425 Int_t bin = fXaxis->FindFixBin(gPad->PadtoY(y));
3426 Int_t binsup = fXaxis->FindFixBin(gPad->PadtoY(y1));
3427 Double_t binval = factor*fH->GetBinContent(bin);
3428 Int_t pxbin = gPad->XtoAbsPixel(gPad->XtoPad(binval));
3429 if (binval == 0 && pxbin > puxmin) pxbin = 10000;
3430 // special case if more than one bin for the pixel
3431 if (binsup-bin>1) {
3435 for (Int_t ibin=bin+1; ibin<binsup; ibin++) {
3439 }
3440 Int_t pxbinmin = gPad->XtoAbsPixel(gPad->XtoPad(binvalmax));
3441 Int_t pxbinmax = gPad->XtoAbsPixel(gPad->XtoPad(binvalmin));
3443 }
3444 if (TMath::Abs(px - pxbin) <= kMaxDiff) return TMath::Abs(px - pxbin);
3445 }
3446 // Loop on the list of associated functions and user objects
3447FUNCTIONS:
3448 TObject *f;
3449 TIter next(fFunctions);
3450 while ((f = (TObject*) next())) {
3451 Int_t dist;
3452 if (f->InheritsFrom(TF1::Class())) dist = f->DistancetoPrimitive(-px,py);
3453 else dist = f->DistancetoPrimitive(px,py);
3454 if (dist < kMaxDiff) {gPad->SetSelected(f); return dist;}
3455 }
3456 return curdist;
3457}
3458
3459////////////////////////////////////////////////////////////////////////////////
3460/// Display a panel with all histogram drawing options.
3461
3463{
3464
3465 gCurrentHist = fH;
3466 if (!gPad) {
3467 Error("DrawPanel", "need to draw histogram first");
3468 return;
3469 }
3471 editor->Show();
3472 gROOT->ProcessLine(TString::Format("((TCanvas*)0x%zx)->Selected((TVirtualPad*)0x%zx,(TObject*)0x%zx,1)",
3473 (size_t)gPad->GetCanvas(), (size_t)gPad, (size_t)fH).Data());
3474}
3475
3476////////////////////////////////////////////////////////////////////////////////
3477/// Execute the actions corresponding to `event`.
3478///
3479/// This function is called when a histogram is clicked with the locator at
3480/// the pixel position px,py.
3481
3483{
3484
3485 if (!gPad) return;
3486
3487 static Int_t bin, px1, py1, px2, py2, pyold;
3488 static std::unique_ptr<TBox> zoombox;
3490
3491 Int_t bin1, bin2;
3492 Double_t xlow, xup, ylow, binval, x, baroffset, barwidth, binwidth;
3493 Bool_t opaque = gPad->OpaqueMoving();
3494
3495 if (!gPad->IsEditable()) return;
3496
3497 if (fPie) {
3498 fPie->ExecuteEvent(event, px, py);
3499 return;
3500 }
3501 // come here if we have a lego/surface in the pad
3502 TView *view = gPad->GetView();
3503
3504 if (!fShowProjection && view && !view->TestBit(kCannotRotate)) {
3505 view->ExecuteRotateView(event, px, py);
3506 return;
3507 }
3508
3509 TAxis *xaxis = fH->GetXaxis();
3510 TAxis *yaxis = fH->GetYaxis();
3511 Int_t dimension = fH->GetDimension();
3512
3513 // In case of option SAME the axis must be the ones of the first drawn histogram
3514 TString IsSame = fH->GetDrawOption();
3515 IsSame.ToLower();
3516 if (IsSame.Index("same")>=0) {
3517 TH1 *h1;
3518 TIter next(gPad->GetListOfPrimitives());
3519 while ((h1 = (TH1 *)next())) {
3520 if (!h1->InheritsFrom(TH1::Class())) continue;
3521 xaxis = h1->GetXaxis();
3522 yaxis = h1->GetYaxis();
3523 break;
3524 }
3525 }
3526
3527 Double_t factor = 1;
3528 if (fH->GetNormFactor() != 0) {
3529 factor = fH->GetNormFactor()/fH->GetSumOfWeights();
3530 }
3531
3532 switch (event) {
3533
3534 case kButton1Down:
3535
3536 if (!opaque) gVirtualX->SetLineColor(-1);
3537 fH->TAttLine::Modify();
3538
3539 if (opaque && dimension ==2) {
3540 zbx1 = gPad->AbsPixeltoX(px);
3541 zbx2 = gPad->AbsPixeltoX(px);
3542 zby1 = gPad->AbsPixeltoY(py);
3543 zby2 = gPad->AbsPixeltoY(py);
3544 px1 = px;
3545 py1 = py;
3546 if (gPad->GetLogx()) {
3547 zbx1 = TMath::Power(10,zbx1);
3548 zbx2 = TMath::Power(10,zbx2);
3549 }
3550 if (gPad->GetLogy()) {
3551 zby1 = TMath::Power(10,zby1);
3552 zby2 = TMath::Power(10,zby2);
3553 }
3554 if (zoombox) Error("ExecuteEvent", "Last zoom box was not deleted");
3555 zoombox = std::make_unique<TBox>(zbx1, zby1, zbx2, zby2);
3556 Int_t ci = TColor::GetColor("#7d7dff");
3557 TColor *zoomcolor = gROOT->GetColor(ci);
3558 if (!TCanvas::SupportAlpha() || !zoomcolor) zoombox->SetFillStyle(3002);
3559 else zoomcolor->SetAlpha(0.5);
3560 zoombox->SetFillColor(ci);
3561 zoombox->Draw();
3562 gPad->Modified();
3563 gPad->Update();
3564 }
3565 // No break !!!
3566
3567 case kMouseMotion:
3568
3569 if (fShowProjection) {ShowProjection3(px,py); break;}
3570
3571 gPad->SetCursor(kPointer);
3572 if (dimension ==1) {
3573 if (Hoption.Bar) {
3574 baroffset = fH->GetBarOffset();
3575 barwidth = fH->GetBarWidth();
3576 } else {
3577 baroffset = 0;
3578 barwidth = 1;
3579 }
3580 x = gPad->AbsPixeltoX(px);
3581 bin = fXaxis->FindFixBin(gPad->PadtoX(x));
3583 xlow = gPad->XtoPad(fXaxis->GetBinLowEdge(bin) + baroffset*binwidth);
3584 xup = gPad->XtoPad(xlow + barwidth*binwidth);
3585 ylow = gPad->GetUymin();
3586 px1 = gPad->XtoAbsPixel(xlow);
3587 px2 = gPad->XtoAbsPixel(xup);
3588 py1 = gPad->YtoAbsPixel(ylow);
3589 py2 = py;
3590 pyold = py;
3591 if (gROOT->GetEditHistograms()) gPad->SetCursor(kArrowVer);
3592 }
3593
3594 break;
3595
3596 case kButton1Motion:
3597
3598 if (dimension ==1) {
3599 if (gROOT->GetEditHistograms()) {
3600 if (!opaque) {
3601 gVirtualX->DrawBox(px1, py1, px2, py2,TVirtualX::kHollow); // Draw the old box
3602 py2 += py - pyold;
3603 gVirtualX->DrawBox(px1, py1, px2, py2,TVirtualX::kHollow); // Draw the new box
3604 pyold = py;
3605 } else {
3606 py2 += py - pyold;
3607 pyold = py;
3608 binval = gPad->PadtoY(gPad->AbsPixeltoY(py2))/factor;
3610 gPad->Modified(kTRUE);
3611 }
3612 }
3613 }
3614
3615 if (opaque && dimension ==2) {
3616 if (TMath::Abs(px1-px)>5 && TMath::Abs(py1-py)>5) {
3617 zbx2 = gPad->AbsPixeltoX(px);
3618 zby2 = gPad->AbsPixeltoY(py);
3619 if (gPad->GetLogx()) zbx2 = TMath::Power(10,zbx2);
3620 if (gPad->GetLogy()) zby2 = TMath::Power(10,zby2);
3621 if (zoombox) {
3622 zoombox->SetX2(zbx2);
3623 zoombox->SetY2(zby2);
3624 }
3625 gPad->Modified();
3626 gPad->Update();
3627 }
3628 }
3629
3630 break;
3631
3632 case kWheelUp:
3633
3634 if (dimension ==2) {
3635 bin1 = xaxis->GetFirst()+1;
3636 bin2 = xaxis->GetLast()-1;
3637 bin1 = TMath::Max(bin1, 1);
3638 bin2 = TMath::Min(bin2, xaxis->GetNbins());
3639 if (bin2>bin1) xaxis->SetRange(bin1,bin2);
3640 bin1 = yaxis->GetFirst()+1;
3641 bin2 = yaxis->GetLast()-1;
3642 bin1 = TMath::Max(bin1, 1);
3643 bin2 = TMath::Min(bin2, yaxis->GetNbins());
3644 if (bin2>bin1) yaxis->SetRange(bin1,bin2);
3645 }
3646 gPad->Modified();
3647 gPad->Update();
3648
3649 break;
3650
3651 case kWheelDown:
3652
3653 if (dimension == 2) {
3654 bin1 = xaxis->GetFirst()-1;
3655 bin2 = xaxis->GetLast()+1;
3656 bin1 = TMath::Max(bin1, 1);
3657 bin2 = TMath::Min(bin2, xaxis->GetNbins());
3658 const bool resetXaxisRange = bin1 == 1 && xaxis->GetFirst() == 1 && bin2 == xaxis->GetNbins() && xaxis->GetLast() == xaxis->GetNbins();
3659 if (bin2>bin1) xaxis->SetRange(bin1,bin2);
3660 if (resetXaxisRange) xaxis->ResetBit(TAxis::kAxisRange);
3661 bin1 = yaxis->GetFirst()-1;
3662 bin2 = yaxis->GetLast()+1;
3663 bin1 = TMath::Max(bin1, 1);
3664 bin2 = TMath::Min(bin2, yaxis->GetNbins());
3665 const bool resetYaxisRange = bin1 == 1 && yaxis->GetFirst() == 1 && bin2 == yaxis->GetNbins() && yaxis->GetLast() == yaxis->GetNbins();
3666 if (bin2>bin1) yaxis->SetRange(bin1,bin2);
3667 if (resetYaxisRange) yaxis->ResetBit(TAxis::kAxisRange);
3668 }
3669 gPad->Modified();
3670 gPad->Update();
3671
3672 break;
3673
3674 case kButton1Up:
3675 if (dimension ==1) {
3676 if (gROOT->GetEditHistograms()) {
3677 binval = gPad->PadtoY(gPad->AbsPixeltoY(py2))/factor;
3679 PaintInit(); // recalculate Hparam structure and recalculate range
3680 }
3681
3682 // might resize pad pixmap so should be called before any paint routine
3684 }
3685 if (opaque && dimension ==2) {
3686 if (zoombox) {
3687 Double_t x1 = TMath::Min(zoombox->GetX1(), zoombox->GetX2());
3688 Double_t x2 = TMath::Max(zoombox->GetX1(), zoombox->GetX2());
3689 Double_t y1 = TMath::Min(zoombox->GetY1(), zoombox->GetY2());
3690 Double_t y2 = TMath::Max(zoombox->GetY1(), zoombox->GetY2());
3691 x1 = TMath::Max(x1,xaxis->GetXmin());
3692 x2 = TMath::Min(x2,xaxis->GetXmax());
3693 y1 = TMath::Max(y1,yaxis->GetXmin());
3694 y2 = TMath::Min(y2,yaxis->GetXmax());
3695 if (x1<x2 && y1<y2) {
3696 xaxis->SetRangeUser(x1, x2);
3697 yaxis->SetRangeUser(y1, y2);
3698 }
3699 zoombox.reset();
3700 }
3701 }
3702 gPad->Modified(kTRUE);
3703 if (opaque) gVirtualX->SetLineColor(-1);
3704
3705 break;
3706
3707 case kButton1Locate:
3708
3709 ExecuteEvent(kButton1Down, px, py);
3710
3711 while (true) {
3712 px = py = 0;
3713 event = gVirtualX->RequestLocator(1, 1, px, py);
3714
3716
3717 if (event != -1) { // button is released
3718 ExecuteEvent(kButton1Up, px, py);
3719 return;
3720 }
3721 }
3722 }
3723}
3724
3725////////////////////////////////////////////////////////////////////////////////
3726/// Get a contour (as a list of TGraphs) using the Delaunay triangulation.
3727
3729{
3730 // Check if fH contains a TGraphDelaunay2D
3732 TGraphDelaunay2D *dt = (TGraphDelaunay2D*)hl->FindObject("TGraphDelaunay2D");
3733 // try with the old painter
3734 TGraphDelaunay *dtOld = nullptr;
3735 if (!dt) dtOld = (TGraphDelaunay*)hl->FindObject("TGraphDelaunay");
3736
3737 if (!dt && !dtOld) return nullptr;
3738
3739 gCurrentHist = fH;
3740
3741 if (!fGraph2DPainter)
3742 ((THistPainter*)this)->fGraph2DPainter = dt ? std::make_unique<TGraph2DPainter>(dt) : std::make_unique<TGraph2DPainter>(dtOld);
3743
3744 return fGraph2DPainter->GetContourList(contour);
3745}
3746
3747////////////////////////////////////////////////////////////////////////////////
3748/// Display the histogram info (bin number, contents, integral up to bin
3749/// corresponding to cursor position px,py.
3750
3752{
3753
3754 if (!gPad) return (char*)"";
3755
3756 Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
3757 Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
3758 Double_t x1 = gPad->PadtoX(gPad->AbsPixeltoX(px+1));
3760 drawOption.ToLower();
3763 if (fH->GetDimension() == 2) {
3764 if (gPad->GetView() || drawOption.Index("cont") >= 0) {
3765 uxmin=gPad->GetUxmin();
3766 uxmax=gPad->GetUxmax();
3769 x = xmin +(xmax-xmin)*(x-uxmin)/(uxmax-uxmin);
3770 uymin=gPad->GetUymin();
3771 uymax=gPad->GetUymax();
3774 y = ymin +(ymax-ymin)*(y-uymin)/(uymax-uymin);
3775 }
3776 }
3778 if (gPad->IsVertical()) {
3779 binx = fXaxis->FindFixBin(x);
3780 if (drawOption.Index("same") >= 0) {
3781 TH1 *h1;
3782 TIter next(gPad->GetListOfPrimitives());
3783 while ((h1 = (TH1 *)next())) {
3784 if (!h1->InheritsFrom(TH1::Class())) continue;
3785 binmin = h1->GetXaxis()->GetFirst();
3786 break;
3787 }
3788 } else {
3789 binmin = fXaxis->GetFirst();
3790 }
3792 // special case if more than 1 bin in x per pixel
3793 if (binx1-binx>1 && fH->GetDimension() == 1) {
3796 for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
3800 binnear=ibin;
3801 }
3802 }
3803 binx = binnear;
3804 }
3805 } else {
3806 x1 = gPad->PadtoY(gPad->AbsPixeltoY(py+1));
3807 binx = fXaxis->FindFixBin(y);
3808 if (drawOption.Index("same") >= 0) {
3809 TH1 *h1;
3810 TIter next(gPad->GetListOfPrimitives());
3811 while ((h1 = (TH1 *)next())) {
3812 if (!h1->InheritsFrom(TH1::Class())) continue;
3813 binmin = h1->GetXaxis()->GetFirst();
3814 break;
3815 }
3816 } else {
3817 binmin = fXaxis->GetFirst();
3818 }
3820 // special case if more than 1 bin in x per pixel
3821 if (binx1-binx>1 && fH->GetDimension() == 1) {
3824 for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
3828 binnear=ibin;
3829 }
3830 }
3831 binx = binnear;
3832 }
3833 }
3834 if (fH->GetDimension() == 1) {
3836 TProfile *tp = (TProfile*)fH;
3837 fObjectInfo.Form("(x=%g, y=%g, binx=%d, binc=%g, bine=%g, binn=%d)",
3839 (Int_t) tp->GetBinEntries(binx));
3840 }
3841 else {
3842 Double_t integ = 0;
3843 for (Int_t bin=binmin;bin<=binx;bin++) {integ += fH->GetBinContent(bin);}
3844 fObjectInfo.Form("(x=%g, y=%g, binx=%d, binc=%g, Sum=%g)",
3846 }
3847 } else if (fH->GetDimension() == 2) {
3848 if (fH->InheritsFrom(TH2Poly::Class())) {
3849 TH2Poly *th2 = (TH2Poly*)fH;
3850 biny = th2->FindBin(x,y);
3851 fObjectInfo.Form("%s (x=%g, y=%g, bin=%d, binc=%g)",
3852 th2->GetBinTitle(biny),x,y,biny,th2->GetBinContent(biny));
3853 }
3854 else if (fH->InheritsFrom(TProfile2D::Class())) {
3856 biny = fYaxis->FindFixBin(y);
3857 Int_t bin = fH->GetBin(binx,biny);
3858 fObjectInfo.Form("(x=%g, y=%g, binx=%d, biny=%d, binc=%g, bine=%g, binn=%d)",
3859 x, y, binx, biny, fH->GetBinContent(bin),
3860 fH->GetBinError(bin), (Int_t) tp->GetBinEntries(bin));
3861 } else {
3862 biny = fYaxis->FindFixBin(y);
3863 fObjectInfo.Form("(x=%g, y=%g, binx=%d, biny=%d, binc=%g bine=%g)",
3866 }
3867 } else {
3868 // 3d case: retrieving the x,y,z bin is not yet implemented
3869 // print just the x,y info
3870 fObjectInfo.Form("(x=%g, y=%g)",x,y);
3871 }
3872
3873 return (char *)fObjectInfo.Data();
3874}
3875
3876////////////////////////////////////////////////////////////////////////////////
3877/// Set highlight (enable/disable) mode for fH
3878
3880{
3881 if (fH->IsHighlight()) return;
3882
3883 fXHighlightBin = -1;
3884 fYHighlightBin = -1;
3885 // delete previous highlight box
3886 if (gXHighlightBox) gXHighlightBox.reset();
3887 if (gYHighlightBox) gYHighlightBox.reset();
3888 // emit Highlighted() signal (user can check on disabled)
3889 if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, fH, fXHighlightBin, fYHighlightBin);
3890}
3891
3892////////////////////////////////////////////////////////////////////////////////
3893/// Check on highlight bin
3894
3896{
3897 // call from DistancetoPrimitive (only if highlight is enable)
3898
3899 Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
3900 Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
3903 if (!gPad->IsVertical()) binx = fXaxis->FindFixBin(y);
3904
3906 if (binx != fXHighlightBin) {
3908 changedBin = kTRUE;
3909 } else if (fH->GetDimension() == 1) return;
3910 if (biny != fYHighlightBin) {
3912 changedBin = kTRUE;
3913 }
3914 if (!changedBin) return;
3915
3916 // Info("HighlightBin", "histo: %p '%s'\txbin: %d, ybin: %d",
3917 // (void *)fH, fH->GetName(), fXHighlightBin, fYHighlightBin);
3918
3919 // paint highlight bin as box (recursive calls PaintHighlightBin)
3920 gPad->Modified(kTRUE);
3921 gPad->Update();
3922
3923 // emit Highlighted() signal
3924 if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, fH, fXHighlightBin, fYHighlightBin);
3925}
3926
3927////////////////////////////////////////////////////////////////////////////////
3928/// Paint highlight bin as TBox object
3929
3931{
3932 // call from PaintTitle
3933
3934 if (!fH->IsHighlight()) return;
3935
3936 Double_t uxmin = gPad->GetUxmin();
3937 Double_t uxmax = gPad->GetUxmax();
3938 Double_t uymin = gPad->GetUymin();
3939 Double_t uymax = gPad->GetUymax();
3940 if (gPad->GetLogx()) {
3941 uxmin = TMath::Power(10.0, uxmin);
3942 uxmax = TMath::Power(10.0, uxmax);
3943 }
3944 if (gPad->GetLogy()) {
3945 uymin = TMath::Power(10.0, uymin);
3946 uymax = TMath::Power(10.0, uymax);
3947 }
3948
3949 // testing specific possibility (after zoom, draw with "same", log, etc.)
3951 if (gPad->IsVertical()) {
3953 if ((hcenter < uxmin) || (hcenter > uxmax)) return;
3954 } else {
3956 if ((hcenter < uymin) || (hcenter > uymax)) return;
3957 }
3958 if (fH->GetDimension() == 2) {
3960 if ((hcenter < uymin) || (hcenter > uymax)) return;
3961 }
3962
3963 // paint X highlight bin (for 1D or 2D)
3965 if (gPad->IsVertical()) {
3968 hby1 = uymin;
3969 hby2 = uymax;
3970 } else {
3971 hbx1 = uxmin;
3972 hbx2 = uxmax;
3975 }
3976
3977 if (!gXHighlightBox) {
3978 gXHighlightBox = std::make_unique<TBox>(hbx1, hby1, hbx2, hby2);
3979 gXHighlightBox->SetBit(kCannotPick);
3980 gXHighlightBox->SetFillColor(TColor::GetColor("#9797ff"));
3981 if (!TCanvas::SupportAlpha()) gXHighlightBox->SetFillStyle(3001);
3982 else gROOT->GetColor(gXHighlightBox->GetFillColor())->SetAlpha(0.5);
3983 }
3984 gXHighlightBox->SetX1(hbx1);
3985 gXHighlightBox->SetX2(hbx2);
3986 gXHighlightBox->SetY1(hby1);
3987 gXHighlightBox->SetY2(hby2);
3988 gXHighlightBox->Paint();
3989
3990 // Info("PaintHighlightBin", "histo: %p '%s'\txbin: %d, ybin: %d",
3991 // (void *)fH, fH->GetName(), fXHighlightBin, fYHighlightBin);
3992
3993 // paint Y highlight bin (only for 2D)
3994 if (fH->GetDimension() != 2) return;
3995 hbx1 = uxmin;
3996 hbx2 = uxmax;
3999
4000 if (!gYHighlightBox) {
4001 gYHighlightBox = std::make_unique<TBox>(hbx1, hby1, hbx2, hby2);
4002 gYHighlightBox->SetBit(kCannotPick);
4003 gYHighlightBox->SetFillColor(gXHighlightBox->GetFillColor());
4004 gYHighlightBox->SetFillStyle(gXHighlightBox->GetFillStyle());
4005 }
4006 gYHighlightBox->SetX1(hbx1);
4007 gYHighlightBox->SetX2(hbx2);
4008 gYHighlightBox->SetY1(hby1);
4009 gYHighlightBox->SetY2(hby2);
4010 gYHighlightBox->Paint();
4011}
4012
4013////////////////////////////////////////////////////////////////////////////////
4014/// Return `kTRUE` if the cell `ix`, `iy` is inside one of the graphical cuts.
4015
4017{
4018
4019 for (Int_t i=0;i<fNcuts;i++) {
4022 if (fCutsOpt[i] > 0) {
4023 if (!fCuts[i]->IsInside(x,y)) return kFALSE;
4024 } else {
4025 if (fCuts[i]->IsInside(x,y)) return kFALSE;
4026 }
4027 }
4028 return kTRUE;
4029}
4030
4031////////////////////////////////////////////////////////////////////////////////
4032/// Return `kTRUE` if the point `x`, `y` is inside one of the graphical cuts.
4033
4035{
4036
4037 for (Int_t i=0;i<fNcuts;i++) {
4038 if (fCutsOpt[i] > 0) {
4039 if (!fCuts[i]->IsInside(x,y)) return kFALSE;
4040 } else {
4041 if (fCuts[i]->IsInside(x,y)) return kFALSE;
4042 }
4043 }
4044 return kTRUE;
4045}
4046
4047////////////////////////////////////////////////////////////////////////////////
4048/// Decode string `choptin` and fill Hoption structure.
4049
4051{
4052
4053 char *l;
4054 char chopt[128];
4056 strlcpy(chopt,choptin,128);
4059
4067 Hoption.Candle = 0;
4068 Hoption.Polar = 0;
4069
4070 // special 2D options
4071 Hoption.List = 0;
4072 Hoption.Zscale = 0;
4073 Hoption.FrontBox = 1;
4074 Hoption.BackBox = 1;
4076
4077 Hoption.Zero = 0;
4078
4080
4081 //check for graphical cuts
4082 MakeCuts(chopt);
4083
4084 for (Int_t i=0;i<nch;i++) chopt[i] = toupper(chopt[i]);
4085 if (hdim > 1) Hoption.Color = 1; // Default drawing option for 2D and 3D histograms
4086 if (!nch) Hoption.Hist = 1;
4087 if (fFunctions->First()) Hoption.Func = 1;
4088 if (fH->GetSumw2N() && hdim == 1) Hoption.Error = 2;
4089
4090 char *l1 = strstr(chopt,"PFC"); // Automatic Fill Color
4091 char *l2 = strstr(chopt,"PLC"); // Automatic Line Color
4092 char *l3 = strstr(chopt,"PMC"); // Automatic Marker Color
4093 if (l1 || l2 || l3) {
4094 Int_t i = gPad->NextPaletteColor();
4095 if (l1) {memcpy(l1," ",3); fH->SetFillColor(i);}
4096 if (l2) {memcpy(l2," ",3); fH->SetLineColor(i);}
4097 if (l3) {memcpy(l3," ",3); fH->SetMarkerColor(i);}
4098 Hoption.Hist = 1; // Make sure something is drawn in case there is no drawing option specified.
4099 }
4100
4101 l = strstr(chopt,"MIN0");
4102 if (l) {
4103 Hoption.MinimumZero = 1;
4104 memcpy(l," ",4);
4105 }
4106
4107 l = strstr(chopt,"SPEC");
4108 if (l) {
4109 Hoption.Color = 0;
4110 memcpy(l," ",4);
4111 Int_t bs=0;
4112 l = strstr(chopt,"BF(");
4113 if (l) {
4114 if (sscanf(&l[3],"%d",&bs) > 0) {
4115 Int_t i=0;
4116 while (l[i]!=')') {
4117 l[i] = ' ';
4118 i++;
4119 }
4120 l[i] = ' ';
4121 }
4122 }
4123 Hoption.Spec = TMath::Max(1600,bs);
4124 return 1;
4125 }
4126
4127 l = strstr(chopt,"GL");
4128 if (l) {
4129 memcpy(l," ",2);
4130 }
4131 l = strstr(chopt,"X+");
4132 if (l) {
4133 Hoption.AxisPos = 10;
4134 memcpy(l," ",2);
4135 }
4136 l = strstr(chopt,"Y+");
4137 if (l) {
4138 Hoption.AxisPos += 1;
4139 memcpy(l," ",2);
4140 }
4141 if ((Hoption.AxisPos == 10 || Hoption.AxisPos == 1) && (nch == 2)) Hoption.Hist = 1;
4142 if (Hoption.AxisPos == 11 && nch == 4) Hoption.Hist = 1;
4143
4144 l = strstr(chopt,"SAMES");
4145 if (l) {
4146 if (nch == 5) Hoption.Hist = 1;
4147 Hoption.Same = 2;
4148 memcpy(l," ",5);
4149 if (l[5] == '0') { Hoption.Same += 10; l[5] = ' '; }
4150 }
4151 l = strstr(chopt,"SAME");
4152 if (l) {
4153 if (nch == 4) Hoption.Hist = 1;
4154 Hoption.Same = 1;
4155 memcpy(l," ",4);
4156 if (l[4] == '0') { Hoption.Same += 10; l[4] = ' '; }
4157 }
4158
4159 l = strstr(chopt,"SCAT");
4160 if (l) {
4161 Warning("MakeChopt","option SCAT is deprecated.");
4162 Hoption.Scat = 1;
4163 memcpy(l," ",4);
4164 Hoption.Color = 0;
4165 }
4166
4167 l = strstr(chopt,"PIE");
4168 if (l) {
4169 Hoption.Pie = 1;
4170 memcpy(l," ",3);
4171 }
4172
4173
4174 l = strstr(chopt,"CANDLE");
4175 if (l) {
4177 Hoption.Candle = candle.ParseOption(l);
4178 Hoption.Color = 0;
4179 }
4180
4181 l = strstr(chopt,"VIOLIN");
4182 if (l) {
4184 Hoption.Candle = candle.ParseOption(l);
4185 Hoption.Color = 0;
4186 }
4187
4188 l = strstr(chopt,"LEGO");
4189 if (l) {
4190 Hoption.Color = 0;
4191 Hoption.Lego = 1; memcpy(l," ",4);
4192 if (l[4] == '1') { Hoption.Lego = 11; l[4] = ' '; }
4193 if (l[4] == '2') { Hoption.Lego = 12; l[4] = ' '; }
4194 if (l[4] == '3') { Hoption.Lego = 13; l[4] = ' '; }
4195 if (l[4] == '4') { Hoption.Lego = 14; l[4] = ' '; }
4196 if (l[4] == '9') { Hoption.Lego = 19; l[4] = ' '; }
4197 l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4198 l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4199 l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4200 }
4201
4202 l = strstr(chopt,"SURF");
4203 if (l) {
4204 Hoption.Color = 0;
4205 Hoption.Surf = 1; memcpy(l," ",4);
4206 if (l[4] == '1') { Hoption.Surf = 11; l[4] = ' '; }
4207 if (l[4] == '2') { Hoption.Surf = 12; l[4] = ' '; }
4208 if (l[4] == '3') { Hoption.Surf = 13; l[4] = ' '; }
4209 if (l[4] == '4') { Hoption.Surf = 14; l[4] = ' '; }
4210 if (l[4] == '5') { Hoption.Surf = 15; l[4] = ' '; }
4211 if (l[4] == '6') { Hoption.Surf = 16; l[4] = ' '; }
4212 if (l[4] == '7') { Hoption.Surf = 17; l[4] = ' '; }
4213 l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4214 l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4215 }
4216
4217 l = strstr(chopt,"TF3");
4218 if (l) {
4219 memcpy(l," ",3);
4220 l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4221 l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4222 }
4223
4224 l = strstr(chopt,"ISO");
4225 if (l) {
4226 memcpy(l," ",3);
4227 l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4228 l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4229 Hoption.Color = 0;
4230 }
4231
4232 l = strstr(chopt,"LIST"); if (l) { Hoption.List = 1; memcpy(l," ",4);}
4233
4234 l = strstr(chopt,"CONT");
4235 if (l) {
4236 memcpy(l," ",4);
4237 if (hdim>1) {
4238 Hoption.Color = 0;
4239 Hoption.Contour = 1;
4240 if (l[4] == '1') { Hoption.Contour = 11; l[4] = ' '; }
4241 if (l[4] == '2') { Hoption.Contour = 12; l[4] = ' '; }
4242 if (l[4] == '3') { Hoption.Contour = 13; l[4] = ' '; }
4243 if (l[4] == '4') { Hoption.Contour = 14; l[4] = ' '; }
4244 if (l[4] == '5') { Hoption.Contour = 15; l[4] = ' '; }
4245 } else {
4246 Hoption.Hist = 1;
4247 }
4248 }
4249 l = strstr(chopt,"HBAR");
4250 if (l) {
4251 Hoption.Hist = 0;
4252 Hoption.Bar = 20; memcpy(l," ",4);
4253 if (l[4] == '1') { Hoption.Bar = 21; l[4] = ' '; }
4254 if (l[4] == '2') { Hoption.Bar = 22; l[4] = ' '; }
4255 if (l[4] == '3') { Hoption.Bar = 23; l[4] = ' '; }
4256 if (l[4] == '4') { Hoption.Bar = 24; l[4] = ' '; }
4257 }
4258 l = strstr(chopt,"BAR");
4259 if (l) {
4260 Hoption.Hist = 0;
4261 Hoption.Bar = 10; memcpy(l," ",3);
4262 if (l[3] == '1') { Hoption.Bar = 11; l[3] = ' '; }
4263 if (l[3] == '2') { Hoption.Bar = 12; l[3] = ' '; }
4264 if (l[3] == '3') { Hoption.Bar = 13; l[3] = ' '; }
4265 if (l[3] == '4') { Hoption.Bar = 14; l[3] = ' '; }
4266 }
4267
4268 l = strstr(chopt,"ARR" );
4269 if (l) {
4270 memcpy(l," ", 3);
4271 if (hdim>1) {
4272 Hoption.Arrow = 1;
4273 Hoption.Color = 0;
4274 l = strstr(chopt,"COL"); if (l) { Hoption.Arrow = 2; memcpy(l," ",3); }
4275 l = strstr(chopt,"Z"); if (l) { Hoption.Zscale = 1; memcpy(l," ",1); }
4276 } else {
4277 Hoption.Hist = 1;
4278 }
4279 }
4280 l = strstr(chopt,"BOX" );
4281 if (l) {
4282 memcpy(l," ", 3);
4283 if (hdim>1) {
4284 Hoption.Color = 0;
4285 Hoption.Box = 1;
4286 if (l[3] == '1') { Hoption.Box = 11; l[3] = ' '; }
4287 if (l[3] == '2') { Hoption.Box = 12; l[3] = ' '; }
4288 if (l[3] == '3') { Hoption.Box = 13; l[3] = ' '; }
4289 } else {
4290 Hoption.Hist = 1;
4291 }
4292 }
4293 l = strstr(chopt,"TEXT");
4294 if (l) {
4295 Int_t angle;
4296 if (sscanf(&l[4],"%d",&angle) > 0) {
4297 if (angle < 0) angle=0;
4298 if (angle > 90) angle=90;
4299 Hoption.Text = 1000+angle;
4300 } else {
4301 Hoption.Text = 1;
4302 }
4303 memcpy(l," ", 4);
4304 l = strstr(chopt,"N");
4305 if (l && fH->InheritsFrom(TH2Poly::Class())) Hoption.Text = 3000 + (Hoption.Text != 1 ? Hoption.Text : 0);
4306 Hoption.Color = 0;
4307 }
4308 l = strstr(chopt,"COLZ");
4309 if (l) {
4310 memcpy(l," ",4);
4311 if (hdim > 1) {
4313 Hoption.Color = 1;
4314 Hoption.Zscale = 1;
4315 if (l[4] == '2') { Hoption.Color = 3; l[4] = ' '; }
4316 l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4317 l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); }
4318 } else {
4319 Hoption.Hist = 1;
4320 }
4321 }
4322 l = strstr(chopt,"COL" );
4323 if (l) {
4324 memcpy(l," ", 3);
4325 if (hdim > 1) {
4327 Hoption.Color = 1;
4328 if (l[3] == '2') { Hoption.Color = 3; l[3] = ' '; }
4329 l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4330 l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); }
4331 } else {
4332 Hoption.Hist = 1;
4333 }
4334 }
4335 l = strstr(chopt,"FUNC"); if (l) { Hoption.Func = 2; memcpy(l," ",4); Hoption.Hist = 0; }
4336 l = strstr(chopt,"HIST"); if (l) { Hoption.Hist = 2; memcpy(l," ",4); Hoption.Func = 0; Hoption.Error = 0;}
4337 l = strstr(chopt,"AXIS"); if (l) { Hoption.Axis = 1; memcpy(l," ",4); }
4338 l = strstr(chopt,"AXIG"); if (l) { Hoption.Axis = 2; memcpy(l," ",4); }
4339 l = strstr(chopt,"SCAT"); if (l) { Hoption.Scat = 1; memcpy(l," ",4); }
4340 l = strstr(chopt,"POLN"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 3; memcpy(l," ",4); }
4341 l = strstr(chopt,"POLF"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 2; memcpy(l," ",4); }
4342 l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 1; memcpy(l," ",3); }
4343 l = strstr(chopt,"CYL"); if (l) { Hoption.System = kCYLINDRICAL; memcpy(l," ",3); }
4344 l = strstr(chopt,"SPH"); if (l) { Hoption.System = kSPHERICAL; memcpy(l," ",3); }
4345 l = strstr(chopt,"PSR"); if (l) { Hoption.System = kRAPIDITY; memcpy(l," ",3); }
4346
4347 l = strstr(chopt,"TRI");
4348 if (l) {
4349 if (!explicitColor) Hoption.Color = 0;
4350 Hoption.Tri = 1; memcpy(l," ",3);
4351 l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4352 l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4353 l = strstr(chopt,"ERR"); if (l) memcpy(l," ",3);
4354 }
4355
4356 l = strstr(chopt,"AITOFF");
4357 if (l) {
4358 Hoption.Proj = 1; memcpy(l," ",6); //Aitoff projection
4359 }
4360 l = strstr(chopt,"MERCATOR");
4361 if (l) {
4362 Hoption.Proj = 2; memcpy(l," ",8); //Mercator projection
4363 }
4364 l = strstr(chopt,"SINUSOIDAL");
4365 if (l) {
4366 Hoption.Proj = 3; memcpy(l," ",10); //Sinusoidal projection
4367 }
4368 l = strstr(chopt,"PARABOLIC");
4369 if (l) {
4370 Hoption.Proj = 4; memcpy(l," ",9); //Parabolic projection
4371 }
4372 l = strstr(chopt,"MOLLWEIDE");
4373 if (l) {
4374 Hoption.Proj = 5; memcpy(l," ",9); //Mollweide projection
4375 }
4376 if (Hoption.Proj > 0) {
4377 if (!explicitColor) Hoption.Color = 0;
4378 Hoption.Contour = 14;
4379 }
4380
4381 if (strstr(chopt,"A")) Hoption.Axis = -1;
4382 if (strstr(chopt,"B")) Hoption.Bar = 1;
4383 if (strstr(chopt,"C") && !strstr(chopt,"CJUST")) { Hoption.Curve =1; Hoption.Hist = -1;}
4384 if (strstr(chopt,"F")) Hoption.Fill =1;
4385 if (strstr(chopt,"][")) {Hoption.Off =1; Hoption.Hist =1;}
4386 if (strstr(chopt,"F2")) Hoption.Fill =2;
4387 if (strstr(chopt,"L")) { Hoption.Line =1; Hoption.Hist = -1;}
4388 if (strstr(chopt,"P")) { Hoption.Mark =1; Hoption.Hist = -1;}
4389 if (strstr(chopt,"Z")) Hoption.Zscale =1;
4390 if (strstr(chopt,"*")) Hoption.Star =1;
4391 if (strstr(chopt,"H")) Hoption.Hist =2;
4392 if (strstr(chopt,"P0")) Hoption.Mark =10;
4393
4394 if (fH->InheritsFrom(TH2Poly::Class())) {
4396 }
4397
4398 if (strstr(chopt,"E")) {
4399 if (hdim == 1) {
4400 Hoption.Error = 1;
4401 if (strstr(chopt,"E1")) Hoption.Error = 11;
4402 if (strstr(chopt,"E2")) Hoption.Error = 12;
4403 if (strstr(chopt,"E3")) Hoption.Error = 13;
4404 if (strstr(chopt,"E4")) Hoption.Error = 14;
4405 if (strstr(chopt,"E5")) Hoption.Error = 15;
4406 if (strstr(chopt,"E6")) Hoption.Error = 16;
4407 if (strstr(chopt,"E0")) Hoption.Error += 40;
4408 if (strstr(chopt,"X0")) {
4409 if (Hoption.Error == 1) Hoption.Error += 20;
4410 Hoption.Error += 10;
4411 }
4413 Hoption.Text += 2000;
4414 Hoption.Error = 0;
4415 }
4416 } else {
4417 if (Hoption.Error == 0) {
4418 Hoption.Error = 100;
4419 if (!explicitColor) Hoption.Color = 0;
4420 }
4421 if (Hoption.Text) {
4422 Hoption.Text += 2000;
4423 Hoption.Error = 0;
4424 }
4425 }
4426 }
4427
4428 if (Hoption.Surf == 15) {
4430 Hoption.Surf = 13;
4431 Warning("MakeChopt","option SURF5 is not supported in Cartesian and Polar modes");
4432 }
4433 }
4434
4435 // Copy options from current style
4436 Hoption.Logx = gPad->GetLogx();
4437 Hoption.Logy = gPad->GetLogy();
4438 Hoption.Logz = gPad->GetLogz();
4439
4440 // Check options incompatibilities
4441 if (Hoption.Bar == 1) Hoption.Hist = -1;
4442 return 1;
4443}
4444
4445////////////////////////////////////////////////////////////////////////////////
4446/// Decode string `choptin` and fill Graphical cuts structure.
4447
4449{
4450
4451 fNcuts = 0;
4452 char *left = (char*)strchr(choptin,'[');
4453 if (!left) return 0;
4454 char *right = (char*)strchr(choptin,']');
4455 if (!right) return 0;
4456 Int_t nch = right-left;
4457 if (nch < 2) return 0;
4458 char *cuts = left+1;
4459 *right = 0;
4460 char *comma, *minus;
4461 Int_t i;
4462 while (true) {
4463 comma = strchr(cuts,',');
4464 if (comma) *comma = 0;
4465 minus = strchr(cuts,'-');
4466 if (minus) cuts = minus+1;
4467 while (*cuts == ' ') cuts++;
4468 Int_t nc = strlen(cuts);
4469 while (cuts[nc-1] == ' ') {cuts[nc-1] = 0; nc--;}
4470 TIter next(gROOT->GetListOfSpecials());
4471 TCutG *cut=nullptr;
4472 TObject *obj;
4473 while ((obj = next())) {
4474 if (!obj->InheritsFrom(TCutG::Class())) continue;
4475 if (strcmp(obj->GetName(),cuts)) continue;
4476 cut = (TCutG*)obj;
4477 break;
4478 }
4479 if (cut) {
4480 fCuts[fNcuts] = cut;
4481 fCutsOpt[fNcuts] = 1;
4482 if (minus) fCutsOpt[fNcuts] = -1;
4483 fNcuts++;
4484 }
4485 if (!comma) break;
4486 cuts = comma+1;
4487 }
4488 for (i=0;i<=nch;i++) left[i] = ' ';
4489 return fNcuts;
4490}
4491
4492////////////////////////////////////////////////////////////////////////////////
4493/// [Control routine to paint any kind of histograms](\ref HP00)
4494
4496{
4497
4498 if (fH->GetBuffer()) fH->BufferEmpty(-1);
4499
4500 //For iOS: put the histogram on the top of stack of pickable objects.
4502
4503 gPad->SetVertical(kTRUE);
4504
4506 gCurrentHist = fH;
4507 TH1 *hsave = fH;
4509
4510 if (!MakeChopt(option)) return; //check options and fill Hoption structure
4511
4512 // Paint using TSpectrum2Painter
4513 if (Hoption.Spec) {
4514 if (!TableInit()) return;
4515 if (!TClass::GetClass("TSpectrum2Painter")) gSystem->Load("libSpectrumPainter");
4516 gROOT->ProcessLineFast(TString::Format("TSpectrum2Painter::PaintSpectrum((TH2F*)0x%zx,\"%s\",%d)",
4517 (size_t)fH, option, Hoption.Spec).Data());
4518 return;
4519 }
4520
4521 // Deflate the labels in case of alphanumeric labels
4525
4526 if (Hoption.Pie) {
4527 if (fH->GetDimension() == 1) {
4528 if (!fPie)
4529 fPie = std::make_unique<TPie>(fH);
4530 fPie->Paint(option);
4531 } else {
4532 Error("Paint", "Option PIE is for 1D histograms only");
4533 }
4534 return;
4535 } else {
4536 fPie.reset();
4537 }
4538
4539 fXbuf.resize(kNMAX);
4540 fYbuf.resize(kNMAX);
4541 if (fH->GetDimension() > 2) {
4542 PaintH3(option);
4544 if (Hoption.Func) {
4549 Hoption = hoptsave;
4550 Hparam = hparsave;
4551 }
4553 fXbuf.clear();
4554 fYbuf.clear();
4555 return;
4556 }
4557 TView *view = gPad->GetView();
4558 if (view) {
4559 if (!Hoption.Lego && !Hoption.Surf && !Hoption.Tri) {
4560 delete view;
4561 gPad->SetView(nullptr);
4562 }
4563 }
4564 if (fH->GetDimension() > 1 || Hoption.Lego || Hoption.Surf) {
4565 // In case of 1D histogram, Z axis becomes Y axis.
4566 Int_t logysav=0, logzsav=0;
4567 if (fH->GetDimension() == 1) {
4570 Hoption.Logz = 0;
4571 if (Hoption.Logy) {
4572 Hoption.Logz = 1;
4573 Hoption.Logy = 0;
4574 }
4575 }
4577 if (Hoption.Func) {
4582 Hoption = hoptsave;
4583 Hparam = hparsave;
4584 }
4587 fXbuf.clear();
4588 fYbuf.clear();
4589 if (fH->GetDimension() == 1) {
4592 }
4593 return;
4594 }
4595
4596 if (Hoption.Bar >= 20) {
4598 fXbuf.clear();
4599 fYbuf.clear();
4600 return;
4601 }
4602
4603 gPad->RangeAxisChanged(); //emit RangeAxisChanged() signal to sync axes
4604 // fill Hparam structure with histo parameters
4605 if (!PaintInit()) {
4606 fXbuf.clear();
4607 fYbuf.clear();
4608 return;
4609 }
4610
4611 // Picture surround (if new page) and page number (if requested).
4612 // Histogram surround (if not option "Same").
4613 PaintFrame();
4614
4615 // Paint histogram axis only
4616 Bool_t gridx = gPad->GetGridx();
4617 Bool_t gridy = gPad->GetGridy();
4618 if (Hoption.Axis > 0) {
4619 if (Hoption.Axis > 1) PaintAxis(kTRUE); //axis with grid
4620 else {
4621 if (gridx) gPad->SetGridx(0);
4622 if (gridy) gPad->SetGridy(0);
4624 if (gridx) gPad->SetGridx(1);
4625 if (gridy) gPad->SetGridy(1);
4626 }
4627 if ((Hoption.Same%10) ==1) Hoption.Same += 1;
4628 goto paintstat;
4629 }
4630 if (gridx || gridy) PaintAxis(kTRUE); // Draw the grid only
4631
4632 // test for options BAR or HBAR
4633 if (Hoption.Bar >= 10) {
4635 }
4636
4637 // do not draw histogram if error bars required
4638 if (!Hoption.Error) {
4639 if (Hoption.Hist && Hoption.Bar<10) PaintHist(option);
4640 }
4641
4642 // test for error bars or option E
4643 if (Hoption.Error) {
4645 if (Hoption.Hist == 2) PaintHist(option);
4646 }
4647
4649
4650 // test for associated function
4651 if (Hoption.Func) {
4656 Hoption = hoptsave;
4657 Hparam = hparsave;
4658 }
4659
4660 if (gridx) gPad->SetGridx(0);
4661 if (gridy) gPad->SetGridy(0);
4663 if (gridx) gPad->SetGridx(1);
4664 if (gridy) gPad->SetGridy(1);
4665
4666 PaintTitle(); // Draw histogram title
4667
4668 // Draw box with histogram statistics and/or fit parameters
4669paintstat:
4670 if ((Hoption.Same%10) != 1 && !fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
4671 TIter next(fFunctions);
4672 TObject *obj = nullptr;
4673 while ((obj = next())) {
4674 if (obj->InheritsFrom(TF1::Class())) break;
4675 obj = nullptr;
4676 }
4677
4678 //Stat is painted twice (first, it will be in canvas' list of primitives),
4679 //second, it will be here, this is not required on iOS.
4680 //Condition is ALWAYS true on a platform different from iOS.
4681 if (!gPad->PadInSelectionMode() && !gPad->PadInHighlightMode())
4682 PaintStat(gStyle->GetOptStat(),(TF1*)obj);
4683 }
4686 fXbuf.clear();
4687 fYbuf.clear();
4688}
4689
4690////////////////////////////////////////////////////////////////////////////////
4691/// [Control function to draw a table as an arrow plot](\ref HP12)
4692
4694{
4696 Double_t dx, dy, x1, x2, y1, y2, xc, yc, dxn, dyn;
4699 Double_t xrg = gPad->GetUxmin();
4700 Double_t yrg = gPad->GetUymin();
4701 Double_t xln = gPad->GetUxmax() - xrg;
4702 Double_t yln = gPad->GetUymax() - yrg;
4703 Double_t cx = (xln/Double_t(ncx))/2.;
4704 Double_t cy = (yln/Double_t(ncy))/2.;
4705 Double_t dn = 1.E-30;
4706
4707 auto arrow = new TArrow();
4708 arrow->SetAngle(30);
4709 arrow->SetFillStyle(1001);
4710 arrow->SetFillColor(fH->GetLineColor());
4711 arrow->SetLineColor(fH->GetLineColor());
4712 arrow->SetLineWidth(fH->GetLineWidth());
4713
4714 // Initialize the levels on the Z axis
4715 Int_t ncolors=0, ndivz=0;
4716 Double_t scale=0.;
4717 if (Hoption.Arrow>1) {
4719 Int_t ndiv = fH->GetContour();
4720 if (ndiv == 0 ) {
4721 ndiv = gStyle->GetNumberContours();
4722 fH->SetContour(ndiv);
4723 }
4724 ndivz = TMath::Abs(ndiv);
4725 if (!fH->TestBit(TH1::kUserContour)) fH->SetContour(ndiv);
4727 }
4728
4729 for (Int_t id=1;id<=2;id++) {
4730 for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
4733 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
4734 xk = fXaxis->GetBinLowEdge(i);
4735 xstep = fXaxis->GetBinWidth(i);
4736 if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
4737 if (i == Hparam.xfirst) {
4738 dx = fH->GetBinContent(i+1, j) - fH->GetBinContent(i, j);
4739 } else if (i == Hparam.xlast) {
4740 dx = fH->GetBinContent(i, j) - fH->GetBinContent(i-1, j);
4741 } else {
4742 dx = 0.5*(fH->GetBinContent(i+1, j) - fH->GetBinContent(i-1, j));
4743 }
4744 if (j == Hparam.yfirst) {
4745 dy = fH->GetBinContent(i, j+1) - fH->GetBinContent(i, j);
4746 } else if (j == Hparam.ylast) {
4747 dy = fH->GetBinContent(i, j) - fH->GetBinContent(i, j-1);
4748 } else {
4749 dy = 0.5*(fH->GetBinContent(i, j+1) - fH->GetBinContent(i, j-1));
4750 }
4751 if (id == 1) {
4754 } else if (id == 2) {
4755 xc = xrg + xln*(Double_t(i - Hparam.xfirst+1)-0.5)/Double_t(ncx);
4756 dxn = cx*dx/dn;
4757 x1 = xc - dxn;
4758 x2 = xc + dxn;
4759 yc = yrg + yln*(Double_t(j - Hparam.yfirst+1)-0.5)/Double_t(ncy);
4760 dyn = cy*dy/dn;
4761 y1 = yc - dyn;
4762 y2 = yc + dyn;
4763 if (Hoption.Arrow>1) {
4764 int color = Int_t(0.01+(fH->GetBinContent(i, j)-fH->GetMinimum())*scale);
4765 Int_t theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz));
4766 if (theColor > ncolors-1) theColor = ncolors-1;
4767 arrow->SetFillColor(gStyle->GetColorPalette(theColor));
4768 arrow->SetLineColor(gStyle->GetColorPalette(theColor));
4769 }
4770 if (TMath::Abs(x2-x1) > 0. || TMath::Abs(y2-y1) > 0.) {
4771 arrow->PaintArrow(x1, y1, x2, y2, 0.015, "|>");
4772 } else {
4773 arrow->PaintArrow(x1, y1, x2, y2, 0.005, "|>");
4774 }
4775 }
4776 }
4777 }
4778 }
4779
4781}
4782
4783////////////////////////////////////////////////////////////////////////////////
4784/// Draw axis (2D case) of an histogram.
4785///
4786/// If `drawGridOnly` is `TRUE`, only the grid is painted (if needed). This allows
4787/// to draw the grid and the axis separately. In `THistPainter::Paint` this
4788/// feature is used to make sure that the grid is drawn in the background and
4789/// the axis tick marks in the foreground of the pad.
4790
4792{
4793
4794 //On iOS, grid should not be pickable and can not be highlighted.
4795 //Condition is never true on a platform different from iOS.
4796 if (drawGridOnly && (gPad->PadInHighlightMode() || gPad->PadInSelectionMode()))
4797 return;
4798
4799 if (Hoption.Axis == -1) return;
4800 if (Hoption.Same && Hoption.Axis <= 0) return;
4801
4802 // Repainting alphanumeric labels axis on a plot done with
4803 // the option HBAR (horizontal) needs some adjustments.
4804 TAxis *xaxis = nullptr;
4805 TAxis *yaxis = nullptr;
4806 if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
4807 if (fXaxis->GetLabels() || fYaxis->GetLabels()) { // One axis has alphanumeric labels
4808 TIter next(gPad->GetListOfPrimitives());
4809 TObject *obj;
4810 // Check if the first TH1 of THStack in the pad is drawn with the option HBAR
4811 while ((obj = next())) {
4812 if (!obj->InheritsFrom(TH1::Class()) &&
4813 !obj->InheritsFrom(THStack::Class())) continue;
4814 TString opt = obj->GetDrawOption();
4815 opt.ToLower();
4816 // if drawn with HBAR, the axis should be inverted and the pad set to horizontal
4817 if (strstr(opt,"hbar")) {
4818 gPad->SetVertical(kFALSE);
4819 xaxis = fXaxis;
4820 yaxis = fYaxis;
4821 if (!strcmp(xaxis->GetName(),"xaxis")) {
4822 fXaxis = yaxis;
4823 fYaxis = xaxis;
4824 }
4825 }
4826 break;
4827 }
4828 }
4829 }
4830
4831 static char chopt[10] = "";
4832 Double_t gridl = 0;
4833 Int_t ndiv, ndivx, ndivy, nx1, nx2, ndivsave;
4834 Int_t useHparam = 0;
4838
4839 Double_t axmin = gPad->GetUxmin();
4840 Double_t axmax = gPad->GetUxmax();
4841 Double_t aymin = gPad->GetUymin();
4842 Double_t aymax = gPad->GetUymax();
4843 char *cw = nullptr;
4844 TGaxis axis;
4845
4846 // In case of option 'cont4' or in case of option 'same' over a 'cont4 plot'
4847 // Hparam must be use for the axis limits.
4848 if (Hoption.Contour == 14) useHparam = 1;
4849 if (Hoption.Same) {
4850 TObject *obj;
4851 TIter next(gPad->GetListOfPrimitives());
4852 while ((obj=next())) {
4853 if (strstr(obj->GetDrawOption(),"cont4")) {
4854 useHparam = 1;
4855 break;
4856 }
4857 }
4858 }
4859
4860 // Paint X axis
4861
4862 //To make X-axis selectable on iOS device.
4863 if (gPad->PadInSelectionMode())
4864 gPad->PushSelectableObject(fXaxis);
4865
4866 //This condition is ALWAYS true, unless it works on iOS (can be false on iOS).
4867 if (gPad->PadInSelectionMode() || !gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && gPad->GetSelected() == fXaxis)) {
4869 if (ndivx > 1000) {
4870 nx2 = ndivx/100;
4871 nx1 = TMath::Max(1, ndivx%100);
4872 ndivx = 100*nx2 + Int_t(Float_t(nx1)*gPad->GetAbsWNDC());
4873 }
4874 axis.SetTextAngle(0);
4876
4877 chopt[0] = 0;
4878 strlcat(chopt, "SDH",10);
4879 if (ndivx < 0) strlcat(chopt, "N",10);
4880 if (gPad->GetGridx()) {
4881 gridl = (aymax-aymin)/(gPad->GetY2() - gPad->GetY1());
4882 strlcat(chopt, "W",10);
4883 }
4884
4885 // Define X-Axis limits
4886 if (Hoption.Logx) {
4887 strlcat(chopt, "G",10);
4888 ndiv = TMath::Abs(ndivx);
4889 if (useHparam) {
4892 } else {
4893 umin = TMath::Power(10,axmin);
4894 umax = TMath::Power(10,axmax);
4895 }
4896 } else {
4897 ndiv = TMath::Abs(ndivx);
4898 if (useHparam) {
4899 umin = Hparam.xmin;
4900 umax = Hparam.xmax;
4901 } else {
4902 umin = axmin;
4903 umax = axmax;
4904 }
4905 }
4906
4907 // Display axis as time
4908 if (fXaxis->GetTimeDisplay()) {
4909 strlcat(chopt,"t",10);
4910 if (strlen(fXaxis->GetTimeFormatOnly()) == 0) {
4912 }
4913 }
4914
4915 // The main X axis can be on the bottom or on the top of the pad
4917 if (xAxisPos == 1) {
4918 // Main X axis top
4919 xAxisYPos1 = aymax;
4920 xAxisYPos2 = aymin;
4921 } else {
4922 // Main X axis bottom
4923 xAxisYPos1 = aymin;
4924 xAxisYPos2 = aymax;
4925 }
4926
4927 // Paint the main X axis (always)
4928 uminsave = umin;
4929 umaxsave = umax;
4930 ndivsave = ndiv;
4931 axis.SetOption(chopt);
4932 if (xAxisPos) {
4933 strlcat(chopt, "-",10);
4934 gridl = -gridl;
4935 }
4936 if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
4937 axis.SetLabelSize(0.);
4938 axis.SetTitle("");
4939 }
4942 umin, umax, ndiv, chopt, gridl, drawGridOnly);
4943
4944 // Paint additional X axis (if needed)
4945 // On iOS, this additional X axis is neither pickable, nor highlighted.
4946 // Additional checks PadInSelectionMode etc. does not effect non-iOS platform.
4947 if (gPad->GetTickx() && !gPad->PadInSelectionMode() && !gPad->PadInHighlightMode()) {
4948 if (xAxisPos) {
4949 cw=strstr(chopt,"-");
4950 *cw='z';
4951 } else {
4952 strlcat(chopt, "-",10);
4953 }
4954 if (gPad->GetTickx() < 2) strlcat(chopt, "U",10);
4955 if ((cw=strstr(chopt,"W"))) *cw='z';
4956 axis.SetTitle("");
4960 }
4961 }//End of "if pad in selection mode etc".
4962
4963 // Paint Y axis
4964 //On iOS, Y axis must pushed into the stack of selectable objects.
4965 if (gPad->PadInSelectionMode())
4966 gPad->PushSelectableObject(fYaxis);
4967
4968 //This conditions is ALWAYS true on a platform, different from iOS (on iOS can be true, can be false).
4969 if (gPad->PadInSelectionMode() || !gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && gPad->GetSelected() == fYaxis)) {
4972
4973 chopt[0] = 0;
4974 strlcat(chopt, "SDH",10);
4975 if (ndivy < 0) strlcat(chopt, "N",10);
4976 if (gPad->GetGridy()) {
4977 gridl = (axmax-axmin)/(gPad->GetX2() - gPad->GetX1());
4978 strlcat(chopt, "W",10);
4979 }
4980
4981 // Define Y-Axis limits
4982 if (Hoption.Logy) {
4983 strlcat(chopt, "G",10);
4984 ndiv = TMath::Abs(ndivy);
4985 if (useHparam) {
4988 } else {
4989 umin = TMath::Power(10,aymin);
4990 umax = TMath::Power(10,aymax);
4991 }
4992 } else {
4993 ndiv = TMath::Abs(ndivy);
4994 if (useHparam) {
4995 umin = Hparam.ymin;
4996 umax = Hparam.ymax;
4997 } else {
4998 umin = aymin;
4999 umax = aymax;
5000 }
5001 }
5002
5003 // Display axis as time
5004 if (fYaxis->GetTimeDisplay()) {
5005 strlcat(chopt,"t",10);
5006 if (strlen(fYaxis->GetTimeFormatOnly()) == 0) {
5008 }
5009 }
5010
5011 // The main Y axis can be on the left or on the right of the pad
5013 if (yAxisPos == 1) {
5014 // Main Y axis left
5015 yAxisXPos1 = axmax;
5016 yAxisXPos2 = axmin;
5017 } else {
5018 // Main Y axis right
5019 yAxisXPos1 = axmin;
5020 yAxisXPos2 = axmax;
5021 }
5022
5023 // Paint the main Y axis (always)
5024 uminsave = umin;
5025 umaxsave = umax;
5026 ndivsave = ndiv;
5027 axis.SetOption(chopt);
5028 if (yAxisPos) {
5029 strlcat(chopt, "+L",10);
5030 gridl = -gridl;
5031 }
5032 if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
5033 axis.SetLabelSize(0.);
5034 axis.SetTitle("");
5035 }
5038 umin, umax, ndiv, chopt, gridl, drawGridOnly);
5039
5040 // Paint the additional Y axis (if needed)
5041 // Additional checks for pad mode are required on iOS: this "second" axis is
5042 // neither pickable, nor highlighted. Additional checks have no effect on non-iOS platform.
5043 if (gPad->GetTicky() && !gPad->PadInSelectionMode() && !gPad->PadInHighlightMode()) {
5044 if (gPad->GetTicky() < 2) {
5045 strlcat(chopt, "U",10);
5047 } else {
5048 strlcat(chopt, "+L",10);
5049 }
5050 if ((cw=strstr(chopt,"W"))) *cw='z';
5051 axis.SetTitle("");
5055 }
5056 }//End of "if pad is in selection mode etc."
5057
5058 // Reset the axis if they have been inverted in case of option HBAR
5059 if (xaxis) {
5060 fXaxis = xaxis;
5061 fYaxis = yaxis;
5062 }
5063}
5064
5065////////////////////////////////////////////////////////////////////////////////
5066/// [Draw a bar-chart in a normal pad.](\ref HP10)
5067
5069{
5070
5071 Int_t bar = Hoption.Bar - 10;
5075 TBox box;
5077 if (hcolor == gPad->GetFrameFillColor()) ++hcolor;
5079 box.SetFillColor(hcolor);
5080 box.SetFillStyle(hstyle);
5081 box.SetLineStyle(fH->GetLineStyle());
5082 box.SetLineColor(fH->GetLineColor());
5083 box.SetLineWidth(fH->GetLineWidth());
5084 for (Int_t bin=fXaxis->GetFirst();bin<=fXaxis->GetLast();bin++) {
5085 y = fH->GetBinContent(bin);
5086 xmin = gPad->XtoPad(fXaxis->GetBinLowEdge(bin));
5087 xmax = gPad->XtoPad(fXaxis->GetBinUpEdge(bin));
5088 ymin = gPad->GetUymin();
5089 ymax = gPad->YtoPad(y);
5090 if (ymax < gPad->GetUymin()) continue;
5091 if (ymax > gPad->GetUymax()) ymax = gPad->GetUymax();
5092 if (ymin < gPad->GetUymin()) ymin = gPad->GetUymin();
5093 if (Hoption.MinimumZero && ymin < 0)
5094 ymin=TMath::Min(0.,gPad->GetUymax());
5095 w = (xmax-xmin)*width;
5096 xmin += offset*(xmax-xmin);
5097 xmax = xmin + w;
5098 if (bar < 1) {
5099 box.PaintBox(xmin,ymin,xmax,ymax);
5100 } else {
5101 umin = xmin + bar*(xmax-xmin)/10.;
5102 umax = xmax - bar*(xmax-xmin)/10.;
5103 box.SetFillColor(TColor::GetColorBright(hcolor)); //bright
5104 box.PaintBox(xmin,ymin,umin,ymax);
5105 box.SetFillColor(hcolor);
5106 box.PaintBox(umin,ymin,umax,ymax);
5107 box.SetFillColor(TColor::GetColorDark(hcolor)); //dark
5108 box.PaintBox(umax,ymin,xmax,ymax);
5109 }
5110 }
5111}
5112
5113////////////////////////////////////////////////////////////////////////////////
5114/// [Draw a bar char in a rotated pad (X vertical, Y horizontal)](\ref HP10)
5115
5117{
5118
5119 gPad->SetVertical(kFALSE);
5120
5121 PaintInitH();
5122
5123 TAxis *xaxis = fXaxis;
5124 TAxis *yaxis = fYaxis;
5125 if (!strcmp(xaxis->GetName(),"xaxis")) {
5126 fXaxis = yaxis;
5127 fYaxis = xaxis;
5128 }
5129
5130 PaintFrame();
5132
5133 Int_t bar = Hoption.Bar - 20;
5137 TBox box;
5139 if (hcolor == gPad->GetFrameFillColor()) ++hcolor;
5141 box.SetFillColor(hcolor);
5142 box.SetFillStyle(hstyle);
5143 box.SetLineStyle(fH->GetLineStyle());
5144 box.SetLineColor(fH->GetLineColor());
5145 box.SetLineWidth(fH->GetLineWidth());
5146 for (Int_t bin=fYaxis->GetFirst();bin<=fYaxis->GetLast();bin++) {
5147 ymin = gPad->YtoPad(fYaxis->GetBinLowEdge(bin));
5148 ymax = gPad->YtoPad(fYaxis->GetBinUpEdge(bin));
5149 xmin = gPad->GetUxmin();
5150 xmax = gPad->XtoPad(fH->GetBinContent(bin));
5151 if (xmax < gPad->GetUxmin()) continue;
5152 if (xmax > gPad->GetUxmax()) xmax = gPad->GetUxmax();
5153 if (xmin < gPad->GetUxmin()) xmin = gPad->GetUxmin();
5154 if (Hoption.MinimumZero && xmin < 0)
5155 xmin=TMath::Min(0.,gPad->GetUxmax());
5156 w = (ymax-ymin)*width;
5157 ymin += offset*(ymax-ymin);
5158 ymax = ymin + w;
5159 if (bar < 1) {
5160 box.PaintBox(xmin,ymin,xmax,ymax);
5161 } else {
5162 umin = ymin + bar*(ymax-ymin)/10.;
5163 umax = ymax - bar*(ymax-ymin)/10.;
5164 box.SetFillColor(TColor::GetColorDark(hcolor)); //dark
5165 box.PaintBox(xmin,ymin,xmax,umin);
5166 box.SetFillColor(hcolor);
5167 box.PaintBox(xmin,umin,xmax,umax);
5168 box.SetFillColor(TColor::GetColorBright(hcolor)); //bright
5169 box.PaintBox(xmin,umax,xmax,ymax);
5170 }
5171 }
5172
5173 PaintTitle();
5174
5175 // Draw box with histogram statistics and/or fit parameters
5176 if ((Hoption.Same%10) != 1 && !fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
5177 TIter next(fFunctions);
5178 TObject *obj = nullptr;
5179 while ((obj = next())) {
5180 if (obj->InheritsFrom(TF1::Class())) break;
5181 obj = nullptr;
5182 }
5183 PaintStat(gStyle->GetOptStat(),(TF1*)obj);
5184 }
5185
5186 fXaxis = xaxis;
5187 fYaxis = yaxis;
5188}
5189
5190////////////////////////////////////////////////////////////////////////////////
5191/// [Control function to draw a 2D histogram as a box plot](\ref HP13)
5192
5194{
5195
5198 if (fH->GetFillColor() == 0) fH->SetFillStyle(0);
5199 if (Hoption.Box == 11) fH->SetFillStyle(1001);
5200 fH->TAttLine::Modify();
5201 fH->TAttFill::Modify();
5202
5203 Double_t z, xk,xstep, yk, ystep, xcent, ycent, xlow, xup, ylow, yup;
5204 Double_t ux1 = gPad->PixeltoX(1);
5205 Double_t ux0 = gPad->PixeltoX(0);
5206 Double_t uy1 = gPad->PixeltoY(1);
5207 Double_t uy0 = gPad->PixeltoY(0);
5208 Double_t dxmin = 0.51*(gPad->PadtoX(ux1)-gPad->PadtoX(ux0));
5209 Double_t dymin = 0.51*(gPad->PadtoY(uy0)-gPad->PadtoY(uy1));
5210
5211 Double_t zmin = TMath::Max(fH->GetMinimum(),0.);
5214 Double_t zminlin = zmin, zmaxlin = zmax;
5215
5216 // In case of option SAME, zmin and zmax values are taken from the
5217 // first plotted 2D histogram.
5218 if (Hoption.Same > 0 && Hoption.Same < 10) {
5219 TH2 *h2;
5220 TIter next(gPad->GetListOfPrimitives());
5221 while ((h2 = (TH2 *)next())) {
5222 if (!h2->InheritsFrom(TH2::Class())) continue;
5223 zmin = TMath::Max(h2->GetMinimum(), 0.);
5224 zmax = TMath::Max(TMath::Abs(h2->GetMaximum()),
5225 TMath::Abs(h2->GetMinimum()));
5226 zminlin = zmin;
5227 zmaxlin = zmax;
5228 if (Hoption.Logz) {
5229 if (zmin <= 0) {
5230 zmin = TMath::Log10(zmax*0.001);
5231 } else {
5232 zmin = TMath::Log10(zmin);
5233 }
5234 zmax = TMath::Log10(zmax);
5235 }
5236 break;
5237 }
5238 } else {
5239 if (Hoption.Logz) {
5240 if (zmin > 0) {
5241 zmin = TMath::Log10(zmin);
5242 zmax = TMath::Log10(zmax);
5243 } else {
5244 return;
5245 }
5246 }
5247 }
5248
5249 Double_t zratio, dz = zmax - zmin;
5251 if (fH->GetMinimum()<0) kZminNeg = kTRUE;
5253
5254 // Define the dark and light colors the "button style" boxes.
5255 Color_t color = fH->GetFillColor();
5256 Color_t light=0, dark=0;
5257 if (Hoption.Box == 11) {
5259 dark = TColor::GetColorDark(color);
5260 }
5261
5262 // Loop over all the bins and draw the boxes
5263 for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
5266 ycent = 0.5*ystep;
5267 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
5268 Int_t bin = j*(fXaxis->GetNbins()+2) + i;
5269 xk = fXaxis->GetBinLowEdge(i);
5270 xstep = fXaxis->GetBinWidth(i);
5271 if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
5272 xcent = 0.5*xstep;
5274 kZNeg = kFALSE;
5275
5276 if (TMath::Abs(z) < zminlin) continue; // Can be the case with ...
5277 if (TMath::Abs(z) > zmaxlin) z = zmaxlin; // ... option Same
5278 if (kZminNeg && z==0) continue; // Do not draw empty bins if case of histo with negative bins.
5279
5280 if (z < 0) {
5281 if (Hoption.Logz) continue;
5282 z = -z;
5283 kZNeg = kTRUE;
5284 }
5285 if (Hoption.Logz) {
5286 if (z != 0) z = TMath::Log10(z);
5287 else z = zmin;
5288 }
5289
5290 if (dz == 0) continue;
5291 zratio = TMath::Sqrt((z-zmin)/dz);
5292 if (zratio == 0) continue;
5293
5294 xup = xcent*zratio + xk + xcent;
5295 xlow = 2*(xk + xcent) - xup;
5296 if (xup-xlow < dxmin) xup = xlow+dxmin;
5297 if (Hoption.Logx) {
5298 if (xup > 0) xup = TMath::Log10(xup);
5299 else continue;
5300 if (xlow > 0) xlow = TMath::Log10(xlow);
5301 else continue;
5302 }
5303
5304 yup = ycent*zratio + yk + ycent;
5305 ylow = 2*(yk + ycent) - yup;
5306 if (yup-ylow < dymin) yup = ylow+dymin;
5307 if (Hoption.Logy) {
5308 if (yup > 0) yup = TMath::Log10(yup);
5309 else continue;
5310 if (ylow > 0) ylow = TMath::Log10(ylow);
5311 else continue;
5312 }
5313
5314 xlow = TMath::Max(xlow, gPad->GetUxmin());
5315 ylow = TMath::Max(ylow, gPad->GetUymin());
5316 xup = TMath::Min(xup , gPad->GetUxmax());
5317 yup = TMath::Min(yup , gPad->GetUymax());
5318
5319 if (xlow >= xup) continue;
5320 if (ylow >= yup) continue;
5321
5322 if (Hoption.Box == 1) {
5323 fH->SetFillColor(color);
5324 fH->TAttFill::Modify();
5325 gPad->PaintBox(xlow, ylow, xup, yup);
5326 if (kZNeg) {
5327 gPad->PaintLine(xlow, ylow, xup, yup);
5328 gPad->PaintLine(xlow, yup, xup, ylow);
5329 }
5330 } else if (Hoption.Box == 11) {
5331 // Draw the center of the box
5332 fH->SetFillColor(color);
5333 fH->TAttFill::Modify();
5334 gPad->PaintBox(xlow, ylow, xup, yup);
5335
5336 // Draw top&left part of the box
5337 Double_t x[7], y[7];
5338 Double_t bwidth = 0.1;
5339 x[0] = xlow; y[0] = ylow;
5340 x[1] = xlow + bwidth*(xup-xlow); y[1] = ylow + bwidth*(yup-ylow);
5341 x[2] = x[1]; y[2] = yup - bwidth*(yup-ylow);
5342 x[3] = xup - bwidth*(xup-xlow); y[3] = y[2];
5343 x[4] = xup; y[4] = yup;
5344 x[5] = xlow; y[5] = yup;
5345 x[6] = xlow; y[6] = ylow;
5346 if (kZNeg) fH->SetFillColor(dark);
5347 else fH->SetFillColor(light);
5348 fH->TAttFill::Modify();
5349 gPad->PaintFillArea(7, x, y);
5350
5351 // Draw bottom&right part of the box
5352 x[0] = xlow; y[0] = ylow;
5353 x[1] = xlow + bwidth*(xup-xlow); y[1] = ylow + bwidth*(yup-ylow);
5354 x[2] = xup - bwidth*(xup-xlow); y[2] = y[1];
5355 x[3] = x[2]; y[3] = yup - bwidth*(yup-ylow);
5356 x[4] = xup; y[4] = yup;
5357 x[5] = xup; y[5] = ylow;
5358 x[6] = xlow; y[6] = ylow;
5359 if (kZNeg) fH->SetFillColor(light);
5360 else fH->SetFillColor(dark);
5361 fH->TAttFill::Modify();
5362 gPad->PaintFillArea(7, x, y);
5363 }
5364 }
5365 }
5366
5370 fH->TAttFill::Modify();
5371}
5372
5373
5374
5375////////////////////////////////////////////////////////////////////////////////
5376/// [Control function to draw a 2D histogram as a candle (box) plot or violin plot](\ref HP14)
5377
5379{
5380 TH1D *hproj = nullptr;
5381 TH2D *h2 = (TH2D*)fH;
5382
5385 myCandle.SetMarkerColor(fH->GetLineColor());
5386 myCandle.SetLineColor(fH->GetLineColor());
5387 myCandle.SetLineWidth(fH->GetLineWidth());
5388 myCandle.SetFillColor(fH->GetFillColor());
5389 myCandle.SetFillStyle(fH->GetFillStyle());
5390 myCandle.SetMarkerSize(fH->GetMarkerSize());
5391 myCandle.SetMarkerStyle(fH->GetMarkerStyle());
5393
5394 Bool_t swapXY = myCandle.IsHorizontal();
5395 const Double_t standardCandleWidth = 0.66;
5396 const Double_t standardHistoWidth = 0.8;
5397
5398 double allMaxContent = 0, allMaxIntegral = 0;
5399 if (myCandle.IsViolinScaled())
5401
5402 if (!swapXY) { // Vertical candle
5403 //Determining the slice with the maximum integral - if necessary
5404 if (myCandle.IsCandleScaled())
5405 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast; i++) {
5406 hproj = h2->ProjectionY("_px", i, i);
5407 if (hproj->Integral() > allMaxIntegral) allMaxIntegral = hproj->Integral();
5408 }
5409 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast; i++) {
5411 Double_t binWidth = fXaxis->GetBinWidth(i);
5412 hproj = h2->ProjectionY("_px", i, i);
5413 if (hproj->GetEntries() != 0) {
5415 Double_t offset = fH->GetBarOffset()*binWidth;
5416 double myMaxContent = hproj->GetBinContent(hproj->GetMaximumBin());
5417 double myIntegral = hproj->Integral();
5419 if (candleWidth > 0.999 && candleWidth < 1.001) {
5422 }
5423 if (Hoption.Logz && myMaxContent > 0) {
5425 if (myCandle.IsViolinScaled() && myMaxContent > 0 && allMaxContent > 0)
5427 } else if (myCandle.IsViolinScaled() && (allMaxContent > 0))
5429 if (myCandle.IsCandleScaled() && (allMaxIntegral > 0))
5431
5432 myCandle.SetAxisPosition(binPosX+binWidth/2. + offset);
5433 myCandle.SetCandleWidth(candleWidth*binWidth);
5434 myCandle.SetHistoWidth(histoWidth*binWidth);
5435 myCandle.SetHistogram(hproj);
5436 myCandle.Paint();
5437 }
5438 }
5439 } else { // Horizontal candle
5440 //Determining the slice with the maximum integral - if necessary
5441 if (myCandle.IsCandleScaled())
5442 for (Int_t i=Hparam.yfirst; i<=Hparam.ylast; i++) {
5443 hproj = h2->ProjectionX("_py", i, i);
5444 if (hproj->Integral() > allMaxIntegral) allMaxIntegral = hproj->Integral();
5445 }
5446 for (Int_t i=Hparam.yfirst; i<=Hparam.ylast; i++) {
5448 Double_t binWidth = fYaxis->GetBinWidth(i);
5449 hproj = h2->ProjectionX("_py", i, i);
5450 if (hproj->GetEntries() != 0) {
5452 Double_t offset = fH->GetBarOffset()*binWidth;
5453 double myMaxContent = hproj->GetBinContent(hproj->GetMaximumBin());
5454 double myIntegral = hproj->Integral();
5456 if (candleWidth > 0.999 && candleWidth < 1.001) {
5459 }
5460 if (Hoption.Logz && myMaxContent > 0) {
5462 if (myCandle.IsViolinScaled() && myMaxContent > 0 && allMaxContent > 0)
5464 } else if (myCandle.IsViolinScaled() && (allMaxContent > 0))
5466 if (myCandle.IsCandleScaled() && (allMaxIntegral > 0))
5468
5469 myCandle.SetAxisPosition(binPosY+binWidth/2. + offset);
5470 myCandle.SetCandleWidth(candleWidth*binWidth);
5471 myCandle.SetHistoWidth(histoWidth*binWidth);
5472 myCandle.SetHistogram(hproj);
5473 myCandle.Paint();
5474 }
5475 }
5476 }
5477 delete hproj;
5478}
5479
5480
5481
5482////////////////////////////////////////////////////////////////////////////////
5483/// Returns the rendering regions for an axis to use in the COL2 option
5484///
5485/// The algorithm analyses the size of the axis compared to the size of
5486/// the rendering region. It figures out the boundaries to use for each color
5487/// of the rendering region. Only one axis is computed here.
5488///
5489/// This allows for a single computation of the boundaries before iterating
5490/// through all of the bins.
5491///
5492/// \param pAxis the axis to consider
5493/// \param nPixels the number of pixels to render axis into
5494/// \param isLog whether the axis is log scale
5495
5496std::vector<THistRenderingRegion>
5498{
5499 std::vector<THistRenderingRegion> regions;
5500
5501 enum STRATEGY { Bins, Pixels } strategy;
5502
5503 Int_t nBins = (pAxis->GetLast() - pAxis->GetFirst() + 1);
5504
5505 if (nBins >= nPixels) {
5506 // more bins than pixels... we should loop over pixels and sample
5507 strategy = Pixels;
5508 } else {
5509 // fewer bins than pixels... we should loop over bins
5510 strategy = Bins;
5511 }
5512
5513 if (isLog) {
5514
5515 Double_t xMin = pAxis->GetBinLowEdge(pAxis->GetFirst());
5516 Int_t binOffset=0;
5517 while (xMin <= 0 && ((pAxis->GetFirst()+binOffset) != pAxis->GetLast()) ) {
5518 binOffset++;
5519 xMin = pAxis->GetBinLowEdge(pAxis->GetFirst()+binOffset);
5520 }
5521 if (xMin <= 0) {
5522 // this should cause an error if we have
5523 return regions;
5524 }
5525 Double_t xMax = pAxis->GetBinUpEdge(pAxis->GetLast());
5526
5527 if (strategy == Bins) {
5528 // logarithmic plot. we find the pixel for the bin
5529 // pixel = eta * log10(V) - alpha
5530 // where eta = nPixels/(log10(Vmax)-log10(Vmin))
5531 // and alpha = nPixels*log10(Vmin)/(log10(Vmax)-log10(Vmin))
5532 // and V is axis value
5534 Double_t offset = -1.0 * eta * TMath::Log10(xMin);
5535
5536 for (Int_t bin=pAxis->GetFirst()+binOffset; bin<=pAxis->GetLast(); bin++) {
5537
5538 // linear plot. we simply need to find the appropriate bin
5539 // for the
5540 Double_t xLowValue = pAxis->GetBinLowEdge(bin);
5541 Double_t xUpValue = pAxis->GetBinUpEdge(bin);
5544 THistRenderingRegion region = {std::make_pair(xPx0, xPx1),
5545 std::make_pair(bin, bin+1)};
5546 regions.push_back(region);
5547 }
5548
5549 } else {
5550
5551 // loop over pixels
5552
5554
5555 for (Int_t pixelIndex=0; pixelIndex<(nPixels-1); pixelIndex++) {
5556 // linear plot
5557 Int_t binLow = pAxis->FindBin(xMin*TMath::Power(10.0, beta*pixelIndex));
5558 Int_t binHigh = pAxis->FindBin(xMin*TMath::Power(10.0, beta*(pixelIndex+1)));
5559 THistRenderingRegion region = { std::make_pair(pixelIndex, pixelIndex+1),
5560 std::make_pair(binLow, binHigh)};
5561 regions.push_back(region);
5562 }
5563 }
5564 } else {
5565 // standard linear plot
5566
5567 if (strategy == Bins) {
5568 // loop over bins
5569 for (Int_t bin=pAxis->GetFirst(); bin<=pAxis->GetLast(); bin++) {
5570
5571 // linear plot. we simply need to find the appropriate bin
5572 // for the
5573 Int_t xPx0 = ((bin - pAxis->GetFirst()) * nPixels)/nBins;
5574 Int_t xPx1 = xPx0 + nPixels/nBins;
5575
5576 // make sure we don't compute beyond our bounds
5577 if (xPx1>= nPixels) xPx1 = nPixels-1;
5578
5579 THistRenderingRegion region = {std::make_pair(xPx0, xPx1),
5580 std::make_pair(bin, bin+1)};
5581 regions.push_back(region);
5582 }
5583 } else {
5584 // loop over pixels
5586 // linear plot
5587 Int_t binLow = (nBins*pixelIndex)/nPixels + pAxis->GetFirst();
5588 Int_t binHigh = binLow + nBins/nPixels;
5589 THistRenderingRegion region = { std::make_pair(pixelIndex, pixelIndex+1),
5590 std::make_pair(binLow, binHigh)};
5591 regions.push_back(region);
5592 }
5593 }
5594 }
5595
5596 return regions;
5597}
5598
5599////////////////////////////////////////////////////////////////////////////////
5600/// [Rendering scheme for the COL2 and COLZ2 options] (\ref HP14)
5601
5603{
5604
5605 if (Hoption.System != kCARTESIAN) {
5606 Error("THistPainter::PaintColorLevelsFast(Option_t*)",
5607 "Only cartesian coordinates supported by 'COL2' option. Using 'COL' option instead.");
5608 PaintColorLevels(nullptr);
5609 return;
5610 }
5611
5612 Double_t z;
5613
5614 // Use existing max or min values. If either is already set
5615 // the appropriate value to use.
5616 Double_t zmin = fH->GetMinimumStored();
5617 Double_t zmax = fH->GetMaximumStored();
5618 Double_t originalZMin = zmin;
5619 Double_t originalZMax = zmax;
5620 if ((zmin == -1111) && (zmax == -1111)) {
5621 fH->GetMinimumAndMaximum(zmin, zmax);
5622 fH->SetMinimum(zmin);
5623 fH->SetMaximum(zmax);
5624 } else if (zmin == -1111) {
5625 zmin = fH->GetMinimum();
5626 fH->SetMinimum(zmin);
5627 } else if (zmax == -1111) {
5628 zmax = fH->GetMaximum();
5629 fH->SetMaximum(zmax);
5630 }
5631
5632 Double_t dz = zmax - zmin;
5633 if (dz <= 0) { // Histogram filled with a constant value
5634 zmax += 0.1*TMath::Abs(zmax);
5635 zmin -= 0.1*TMath::Abs(zmin);
5636 dz = zmax - zmin;
5637 }
5638
5639 if (Hoption.Logz) {
5640 if (zmin > 0) {
5641 zmin = TMath::Log10(zmin);
5642 zmax = TMath::Log10(zmax);
5643 dz = zmax - zmin;
5644 } else {
5645 Error("THistPainter::PaintColorLevelsFast(Option_t*)",
5646 "Cannot plot logz because bin content is less than 0.");
5647 return;
5648 }
5649 }
5650
5651 // Initialize the levels on the Z axis
5652 Int_t ndiv = fH->GetContour();
5653 if (ndiv == 0 ) {
5654 ndiv = gStyle->GetNumberContours();
5655 fH->SetContour(ndiv);
5656 }
5657 std::vector<Double_t> colorBounds(ndiv);
5658 std::vector<Double_t> contours(ndiv, 0);
5659 if (!fH->TestBit(TH1::kUserContour)) {
5660 fH->SetContour(ndiv);
5661 } else {
5662 fH->GetContour(contours.data());
5663 }
5664
5665 Double_t step = 1.0/ndiv;
5666 for (Int_t i=0; i<ndiv; ++i) {
5667 colorBounds[i] = step*i;
5668 }
5669
5670 auto pFrame = gPad->GetFrame();
5671 Int_t px0 = gPad->XtoPixel(pFrame->GetX1());
5672 Int_t px1 = gPad->XtoPixel(pFrame->GetX2());
5673 Int_t py0 = gPad->YtoPixel(pFrame->GetY1());
5674 Int_t py1 = gPad->YtoPixel(pFrame->GetY2());
5675 Int_t nXPixels = px1-px0;
5676 Int_t nYPixels = py0-py1; // y=0 is at the top of the screen
5677
5678 std::vector<Double_t> buffer(nXPixels*nYPixels, 0);
5679
5682 if (xRegions.empty() || yRegions.empty()) {
5683 Error("THistPainter::PaintColorLevelFast(Option_t*)",
5684 "Encountered error while computing rendering regions.");
5685 return;
5686 }
5687
5690 Double_t minValue = 1.;
5691 Double_t maxValue = 0.;
5692 for (auto& yRegion : yRegions) {
5693 for (auto& xRegion : xRegions ) {
5694
5695 const auto& xBinRange = xRegion.fBinRange;
5696 const auto& yBinRange = yRegion.fBinRange;
5697
5698 // sample the range
5699 z = fH->GetBinContent(xBinRange.second-1, yBinRange.second-1);
5700
5701 if (Hoption.Logz) {
5702 if (z > 0) z = TMath::Log10(z);
5703 else z = zmin;
5704 }
5705
5706 // obey the user's max and min values if they were set
5707 if (z > zmax) z = zmax;
5708 if (z < zmin) z = zmin;
5709
5711 // contours are absolute values
5712 auto index = TMath::BinarySearch(contours.size(), contours.data(), z);
5713 z = colorBounds[index];
5714 } else {
5715 Int_t index = 0;
5716 if (dz != 0) {
5717 index = 0.001 + ((z - zmin)/dz)*ndiv;
5718 }
5719
5720 if (index == static_cast<Int_t>(colorBounds.size())) {
5721 index--;
5722 }
5723
5724 // Do a little bookkeeping to use later for getting libAfterImage to produce
5725 // the correct colors
5726 if (index == 0) {
5727 minExists = kTRUE;
5728 } else if (index == static_cast<Int_t>(colorBounds.size()-1)) {
5729 maxExists = kTRUE;
5730 }
5731
5732 z = colorBounds[index];
5733
5734 if (z < minValue) {
5735 minValue = z;
5736 }
5737 if (z > maxValue) {
5738 maxValue = z;
5739 }
5740 }
5741
5742 // fill in the actual pixels
5743 const auto& xPixelRange = xRegion.fPixelRange;
5744 const auto& yPixelRange = yRegion.fPixelRange;
5745 for (Int_t xPx = xPixelRange.first; xPx <= xPixelRange.second; ++xPx) {
5746 for (Int_t yPx = yPixelRange.first; yPx <= yPixelRange.second; ++yPx) {
5748 buffer[pixel] = z;
5749 }
5750 }
5751 } // end px loop
5752 } // end py loop
5753
5754 // This is a bit of a hack to ensure that we span the entire color range and
5755 // don't screw up the colors for a sparse histogram. No one will notice that I set a
5756 // single pixel on the edge of the image to a different color. This is even more
5757 // true because the chosen pixels will be covered by the axis.
5758 if (minValue != maxValue) {
5759 if ( !minExists) {
5760 buffer.front() = 0;
5761 }
5762
5763 if ( !maxExists) {
5764 buffer[buffer.size()-nXPixels] = 0.95;
5765 }
5766 }
5767
5768 // Generate the TImage
5771 pImage->SetImageQuality(TAttImage::kImgBest);
5772 pImage->SetImage(buffer.data(), nXPixels, nYPixels, pPalette);
5773 delete pPalette;
5774
5775 Window_t wid = static_cast<Window_t>(gVirtualX->GetWindowID(gPad->GetPixmapID()));
5776 pImage->PaintImage(wid, px0, py1, 0, 0, nXPixels, nYPixels);
5777 delete pImage;
5778
5780
5781 // Reset the maximum and minimum values to their original values
5782 // when this function was called. If we don't do this, an initial
5783 // value of -1111 will be replaced with the true max or min values.
5786}
5787
5788////////////////////////////////////////////////////////////////////////////////
5789/// [Control function to draw a 2D histogram as a color plot.](\ref HP14)
5790
5792{
5793 Double_t z, e, zc, xk, xstep, yk, ystep, xlow, xup, ylow, yup;
5794
5795 Double_t zmin = fH->GetMinimum();
5796 Double_t zmax = fH->GetMaximum();
5797
5798 Double_t dz = zmax - zmin;
5799 if (dz <= 0) { // Histogram filled with a constant value
5800 zmax += 0.1*TMath::Abs(zmax);
5801 zmin -= 0.1*TMath::Abs(zmin);
5802 dz = zmax - zmin;
5803 }
5804
5805 // In case of option SAME, zmin and zmax values are taken from the
5806 // first plotted 2D histogram.
5807 if (Hoption.Same > 0 && Hoption.Same < 10) {
5808 TH2 *h2;
5809 TIter next(gPad->GetListOfPrimitives());
5810 while ((h2 = (TH2 *)next())) {
5811 if (!h2->InheritsFrom(TH2::Class())) continue;
5812 zmin = h2->GetMinimum();
5813 zmax = h2->GetMaximum();
5814 fH->SetMinimum(zmin);
5815 fH->SetMaximum(zmax);
5816 if (Hoption.Logz) {
5817 if (zmin <= 0) {
5818 zmin = TMath::Log10(zmax*0.001);
5819 } else {
5820 zmin = TMath::Log10(zmin);
5821 }
5822 zmax = TMath::Log10(zmax);
5823 }
5824 dz = zmax - zmin;
5825 break;
5826 }
5827 } else {
5828 if (Hoption.Logz) {
5829 if (zmin > 0) {
5830 zmin = TMath::Log10(zmin);
5831 zmax = TMath::Log10(zmax);
5832 dz = zmax - zmin;
5833 } else {
5834 return;
5835 }
5836 }
5837 }
5838
5841 fH->SetFillStyle(1001);
5842 fH->TAttFill::Modify();
5843
5844 // Initialize the levels on the Z axis
5846 Int_t ndiv = fH->GetContour();
5847 if (ndiv == 0) {
5848 ndiv = gStyle->GetNumberContours();
5849 fH->SetContour(ndiv);
5850 }
5851 Int_t ndivz = TMath::Abs(ndiv);
5852 if (!fH->TestBit(TH1::kUserContour)) fH->SetContour(ndiv);
5853 Double_t scale = (dz ? ndivz / dz : 1.0);
5854
5855 Double_t xmin = gPad->GetUxmin();
5856 Double_t xmax = gPad->GetUxmax();
5857 Double_t ymin = gPad->GetUymin();
5858 Double_t ymax = gPad->GetUymax();
5859
5860 // range used for polar coordinates
5861 Double_t pxmin = xmin, pxmax = xmax, pymin = ymin, pymax = ymax, pkr = 0.5;
5862 if ((Hoption.System == kPOLAR) && (Hoption.Polar == 2)) {
5863 pxmin = fXaxis->GetXmin();
5864 pxmax = fXaxis->GetXmax();
5865 if (Hoption.Logx) {
5866 if (pxmax <= 0)
5867 return;
5869 if (pxmin <= 0)
5870 pxmin = pxmax - 5;
5871 else
5873 }
5874 pkr = 0.45; // makes fixed range more pretty
5875 pymin = fYaxis->GetXmin();
5876 pymax = fYaxis->GetXmax();
5877 if (Hoption.Logy) {
5878 if (pymax <= 0)
5879 return;
5881 if (pymin <= 0)
5882 pymin = pymax - 5;
5883 else
5885 } else if ((pymax > 0) && (pymin > 0)) {
5886 // force minimal radius to 0 to display natural polar graphics
5887 pymin = 0;
5888 }
5889 }
5890
5891 if ((Hoption.System == kPOLAR) && (Hoption.Polar == 3)) {
5892 // do not touch boundaries when draw without axis histogram
5893 if (!Hoption.Same)
5894 pkr = 0.45;
5895 // for natural coordinates force minimal radius to 0
5896 if (!Hoption.Logy && (pymax > 0))
5897 pymin = 0;
5898 }
5899
5900 Int_t color;
5901 TProfile2D* prof2d = dynamic_cast<TProfile2D*>(fH);
5902 for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
5905 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
5906 Int_t bin = j*(fXaxis->GetNbins()+2) + i;
5907 xk = fXaxis->GetBinLowEdge(i);
5908 xstep = fXaxis->GetBinWidth(i);
5909 if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
5910 z = fH->GetBinContent(bin);
5911 e = fH->GetBinError(bin);
5912 // if fH is a profile histogram do not draw empty bins
5913 if (prof2d) {
5914 const Double_t binEntries = prof2d->GetBinEntries(bin);
5915 if (binEntries == 0)
5916 continue;
5917 } else {
5918 // don't draw the empty bins for non-profile histograms
5919 // with positive content
5920 if (z == 0 && e == 0) {
5921 if (zmin >= 0 || Hoption.Logz) continue;
5922 if (Hoption.Color == 2) continue;
5923 }
5924 }
5925
5926 if (Hoption.Logz)
5927 z = z > 0 ? TMath::Log10(z) : zmin;
5928 if (z < zmin && !Hoption.Zero)
5929 continue;
5930 xup = xk + xstep;
5931 xlow = xk;
5932 if (Hoption.Logx) {
5933 if ((xup <= 0) || (xlow <= 0))
5934 continue;
5935 xup = TMath::Log10(xup);
5936 xlow = TMath::Log10(xlow);
5937 }
5938 yup = yk + ystep;
5939 ylow = yk;
5940 if (Hoption.Logy) {
5941 if ((yup <= 0) || (ylow <= 0))
5942 continue;
5943 yup = TMath::Log10(yup);
5944 ylow = TMath::Log10(ylow);
5945 }
5946 if ((xup < xmin) || (yup < ymin) || (xlow > xmax) || (ylow > ymax))
5947 continue;
5948 if (xlow < xmin)
5949 xlow = xmin;
5950 if (ylow < ymin)
5951 ylow = ymin;
5952 if (xup > xmax)
5953 xup = xmax;
5954 if (yup > ymax)
5955 yup = ymax;
5956
5958 zc = fH->GetContourLevelPad(0);
5959 if (z < zc) continue;
5960 color = -1;
5961 for (Int_t k=0; k<ndiv; k++) {
5962 zc = fH->GetContourLevelPad(k);
5963 if (z < zc) {
5964 continue;
5965 } else {
5966 color++;
5967 }
5968 }
5969 } else {
5970 color = Hoption.Zero ? Int_t(0.01+(std::max(z, zmin)-zmin)*scale) : Int_t(0.01+(z-zmin)*scale);
5971 }
5972
5973 Int_t theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz));
5974 if (theColor > ncolors-1)
5975 theColor = ncolors-1;
5977 if (Hoption.System != kPOLAR) {
5979 fH->TAttFill::Modify();
5980 gPad->PaintBox(xlow, ylow, xup, yup);
5981 } else {
5982 Double_t midx = (xmin + xmax) / 2;
5983 Double_t midy = (ymin + ymax) / 2;
5984 Double_t rx = xmax - xmin;
5985 Double_t ry = ymax - ymin;
5986 Double_t a1, a2;
5987
5988 if (Hoption.Polar == 3) {
5989 a1 = xlow / TMath::Pi() * 180;
5990 a2 = xup / TMath::Pi() * 180;
5991 } else {
5992 a1 = ((xlow - pxmin) / (pxmax - pxmin) - 0.5) * 360;
5993 a2 = ((xup - pxmin) / (pxmax - pxmin) - 0.5) * 360;
5994 }
5995 Double_t r1 = (ylow - pymin) / (pymax - pymin) * rx * pkr;
5996 Double_t r2 = (yup - pymin) / (pymax - pymin) * rx * pkr;
5997
5998 TCrown crown(midx, midy, r1, r2, a1, a2);
5999 crown.SetYXRatio(rx > 0 ? ry / rx : 1);
6000 crown.SetFillColor(fillColor);
6001 crown.SetLineColor(fH->GetLineColor());
6002 crown.SetLineWidth(fH->GetLineWidth());
6003 crown.SetLineStyle(fH->GetLineStyle());
6004 crown.Paint();
6005 }
6006 }
6007 }
6008
6010
6013 fH->TAttFill::Modify();
6014
6015}
6016
6017////////////////////////////////////////////////////////////////////////////////
6018/// [Control function to draw a 2D histogram as a contour plot.](\ref HP16)
6019
6021{
6022
6023 Int_t i, j, count, ncontour, icol, n, lj, m, ix, jx, ljfill;
6024 Int_t itars, mode, ir[4];
6025 Double_t xsave, ysave, thesave,phisave,x[4], y[4], zc[4];
6026
6027 if (Hoption.Contour == 14) {
6028 Hoption.Surf = 12;
6029 Hoption.Axis = 1;
6030 thesave = gPad->GetTheta();
6031 phisave = gPad->GetPhi();
6032 gPad->SetPhi(0.);
6033 gPad->SetTheta(90.);
6035 gPad->SetPhi(phisave);
6036 gPad->SetTheta(thesave);
6037 TView *view = gPad->GetView();
6038 if (view) view->SetBit(kCannotRotate); //tested in ExecuteEvent
6039 PaintAxis();
6040 return;
6041 }
6042
6043 if (Hoption.Same) {
6044 // If the contour is painted on a 3d plot, the contour lines are
6045 // paint in 3d too.
6046 TObject *obj;
6047 TIter next(gPad->GetListOfPrimitives());
6048 while ((obj=next())) {
6049 if (strstr(obj->GetDrawOption(),"surf") ||
6050 strstr(obj->GetDrawOption(),"lego") ||
6051 strstr(obj->GetDrawOption(),"tri")) {
6052 Hoption.Surf = 16;
6054 return;
6055 }
6056 }
6057 }
6058
6059 if (Hoption.Contour == 15) {
6060 TGraphDelaunay2D *dt = nullptr;
6061 TGraphDelaunay *dtOld = nullptr;
6063 dt = (TGraphDelaunay2D*)hl->FindObject("TGraphDelaunay2D");
6064 if (!dt) dtOld = (TGraphDelaunay*)hl->FindObject("TGraphDelaunay");
6065 if (!dt && !dtOld) return;
6066 if (!fGraph2DPainter)
6067 fGraph2DPainter = dt ? std::make_unique<TGraph2DPainter>(dt) : std::make_unique<TGraph2DPainter>(dtOld);
6068 fGraph2DPainter->Paint(option);
6069 return;
6070 }
6071
6072 gPad->SetBit(TGraph::kClipFrame);
6073
6074 std::vector<Double_t> levels(2*kMAXCONTOUR);
6075 std::vector<Double_t> xarr(2*kMAXCONTOUR);
6076 std::vector<Double_t> yarr(2*kMAXCONTOUR);
6077 std::vector<Int_t> itarr(2*kMAXCONTOUR);
6078
6079 Int_t npmax = 0;
6080 for (i=0;i<2*kMAXCONTOUR;i++) itarr[i] = 0;
6081
6082 ncontour = fH->GetContour();
6083 if (ncontour == 0) {
6086 }
6087 if (ncontour > kMAXCONTOUR) {
6088 Warning("PaintContour", "maximum number of contours is %d, asked for %d",
6091 }
6093
6094 for (i=0;i<ncontour;i++) levels[i] = fH->GetContourLevelPad(i);
6098 if (Hoption.Contour == 13) {
6099 fH->TAttLine::Modify();
6100 }
6101
6102 std::vector<std::unique_ptr<TPolyLine>> polys;
6103 TObjArray *contours = nullptr;
6104 TList *list = nullptr;
6105 TGraph *graph = nullptr;
6106 std::vector<Int_t> np;
6107 if (Hoption.Contour == 1 || (Hoption.List && (Hoption.Contour == 11 || Hoption.Contour == 12 || Hoption.Contour == 13))) {
6108 np.resize(ncontour);
6109 for (i=0;i<ncontour;i++)
6110 np[i] = 0;
6111 for (i=0;i<ncontour;i++)
6112 polys.emplace_back(std::make_unique<TPolyLine>(100));
6113 if (Hoption.List == 1) {
6114 contours = (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
6115 if (contours) {
6116 gROOT->GetListOfSpecials()->Remove(contours);
6117 count = contours->GetSize();
6118 for (i=0;i<count;i++) {
6119 list = (TList*)contours->At(i);
6120 if (list) list->Delete();
6121 }
6122 contours->Delete();
6123 delete contours;
6124 }
6126 contours->SetName("contours");
6127 gROOT->GetListOfSpecials()->Add(contours);
6128 for (i=0;i<ncontour;i++) {
6129 list = new TList();
6130 contours->Add(list);
6131 }
6132 }
6133 }
6137
6138 Int_t k,ipoly;
6139 for (j=Hparam.yfirst; j<Hparam.ylast; j++) {
6140 y[0] = fYaxis->GetBinCenter(j);
6141 y[1] = y[0];
6142 y[2] = fYaxis->GetBinCenter(j+1);
6143 y[3] = y[2];
6144 for (i=Hparam.xfirst; i<Hparam.xlast; i++) {
6145 zc[0] = fH->GetBinContent(i, j);
6146 zc[1] = fH->GetBinContent(i+1, j);
6147 zc[2] = fH->GetBinContent(i+1, j+1);
6148 zc[3] = fH->GetBinContent(i, j+1);
6149 if (!IsInside(fXaxis->GetBinCenter(i),fYaxis->GetBinCenter(j))) continue;
6150 if (Hoption.Logz) {
6151 if (zc[0] > 0) zc[0] = TMath::Log10(zc[0]);
6152 else zc[0] = Hparam.zmin;
6153 if (zc[1] > 0) zc[1] = TMath::Log10(zc[1]);
6154 else zc[1] = Hparam.zmin;
6155 if (zc[2] > 0) zc[2] = TMath::Log10(zc[2]);
6156 else zc[2] = Hparam.zmin;
6157 if (zc[3] > 0) zc[3] = TMath::Log10(zc[3]);
6158 else zc[3] = Hparam.zmin;
6159 }
6160 for (k=0;k<4;k++) {
6161 ir[k] = TMath::BinarySearch(ncontour, levels.data(), zc[k]);
6162 }
6163 if (ir[0] != ir[1] || ir[1] != ir[2] || ir[2] != ir[3] || ir[3] != ir[0]) {
6164 x[0] = fXaxis->GetBinCenter(i);
6165 x[3] = x[0];
6166 x[1] = fXaxis->GetBinCenter(i+1);
6167 x[2] = x[1];
6168 if (zc[0] <= zc[1]) n = 0; else n = 1;
6169 if (zc[2] <= zc[3]) m = 2; else m = 3;
6170 if (zc[n] > zc[m]) n = m;
6171 n++;
6172 lj=1;
6173 for (ix=1;ix<=4;ix++) {
6174 m = n%4 + 1;
6175 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],zc[m-1],
6176 ir[m-1],x[m-1],y[m-1], xarr.data()+lj-1,yarr.data()+lj-1,itarr.data()+lj-1, levels.data());
6177 lj += 2*ljfill;
6178 n = m;
6179 }
6180
6181 if (zc[0] <= zc[1]) n = 0; else n = 1;
6182 if (zc[2] <= zc[3]) m = 2; else m = 3;
6183 if (zc[n] > zc[m]) n = m;
6184 n++;
6185 lj=2;
6186 for (ix=1;ix<=4;ix++) {
6187 if (n == 1) m = 4;
6188 else m = n-1;
6189 ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],zc[m-1],
6190 ir[m-1],x[m-1],y[m-1],xarr.data()+lj-1,yarr.data()+lj-1,itarr.data()+lj-1, levels.data());
6191 lj += 2*ljfill;
6192 n = m;
6193 }
6194
6195 // Re-order endpoints
6196
6197 count = 0;
6198 for (ix=1; ix<=lj-5; ix +=2) {
6199 //count = 0;
6200 while (itarr[ix-1] != itarr[ix]) {
6201 xsave = xarr[ix];
6202 ysave = yarr[ix];
6203 itars = itarr[ix];
6204 for (jx=ix; jx<=lj-5; jx +=2) {
6205 xarr[jx] = xarr[jx+2];
6206 yarr[jx] = yarr[jx+2];
6207 itarr[jx] = itarr[jx+2];
6208 }
6209 xarr[lj-3] = xsave;
6210 yarr[lj-3] = ysave;
6211 itarr[lj-3] = itars;
6212 if (count > 100) break;
6213 count++;
6214 }
6215 }
6216
6217 if (count > 100) continue;
6218 for (ix=1; ix<=lj-2; ix +=2) {
6219 theColor = Int_t((itarr[ix-1]+0.99)*Float_t(ncolors)/Float_t(ndivz));
6221 if (Hoption.Contour == 11) {
6223 }
6224 if (Hoption.Contour == 12) {
6225 mode = icol%5;
6226 if (mode == 0) mode = 5;
6228 }
6229 if (Hoption.Contour != 1) {
6230 fH->TAttLine::Modify();
6231 gPad->PaintPolyLine(2,xarr.data()+ix-1,yarr.data()+ix-1);
6232 if ((Hoption.Contour != 11 && Hoption.Contour != 12 && Hoption.Contour != 13) || !Hoption.List)
6233 continue;
6234 }
6235
6236 ipoly = itarr[ix-1];
6237 if (ipoly >=0 && ipoly <ncontour) {
6238 polys[ipoly]->SetPoint(np[ipoly] ,xarr[ix-1],yarr[ix-1]);
6239 polys[ipoly]->SetPoint(np[ipoly]+1,xarr[ix], yarr[ix]);
6240 np[ipoly] += 2;
6241 if (npmax < np[ipoly]) npmax = np[ipoly];
6242 }
6243 }
6244 } // end of if (ir[0]
6245 } //end of for (i
6246 } //end of for (j
6247
6249 std::vector<Double_t> xp, yp;
6251 Int_t istart;
6252 Int_t first = ncontour;
6253 std::vector<Int_t> polysort;
6255 if (Hoption.Contour != 1) {
6256 if (!Hoption.List || (Hoption.Contour != 11 && Hoption.Contour != 12 && Hoption.Contour != 13))
6257 goto theEND;
6258 }
6259
6260 //The 2 points line generated above are now sorted/merged to generate
6261 //a list of consecutive points.
6262 // If the option "List" has been specified, the list of points is saved
6263 // in the form of TGraph objects in the ROOT list of special objects.
6264 xmin = gPad->GetUxmin();
6265 ymin = gPad->GetUymin();
6266 xp.resize(2*npmax);
6267 yp.resize(2*npmax);
6268 polysort.resize(ncontour);
6269 //find first positive contour
6270 for (ipoly=0;ipoly<ncontour;ipoly++) {
6271 if (levels[ipoly] >= 0) {first = ipoly; break;}
6272 }
6273 //store negative contours from 0 to minimum, then all positive contours
6274 k = 0;
6275 for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;}
6276 for (ipoly=first;ipoly<ncontour;ipoly++) {polysort[k] = ipoly; k++;}
6277 // if Contour==1 we can now draw sorted contours, otherwise (11,12,13) just store
6278 contListNb = 0;
6279 if (Hoption.Contour == 1) fH->SetFillStyle(1001);
6280 for (k=0;k<ncontour;k++) {
6281 ipoly = polysort[k];
6282 if (Hoption.List) list = (TList*)contours->At(contListNb);
6283 contListNb++;
6284 if (np[ipoly] == 0)
6285 continue;
6286 Double_t *xx = polys[ipoly]->GetX();
6287 Double_t *yy = polys[ipoly]->GetY();
6288 istart = 0;
6289 while (true) {
6290 iminus = npmax;
6291 iplus = iminus+1;
6292 xp[iminus]= xx[istart]; yp[iminus] = yy[istart];
6293 xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1];
6294 xx[istart] = xmin; yy[istart] = ymin;
6295 xx[istart+1] = xmin; yy[istart+1] = ymin;
6296 while (true) {
6297 nadd = 0;
6298 for (i=2;i<np[ipoly];i+=2) {
6299 if ((iplus < 2*npmax-1) && (xx[i] == xp[iplus]) && (yy[i] == yp[iplus])) {
6300 iplus++;
6301 xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1];
6302 xx[i] = xmin; yy[i] = ymin;
6303 xx[i+1] = xmin; yy[i+1] = ymin;
6304 nadd++;
6305 }
6306 if ((iminus > 0) && (xx[i+1] == xp[iminus]) && (yy[i+1] == yp[iminus])) {
6307 iminus--;
6308 xp[iminus] = xx[i]; yp[iminus] = yy[i];
6309 xx[i] = xmin; yy[i] = ymin;
6310 xx[i+1] = xmin; yy[i+1] = ymin;
6311 nadd++;
6312 }
6313 }
6314 if (nadd == 0) break;
6315 }
6318 if (Hoption.Contour == 1) {
6319 if (ndivz > 1) fH->SetFillColor(icol);
6320 fH->TAttFill::Modify();
6321 gPad->PaintFillArea(iplus-iminus+1,xp.data()+iminus,yp.data()+iminus);
6322 }
6323 if (Hoption.List) {
6324 graph = new TGraph(iplus-iminus+1,xp.data()+iminus,yp.data()+iminus);
6325 if (Hoption.Contour == 1)
6326 graph->SetFillColor(icol);
6327 else if (Hoption.Contour == 11)
6328 graph->SetLineColor(icol);
6329 else if (Hoption.Contour == 12) {
6330 mode = icol%5;
6331 if (mode == 0) mode = 5;
6332 graph->SetLineStyle(mode);
6333 }
6334 graph->SetLineWidth(fH->GetLineWidth());
6335 list->Add(graph);
6336 }
6337 //check if more points are left
6338 istart = 0;
6339 for (i=2;i<np[ipoly];i+=2) {
6340 if (xx[i] != xmin && yy[i] != ymin) {
6341 istart = i;
6342 break;
6343 }
6344 }
6345 if (istart == 0) break;
6346 }
6347 }
6348
6349theEND:
6350 gPad->ResetBit(TGraph::kClipFrame);
6355}
6356
6357////////////////////////////////////////////////////////////////////////////////
6358/// Fill the matrix `xarr` and `yarr` for Contour Plot.
6359
6363{
6364
6365 Bool_t vert;
6367 Int_t n, i, icount;
6368
6369 if (x1 == x2) {
6370 vert = kTRUE;
6371 tlen = y2 - y1;
6372 } else {
6373 vert = kFALSE;
6374 tlen = x2 - x1;
6375 }
6376
6377 n = icont1 +1;
6378 tdif = elev2 - elev1;
6379 i = 0;
6380 icount = 0;
6381 while (n <= icont2 && i <= kMAXCONTOUR/2 -3) {
6382 //elev = fH->GetContourLevel(n);
6383 elev = levels[n];
6384 diff = elev - elev1;
6385 pdif = diff/tdif;
6386 xlen = tlen*pdif;
6387 if (vert) {
6388 if (Hoption.Logx)
6389 xarr[i] = TMath::Log10(x1);
6390 else
6391 xarr[i] = x1;
6392 if (Hoption.Logy)
6393 yarr[i] = TMath::Log10(y1 + xlen);
6394 else
6395 yarr[i] = y1 + xlen;
6396 } else {
6397 if (Hoption.Logx)
6398 xarr[i] = TMath::Log10(x1 + xlen);
6399 else
6400 xarr[i] = x1 + xlen;
6401 if (Hoption.Logy)
6402 yarr[i] = TMath::Log10(y1);
6403 else
6404 yarr[i] = y1;
6405 }
6406 itarr[i] = n;
6407 icount++;
6408 i +=2;
6409 n++;
6410 }
6411 return icount;
6412}
6413
6414////////////////////////////////////////////////////////////////////////////////
6415/// [Draw 1D histograms error bars.](\ref HP09)
6416
6418{
6419
6420 // On iOS, we do not highlight histogram, if it's not picked at the moment
6421 // (but part of histogram (axis or pavestat) was picked, that's why this code
6422 // is called at all. This conditional statement never executes on non-iOS platform.
6423 if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH) return;
6424
6425 const Int_t kBASEMARKER=8;
6426 Double_t xp, yp, ex1, ex2, ey1, ey2;
6427 Double_t delta;
6429 Double_t xi1, xi2, xi3, xi4, yi1, yi2, yi3, yi4;
6431 Double_t logxmin = 0;
6432 Double_t logymin = 0;
6433 Double_t offset = 0.;
6434 Double_t width = 0.;
6435 Int_t i, k, npoints, first, last, fixbin;
6436 Int_t if1 = 0;
6437 Int_t if2 = 0;
6441 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};
6442 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};
6443
6444 std::vector<Double_t> xline, yline, xsegm, ysegm, xmarker, ymarker;
6446 if (Hoption.Error >= 40) {Hoption.Error -=40; option0 = 1;}
6447 if (Int_t(Hoption.Error/10) == 2) {optionEX0 = 1; Hoption.Error -= 10;}
6448 if (Hoption.Error == 31) {optionEX0 = 1; Hoption.Error = 1;}
6449 if (Hoption.Error == 11) option1 = 1;
6450 if (Hoption.Error == 12) option2 = 1;
6451 if (Hoption.Error == 13) option3 = 1;
6452 if (Hoption.Error == 14) {option4 = 1; option3 = 1;}
6453 if (Hoption.Error == 15) {optionI0 = 1; option3 = 1;}
6454 if (Hoption.Error == 16) {optionI0 = 1; option4 = 1; option3 = 1;}
6455 if (option2+option3 == 0) optionE = 1;
6456 if (Hoption.Error == 0) optionE = 0;
6457 if (fXaxis->GetXbins()->fN) fixbin = 0;
6458 else fixbin = 1;
6459
6460 offset = fH->GetBarOffset();
6461 width = fH->GetBarWidth();
6462
6464 if (optionEX0) {
6465 xerror = 0;
6466 } else {
6467 xerror = gStyle->GetErrorX();
6468 }
6470 if (errormarker == 1) symbolsize = 0.01;
6472 if (errormarker >= 20 && errormarker <= 49) {
6473 sbasex *= cxx[errormarker-20];
6474 sbasey *= cyy[errormarker-20];
6475 }
6476 // set the graphics attributes
6477
6478 fH->TAttLine::Modify();
6479 fH->TAttFill::Modify();
6480 fH->TAttMarker::Modify();
6481
6482 // set the first and last bin
6483
6484 Double_t factor = Hparam.factor;
6485 first = Hparam.xfirst;
6486 last = Hparam.xlast;
6487 npoints = last - first +1;
6488 xmin = gPad->GetUxmin();
6489 xmax = gPad->GetUxmax();
6490 ymin = gPad->GetUymin();
6491 ymax = gPad->GetUymax();
6492
6493 xsegm.reserve(1024);
6494 ysegm.reserve(1024);
6495 if (!xsegm.capacity() || !ysegm.capacity()) {
6496 Error("PaintErrors", "out of memory for lines painting");
6497 return;
6498 }
6499
6500 auto flush_segmentes = [&]() {
6501 if (xsegm.size() > 0) {
6502 gPad->PaintSegments(xsegm.size()/2, xsegm.data(), ysegm.data());
6503 xsegm.clear();
6504 ysegm.clear();
6505 }
6506 };
6507
6509 xsegm.emplace_back(x1);
6510 xsegm.emplace_back(x2);
6511 ysegm.emplace_back(y1);
6512 ysegm.emplace_back(y2);
6513 if (xsegm.size() == xsegm.capacity())
6515 };
6516
6517 auto flush_markers = [&]() {
6518 if (xmarker.size() > 0) {
6519 gPad->PaintPolyMarker(xmarker.size(), xmarker.data(), ymarker.data());
6520 xmarker.clear();
6521 ymarker.clear();
6522 }
6523 };
6524
6525 auto add_marker = [&](Double_t x, Double_t y) {
6526 if (xmarker.capacity() == 0) {
6527 xmarker.reserve(256);
6528 ymarker.reserve(256);
6529 }
6530
6531 xmarker.emplace_back(x);
6532 ymarker.emplace_back(y);
6533 if (xmarker.size() == xmarker.capacity()) {
6535 flush_markers();
6536 }
6537 };
6538
6539
6540 if (option3) {
6541 xline.resize(2*npoints);
6542 yline.resize(2*npoints);
6543 if ((npoints > 0) && (xline.empty() || yline.empty())) {
6544 Error("PaintErrors", "too many points, out of memory");
6545 return;
6546 }
6547 if1 = 1;
6548 if2 = 2*npoints;
6549 }
6550
6551 // compute the offset of the error bars due to the symbol size
6552 s2x = gPad->PixeltoX(Int_t(0.5*sbasex)) - gPad->PixeltoX(0);
6553 s2y =-gPad->PixeltoY(Int_t(0.5*sbasey)) + gPad->PixeltoY(0);
6554
6555 // compute size of the lines at the end of the error bars
6557 bxsize = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
6558 bysize =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
6559
6560
6561 if (fixbin) {
6563 else xp = Hparam.xmin + 0.5*Hparam.xbinsize;
6564 } else {
6565 delta = fH->GetBinWidth(first);
6566 xp = fH->GetBinLowEdge(first) + 0.5*delta;
6567 }
6568
6569 // if errormarker = 0 or symbolsize = 0. no symbol is drawn
6572
6573 // ---------------------- Loop over the points---------------------
6574 for (k=first; k<=last; k++) {
6575
6576 // get the data
6577 // xp = X position of the current point
6578 // yp = Y position of the current point
6579 // ex1 = Low X error
6580 // ex2 = Up X error
6581 // ey1 = Low Y error
6582 // ey2 = Up Y error
6583 // (xi,yi) = Error bars coordinates
6584
6585 // apply offset on errors for bar histograms
6586 Double_t xminTmp = gPad->XtoPad(fXaxis->GetBinLowEdge(k));
6587 Double_t xmaxTmp = gPad->XtoPad(fXaxis->GetBinUpEdge(k));
6588 if (Hoption.Logx) {
6591 }
6594 xmaxTmp = xminTmp + w;
6595 xp = (xminTmp+xmaxTmp)/2.;
6596
6597 if (Hoption.Logx) {
6598 if (xp <= 0) goto L30;
6599 if (xp < logxmin) goto L30;
6600 if (xp > TMath::Power(10,xmax)) break;
6601 } else {
6602 if (xp < xmin) goto L30;
6603 if (xp > xmax) break;
6604 }
6605 yp = factor*fH->GetBinContent(k);
6606 if (optionI0 && yp==0) goto L30;
6607 if (fixbin) {
6609 } else {
6610 delta = fH->GetBinWidth(k);
6611 ex1 = xerror*delta;
6612 }
6613 if (fH->GetBinErrorOption() == TH1::kNormal) {
6614 ey1 = factor*fH->GetBinError(k);
6615 ey2 = ey1;
6616 } else {
6617 ey1 = factor*fH->GetBinErrorLow(k);
6618 ey2 = factor*fH->GetBinErrorUp(k);
6619 }
6620 ex2 = ex1;
6621
6622 xi4 = xp;
6623 xi3 = xp;
6624 xi2 = xp + ex2;
6625 xi1 = xp - ex1;
6626
6627 yi1 = yp;
6628 yi2 = yp;
6629 yi3 = yp - ey1;
6630 yi4 = yp + ey2;
6631
6632 // take the LOG if necessary
6633 if (Hoption.Logx) {
6638 }
6639 if (Hoption.Logy) {
6644 }
6645
6646 // test if error bars are not outside the limits
6647 // otherwise they are truncated
6648
6653
6654 // test if the marker is on the frame limits. If "Yes", the
6655 // marker will not be drawn and the error bars will be readjusted.
6656
6657 drawmarker = kTRUE;
6658 if (!option0 && !option3) {
6659 if (Hoption.Logy && yp < logymin) goto L30;
6660 if (yi1 < ymin || yi1 > ymax) goto L30;
6661 if (Hoption.Error != 0 && yp == 0 && ey1 <= 0) drawmarker = kFALSE;
6662 }
6664
6665 // draw the error rectangles
6666 if (option2) {
6667 if ((yi3 >= ymax) || (yi4 <= ymin))
6668 goto L30;
6669 gPad->PaintBox(xi1,yi3,xi2,yi4);
6670 }
6671
6672 // keep points for fill area drawing
6673 if (option3) {
6674 xline[if1-1] = xi3;
6675 xline[if2-1] = xi3;
6676 yline[if1-1] = yi4;
6677 yline[if2-1] = yi3;
6678 if1++;
6679 if2--;
6680 }
6681
6682 // draw the error bars
6683 if (Hoption.Logy && yp < logymin)
6685 if (optionE && drawmarker) {
6686 if ((yi3 < yi1 - s2y) && (yi3 < ymax))
6688 if ((yi1 + s2y < yi4) && (yi4 > ymin))
6690 // don't duplicate the horizontal line
6691 if (Hoption.Hist != 2) {
6693 if (xi1 < xi3 - s2x)
6695 if (xi3 + s2x < xi2)
6697 }
6698 }
6699 }
6700 if (optionE && !drawmarker && (ey1 != 0 || ey2 !=0)) {
6701 if ((yi3 < yi1) && (yi3 < ymax))
6703 if ((yi1 < yi4) && (yi4 > ymin))
6705 // don't duplicate the horizontal line
6706 if (Hoption.Hist != 2) {
6708 if (xi1 < xi3)
6710 if (xi3 < xi2)
6712 }
6713 }
6714 }
6715
6716 // draw line at the end of the error bars
6717
6718 if (option1 && drawmarker) {
6719
6725 if (xi1 < xi3-s2x)
6727 if (xi2 > xi3+s2x)
6729 }
6730 }
6731
6732 // draw the marker
6733
6734 if (drawmarker)
6735 add_marker(xi3, yi1);
6736
6737L30:
6738 if (fixbin) xp += Hparam.xbinsize;
6739 else {
6740 if (k < last) {
6741 delta = fH->GetBinWidth(k+1);
6742 xp = fH->GetBinLowEdge(k+1) + 0.5*delta;
6743 }
6744 }
6745 } //end of for loop
6746
6748
6749 flush_markers();
6750
6751
6752 // draw the filled area
6753
6754 if (option3) {
6755 TGraph graph;
6756 graph.SetLineStyle(fH->GetLineStyle());
6757 graph.SetLineColor(fH->GetLineColor());
6758 graph.SetLineWidth(fH->GetLineWidth());
6759 graph.SetFillStyle(fH->GetFillStyle());
6760 graph.SetFillColor(fH->GetFillColor());
6761 Int_t logx = gPad->GetLogx();
6762 Int_t logy = gPad->GetLogy();
6763 gPad->SetLogx(0);
6764 gPad->SetLogy(0);
6765
6766 // In some cases the number of points in the fill area is smaller than
6767 // 2*npoints. In such cases the array xline and yline must be arranged
6768 // before being plotted. The next loop does that.
6769 if (if2 > npoints) {
6770 for (i=1; i<if1; i++) {
6771 xline[if1-2+i] = xline[if2-1+i];
6772 yline[if1-2+i] = yline[if2-1+i];
6773 }
6774 npoints = if1-1;
6775 }
6776 if (option4) graph.PaintGraph(2*npoints,xline.data(),yline.data(),"FC");
6777 else graph.PaintGraph(2*npoints,xline.data(),yline.data(),"F");
6778 gPad->SetLogx(logx);
6779 gPad->SetLogy(logy);
6780 }
6781}
6782
6783////////////////////////////////////////////////////////////////////////////////
6784/// Draw 2D histograms errors.
6785
6787{
6788
6789 fH->TAttMarker::Modify();
6790 fH->TAttLine::Modify();
6791
6792 // Define the 3D view
6793 fXbuf[0] = Hparam.xmin;
6794 fYbuf[0] = Hparam.xmax;
6795 fXbuf[1] = Hparam.ymin;
6796 fYbuf[1] = Hparam.ymax;
6797 fXbuf[2] = Hparam.zmin;
6798 fYbuf[2] = Hparam.zmax*(1. + gStyle->GetHistTopMargin());
6799 fLego = std::make_unique<TPainter3dAlgorithms>(fXbuf.data(), fYbuf.data());
6800 TView *view = gPad ? gPad->GetView() : nullptr;
6801 if (!view) {
6802 Error("Paint2DErrors", "no TView in current pad");
6803 return;
6804 }
6805 Double_t thedeg = 90 - gPad->GetTheta();
6806 Double_t phideg = -90 - gPad->GetPhi();
6807 Double_t psideg = view->GetPsi();
6808 Int_t irep;
6809 view->SetView(phideg, thedeg, psideg, irep);
6810
6811 // Set color/style for back box
6812 fLego->SetFillStyle(gPad->GetFrameFillStyle());
6813 fLego->SetFillColor(gPad->GetFrameFillColor());
6814 fLego->TAttFill::Modify();
6815 Int_t backcolor = gPad->GetFrameFillColor();
6816 if (Hoption.System != kCARTESIAN) backcolor = 0;
6817 view->PadRange(backcolor);
6818 fLego->SetFillStyle(fH->GetFillStyle());
6819 fLego->SetFillColor(fH->GetFillColor());
6820 fLego->TAttFill::Modify();
6821
6822 // Paint the Back Box if needed
6823 if (Hoption.BackBox && !Hoption.Same && !Hoption.Lego && !Hoption.Surf) {
6824 fLego->InitMoveScreen(-1.1,1.1);
6825 fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
6827 fLego->BackBox(90);
6828 }
6829
6830 // Paint the Errors
6831 Double_t x, ex, x1, x2;
6832 Double_t y, ey, y1, y2;
6833 Double_t z, ez1, ez2, z1, z2;
6834 Double_t temp1[3],temp2[3];
6836 if (Hoption.Error == 110) {
6837 xyerror = 0;
6838 } else {
6840 }
6841
6843 for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
6844 y = fYaxis->GetBinCenter(j);
6846 y1 = y-ey;
6847 y2 = y+ey;
6848 if (Hoption.Logy) {
6849 if (y > 0) y = TMath::Log10(y);
6850 else continue;
6851 if (y1 > 0) y1 = TMath::Log10(y1);
6852 else y1 = Hparam.ymin;
6853 if (y2 > 0) y2 = TMath::Log10(y2);
6854 else y2 = Hparam.ymin;
6855 }
6858 for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
6859 xk = fXaxis->GetBinLowEdge(i);
6860 xstep = fXaxis->GetBinWidth(i);
6861 if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
6862 Int_t bin = fH->GetBin(i,j);
6863 x = fXaxis->GetBinCenter(i);
6865 x1 = x-ex;
6866 x2 = x+ex;
6867 if (Hoption.Logx) {
6868 if (x > 0) x = TMath::Log10(x);
6869 else continue;
6870 if (x1 > 0) x1 = TMath::Log10(x1);
6871 else x1 = Hparam.xmin;
6872 if (x2 > 0) x2 = TMath::Log10(x2);
6873 else x2 = Hparam.xmin;
6874 }
6875 z = fH->GetBinContent(bin);
6876 if (fH->GetBinErrorOption() == TH1::kNormal) {
6877 ez1 = fH->GetBinError(bin);
6878 ez2 = ez1;
6879 }
6880 else {
6882 ez2 = fH->GetBinErrorUp(bin);
6883 }
6884 z1 = z - ez1;
6885 z2 = z + ez2;
6886 if (Hoption.Logz) {
6887 if (z > 0) z = TMath::Log10(z);
6888 else z = Hparam.zmin;
6889 if (z1 > 0) z1 = TMath::Log10(z1);
6890 else z1 = Hparam.zmin;
6891 if (z2 > 0) z2 = TMath::Log10(z2);
6892 else z2 = Hparam.zmin;
6893
6894 }
6895 if (z <= Hparam.zmin) continue;
6896 if (z > Hparam.zmax) z = Hparam.zmax;
6897
6898 temp1[0] = x1;
6899 temp1[1] = y;
6900 temp1[2] = z;
6901 temp2[0] = x2;
6902 temp2[1] = y;
6903 temp2[2] = z;
6904 gPad->PaintLine3D(temp1, temp2);
6905 temp1[0] = x;
6906 temp1[1] = y1;
6907 temp1[2] = z;
6908 temp2[0] = x;
6909 temp2[1] = y2;
6910 temp2[2] = z;
6911 gPad->PaintLine3D(temp1, temp2);
6912 temp1[0] = x;
6913 temp1[1] = y;
6914 temp1[2] = z1;
6915 temp2[0] = x;
6916 temp2[1] = y;
6917 temp2[2] = z2;
6918 gPad->PaintLine3D(temp1, temp2);
6919 temp1[0] = x;
6920 temp1[1] = y;
6921 temp1[2] = z;
6922 view->WCtoNDC(temp1, &temp2[0]);
6923 gPad->PaintPolyMarker(1, &temp2[0], &temp2[1]);
6924 }
6925 }
6926
6927 // Paint the Front Box if needed
6928 if (Hoption.FrontBox) {
6929 fLego->InitMoveScreen(-1.1,1.1);
6931 fLego->FrontBox(90);
6932 }
6933
6934 // Paint the Axis if needed
6935 if (!Hoption.Axis && !Hoption.Same && !Hoption.Lego && !Hoption.Surf) {
6936 TGaxis axis;
6937 PaintLegoAxis(&axis, 90);
6938 }
6939
6940 fLego.reset();
6941}
6942
6943////////////////////////////////////////////////////////////////////////////////
6944/// Calculate range and clear pad (canvas).
6945
6947{
6948
6949 if (Hoption.Same) return;
6950
6952
6953 if (Hoption.Lego || Hoption.Surf || Hoption.Tri ||
6954 Hoption.Contour == 14 || Hoption.Error >= 100) {
6955 TObject *frame = gPad->FindObject("TFrame");
6956 if (frame) gPad->Remove(frame);
6957 return;
6958 }
6959
6960 //The next statement is always executed on non-iOS platform,
6961 //on iOS depends on pad mode.
6962 if (!gPad->PadInSelectionMode() && !gPad->PadInHighlightMode())
6963 gPad->PaintPadFrame(Hparam.xmin,Hparam.ymin,Hparam.xmax,Hparam.ymax);
6964}
6965
6966////////////////////////////////////////////////////////////////////////////////
6967/// [Paint functions associated to an histogram.](\ref HP28")
6968
6970{
6971 auto lnk = fFunctions->FirstLink();
6972
6973 while (lnk) {
6974 auto obj = lnk->GetObject();
6976 if (obj->InheritsFrom(TF2::Class())) {
6977 if (!obj->TestBit(TF2::kNotDraw)) {
6978 if (Hoption.Lego || Hoption.Surf || Hoption.Error >= 100) {
6979 TF2 *f2 = (TF2*)obj;
6980 f2->SetMinimum(fH->GetMinimum());
6981 f2->SetMaximum(fH->GetMaximum());
6982 f2->SetRange(fH->GetXaxis()->GetXmin(), fH->GetYaxis()->GetXmin(), fH->GetXaxis()->GetXmax(), fH->GetYaxis()->GetXmax() );
6983 f2->Paint("surf same");
6984 } else {
6985 obj->Paint("cont3 same");
6986 }
6987 }
6988 } else if (obj->InheritsFrom(TF1::Class())) {
6989 if (!obj->TestBit(TF1::kNotDraw)) obj->Paint("lsame");
6990 } else {
6991 //Let's make this 'function' selectable on iOS device (for example, it can be TPaveStat).
6992 gPad->PushSelectableObject(obj);
6993
6994 //The next statement is ALWAYS executed on non-iOS platform, on iOS it depends on pad's mode
6995 //and picked object.
6996 if (!gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && obj == gPad->GetSelected()))
6997 obj->Paint(lnk->GetOption());
6998 }
6999 lnk = lnk->Next();
7000 }
7001}
7002
7003////////////////////////////////////////////////////////////////////////////////
7004/// [Control routine to draw 1D histograms](\ref HP01b)
7005
7007{
7008
7009 //On iOS: do not highlight hist, if part of it was selected.
7010 //Never executes on non-iOS platform.
7011 if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH)
7012 return;
7013
7014 static char chopth[17];
7015
7017 Int_t i, j, first, last, nbins, fixbin;
7018 Double_t c1, yb;
7019 yb = 0;
7020
7021 strlcpy(chopth, " ",17);
7022
7025 Double_t baroffset = fH->GetBarOffset();
7026 Double_t barwidth = fH->GetBarWidth();
7029 gStyle->SetBarOffset(baroffset);
7030 gStyle->SetBarWidth(barwidth);
7031
7032 // Create "LIFE" structure to keep current histogram status
7033
7034 first = Hparam.xfirst;
7035 last = Hparam.xlast;
7036 nbins = last - first + 1;
7037
7038 std::vector<Double_t> keepx, keepy;
7039 if (fXaxis->GetXbins()->fN) fixbin = 0;
7040 else fixbin = 1;
7041 if (fixbin) keepx.resize(2);
7042 else keepx.resize(nbins+1);
7043 keepy.resize(nbins);
7044 Double_t logymin = 0;
7046
7047 // Loop on histogram bins
7048
7049 for (j=first; j<=last;j++) {
7051 if (TMath::Abs(ymax-ymin) > 0) {
7053 else yb = c1;
7054 }
7055 if (!Hoption.Line) {
7056 yb = TMath::Max(yb, ymin);
7057 yb = TMath::Min(yb, ymax);
7058 }
7059 keepy[j-first] = yb;
7060 }
7061
7062 // Draw histogram according to value of FillStyle and FillColor
7063
7064 if (fixbin) { keepx[0] = Hparam.xmin; keepx[1] = Hparam.xmax; }
7065 else {
7066 for (i=0; i<nbins; i++) keepx[i] = fXaxis->GetBinLowEdge(i+first);
7067 keepx[nbins] = fXaxis->GetBinUpEdge(nbins-1+first);
7068 }
7069
7070 // Prepare Fill area (systematic with option "Bar").
7071
7073 htype = oldhtype;
7074 if (Hoption.Bar) {
7075 if (htype == 0 || htype == 1000) htype = 1001;
7076 }
7077
7079
7080 // Code option for GrapHist
7081
7082 if (Hoption.Line) chopth[0] = 'L';
7083 if (Hoption.Star) chopth[1] = '*';
7084 if (Hoption.Mark) chopth[2] = 'P';
7085 if (Hoption.Mark == 10) chopth[3] = '0';
7087 if (Hoption.Curve) chopth[3] = 'C';
7088 if (Hoption.Hist > 0) chopth[4] = 'H';
7089 else if (Hoption.Bar) chopth[5] = 'B';
7090 if (Hoption.Logy) chopth[6] = '1';
7091 if (fH->GetFillColor() && htype) {
7092 if (Hoption.Hist > 0 || Hoption.Curve || Hoption.Line) {
7093 chopth[7] = 'F';
7094 }
7095 }
7096 }
7097 if (!fixbin && strlen(chopth)) {
7098 chopth[8] = 'N';
7099 }
7100
7101 if (Hoption.Fill == 2) chopth[13] = '2';
7102
7103 // Option LOGX
7104
7105 if (Hoption.Logx) {
7106 chopth[9] = 'G';
7107 chopth[10] = 'X';
7108 if (fixbin) {
7109 keepx[0] = TMath::Power(10,keepx[0]);
7110 keepx[1] = TMath::Power(10,keepx[1]);
7111 }
7112 }
7113
7114 if (Hoption.Off) {
7115 chopth[11] = ']';
7116 chopth[12] = '[';
7117 }
7118
7119 // Draw the histogram
7120
7121 TGraph graph;
7122 graph.SetLineWidth(lw);
7123 graph.SetLineStyle(fH->GetLineStyle());
7124 graph.SetLineColor(fH->GetLineColor());
7125 graph.SetFillStyle(htype);
7126 graph.SetFillColor(fH->GetFillColor());
7128 graph.SetMarkerSize(fH->GetMarkerSize());
7131
7132 graph.PaintGrapHist(nbins, keepx.data(), keepy.data() ,chopth);
7133
7136
7138}
7139
7140////////////////////////////////////////////////////////////////////////////////
7141/// [Control function to draw a 3D histograms.](\ref HP01d)
7142
7144{
7145
7146 TString cmd;
7147 TString opt = option;
7148 opt.ToLower();
7149 Int_t irep;
7150 Float_t NEntries = fH->GetEntries();
7151
7152 if (fCurrentF3 || strstr(opt,"tf3")) {
7153 PaintTF3();
7154 return;
7155 }
7156
7157 if (NEntries > 0) {
7158 if (Hoption.Box || Hoption.Lego || Hoption.Color) {
7159 if (Hoption.Box == 11 || Hoption.Lego == 11) {
7160 PaintH3Box(1);
7161 } else if (Hoption.Box == 12 || Hoption.Lego == 12 || Hoption.Color == 1) {
7162 PaintH3Box(2);
7163 } else if (Hoption.Box == 13 || Hoption.Lego == 13) {
7164 PaintH3Box(3);
7165 } else {
7167 }
7168 return;
7169 }
7170
7171 if (strstr(opt,"iso")) {
7172 PaintH3Iso();
7173 return;
7174 }
7175 }
7176
7177 TView *view = gPad ? gPad->GetView() : nullptr;
7178 if (!view) return;
7179
7180 if (strstr(opt,"fb")) Hoption.FrontBox = 0;
7181 if (strstr(opt,"bb")) Hoption.BackBox = 0;
7182
7183 Double_t thedeg = 90 - gPad->GetTheta();
7184 Double_t phideg = -90 - gPad->GetPhi();
7185 Double_t psideg = view->GetPsi();
7186 view->SetView(phideg, thedeg, psideg, irep);
7187
7188 if(NEntries > 0) { // Paint as 3D scatter plot
7189 cmd.Form("TPolyMarker3D::PaintH3((TH1 *)0x%zx,\"%s\");",(size_t)fH,option);
7190 gROOT->ProcessLine(cmd.Data());
7191 } else {
7192 TAxis* xAxis = fH->GetXaxis();
7193 TAxis* yAxis = fH->GetYaxis();
7194 TAxis* zAxis = fH->GetZaxis();
7195 Double_t xmin = xAxis->GetXmin();
7196 Double_t xmax = xAxis->GetXmax();
7197 Double_t ymin = yAxis->GetXmin();
7198 Double_t ymax = yAxis->GetXmax();
7199 Double_t zmin = zAxis->GetXmin();
7200 Double_t zmax = zAxis->GetXmax();
7201 view->SetRange(xmin, ymin, zmin, xmax, ymax, zmax); // Set the axis limits (Xmin, Ymin, Zmin, Xmax, Ymax, Zmax)
7202 }
7203
7204 if (Hoption.Same) return;
7205
7206 // Draw axis
7207 view->SetOutlineToCube();
7208 TSeqCollection *ol = view->GetOutline();
7209 if (ol && Hoption.BackBox && Hoption.FrontBox) ol->Paint(option);
7211
7212 if (!Hoption.Axis && !Hoption.Same) {
7213 TGaxis axis;
7214 PaintLegoAxis(&axis, 90);
7215 }
7216
7217 // Draw palette. In case of 4D plot with TTree::Draw() the palette should
7218 // be painted with the option colz.
7219 if (fH->GetDrawOption() && strstr(opt,"colz")) {
7220 Int_t ndiv = fH->GetContour();
7221 if (ndiv == 0 ) {
7222 ndiv = gStyle->GetNumberContours();
7223 fH->SetContour(ndiv);
7224 }
7225 PaintPalette();
7226 }
7227
7228 // Draw title
7229 PaintTitle();
7230
7231 //Draw stats and fit results
7232 TF1 *fit = nullptr;
7233 TIter next(fFunctions);
7234 while (auto obj = next()) {
7235 if (obj->InheritsFrom(TF1::Class())) {
7236 fit = (TF1*)obj;
7237 break;
7238 }
7239 }
7240 if ((Hoption.Same%10) != 1) {
7241 if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
7243 }
7244 }
7245
7246}
7247
7248////////////////////////////////////////////////////////////////////////////////
7249/// Compute histogram parameters used by the drawing routines.
7250
7252{
7253
7254 if (fH->GetDimension() > 1 || Hoption.Lego || Hoption.Surf) return 1;
7255
7256 Int_t i;
7257 static const char *where = "PaintInit";
7259 Int_t maximum = 0;
7260 Int_t minimum = 0;
7261 if (fH->GetMaximumStored() != -1111) maximum = 1;
7262 if (fH->GetMinimumStored() != -1111) minimum = 1;
7263
7264 // Compute X axis parameters
7265
7266 Int_t last = fXaxis->GetLast();
7267 Int_t first = fXaxis->GetFirst();
7270 Hparam.xlast = last;
7271 Hparam.xfirst = first;
7274
7275 // if log scale in X, replace xmin,max by the log
7276 if (Hoption.Logx) {
7277 if (Hparam.xmax<=0) {
7278 Error(where, "cannot set X axis to log scale");
7279 return 0;
7280 }
7281 if (Hparam.xlowedge <=0 ) {
7282 if (Hoption.Same) {
7283 TH1* h1 = nullptr;
7284 TObject *obj;
7285 TIter next(gPad->GetListOfPrimitives());
7286 while ((obj = (TObject *)next())) {
7287 if (obj->InheritsFrom(TH1::Class())) { h1 = (TH1*)(obj) ; break; }
7288 if (obj->InheritsFrom(THStack::Class())) { h1 = ((THStack*)(obj))->GetHistogram() ; break; }
7289 if (obj->InheritsFrom(TGraph::Class())) { h1 = ((TGraph*)(obj))->GetHistogram() ; break; }
7290 if (obj->InheritsFrom(TMultiGraph::Class())) { h1 = ((TMultiGraph*)(obj))->GetHistogram(); break; }
7291 if (obj->InheritsFrom(TGraph2D::Class())) { h1 = ((TGraph2D*)(obj))->GetHistogram(); break; }
7292 if (obj->InheritsFrom(TF1::Class())) { h1 = ((TF1*)(obj))->GetHistogram(); break; }
7293 }
7294 if (h1) {
7296 } else {
7297 Error(where, "undefined user's coordinates. Cannot use option SAME");
7298 return 0;
7299 }
7300 } else {
7301 for (i=first; i<=last; i++) {
7302 Double_t binLow = fXaxis->GetBinLowEdge(i);
7303 if (binLow>0) {
7304 Hparam.xlowedge = binLow;
7305 break;
7306 }
7307 if (binLow == 0 && fH->GetBinContent(i) !=0) {
7308 Hparam.xlowedge = fXaxis->GetBinUpEdge(i)*0.001;
7309 break;
7310 }
7311 }
7312 if (Hparam.xlowedge<=0) {
7313 Error(where, "cannot set X axis to log scale");
7314 return 0;
7315 }
7316 }
7318 }
7323 if (Hparam.xlast > last) Hparam.xlast = last;
7324 if (Hparam.xfirst < first) Hparam.xfirst = first;
7325 }
7326
7327 // Compute Y axis parameters
7328 Double_t bigp = TMath::Power(10,32);
7329 Double_t ymax = -bigp;
7330 Double_t ymin = bigp;
7331 Double_t c1, e1;
7332 Double_t xv[1];
7333 Double_t fval;
7334 TObject *f;
7335 TF1 *f1;
7336 Double_t allchan = 0;
7337 Int_t nonNullErrors = 0;
7338 TIter next(fFunctions);
7339 for (i=first; i<=last;i++) {
7340 c1 = fH->GetBinContent(i);
7341 if (std::isnan(c1) || std::isinf(c1))
7342 continue;
7344 if (Hoption.Logy) {
7345 if (c1 > 0) ymin = TMath::Min(ymin,c1);
7346 } else {
7348 }
7349 if (Hoption.Error) {
7351 e1 = fH->GetBinError(i);
7352 else
7353 e1 = fH->GetBinErrorUp(i);
7354 if (e1 > 0) nonNullErrors++;
7357 e1 = fH->GetBinErrorLow(i);
7358
7359 if (Hoption.Logy) {
7360 if (c1-e1>0.01*TMath::Abs(c1)) ymin = TMath::Min(ymin,c1-e1);
7361 } else {
7363 }
7364 }
7365 if (Hoption.Func) {
7366 xv[0] = fXaxis->GetBinCenter(i);
7367 while ((f = (TObject*) next())) {
7368 if (f->IsA() == TF1::Class()) {
7369 f1 = (TF1*)f;
7370 if (xv[0] < f1->GetXmin() || xv[0] > f1->GetXmax()) continue;
7371 fval = f1->Eval(xv[0],0,0);
7372 if (f1->GetMaximumStored() != -1111) fval = TMath::Min(f1->GetMaximumStored(), fval);
7374 if (Hoption.Logy) {
7375 if (c1 > 0 && fval > 0.3*c1) ymin = TMath::Min(ymin,fval);
7376 }
7377 }
7378 }
7379 next.Reset();
7380 }
7381 allchan += c1;
7382 }
7383 if (!nonNullErrors) {
7384 if (Hoption.Error) {
7385 if (!Hoption.Mark && !Hoption.Line && !Hoption.Star && !Hoption.Curve) Hoption.Hist = 2;
7386 Hoption.Error=0;
7387 }
7388 }
7389
7390
7391 // Take into account maximum , minimum
7392
7393 if (Hoption.Logy && ymin <= 0) {
7394 if (ymax >= 1) ymin = TMath::Max(.005,ymax*1e-10);
7395 else ymin = 0.001*ymax;
7396 }
7397
7398 Double_t xm = ymin;
7399 if (maximum) ymax = fH->GetMaximumStored();
7400 if (minimum) xm = fH->GetMinimumStored();
7401 if (Hoption.Logy && xm < 0) {
7402 Error(where, "log scale requested with a negative argument (%f)", xm);
7403 return 0;
7404 } else if (Hoption.Logy && xm>=0 && ymax==0) { // empty histogram in log scale
7405 ymin = 0.01;
7406 ymax = 10.;
7407 } else {
7408 ymin = xm;
7409 }
7410
7411 if (ymin >= ymax) {
7412 if (Hoption.Logy) {
7413 if (ymax > 0) ymin = 0.001*ymax;
7414 else {
7415 if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", ymax);
7416 return 0;
7417 }
7418 }
7419 else {
7420 if (ymin > 0) {
7421 ymin = 0;
7422 ymax *= 2;
7423 } else if (ymin < 0) {
7424 ymax = 0;
7425 ymin *= 2;
7426 } else {
7427 ymin = 0;
7428 ymax = 1;
7429 }
7430 }
7431 }
7432
7433 // In some cases, mainly because of precision issues, ymin and ymax could almost equal.
7434 if (TMath::AreEqualRel(ymin,ymax,1E-15)) {
7435 ymin = ymin*(1-1E-14);
7436 ymax = ymax*(1+1E-14);
7437 }
7438
7439 // take into account normalization factor
7440 Hparam.allchan = allchan;
7441 Double_t factor = allchan;
7442 if (fH->GetNormFactor() > 0) factor = fH->GetNormFactor();
7443 if (allchan) factor /= allchan;
7444 if (factor == 0) factor = 1;
7445 Hparam.factor = factor;
7446 ymax = factor*ymax;
7447 ymin = factor*ymin;
7448 //just in case the norm factor is negative
7449 // this may happen with a positive norm factor and a negative integral !
7450 if (ymax < ymin) {
7451 Double_t temp = ymax;
7452 ymax = ymin;
7453 ymin = temp;
7454 }
7455
7456 // For log scales, histogram coordinates are LOG10(ymin) and
7457 // LOG10(ymax). Final adjustment (if not option "Same"
7458 // or "+" for ymax) of ymax and ymin for logarithmic scale, if
7459 // Maximum and Minimum are not defined.
7460 if (Hoption.Logy) {
7461 if (ymin <=0 || ymax <=0) {
7462 Error(where, "Cannot set Y axis to log scale");
7463 return 0;
7464 }
7466 if (!minimum) ymin += TMath::Log10(0.5);
7468 if (!maximum) ymax += TMath::Log10(2*(0.9/0.95));
7469 if (!Hoption.Same) {
7470 Hparam.ymin = ymin;
7471 Hparam.ymax = ymax;
7472 }
7473 return 1;
7474 }
7475
7476 // final adjustment of ymin for linear scale.
7477 // if minimum is not set , then ymin is set to zero if >0
7478 // or to ymin - margin if <0.
7479 if (!minimum) {
7480 if (Hoption.MinimumZero) {
7481 if (ymin >= 0) ymin = 0;
7482 else ymin -= yMARGIN*(ymax-ymin);
7483 } else {
7485 if (ymin >= 0 && (ymin-dymin <= 0)) ymin = 0;
7486 else ymin -= dymin;
7487 }
7488 }
7489
7490 // final adjustment of YMAXI for linear scale (if not option "Same"):
7491 // decrease histogram height to MAX% of allowed height if HMAXIM
7492 // has not been called.
7493 if (!maximum) {
7494 ymax += yMARGIN*(ymax-ymin);
7495 }
7496
7497 Hparam.ymin = ymin;
7498 Hparam.ymax = ymax;
7499 return 1;
7500}
7501
7502////////////////////////////////////////////////////////////////////////////////
7503/// Compute histogram parameters used by the drawing routines for a rotated pad.
7504
7506{
7507
7508 static const char *where = "PaintInitH";
7510 Int_t maximum = 0;
7511 Int_t minimum = 0;
7512 if (fH->GetMaximumStored() != -1111) maximum = 1;
7513 if (fH->GetMinimumStored() != -1111) minimum = 1;
7514
7515 // Compute X axis parameters
7516
7517 Int_t last = fXaxis->GetLast();
7518 Int_t first = fXaxis->GetFirst();
7521 Hparam.xlast = last;
7522 Hparam.xfirst = first;
7525
7526 // if log scale in Y, replace ymin,max by the log
7527 if (Hoption.Logy) {
7528 if (Hparam.xlowedge <=0 ) {
7531 }
7532 if (Hparam.ymin <=0 || Hparam.ymax <=0) {
7533 Error(where, "cannot set Y axis to log scale");
7534 return 0;
7535 }
7540 if (Hparam.xlast > last) Hparam.xlast = last;
7541 }
7542
7543 // Compute Y axis parameters
7544 Double_t bigp = TMath::Power(10,32);
7545 Double_t xmax = -bigp;
7546 Double_t xmin = bigp;
7547 Double_t c1, e1;
7548 Double_t xv[1];
7549 Double_t fval;
7550 Int_t i;
7551 TObject *f;
7552 TF1 *f1;
7553 Double_t allchan = 0;
7554 TIter next(fFunctions);
7555 for (i=first; i<=last;i++) {
7556 c1 = fH->GetBinContent(i);
7559 if (Hoption.Error) {
7560 e1 = fH->GetBinError(i);
7563 }
7564 if (Hoption.Func) {
7565 xv[0] = fXaxis->GetBinCenter(i);
7566 while ((f = (TObject*) next())) {
7567 if (f->IsA() == TF1::Class()) {
7568 f1 = (TF1*)f;
7569 if (xv[0] < f1->GetXmin() || xv[0] > f1->GetXmax()) continue;
7570 fval = f1->Eval(xv[0],0,0);
7572 if (Hoption.Logy) {
7573 if (fval > 0.3*c1) xmin = TMath::Min(xmin,fval);
7574 }
7575 }
7576 }
7577 next.Reset();
7578 }
7579 allchan += c1;
7580 }
7581
7582 // Take into account maximum , minimum
7583
7584 if (Hoption.Logx && xmin <= 0) {
7585 if (xmax >= 1) xmin = TMath::Max(.5,xmax*1e-10);
7586 else xmin = 0.001*xmax;
7587 }
7588 Double_t xm = xmin;
7589 if (maximum) xmax = fH->GetMaximumStored();
7590 if (minimum) xm = fH->GetMinimumStored();
7591 if (Hoption.Logx && xm <= 0) {
7592 Error(where, "log scale requested with zero or negative argument (%f)", xm);
7593 return 0;
7594 }
7595 else xmin = xm;
7596 if (xmin >= xmax) {
7597 if (Hoption.Logx) {
7598 if (xmax > 0) xmin = 0.001*xmax;
7599 else {
7600 if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", xmax);
7601 return 0;
7602 }
7603 }
7604 else {
7605 if (xmin > 0) {
7606 xmin = 0;
7607 xmax *= 2;
7608 } else if (xmin < 0) {
7609 xmax = 0;
7610 xmin *= 2;
7611 } else {
7612 xmin = 0;
7613 xmax = 1;
7614 }
7615 }
7616 }
7617
7618 // take into account normalization factor
7619 Hparam.allchan = allchan;
7620 Double_t factor = allchan;
7621 if (fH->GetNormFactor() > 0) factor = fH->GetNormFactor();
7622 if (allchan) factor /= allchan;
7623 if (factor == 0) factor = 1;
7624 Hparam.factor = factor;
7625 xmax = factor*xmax;
7626 xmin = factor*xmin;
7627
7628 // For log scales, histogram coordinates are LOG10(ymin) and
7629 // LOG10(ymax). Final adjustment (if not option "Same"
7630 // or "+" for ymax) of ymax and ymin for logarithmic scale, if
7631 // Maximum and Minimum are not defined.
7632 if (Hoption.Logx) {
7633 if (xmin <=0 || xmax <=0) {
7634 Error(where, "Cannot set Y axis to log scale");
7635 return 0;
7636 }
7638 if (!minimum) xmin += TMath::Log10(0.5);
7640 if (!maximum) xmax += TMath::Log10(2*(0.9/0.95));
7641 if (!Hoption.Same) {
7642 Hparam.xmin = xmin;
7643 Hparam.xmax = xmax;
7644 }
7645 return 1;
7646 }
7647
7648 // final adjustment of ymin for linear scale.
7649 // if minimum is not set , then ymin is set to zero if >0
7650 // or to ymin - margin if <0.
7651 if (!minimum) {
7652 if (xmin >= 0) xmin = 0;
7653 else xmin -= yMARGIN*(xmax-xmin);
7654 }
7655
7656 // final adjustment of YMAXI for linear scale (if not option "Same"):
7657 // decrease histogram height to MAX% of allowed height if HMAXIM
7658 // has not been called.
7659 if (!maximum) {
7660 xmax += yMARGIN*(xmax-xmin);
7661 }
7662 Hparam.xmin = xmin;
7663 Hparam.xmax = xmax;
7664 return 1;
7665}
7666
7667////////////////////////////////////////////////////////////////////////////////
7668/// [Control function to draw a 3D histogram with boxes.](\ref HP25)
7669
7671{
7672 // Predefined box structure
7673 Double_t wxyz[8][3] = { {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1},
7674 {-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1} };
7675 Int_t iface[6][4] = { {0,3,2,1}, {4,5,6,7},
7676 {0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7} };
7677
7678 // Define dimensions of world space
7679 TAxis *xaxis = fH->GetXaxis();
7680 TAxis *yaxis = fH->GetYaxis();
7681 TAxis *zaxis = fH->GetZaxis();
7682
7683 fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
7684 fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
7685 fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
7686 fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
7687 fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
7688 fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
7689
7690 fLego = std::make_unique<TPainter3dAlgorithms>(fXbuf.data(), fYbuf.data());
7691
7692 // Set view
7693 TView *view = gPad ? gPad->GetView() : nullptr;
7694 if (!view) {
7695 Error("PaintH3", "no TView in current pad");
7696 return;
7697 }
7698 Double_t thedeg = 90 - gPad->GetTheta();
7699 Double_t phideg = -90 - gPad->GetPhi();
7700 Double_t psideg = view->GetPsi();
7701 Int_t irep;
7702 view->SetView(phideg, thedeg, psideg, irep);
7703
7704 Int_t backcolor = gPad->GetFrameFillColor();
7705 view->PadRange(backcolor);
7706
7707 // Draw back surfaces of frame box
7708 fLego->InitMoveScreen(-1.1,1.1);
7709 if (Hoption.BackBox) {
7710 fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
7712 fLego->BackBox(90);
7713 }
7714
7716
7717 // Define order of drawing
7718 Double_t *tnorm = view->GetTnorm();
7719 if (!tnorm) return;
7720 Int_t incrx = (tnorm[ 8] < 0.) ? -1 : +1;
7721 Int_t incry = (tnorm[ 9] < 0.) ? -1 : +1;
7722 Int_t incrz = (tnorm[10] < 0.) ? -1 : +1;
7723 Int_t ix1 = (incrx == +1) ? xaxis->GetFirst() : xaxis->GetLast();
7724 Int_t iy1 = (incry == +1) ? yaxis->GetFirst() : yaxis->GetLast();
7725 Int_t iz1 = (incrz == +1) ? zaxis->GetFirst() : zaxis->GetLast();
7726 Int_t ix2 = (incrx == +1) ? xaxis->GetLast() : xaxis->GetFirst();
7727 Int_t iy2 = (incry == +1) ? yaxis->GetLast() : yaxis->GetFirst();
7728 Int_t iz2 = (incrz == +1) ? zaxis->GetLast() : zaxis->GetFirst();
7729
7730 // Set graphic attributes (colour, style, etc.)
7735
7736 fH->SetFillStyle(1001);
7737 fH->TAttFill::Modify();
7738 fH->TAttLine::Modify();
7741
7742 // Create bin boxes and draw
7746
7747 Double_t pmin[3], pmax[3], sxyz[8][3];
7748 for (Int_t ix = ix1; ix !=ix2+incrx; ix += incrx) {
7749 pmin[0] = xaxis->GetBinLowEdge(ix);
7750 pmax[0] = xaxis->GetBinUpEdge(ix);
7751 for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
7752 pmin[1] = yaxis->GetBinLowEdge(iy);
7753 pmax[1] = yaxis->GetBinUpEdge(iy);
7754 for (Int_t iz = iz1; iz != iz2+incrz; iz += incrz) {
7755 pmin[2] = zaxis->GetBinLowEdge(iz);
7756 pmax[2] = zaxis->GetBinUpEdge(iz);
7757 Double_t w = fH->GetBinContent(fH->GetBin(ix,iy,iz));
7758 Bool_t neg = kFALSE;
7759 Int_t n = 5;
7760 if (w<0) {
7761 w = -w;
7762 neg = kTRUE;
7763 }
7764 if (w < wmin) continue;
7765 if (w > wmax) w = wmax;
7766 Double_t scale = (TMath::Power((w-wmin)/(wmax-wmin),1./3.))/2.;
7767 if (scale == 0) continue;
7768 for (Int_t i=0; i<3; ++i) {
7769 Double_t c = (pmax[i] + pmin[i])*0.5;
7770 Double_t d = (pmax[i] - pmin[i])*scale;
7771 for (Int_t k=0; k<8; ++k) { // set bin box vertices
7772 sxyz[k][i] = wxyz[k][i]*d + c;
7773 }
7774 }
7775 for (Int_t k=0; k<8; ++k) { // transform to normalized space
7776 view->WCtoNDC(&sxyz[k][0],&sxyz[k][0]);
7777 }
7778 Double_t x[8], y[8]; // draw bin box faces
7779 for (Int_t k=0; k<6; ++k) {
7780 for (Int_t i=0; i<4; ++i) {
7781 Int_t iv = iface[k][i];
7782 x[i] = sxyz[iv][0];
7783 y[i] = sxyz[iv][1];
7784 }
7785 x[4] = x[0] ; y[4] = y[0];
7786 if (neg) {
7787 x[5] = x[2] ; y[5] = y[2];
7788 x[6] = x[3] ; y[6] = y[3];
7789 x[7] = x[1] ; y[7] = y[1];
7790 n = 8;
7791 } else {
7792 n = 5;
7793 }
7794 Double_t z = (x[2]-x[0])*(y[3]-y[1]) - (y[2]-y[0])*(x[3]-x[1]);
7795 if (z <= 0.) continue;
7796 if (iopt == 2) {
7797 theColor = ncolors*((w-wmin)/(wmax-wmin)) -1;
7799 } else {
7800 if (k == 3 || k == 5) {
7802 } else if (k == 0 || k == 1) {
7804 } else {
7806 }
7807 }
7808 fH->TAttFill::Modify();
7809 gPad->PaintFillArea(4, x, y);
7810 if (iopt != 3)gPad->PaintPolyLine(n, x, y);
7811 }
7812 }
7813 }
7814 }
7815
7816 // Draw front surfaces of frame box
7817 if (Hoption.FrontBox) fLego->FrontBox(90);
7818
7819 // Draw axis and title
7820 if (!Hoption.Axis && !Hoption.Same) {
7821 TGaxis axis;
7822 PaintLegoAxis(&axis, 90);
7823 }
7824 PaintTitle();
7825
7826 // Draw palette. if needed.
7827 if (Hoption.Zscale) {
7828 Int_t ndiv = fH->GetContour();
7829 if (ndiv == 0 ) {
7830 ndiv = gStyle->GetNumberContours();
7831 fH->SetContour(ndiv);
7832 }
7833 PaintPalette();
7834 }
7835
7836 //Draw stats and fit results
7837 TF1 *fit = nullptr;
7838 TIter next(fFunctions);
7839 while (auto obj = next()) {
7840 if (obj->InheritsFrom(TF1::Class())) {
7841 fit = (TF1*)obj;
7842 break;
7843 }
7844 }
7845 if ((Hoption.Same%10) != 1) {
7846 if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
7848 }
7849 }
7850
7851 fLego.reset();
7852
7855 fH->TAttFill::Modify();
7856}
7857
7858////////////////////////////////////////////////////////////////////////////////
7859/// [Control function to draw a 3D histogram with boxes.](\ref HP25)
7860
7862{
7863 // Predefined box structure
7864 Double_t wxyz[8][3] = {
7865 {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1}, // bottom vertices
7866 {-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1} // top vertices
7867 };
7868 Int_t iface[6][4] = {
7869 {0,3,2,1}, {4,5,6,7}, // bottom and top faces
7870 {0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7} // side faces
7871 };
7872 Double_t normal[6][3] = {
7873 {0,0,-1}, {0,0,1}, // Z-, Z+
7874 {0,-1,0}, {1,0,0}, {0,1,0}, {-1,0,0} // Y-, X+, Y+, X-
7875 };
7876
7877 // Define dimensions of world space
7878 TAxis *xaxis = fH->GetXaxis();
7879 TAxis *yaxis = fH->GetYaxis();
7880 TAxis *zaxis = fH->GetZaxis();
7881
7882 fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
7883 fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
7884 fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
7885 fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
7886 fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
7887 fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
7888
7889 fLego = std::make_unique<TPainter3dAlgorithms>(fXbuf.data(), fYbuf.data());
7890
7891 // Set view
7892 TView *view = gPad ? gPad->GetView() : nullptr;
7893 if (!view) {
7894 Error("PaintH3", "no TView in current pad");
7895 return;
7896 }
7897 Double_t thedeg = 90 - gPad->GetTheta();
7898 Double_t phideg = -90 - gPad->GetPhi();
7899 Double_t psideg = view->GetPsi();
7900 Int_t irep;
7901 view->SetView(phideg, thedeg, psideg, irep);
7902
7903 Int_t backcolor = gPad->GetFrameFillColor();
7904 view->PadRange(backcolor);
7905
7906 // Draw front surfaces of frame box
7907 if (Hoption.FrontBox) {
7908 fLego->InitMoveScreen(-1.1,1.1);
7910 }
7911
7912 // Initialize hidden line removal algorithm "raster screen"
7913 fLego->InitRaster(-1.1,-1.1,1.1,1.1,1000,800);
7914
7915 // Define order of drawing
7916 Double_t *tnorm = view->GetTnorm();
7917 if (!tnorm) return;
7918 Int_t incrx = (tnorm[ 8] < 0.) ? +1 : -1;
7919 Int_t incry = (tnorm[ 9] < 0.) ? +1 : -1;
7920 Int_t incrz = (tnorm[10] < 0.) ? +1 : -1;
7921 Int_t ix1 = (incrx == +1) ? xaxis->GetFirst() : xaxis->GetLast();
7922 Int_t iy1 = (incry == +1) ? yaxis->GetFirst() : yaxis->GetLast();
7923 Int_t iz1 = (incrz == +1) ? zaxis->GetFirst() : zaxis->GetLast();
7924 Int_t ix2 = (incrx == +1) ? xaxis->GetLast() : xaxis->GetFirst();
7925 Int_t iy2 = (incry == +1) ? yaxis->GetLast() : yaxis->GetFirst();
7926 Int_t iz2 = (incrz == +1) ? zaxis->GetLast() : zaxis->GetFirst();
7927
7928 // Set line attributes (colour, style, etc.)
7929 fH->TAttLine::Modify();
7930
7931 // Create bin boxes and draw
7932 const Int_t NTMAX = 100;
7933 Double_t tt[NTMAX][2];
7937 Double_t pmin[3], pmax[3], sxyz[8][3], pp[4][2];
7938 for (Int_t ix = ix1; ix !=ix2+incrx; ix += incrx) {
7939 pmin[0] = xaxis->GetBinLowEdge(ix);
7940 pmax[0] = xaxis->GetBinUpEdge(ix);
7941 for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
7942 pmin[1] = yaxis->GetBinLowEdge(iy);
7943 pmax[1] = yaxis->GetBinUpEdge(iy);
7944 for (Int_t iz = iz1; iz != iz2+incrz; iz += incrz) {
7945 pmin[2] = zaxis->GetBinLowEdge(iz);
7946 pmax[2] = zaxis->GetBinUpEdge(iz);
7947 Double_t w = fH->GetBinContent(fH->GetBin(ix,iy,iz));
7948 Bool_t neg = kFALSE;
7949 if (w<0) {
7950 w = -w;
7951 neg = kTRUE;
7952 }
7953 if (w < wmin) continue;
7954 if (w > wmax) w = wmax;
7955 Double_t scale = (TMath::Power((w-wmin)/(wmax-wmin),1./3.))/2.;
7956 if (scale == 0) continue;
7957 for (Int_t i=0; i<3; ++i) {
7958 Double_t c = (pmax[i] + pmin[i])*0.5;
7959 Double_t d = (pmax[i] - pmin[i])*scale;
7960 for (Int_t k=0; k<8; ++k) { // set bin box vertices
7961 sxyz[k][i] = wxyz[k][i]*d + c;
7962 }
7963 }
7964 for (Int_t k=0; k<8; ++k) { // transform to normalized space
7965 view->WCtoNDC(&sxyz[k][0],&sxyz[k][0]);
7966 }
7967 for (Int_t k=0; k<6; ++k) { // draw box faces
7968 Double_t zn;
7969 view->FindNormal(normal[k][0], normal[k][1], normal[k][2], zn);
7970 if (zn <= 0) continue;
7971 for (Int_t i=0; i<4; ++i) {
7972 Int_t ip = iface[k][i];
7973 pp[i][0] = sxyz[ip][0];
7974 pp[i][1] = sxyz[ip][1];
7975 }
7976 for (Int_t i=0; i<4; ++i) {
7977 Int_t i1 = i;
7978 Int_t i2 = (i == 3) ? 0 : i + 1;
7979 Int_t nt;
7980 fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
7981 Double_t xdel = pp[i2][0] - pp[i1][0];
7982 Double_t ydel = pp[i2][1] - pp[i1][1];
7983 Double_t x[2], y[2];
7984 for (Int_t it = 0; it < nt; ++it) {
7985 x[0] = pp[i1][0] + xdel*tt[it][0];
7986 y[0] = pp[i1][1] + ydel*tt[it][0];
7987 x[1] = pp[i1][0] + xdel*tt[it][1];
7988 y[1] = pp[i1][1] + ydel*tt[it][1];
7989 gPad->PaintPolyLine(2, x, y);
7990 }
7991 }
7992 if (neg) {
7993 Int_t i1 = 0;
7994 Int_t i2 = 2;
7995 Int_t nt;
7996 fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
7997 Double_t xdel = pp[i2][0] - pp[i1][0];
7998 Double_t ydel = pp[i2][1] - pp[i1][1];
7999 Double_t x[2], y[2];
8000 for (Int_t it = 0; it < nt; ++it) {
8001 x[0] = pp[i1][0] + xdel*tt[it][0];
8002 y[0] = pp[i1][1] + ydel*tt[it][0];
8003 x[1] = pp[i1][0] + xdel*tt[it][1];
8004 y[1] = pp[i1][1] + ydel*tt[it][1];
8005 gPad->PaintPolyLine(2, x, y);
8006 }
8007 i1 = 1;
8008 i2 = 3;
8009 fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
8010 xdel = pp[i2][0] - pp[i1][0];
8011 ydel = pp[i2][1] - pp[i1][1];
8012 for (Int_t it = 0; it < nt; ++it) {
8013 x[0] = pp[i1][0] + xdel*tt[it][0];
8014 y[0] = pp[i1][1] + ydel*tt[it][0];
8015 x[1] = pp[i1][0] + xdel*tt[it][1];
8016 y[1] = pp[i1][1] + ydel*tt[it][1];
8017 gPad->PaintPolyLine(2, x, y);
8018 }
8019 }
8020 fLego->FillPolygonBorder(4, &pp[0][0]); // update raster screen
8021 }
8022 }
8023 }
8024 }
8025
8026 // Draw frame box
8027 if (Hoption.BackBox) {
8028 fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
8030 fLego->BackBox(90);
8031 }
8032
8033 if (Hoption.FrontBox) fLego->FrontBox(90);
8034
8035 // Draw axis and title
8036 if (!Hoption.Axis && !Hoption.Same) {
8037 TGaxis axis;
8038 PaintLegoAxis(&axis, 90);
8039 }
8040 PaintTitle();
8041
8042 //Draw stats and fit results
8043 TF1 *fit = nullptr;
8044 TIter next(fFunctions);
8045 while (auto obj = next()) {
8046 if (obj->InheritsFrom(TF1::Class())) {
8047 fit = (TF1*)obj;
8048 break;
8049 }
8050 }
8051 if ((Hoption.Same%10) != 1) {
8052 if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
8054 }
8055 }
8056
8057 fLego.reset();
8058}
8059
8060////////////////////////////////////////////////////////////////////////////////
8061/// [Control function to draw a 3D histogram with Iso Surfaces.](\ref HP25)
8062
8064{
8065
8066 const Double_t ydiff = 1;
8067 const Double_t yligh1 = 10;
8068 const Double_t qa = 0.15;
8069 const Double_t qd = 0.15;
8070 const Double_t qs = 0.8;
8072 Int_t i, irep;
8073 Int_t nbcol = 28;
8074 Int_t icol1 = 201;
8075 Int_t ic1 = icol1;
8076 Int_t ic2 = ic1+nbcol;
8077 Int_t ic3 = ic2+nbcol;
8078
8079 TAxis *xaxis = fH->GetXaxis();
8080 TAxis *yaxis = fH->GetYaxis();
8081 TAxis *zaxis = fH->GetZaxis();
8082
8083 Int_t nx = fH->GetNbinsX();
8084 Int_t ny = fH->GetNbinsY();
8085 Int_t nz = fH->GetNbinsZ();
8086
8087 std::vector<Double_t> x(nx);
8088 std::vector<Double_t> y(ny);
8089 std::vector<Double_t> z(nz);
8090
8091 for (i=0; i<nx; i++) x[i] = xaxis->GetBinCenter(i+1);
8092 for (i=0; i<ny; i++) y[i] = yaxis->GetBinCenter(i+1);
8093 for (i=0; i<nz; i++) z[i] = zaxis->GetBinCenter(i+1);
8094
8095 fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
8096 fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
8097 fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
8098 fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
8099 fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
8100 fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
8101
8102 Double_t s[3];
8103 s[0] = fH->GetSumOfWeights()/(fH->GetNbinsX()*fH->GetNbinsY()*fH->GetNbinsZ());
8104 s[1] = 0.5*s[0];
8105 s[2] = 1.5*s[0];
8106
8107 fLego = std::make_unique<TPainter3dAlgorithms>(fXbuf.data(), fYbuf.data());
8108
8109 TView *view = gPad ? gPad->GetView() : nullptr;
8110 if (!view) {
8111 Error("PaintH3Iso", "no TView in current pad");
8112 return;
8113 }
8114 Double_t thedeg = 90 - gPad->GetTheta();
8115 Double_t phideg = -90 - gPad->GetPhi();
8116 Double_t psideg = view->GetPsi();
8117 view->SetView(phideg, thedeg, psideg, irep);
8118
8119 Int_t backcolor = gPad->GetFrameFillColor();
8120 if (Hoption.System != kCARTESIAN) backcolor = 0;
8121 view->PadRange(backcolor);
8122
8123 Double_t dcol = 0.5/Double_t(nbcol);
8124 TColor *colref = gROOT->GetColor(fH->GetFillColor());
8125 if (!colref) {
8126 return;
8127 }
8128 Float_t r, g, b, hue, light, satur;
8129 colref->GetRGB(r,g,b);
8131 TColor *acol;
8132 for (Int_t col=0;col<nbcol;col++) {
8133 acol = gROOT->GetColor(col+icol1);
8134 TColor::HLStoRGB(hue, .4+col*dcol, satur, r, g, b);
8135 if (acol) acol->SetRGB(r, g, b);
8136 }
8137
8138 fLego->InitMoveScreen(-1.1,1.1);
8139
8140 if (Hoption.BackBox) {
8141 fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
8143 fLego->BackBox(90);
8144 }
8145
8146 fLego->LightSource(0, ydiff, 0, 0, 0, irep);
8147 fLego->LightSource(1, yligh1, 1, 1, 1, irep);
8148 fLego->SurfaceProperty(qa, qd, qs, 1, irep);
8149 fmin = ydiff*qa;
8150 fmax = ydiff*qa + (yligh1+0.1)*(qd+qs);
8151 fLego->SetIsoSurfaceParameters(fmin, fmax, nbcol, ic1, ic2, ic3);
8152
8153 fLego->IsoSurface(1, s, nx, ny, nz, x.data(), y.data(), z.data(), "BF");
8154
8155 if (Hoption.FrontBox) {
8156 fLego->InitMoveScreen(-1.1,1.1);
8158 fLego->FrontBox(90);
8159 }
8160 if (!Hoption.Axis && !Hoption.Same) {
8161 TGaxis axis;
8162 PaintLegoAxis(&axis, 90);
8163 }
8164
8165 PaintTitle();
8166
8167 //Draw stats and fit results
8168 TF1 *fit = nullptr;
8169 TIter next(fFunctions);
8170 while (auto obj = next()) {
8171 if (obj->InheritsFrom(TF1::Class())) {
8172 fit = (TF1*)obj;
8173 break;
8174 }
8175 }
8176 if ((Hoption.Same%10) != 1) {
8177 if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
8179 }
8180 }
8181
8182 fLego.reset();
8183}
8184
8185////////////////////////////////////////////////////////////////////////////////
8186/// [Control function to draw a 2D histogram as a lego plot.](\ref HP17)
8187
8189{
8190
8191 Int_t raster = 1;
8192 if (Hparam.zmin == 0 && Hparam.zmax == 0) {Hparam.zmin = -1; Hparam.zmax = 1;}
8193 Int_t nx = Hparam.xlast - Hparam.xfirst + 1;
8194 Int_t ny = Hparam.ylast - Hparam.yfirst + 1;
8195 Double_t zmin = Hparam.zmin;
8196 Double_t zmax = Hparam.zmax;
8201 Double_t dangle = 10*3.141592/180; //Delta angle for Rapidity option
8202 Double_t deltaz = TMath::Abs(zmin);
8203 if (deltaz == 0) deltaz = 1;
8204 if (zmin >= zmax) {
8205 zmin -= 0.5*deltaz;
8206 zmax += 0.5*deltaz;
8207 }
8208 Double_t z1c = zmin;
8209 Double_t z2c = zmin + (zmax-zmin)*(1+gStyle->GetHistTopMargin());
8210
8211 // Compute the lego limits and instantiate a lego object
8212 fXbuf[0] = -1;
8213 fYbuf[0] = 1;
8214 fXbuf[1] = -1;
8215 fYbuf[1] = 1;
8216 if (Hoption.System == kPOLAR) {
8217 fXbuf[2] = z1c;
8218 fYbuf[2] = z2c;
8219 } else if (Hoption.System == kCYLINDRICAL) {
8220 if (Hoption.Logy) {
8221 if (ylab1 > 0) fXbuf[2] = TMath::Log10(ylab1);
8222 else fXbuf[2] = 0;
8223 if (ylab2 > 0) fYbuf[2] = TMath::Log10(ylab2);
8224 else fYbuf[2] = 0;
8225 } else {
8226 fXbuf[2] = ylab1;
8227 fYbuf[2] = ylab2;
8228 }
8229 z1c = 0; z2c = 1;
8230 } else if (Hoption.System == kSPHERICAL) {
8231 fXbuf[2] = -1;
8232 fYbuf[2] = 1;
8233 z1c = 0; z2c = 1;
8234 } else if (Hoption.System == kRAPIDITY) {
8235 fXbuf[2] = -1/TMath::Tan(dangle);
8236 fYbuf[2] = 1/TMath::Tan(dangle);
8237 } else {
8238 fXbuf[0] = xlab1;
8239 fYbuf[0] = xlab2;
8240 fXbuf[1] = ylab1;
8241 fYbuf[1] = ylab2;
8242 fXbuf[2] = z1c;
8243 fYbuf[2] = z2c;
8244 raster = 0;
8245 }
8246
8247 fLego = std::make_unique<TPainter3dAlgorithms>(fXbuf.data(), fYbuf.data(), Hoption.System);
8248
8249 Int_t nids = -1;
8250 TH1 * hid = nullptr;
8251 Color_t colormain = -1, colordark = -1;
8253
8254 // LEGO3 is like LEGO1 except that the black lines around each lego are not drawn.
8255 if (Hoption.Lego == 13) {
8256 Hoption.Lego = 11;
8257 fLego->SetMesh(0);
8258 }
8259 // LEGO4 is like LEGO1 except no shadows are drawn.
8260 if (Hoption.Lego == 14) {
8261 Hoption.Lego = 11;
8263 }
8264
8265 // Initialize the levels on the Z axis
8266 Int_t ndiv = fH->GetContour();
8267 if (ndiv == 0 ) {
8268 ndiv = gStyle->GetNumberContours();
8269 fH->SetContour(ndiv);
8270 }
8271 Int_t ndivz = TMath::Abs(ndiv);
8272 if (!fH->TestBit(TH1::kUserContour)) fH->SetContour(ndiv);
8273
8274 // Initialize colors
8275 if (!fStack) {
8276 fLego->SetEdgeAtt(fH->GetLineColor(),fH->GetLineStyle(),fH->GetLineWidth(),0);
8277 } else {
8278 for (Int_t id=0;id<=fStack->GetSize();id++) {
8279 hid = (TH1*)fStack->At((id==0)?id:id-1);
8280 fLego->SetEdgeAtt(hid->GetLineColor(),hid->GetLineStyle(),hid->GetLineWidth(),id);
8281 }
8282 }
8283
8284 if (Hoption.Lego == 11) {
8285 nids = 1;
8286 if (fStack) nids = fStack->GetSize();
8287 hid = fH;
8288 for (Int_t id=0;id<=nids;id++) {
8289 if (id > 0 && fStack) hid = (TH1*)fStack->At(id-1);
8290 colormain = hid->GetFillColor();
8291 if (colormain == 1) colormain = 17; //avoid drawing with black
8293 else colordark = colormain;
8294 fLego->SetColorMain(colormain,id);
8295 fLego->SetColorDark(colordark,id);
8296 if (id <= 1) fLego->SetColorMain(colormain,-1); // Set Bottom color
8297 if (id == nids) fLego->SetColorMain(colormain,99); // Set Top color
8298 }
8299 }
8300
8301 // Now ready to draw the lego plot
8302 Int_t irep = 0;
8303
8304 TView *view = gPad ? gPad->GetView() : nullptr;
8305 if (!view) {
8306 Error("PaintLego", "no TView in current pad");
8307 return;
8308 }
8309
8310 Double_t thedeg = 90 - gPad->GetTheta();
8311 Double_t phideg = -90 - gPad->GetPhi();
8312 Double_t psideg = view->GetPsi();
8313 view->SetView(phideg, thedeg, psideg, irep);
8314
8315 fLego->SetLineColor(kBlack); // zgrid color for lego1 & lego2
8316 fLego->SetFillStyle(fH->GetFillStyle());
8317
8318 // Set color/style for back box
8319 fLego->SetFillStyle(gPad->GetFrameFillStyle());
8320 fLego->SetFillColor(gPad->GetFrameFillColor());
8321 fLego->TAttFill::Modify();
8322
8323 Int_t backcolor = gPad->GetFrameFillColor();
8324 if (Hoption.System != kCARTESIAN) backcolor = 0;
8325 view->PadRange(backcolor);
8326
8327 fLego->SetFillStyle(fH->GetFillStyle());
8328 fLego->SetFillColor(fH->GetFillColor());
8329 fLego->TAttFill::Modify();
8330
8331 fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
8332
8333 if (raster) fLego->InitRaster(-1.1,-1.1,1.1,1.1,1000,800);
8334 else fLego->InitMoveScreen(-1.1,1.1);
8335
8336 if (Hoption.Lego == 19) {
8338 if (Hoption.BackBox) fLego->BackBox(90);
8339 if (Hoption.FrontBox) fLego->FrontBox(90);
8340 if (!Hoption.Axis) { TGaxis axis; PaintLegoAxis(&axis, 90); }
8341 return;
8342 }
8343
8344 if (Hoption.Lego == 11 || Hoption.Lego == 12) {
8347 fLego->BackBox(90);
8348 }
8349 }
8350
8351 if (Hoption.Lego == 12) DefineColorLevels(ndivz);
8352
8353 fLego->SetLegoFunction(&TPainter3dAlgorithms::LegoFunction);
8355 if (Hoption.Lego == 11) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode3);
8356 if (Hoption.Lego == 12) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode2);
8357 if (Hoption.System == kPOLAR) {
8358 if (Hoption.Lego == 1) fLego->LegoPolar(1,nx,ny,"FB");
8359 if (Hoption.Lego == 11) fLego->LegoPolar(1,nx,ny,"BF");
8360 if (Hoption.Lego == 12) fLego->LegoPolar(1,nx,ny,"BF");
8361 } else if (Hoption.System == kCYLINDRICAL) {
8362 if (Hoption.Lego == 1) fLego->LegoCylindrical(1,nx,ny,"FB");
8363 if (Hoption.Lego == 11) fLego->LegoCylindrical(1,nx,ny,"BF");
8364 if (Hoption.Lego == 12) fLego->LegoCylindrical(1,nx,ny,"BF");
8365 } else if (Hoption.System == kSPHERICAL) {
8366 if (Hoption.Lego == 1) fLego->LegoSpherical(0,1,nx,ny,"FB");
8367 if (Hoption.Lego == 11) fLego->LegoSpherical(0,1,nx,ny,"BF");
8368 if (Hoption.Lego == 12) fLego->LegoSpherical(0,1,nx,ny,"BF");
8369 } else if (Hoption.System == kRAPIDITY) {
8370 if (Hoption.Lego == 1) fLego->LegoSpherical(1,1,nx,ny,"FB");
8371 if (Hoption.Lego == 11) fLego->LegoSpherical(1,1,nx,ny,"BF");
8372 if (Hoption.Lego == 12) fLego->LegoSpherical(1,1,nx,ny,"BF");
8373 } else {
8374 if (Hoption.Lego == 1) {
8376 fLego->LegoCartesian(90,nx,ny,"FB");}
8377 if (Hoption.Lego == 11) fLego->LegoCartesian(90,nx,ny,"BF");
8378 if (Hoption.Lego == 12) fLego->LegoCartesian(90,nx,ny,"BF");
8379 }
8380
8381 if (Hoption.Lego == 1 || Hoption.Lego == 11) {
8384 fLego->BackBox(90);
8385 }
8386 }
8387 if (Hoption.System == kCARTESIAN) {
8388 fLego->InitMoveScreen(-1.1,1.1);
8390 if (Hoption.FrontBox) fLego->FrontBox(90);
8391 }
8392 if (!Hoption.Axis && !Hoption.Same) {
8393 TGaxis axis;
8394 PaintLegoAxis(&axis, 90);
8395 }
8397 fLego.reset();
8398}
8399
8400////////////////////////////////////////////////////////////////////////////////
8401/// Draw the axis for legos and surface plots.
8402
8404{
8405
8406 static Double_t epsil = 0.001;
8407
8410 Double_t r[24] /* was [3][8] */;
8411 Int_t ndivx, ndivy, ndivz, i;
8412 Double_t x1[3], x2[3], y1[3], y2[3], z1[3], z2[3], av[24] /* was [3][8] */;
8413 static char chopax[8], chopay[8], chopaz[8];
8414 Int_t ix1, ix2, iy1, iy2, iz1, iz2;
8415 Double_t rad;
8416
8417 TView *view = gPad ? gPad->GetView() : nullptr;
8418 if (!view) {
8419 Error("PaintLegoAxis", "no TView in current pad");
8420 <