Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 
17 #include "Riostream.h"
18 #include "TROOT.h"
19 #include "TClass.h"
20 #include "TSystem.h"
21 #include "THistPainter.h"
22 #include "TH2.h"
23 #include "TH2Poly.h"
24 #include "TH3.h"
25 #include "TProfile.h"
26 #include "TProfile2D.h"
27 #include "THStack.h"
28 #include "TF2.h"
29 #include "TF3.h"
30 #include "TCutG.h"
31 #include "TMatrixDBase.h"
32 #include "TMatrixFBase.h"
33 #include "TVectorD.h"
34 #include "TVectorF.h"
35 #include "TCanvas.h"
36 #include "TPad.h"
37 #include "TPaveStats.h"
38 #include "TFrame.h"
39 #include "TLatex.h"
40 #include "TLine.h"
41 #include "TPolyLine.h"
42 #include "TPoints.h"
43 #include "TStyle.h"
44 #include "TGraph.h"
45 #include "TMultiGraph.h"
46 #include "TPie.h"
47 #include "TGaxis.h"
48 #include "TColor.h"
49 #include "TPainter3dAlgorithms.h"
50 #include "TGraph2DPainter.h"
51 #include "TGraphDelaunay2D.h"
52 #include "TView.h"
53 #include "TMath.h"
54 #include "TRandom2.h"
55 #include "TObjArray.h"
56 #include "TVectorD.h"
57 #include "Hoption.h"
58 #include "Hparam.h"
59 #include "TPluginManager.h"
60 #include "TPaletteAxis.h"
61 #include "TCrown.h"
62 #include "TArrow.h"
63 #include "TVirtualPadEditor.h"
64 #include "TEnv.h"
65 #include "TPoint.h"
66 #include "TImage.h"
67 #include "TCandle.h"
68 
69 /*! \class THistPainter
70 \ingroup Histpainter
71 \brief The histogram painter class. Implements all histograms' drawing's options.
72 
73 - [Introduction](#HP00)
74 - [Histograms' plotting options](#HP01)
75  - [Options supported for 1D and 2D histograms](#HP01a)
76  - [Options supported for 1D histograms](#HP01b)
77  - [Options supported for 2D histograms](#HP01c)
78  - [Options supported for 3D histograms](#HP01d)
79  - [Options supported for histograms' stacks (THStack)](#HP01e)
80 - [Setting the Style](#HP02)
81 - [Setting line, fill, marker, and text attributes](#HP03)
82 - [Setting Tick marks on the histogram axis](#HP04)
83 - [Giving titles to the X, Y and Z axis](#HP05)
84 - [The option "SAME"](#HP060)
85  - [Limitations](#HP060a)
86 - [Colors automatically picked in palette](#HP061)
87 - [Superimposing two histograms with different scales in the same pad](#HP06)
88 - [Statistics Display](#HP07)
89 - [Fit Statistics](#HP08)
90 - [The error bars options](#HP09)
91 - [The bar chart option](#HP100)
92 - [The "BAR" and "HBAR" options](#HP10)
93 - [The SCATter plot option (default for 2D histograms)](#HP11)
94 - [The ARRow option](#HP12)
95 - [The BOX option](#HP13)
96 - [The COLor option](#HP14)
97 - [The CANDLE and VIOLIN options](#HP140)
98  - [The CANDLE option](#HP140a)
99  - [The VIOLIN option](#HP140b)
100 - [The TEXT and TEXTnn Option](#HP15)
101 - [The CONTour options](#HP16)
102  - [The LIST option](#HP16a)
103  - [The AITOFF, MERCATOR, SINUSOIDAL and PARABOLIC options](#HP16b)
104 - [The LEGO options](#HP17)
105 - [The "SURFace" options](#HP18)
106 - [Cylindrical, Polar, Spherical and PseudoRapidity/Phi options](#HP19)
107 - [Base line for bar-charts and lego plots](#HP20)
108 - [TH2Poly Drawing](#HP20a)
109 - [The SPEC option](#HP21)
110 - [Option "Z" : Adding the color palette on the right side of the pad](#HP22)
111 - [Setting the color palette](#HP23)
112 - [Drawing a sub-range of a 2-D histogram; the [cutg] option](#HP24)
113 - [Drawing options for 3D histograms](#HP25)
114 - [Drawing option for histograms' stacks](#HP26)
115 - [Drawing of 3D implicit functions](#HP27)
116 - [Associated functions drawing](#HP28)
117 - [Drawing using OpenGL](#HP29)
118  - [General information: plot types and supported options](#HP29a)
119  - [TH3 as color boxes](#HP290)
120  - [TH3 as boxes (spheres)](#HP29b)
121  - [TH3 as iso-surface(s)](#HP29c)
122  - [TF3 (implicit function)](#HP29d)
123  - [Parametric surfaces](#HP29e)
124  - [Interaction with the plots](#HP29f)
125  - [Selectable parts](#HP29g)
126  - [Rotation and zooming](#HP29h)
127  - [Panning](#HP29i)
128  - [Box cut](#HP29j)
129  - [Plot specific interactions (dynamic slicing etc.)](#HP29k)
130  - [Surface with option "GLSURF"](#HP29l)
131  - [TF3](#HP29m)
132  - [Box](#HP29n)
133  - [Iso](#HP29o)
134  - [Parametric plot](#HP29p)
135 - [Highlight mode for histogram](#HP30)
136  - [Highlight mode and user function](#HP30a)
137 
138 
139 ## <a name="HP00"></a> Introduction
140 
141 
142 Histograms are drawn via the `THistPainter` class. Each histogram has a
143 pointer to its own painter (to be usable in a multithreaded program). When the
144 canvas has to be redrawn, the `Paint` function of each objects in the
145 pad is called. In case of histograms, `TH1::Paint` invokes directly
146 `THistPainter::Paint`.
147 
148 To draw a histogram `h` it is enough to do:
149 
150  h->Draw();
151 
152 `h` can be of any kind: 1D, 2D or 3D. To choose how the histogram will
153 be drawn, the `Draw()` method can be invoked with an option. For instance
154 to draw a 2D histogram as a lego plot it is enough to do:
155 
156  h->Draw("lego");
157 
158 `THistPainter` offers many options to paint 1D, 2D and 3D histograms.
159 
160 When the `Draw()` method of a histogram is called for the first time
161 (`TH1::Draw`), it creates a `THistPainter` object and saves a
162 pointer to this "painter" as a data member of the histogram. The
163 `THistPainter` class specializes in the drawing of histograms. It is
164 separated from the histogram so that one can have histograms without the
165 graphics overhead, for example in a batch program. Each histogram having its own
166 painter (rather than a central singleton painter painting all histograms), allows
167 two histograms to be drawn in two threads without overwriting the painter's
168 values.
169 
170 When a displayed histogram is filled again, there is no need to call the
171 `Draw()` method again; the image will be refreshed the next time the
172 pad will be updated.
173 
174 A pad is updated after one of these three actions:
175 
176 1. a carriage control on the ROOT command line,
177 2. a click inside the pad,
178 3. a call to `TPad::Update`.
179 
180 
181 By default a call to `TH1::Draw()` clears the pad of all objects
182 before drawing the new image of the histogram. One can use the `SAME`
183 option to leave the previous display intact and superimpose the new histogram.
184 The same histogram can be drawn with different graphics options in different
185 pads.
186 
187 When a displayed histogram is deleted, its image is automatically removed
188 from the pad.
189 
190 To create a copy of the histogram when drawing it, one can use
191 `TH1::DrawClone()`. This will clone the histogram and allow to change
192 and delete the original one without affecting the clone.
193 
194 
195 ### <a name="HP01"></a> Histograms' plotting options
196 
197 
198 Most options can be concatenated with or without spaces or commas, for example:
199 
200  h->Draw("E1 SAME");
201 
202 The options are not case sensitive:
203 
204  h->Draw("e1 same");
205 
206 
207 The default drawing option can be set with `TH1::SetOption` and retrieve
208 using `TH1::GetOption`:
209 
210  root [0] h->Draw(); // Draw "h" using the standard histogram representation.
211  root [1] h->Draw("E"); // Draw "h" using error bars
212  root [3] h->SetOption("E"); // Change the default drawing option for "h"
213  root [4] h->Draw(); // Draw "h" using error bars
214  root [5] h->GetOption(); // Retrieve the default drawing option for "h"
215  (const Option_t* 0xa3ff948)"E"
216 
217 
218 #### <a name="HP01a"></a> Options supported for 1D and 2D histograms
219 
220 | Option | Description |
221 |----------|-------------------------------------------------------------------|
222 | "E" | Draw error bars. |
223 | "AXIS" | Draw only axis. |
224 | "AXIG" | Draw only grid (if the grid is requested). |
225 | <a name="OPTHIST">"HIST"</a> | 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). |
226 | "FUNC" | When an histogram has a fitted function, this option allows to draw the fit result only. |
227 | "SAME" | Superimpose on previous picture in the same pad. |
228 | "SAMES" | Same as "SAME" and draw the statistics box|
229 | "PFC" | Palette Fill Color: histogram's fill color is taken in the current palette. |
230 | "PLC" | Palette Line Color: histogram's line color is taken in the current palette. |
231 | "PMC" | Palette Marker Color: histogram's marker color is taken in the current palette. |
232 | "LEGO" | Draw a lego plot with hidden line removal. |
233 | "LEGO1" | Draw a lego plot with hidden surface removal. |
234 | "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.|
235 | "LEGO3" | Draw a lego plot with hidden surface removal, like LEGO1 but the border lines of each lego-bar are not drawn.|
236 | "LEGO4" | Draw a lego plot with hidden surface removal, like LEGO1 but without the shadow effect on each lego-bar.|
237 | "TEXT" | Draw bin contents as text (format set via `gStyle->SetPaintTextFormat`).|
238 | "TEXTnn" | Draw bin contents as text at angle nn (0 < nn < 90). |
239 | "X+" | The X-axis is drawn on the top side of the plot. |
240 | "Y+" | The Y-axis is drawn on the right side of the plot. |
241 | "MIN0" | Set minimum value for the Y axis to 0, equivalent to gStyle->SetHistMinimumZero(). |
242 
243 #### <a name="HP01b"></a> Options supported for 1D histograms
244 
245 | Option | Description |
246 |----------|-------------------------------------------------------------------|
247 | " " | Default. |
248 | "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.|
249 | "][" | When this option is selected the first and last vertical lines of the histogram are not drawn.|
250 | "B" | Bar chart option.|
251 | "BAR" | Like option "B", but bars can be drawn with a 3D effect.|
252 | "HBAR" | Like option "BAR", but bars are drawn horizontally.|
253 | "C" | Draw a smooth Curve through the histogram bins.|
254 | "E0" | Draw error bars. Markers are drawn for bins with 0 contents.|
255 | "E1" | Draw error bars with perpendicular lines at the edges.|
256 | "E2" | Draw error bars with rectangles.|
257 | "E3" | Draw a fill area through the end points of the vertical error bars.|
258 | "E4" | Draw a smoothed filled area through the end points of the error bars.|
259 | "E5" | Like E3 but ignore the bins with 0 contents.|
260 | "E6" | Like E4 but ignore the bins with 0 contents.|
261 | "X0" | When used with one of the "E" option, it suppress the error bar along X as `gStyle->SetErrorX(0)` would do.|
262 | "L" | Draw a line through the bin contents.|
263 | "P" | Draw current marker at each bin except empty bins.|
264 | "P0" | Draw current marker at each bin including empty bins.|
265 | "PIE" | Draw histogram as a Pie Chart.|
266 | "*H" | Draw histogram with a * at each bin.|
267 | "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.|
268 
269 
270 #### <a name="HP01c"></a> Options supported for 2D histograms
271 
272 | Option | Description |
273 |-----------|------------------------------------------------------------------|
274 | " " | Default (scatter plot).|
275 | "ARR" | Arrow mode. Shows gradient between adjacent cells.|
276 | "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.|
277 | "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.|
278 | "COL" | A box is drawn for each cell with a color scale varying with contents. All the none empty bins 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.|
279 | "COLZ" | Same as "COL". In addition the color palette is also drawn.|
280 | "COL2" | Alternative rendering algorithm to "COL". Can significantly improve rendering performance for large, non-sparse 2-D histograms.|
281 | "COLZ2" | Same as "COL2". In addition the color palette is also drawn.|
282 | "Z CJUST" | In combination with colored options "COL","CONT0" etc: Justify labels in the color palette at color boudaries. For more details see `TPaletteAxis`|
283 | "CANDLE" | Draw a candle plot along X axis.|
284 | "CANDLEX" | Same as "CANDLE".|
285 | "CANDLEY" | Draw a candle plot along Y axis.|
286 | "CANDLEXn"| Draw a candle plot along X axis. Different candle-styles with n from 1 to 6.|
287 | "CANDLEYn"| Draw a candle plot along Y axis. Different candle-styles with n from 1 to 6.|
288 | "VIOLIN" | Draw a violin plot along X axis.|
289 | "VIOLINX" | Same as "VIOLIN".|
290 | "VIOLINY" | Draw a violin plot along Y axis.|
291 | "VIOLINXn"| Draw a violin plot along X axis. Different violin-styles with n being 1 or 2.|
292 | "VIOLINYn"| Draw a violin plot along Y axis. Different violin-styles with n being 1 or 2.|
293 | "CONT" | Draw a contour plot (same as CONT0).|
294 | "CONT0" | Draw a contour plot using surface colors to distinguish contours.|
295 | "CONT1" | Draw a contour plot using line styles to distinguish contours.|
296 | "CONT2" | Draw a contour plot using the same line style for all contours.|
297 | "CONT3" | Draw a contour plot using fill area colors.|
298 | "CONT4" | Draw a contour plot using surface colors (SURF option at theta = 0).|
299 | "CONT5" | (TGraph2D only) Draw a contour plot using Delaunay triangles.|
300 | "LIST" | Generate a list of TGraph objects for each contour.|
301 | "CYL" | Use Cylindrical coordinates. The X coordinate is mapped on the angle and the Y coordinate on the cylinder length.|
302 | "POL" | Use Polar coordinates. The X coordinate is mapped on the angle and the Y coordinate on the radius.|
303 | "SAME0" | Same as "SAME" but do not use the z-axis range of the first plot. |
304 | "SAMES0" | Same as "SAMES" but do not use the z-axis range of the first plot. |
305 | "SPH" | Use Spherical coordinates. The X coordinate is mapped on the latitude and the Y coordinate on the longitude.|
306 | "PSR" | Use PseudoRapidity/Phi coordinates. The X coordinate is mapped on Phi.|
307 | "SURF" | Draw a surface plot with hidden line removal.|
308 | "SURF1" | Draw a surface plot with hidden surface removal.|
309 | "SURF2" | Draw a surface plot using colors to show the cell contents.|
310 | "SURF3" | Same as SURF with in addition a contour view drawn on the top.|
311 | "SURF4" | Draw a surface using Gouraud shading.|
312 | "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.|
313 | "LEGO9" | Draw the 3D axis only. Mainly needed for internal use |
314 | "FB" | With LEGO or SURFACE, suppress the Front-Box.|
315 | "BB" | With LEGO or SURFACE, suppress the Back-Box.|
316 | "A" | With LEGO or SURFACE, suppress the axis.|
317 | "SCAT" | Draw a scatter-plot (default).|
318 | "[cutg]" | Draw only the sub-range selected by the TCutG named "cutg".|
319 
320 
321 #### <a name="HP01d"></a> Options supported for 3D histograms
322 
323 | Option | Description |
324 |----------|-------------------------------------------------------------------|
325 | " " | Default (scatter plot).|
326 | "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)`.|
327 | "BOX" | Draw a for each cell with volume proportional to the content's absolute value. An hidden line removal algorithm is used|
328 | "BOX1" | Same as BOX but an hidden surface removal algorithm is used|
329 | "BOX2" | The boxes' colors are picked in the current palette according to the bins' contents|
330 | "BOX2Z" | Same as "BOX2". In addition the color palette is also drawn.|
331 | "BOX3" | Same as BOX1, but the border lines of each lego-bar are not drawn.|
332 | "LEGO" | Same as `BOX`.|
333 
334 
335 #### <a name="HP01e"></a> Options supported for histograms' stacks (`THStack`)
336 
337 | Option | Description |
338 |------------|-----------------------------------------------------------------|
339 | " " | Default, the histograms are drawn on top of each other (as lego plots for 2D histograms).|
340 | "NOSTACK" | Histograms in the stack are all paint in the same pad as if the option `SAME` had been specified.|
341 | "NOSTACKB" | Histograms are drawn next to each other as bar charts.|
342 | "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.|
343 | "PFC" | Palette Fill Color: stack's fill color is taken in the current palette. |
344 | "PLC" | Palette Line Color: stack's line color is taken in the current palette. |
345 | "PMC" | Palette Marker Color: stack's marker color is taken in the current palette. |
346 
347 
348 
349 ### <a name="HP02"></a> Setting the Style
350 
351 
352 Histograms use the current style (`gStyle`). When one changes the current
353 style and would like to propagate the changes to the histogram,
354 `TH1::UseCurrentStyle` should be called. Call `UseCurrentStyle` on
355 each histogram is needed.
356 
357 To force all the histogram to use the current style use:
358 
359  gROOT->ForceStyle();
360 
361 All the histograms read after this call will use the current style.
362 
363 
364 ### <a name="HP03"></a> Setting line, fill, marker, and text attributes
365 
366 
367 The histogram classes inherit from the attribute classes:
368 `TAttLine`, `TAttFill` and `TAttMarker`.
369 See the description of these classes for the list of options.
370 
371 
372 ### <a name="HP04"></a> Setting Tick marks on the histogram axis
373 
374 
375 The `TPad::SetTicks` method specifies the type of tick marks on the axis.
376 If ` tx = gPad->GetTickx()` and `ty = gPad->GetTicky()` then:
377 
378  tx = 1; tick marks on top side are drawn (inside)
379  tx = 2; tick marks and labels on top side are drawn
380  ty = 1; tick marks on right side are drawn (inside)
381  ty = 2; tick marks and labels on right side are drawn
382 
383 By default only the left Y axis and X bottom axis are drawn
384 (`tx = ty = 0`)
385 
386 `TPad::SetTicks(tx,ty)` allows to set these options.
387 See also The `TAxis` functions to set specific axis attributes.
388 
389 In case multiple color filled histograms are drawn on the same pad, the fill
390 area may hide the axis tick marks. One can force a redraw of the axis over all
391 the histograms by calling:
392 
393  gPad->RedrawAxis();
394 
395 
396 ### <a name="HP05"></a> Giving titles to the X, Y and Z axis
397 
398 
399  h->GetXaxis()->SetTitle("X axis title");
400  h->GetYaxis()->SetTitle("Y axis title");
401 
402 The histogram title and the axis titles can be any `TLatex` string.
403 The titles are part of the persistent histogram.
404 
405 
406 ### <a name="HP060"></a> The option "SAME"
407 
408 
409 By default, when an histogram is drawn, the current pad is cleared before
410 drawing. In order to keep the previous drawing and draw on top of it the
411 option `SAME` should be use. The histogram drawn with the option
412 `SAME` uses the coordinates system available in the current pad.
413 
414 This option can be used alone or combined with any valid drawing option but
415 some combinations must be use with care.
416 
417 #### <a name="HP060a"></a> Limitations
418 
419 - It does not work when combined with the `LEGO` and `SURF` options unless the
420  histogram plotted with the option `SAME` has exactly the same
421  ranges on the X, Y and Z axis as the currently drawn histogram. To superimpose
422  lego plots [histograms' stacks](#HP26) should be used.</li>
423 
424 
425 ### <a name="HP061"></a> Colors automatically picked in palette
426 
427 \since **ROOT version 6.09/01**
428 
429 When several histograms are painted in the same canvas thanks to the option "SAME"
430 or via a `THStack` it might be useful to have an easy and automatic way to choose
431 their color. The simplest way is to pick colors in the current active color
432 palette. Palette coloring for histogram is activated thanks to the options `PFC`
433 (Palette Fill Color), `PLC` (Palette Line Color) and `PMC` (Palette Marker Color).
434 When one of these options is given to `TH1::Draw` the histogram get its color
435 from the current color palette defined by `gStyle->SetPalette(…)`. The color
436 is determined according to the number of objects having palette coloring in
437 the current pad.
438 
439 Begin_Macro(source)
440 ../../../tutorials/hist/histpalettecolor.C
441 End_Macro
442 
443 Begin_Macro(source)
444 ../../../tutorials/hist/thstackpalettecolor.C
445 End_Macro
446 
447 Begin_Macro(source)
448 ../../../tutorials/hist/thstack2palettecolor.C
449 End_Macro
450 
451 ### <a name="HP06"></a> Superimposing two histograms with different scales in the same pad
452 
453 
454 The following example creates two histograms, the second histogram is the bins
455 integral of the first one. It shows a procedure to draw the two histograms in
456 the same pad and it draws the scale of the second histogram using a new vertical
457 axis on the right side. See also the tutorial `transpad.C` for a variant
458 of this example.
459 
460 Begin_Macro(source)
461 {
462  auto c1 = new TCanvas("c1","c1",600,400);
463  // create/fill draw h1
464  gStyle->SetOptStat(kFALSE);
465  auto h1 = new TH1F("h1","Superimposing two histograms with different scales",100,-3,3);
466  Int_t i;
467  for (i=0;i<10000;i++) h1->Fill(gRandom->Gaus(0,1));
468  h1->Draw();
469  c1->Update();
470 
471  // create hint1 filled with the bins integral of h1
472  auto hint1 = new TH1F("hint1","h1 bins integral",100,-3,3);
473  float sum = 0.f;
474  for (i=1;i<=100;i++) {
475  sum += h1->GetBinContent(i);
476  hint1->SetBinContent(i,sum);
477  }
478 
479  // scale hint1 to the pad coordinates
480  float rightmax = 1.1*hint1->GetMaximum();
481  float scale = gPad->GetUymax()/rightmax;
482  hint1->SetLineColor(kRed);
483  hint1->Scale(scale);
484  hint1->Draw("same");
485 
486  // draw an axis on the right side
487  auto axis = new TGaxis(gPad->GetUxmax(),gPad->GetUymin(),
488  gPad->GetUxmax(), gPad->GetUymax(),0,rightmax,510,"+L");
489  axis->SetLineColor(kRed);
490  axis->SetTextColor(kRed);
491  axis->Draw();
492 }
493 End_Macro
494 
495 
496 ### <a name="HP07"></a> Statistics Display
497 
498 
499 The type of information shown in the histogram statistics box can be selected
500 with:
501 
502  gStyle->SetOptStat(mode);
503 
504 The `mode` has up to nine digits that can be set to on (1 or 2), off (0).
505 
506  mode = ksiourmen (default = 000001111)
507  k = 1; kurtosis printed
508  k = 2; kurtosis and kurtosis error printed
509  s = 1; skewness printed
510  s = 2; skewness and skewness error printed
511  i = 1; integral of bins printed
512  i = 2; integral of bins with option "width" printed
513  o = 1; number of overflows printed
514  u = 1; number of underflows printed
515  r = 1; standard deviation printed
516  r = 2; standard deviation and standard deviation error printed
517  m = 1; mean value printed
518  m = 2; mean and mean error values printed
519  e = 1; number of entries printed
520  n = 1; name of histogram is printed
521 
522 For example:
523 
524  gStyle->SetOptStat(11);
525 
526 displays only the name of histogram and the number of entries, whereas:
527 
528  gStyle->SetOptStat(1101);
529 
530 displays the name of histogram, mean value and standard deviation.
531 
532 <b>WARNING 1:</b> never do:
533 
534  gStyle->SetOptStat(0001111);
535 
536 but instead do:
537 
538  gStyle->SetOptStat(1111);
539 
540 because `0001111` will be taken as an octal number!
541 
542 <b>WARNING 2:</b> for backward compatibility with older versions
543 
544  gStyle->SetOptStat(1);
545 
546 is taken as:
547 
548  gStyle->SetOptStat(1111)
549 
550 To print only the name of the histogram do:
551 
552  gStyle->SetOptStat(1000000001);
553 
554 <b>NOTE</b> that in case of 2D histograms, when selecting only underflow
555 (10000) or overflow (100000), the statistics box will show all combinations
556 of underflow/overflows and not just one single number.
557 
558 The parameter mode can be any combination of the letters `kKsSiIourRmMen`
559 
560  k : kurtosis printed
561  K : kurtosis and kurtosis error printed
562  s : skewness printed
563  S : skewness and skewness error printed
564  i : integral of bins printed
565  I : integral of bins with option "width" printed
566  o : number of overflows printed
567  u : number of underflows printed
568  r : standard deviation printed
569  R : standard deviation and standard deviation error printed
570  m : mean value printed
571  M : mean value mean error values printed
572  e : number of entries printed
573  n : name of histogram is printed
574 
575 For example, to print only name of histogram and number of entries do:
576 
577  gStyle->SetOptStat("ne");
578 
579 To print only the name of the histogram do:
580 
581  gStyle->SetOptStat("n");
582 
583 The default value is:
584 
585  gStyle->SetOptStat("nemr");
586 
587 When a histogram is painted, a `TPaveStats` object is created and added
588 to the list of functions of the histogram. If a `TPaveStats` object
589 already exists in the histogram list of functions, the existing object is just
590 updated with the current histogram parameters.
591 
592 Once a histogram is painted, the statistics box can be accessed using
593 `h->FindObject("stats")`. In the command line it is enough to do:
594 
595  Root > h->Draw()
596  Root > TPaveStats *st = (TPaveStats*)h->FindObject("stats")
597 
598 because after `h->Draw()` the histogram is automatically painted. But
599 in a script file the painting should be forced using `gPad->Update()`
600 in order to make sure the statistics box is created:
601 
602  h->Draw();
603  gPad->Update();
604  TPaveStats *st = (TPaveStats*)h->FindObject("stats");
605 
606 Without `gPad->Update()` the line `h->FindObject("stats")` returns a null pointer.
607 
608 When a histogram is drawn with the option `SAME`, the statistics box
609 is not drawn. To force the statistics box drawing with the option
610 `SAME`, the option `SAMES` must be used.
611 If the new statistics box hides the previous statistics box, one can change
612 its position with these lines (`h` being the pointer to the histogram):
613 
614  Root > TPaveStats *st = (TPaveStats*)h->FindObject("stats")
615  Root > st->SetX1NDC(newx1); //new x start position
616  Root > st->SetX2NDC(newx2); //new x end position
617 
618 To change the type of information for an histogram with an existing
619 `TPaveStats` one should do:
620 
621  st->SetOptStat(mode);
622 
623 Where `mode` has the same meaning than when calling `gStyle->SetOptStat(mode)`
624 (see above).
625 
626 One can delete the statistics box for a histogram `TH1* h` with:
627 
628  h->SetStats(0)
629 
630 and activate it again with:
631 
632  h->SetStats(1).
633 
634 Labels used in the statistics box ("Mean", "Std Dev", ...) can be changed from
635 `$ROOTSYS/etc/system.rootrc` or `.rootrc` (look for the string `Hist.Stats.`).
636 
637 
638 ### <a name="HP08"></a> Fit Statistics
639 
640 
641 The type of information about fit parameters printed in the histogram statistics
642 box can be selected via the parameter mode. The parameter mode can be
643 `= pcev` (default `= 0111`)
644 
645  p = 1; print Probability
646  c = 1; print Chisquare/Number of degrees of freedom
647  e = 1; print errors (if e=1, v must be 1)
648  v = 1; print name/values of parameters
649 
650 Example:
651 
652  gStyle->SetOptFit(1011);
653 
654 print fit probability, parameter names/values and errors.
655 
656 1. When `v" = 1` is specified, only the non-fixed parameters are shown.
657 2. When `v" = 2` all parameters are shown.
658 
659 Note: `gStyle->SetOptFit(1)` means "default value", so it is equivalent
660 to `gStyle->SetOptFit(111)`
661 
662 
663 ### <a name="HP09"></a> The error bars options
664 
665 
666 | Option | Description |
667 |----------|-------------------------------------------------------------------|
668 | "E" | Default. Shows only the error bars, not a marker.|
669 | "E1" | Small lines are drawn at the end of the error bars.|
670 | "E2" | Error rectangles are drawn.|
671 | "E3" | A filled area is drawn through the end points of the vertical error bars.|
672 | "E4" | A smoothed filled area is drawn through the end points of the vertical error bars.|
673 | "E0" | Draw also bins with null contents.|
674 
675 Begin_Macro(source)
676 {
677  auto c1 = new TCanvas("c1","c1",600,400);
678  auto he = new TH1F("he","Distribution drawn with error bars (option E1) ",100,-3,3);
679  for (int i=0; i<10000; i++) he->Fill(gRandom->Gaus(0,1));
680  gStyle->SetEndErrorSize(3);
681  gStyle->SetErrorX(1.);
682  he->SetMarkerStyle(20);
683  he->Draw("E1");
684 }
685 End_Macro
686 
687 The options "E3" and "E4" draw an error band through the end points of the
688 vertical error bars. With "E4" the error band is smoothed. Because of the
689 smoothing algorithm used some artefacts may appear at the end of the band
690 like in the following example. In such cases "E3" should be used instead
691 of "E4".
692 
693 Begin_Macro(source)
694 {
695  auto ce4 = new TCanvas("ce4","ce4",600,400);
696  ce4->Divide(2,1);
697  auto he4 = new TH1F("he4","Distribution drawn with option E4",100,-3,3);
698  Int_t i;
699  for (i=0;i<10000;i++) he4->Fill(gRandom->Gaus(0,1));
700  he4->SetFillColor(kRed);
701  he4->GetXaxis()->SetRange(40,48);
702  ce4->cd(1);
703  he4->Draw("E4");
704  ce4->cd(2);
705  auto he3 = (TH1F*)he4->DrawClone("E3");
706  he3->SetTitle("Distribution drawn option E3");
707 }
708 End_Macro
709 
710 2D histograms can be drawn with error bars as shown is the following example:
711 
712 Begin_Macro(source)
713 {
714  auto c2e = new TCanvas("c2e","c2e",600,400);
715  auto h2e = new TH2F("h2e","TH2 drawn with option E",40,-4,4,40,-20,20);
716  float px, py;
717  for (Int_t i = 0; i < 25000; i++) {
718  gRandom->Rannor(px,py);
719  h2e->Fill(px,5*py);
720  }
721  h2e->Draw("E");
722 }
723 End_Macro
724 
725 
726 ### <a name="HP100"></a> The bar chart option
727 
728 
729 The option "B" allows to draw simple vertical bar charts.
730 The bar width is controlled with `TH1::SetBarWidth()`,
731 and the bar offset within the bin, with `TH1::SetBarOffset()`.
732 These two settings are useful to draw several histograms on the
733 same plot as shown in the following example:
734 
735 Begin_Macro(source)
736 {
737  int i;
738  const Int_t nx = 8;
739  string os_X[nx] = {"8","32","128","512","2048","8192","32768","131072"};
740  float d_35_0[nx] = {0.75, -3.30, -0.92, 0.10, 0.08, -1.69, -1.29, -2.37};
741  float d_35_1[nx] = {1.01, -3.02, -0.65, 0.37, 0.34, -1.42, -1.02, -2.10};
742 
743  auto cb = new TCanvas("cb","cb",600,400);
744  cb->SetGrid();
745 
746  gStyle->SetHistMinimumZero();
747 
748  auto h1b = new TH1F("h1b","Option B example",nx,0,nx);
749  h1b->SetFillColor(4);
750  h1b->SetBarWidth(0.4);
751  h1b->SetBarOffset(0.1);
752  h1b->SetStats(0);
753  h1b->SetMinimum(-5);
754  h1b->SetMaximum(5);
755 
756  for (i=1; i<=nx; i++) {
757  h1b->SetBinContent(i, d_35_0[i-1]);
758  h1b->GetXaxis()->SetBinLabel(i,os_X[i-1].c_str());
759  }
760 
761  h1b->Draw("b");
762 
763  auto h2b = new TH1F("h2b","h2b",nx,0,nx);
764  h2b->SetFillColor(38);
765  h2b->SetBarWidth(0.4);
766  h2b->SetBarOffset(0.5);
767  h2b->SetStats(0);
768  for (i=1;i<=nx;i++) h2b->SetBinContent(i, d_35_1[i-1]);
769 
770  h2b->Draw("b same");
771 }
772 End_Macro
773 
774 
775 ### <a name="HP10"></a> The "BAR" and "HBAR" options
776 
777 
778 When the option `bar` or `hbar` is specified, a bar chart is drawn. A vertical
779 bar-chart is drawn with the options `bar`, `bar0`, `bar1`, `bar2`, `bar3`, `bar4`.
780 An horizontal bar-chart is drawn with the options `hbar`, `hbar0`, `hbar1`,
781 `hbar2`, `hbar3`, `hbar4` (hbars.C).
782 
783 - The bar is filled with the histogram fill color.
784 - The left side of the bar is drawn with a light fill color.
785 - The right side of the bar is drawn with a dark fill color.
786 - The percentage of the bar drawn with either the light or dark color is:
787  - 0% for option "(h)bar" or "(h)bar0"
788  - 10% for option "(h)bar1"
789  - 20% for option "(h)bar2"
790  - 30% for option "(h)bar3"
791  - 40% for option "(h)bar4"
792 
793 When an histogram has errors the option ["HIST"](#OPTHIST) together with the `(h)bar` option.
794 
795 Begin_Macro(source)
796 ../../../tutorials/hist/hbars.C
797 End_Macro
798 
799 To control the bar width (default is the bin width) `TH1::SetBarWidth()`
800 should be used.
801 
802 To control the bar offset (default is 0) `TH1::SetBarOffset()` should
803 be used.
804 
805 These two parameters are useful when several histograms are plotted using
806 the option `SAME`. They allow to plot the histograms next to each other.
807 
808 
809 ### <a name="HP11"></a> The SCATter plot option (default for 2D histograms)
810 
811 
812 For each cell (i,j) a number of points proportional to the cell content is
813 drawn. A maximum of `kNMAX` points per cell is drawn. If the maximum is above
814 `kNMAX` contents are normalized to `kNMAX` (`kNMAX=2000`).
815 If option is of the form `scat=ff`, (eg `scat=1.8`,
816 `scat=1e-3`), then `ff` is used as a scale factor to compute the
817 number of dots. `scat=1` is the default.
818 
819 By default the scatter plot is painted with a "dot marker" which not scalable
820 (see the `TAttMarker` documentation). To change the marker size, a scalable marker
821 type should be used. For instance a circle (marker style 20).
822 
823 Begin_Macro(source)
824 {
825  auto c1 = new TCanvas("c1","c1",600,400);
826  auto hscat = new TH2F("hscat","Option SCATter example (default for 2D histograms) ",40,-4,4,40,-20,20);
827  float px, py;
828  for (Int_t i = 0; i < 25000; i++) {
829  gRandom->Rannor(px,py);
830  hscat->Fill(px,5*py);
831  hscat->Fill(3+0.5*px,2*py-10.);
832  }
833  hscat->Draw("scat=0.5");
834 }
835 End_Macro
836 
837 
838 ### <a name="HP12"></a> The ARRow option
839 
840 
841 Shows gradient between adjacent cells. For each cell (i,j) an arrow is drawn
842 The orientation of the arrow follows the cell gradient.
843 
844 Begin_Macro(source)
845 {
846  auto c1 = new TCanvas("c1","c1",600,400);
847  auto harr = new TH2F("harr","Option ARRow example",20,-4,4,20,-20,20);
848  harr->SetLineColor(kRed);
849  float px, py;
850  for (Int_t i = 0; i < 25000; i++) {
851  gRandom->Rannor(px,py);
852  harr->Fill(px,5*py);
853  harr->Fill(3+0.5*px,2*py-10.,0.1);
854  }
855  harr->Draw("ARR");
856 }
857 End_Macro
858 
859 \since **ROOT version 6.17/01**
860 
861 The option `ARR` can be combined with the option `COL` or `COLZ`.
862 
863 Begin_Macro(source)
864 {
865  auto c1 = new TCanvas("c1","c1",600,400);
866  auto harr = new TH2F("harr","Option ARR + COLZ example",20,-4,4,20,-20,20);
867  harr->SetStats(0);
868  float px, py;
869  for (Int_t i = 0; i < 25000; i++) {
870  gRandom->Rannor(px,py);
871  harr->Fill(px,5*py);
872  harr->Fill(3+0.5*px,2*py-10.,0.1);
873  }
874  harr->Draw("ARR COLZ");
875 }
876 End_Macro
877 
878 
879 ### <a name="HP13"></a> The BOX option
880 
881 
882 For each cell (i,j) a box is drawn. The size (surface) of the box is
883 proportional to the absolute value of the cell content.
884 The cells with a negative content are drawn with a `X` on top of the box.
885 
886 Begin_Macro(source)
887 {
888  auto c1 = new TCanvas("c1","c1",600,400);
889  auto hbox = new TH2F("hbox","Option BOX example",3,0,3,3,0,3);
890  hbox->SetFillColor(42);
891  hbox->Fill(0.5, 0.5, 1.);
892  hbox->Fill(0.5, 1.5, 4.);
893  hbox->Fill(0.5, 2.5, 3.);
894  hbox->Fill(1.5, 0.5, 2.);
895  hbox->Fill(1.5, 1.5, 12.);
896  hbox->Fill(1.5, 2.5, -6.);
897  hbox->Fill(2.5, 0.5, -4.);
898  hbox->Fill(2.5, 1.5, 6.);
899  hbox->Fill(2.5, 2.5, 0.5);
900  hbox->Draw("BOX");
901 }
902 End_Macro
903 
904 With option `BOX1` a button is drawn for each cell with surface
905 proportional to content's absolute value. A sunken button is drawn for
906 negative values a raised one for positive.
907 
908 Begin_Macro(source)
909 {
910  auto c1 = new TCanvas("c1","c1",600,400);
911  auto hbox1 = new TH2F("hbox1","Option BOX1 example",3,0,3,3,0,3);
912  hbox1->SetFillColor(42);
913  hbox1->Fill(0.5, 0.5, 1.);
914  hbox1->Fill(0.5, 1.5, 4.);
915  hbox1->Fill(0.5, 2.5, 3.);
916  hbox1->Fill(1.5, 0.5, 2.);
917  hbox1->Fill(1.5, 1.5, 12.);
918  hbox1->Fill(1.5, 2.5, -6.);
919  hbox1->Fill(2.5, 0.5, -4.);
920  hbox1->Fill(2.5, 1.5, 6.);
921  hbox1->Fill(2.5, 2.5, 0.5);
922  hbox1->Draw("BOX1");
923 }
924 End_Macro
925 
926 When the option `SAME` (or "SAMES") is used with the option `BOX`,
927 the boxes' sizes are computing taking the previous plots into account. The range
928 along the Z axis is imposed by the first plot (the one without option
929 `SAME`); therefore the order in which the plots are done is relevant.
930 
931 Begin_Macro(source)
932 {
933  auto c1 = new TCanvas("c1","c1",600,400);
934  auto hb1 = new TH2F("hb1","Example of BOX plots with option SAME ",40,-3,3,40,-3,3);
935  auto hb2 = new TH2F("hb2","hb2",40,-3,3,40,-3,3);
936  auto hb3 = new TH2F("hb3","hb3",40,-3,3,40,-3,3);
937  auto hb4 = new TH2F("hb4","hb4",40,-3,3,40,-3,3);
938  for (Int_t i=0;i<1000;i++) {
939  double x,y;
940  gRandom->Rannor(x,y);
941  if (x>0 && y>0) hb1->Fill(x,y,4);
942  if (x<0 && y<0) hb2->Fill(x,y,3);
943  if (x>0 && y<0) hb3->Fill(x,y,2);
944  if (x<0 && y>0) hb4->Fill(x,y,1);
945  }
946  hb1->SetFillColor(1);
947  hb2->SetFillColor(2);
948  hb3->SetFillColor(3);
949  hb4->SetFillColor(4);
950  hb1->Draw("box");
951  hb2->Draw("box same");
952  hb3->Draw("box same");
953  hb4->Draw("box same");
954 }
955 End_Macro
956 
957 \since **ROOT version 6.17/01:**
958 
959 Sometimes the change of the range of the Z axis is unwanted, in which case, one
960 can use `SAME0` (or `SAMES0`) option to opt out of this change.
961 
962 Begin_Macro(source)
963 {
964  auto h2 = new TH2F("h2"," ",10,0,10,10,20,30);
965  auto hf = (TH2F*)h2->Clone("hf");
966  h2->SetBit(TH1::kNoStats);
967  hf->SetBit(TH1::kNoStats);
968  h2->Fill(5,22);
969  h2->Fill(5,23);
970  h2->Fill(6,22);
971  h2->Fill(6,23);
972  hf->Fill(6,23);
973  hf->Fill(6,23);
974  hf->Fill(6,23);
975  hf->Fill(6,23);
976  hf->Fill(5,23);
977 
978  auto hf_copy1 = hf->Clone("hf_copy1");
979  auto lt = new TLatex();
980 
981  auto cx = new TCanvas(); cx->Divide(2,1);
982 
983  cx->cd(1);
984  h2->Draw("box");
985  hf->Draw("text colz same");
986  lt->DrawLatexNDC(0.3,0.5,"SAME");
987 
988  cx->cd(2);
989  h2->Draw("box");
990  hf_copy1->Draw("text colz same0");
991  lt->DrawLatexNDC(0.3,0.5,"SAME0");
992 }
993 End_Macro
994 
995 
996 ### <a name="HP14"></a> The COLor option
997 
998 
999 For each cell (i,j) a box is drawn with a color proportional to the cell
1000 content.
1001 
1002 The color table used is defined in the current style.
1003 
1004 If the histogram's minimum and maximum are the same (flat histogram), the
1005 mapping on colors is not possible, therefore nothing is painted. To paint a
1006 flat histogram it is enough to set the histogram minimum
1007 (`TH1::SetMinimum()`) different from the bins' content.
1008 
1009 The default number of color levels used to paint the cells is 20.
1010 It can be changed with `TH1::SetContour()` or
1011 `TStyle::SetNumberContours()`. The higher this number is, the smoother
1012 is the color change between cells.
1013 
1014 The color palette in TStyle can be modified via `gStyle->SetPalette()`.
1015 
1016 All the non-empty bins are painted. Empty bins are not painted unless
1017 some bins have a negative content because in that case the null bins
1018 might be not empty.
1019 
1020 `TProfile2D` histograms are handled differently because, for this type of 2D
1021 histograms, it is possible to know if an empty bin has been filled or not. So even
1022 if all the bins' contents are positive some empty bins might be painted. And vice versa,
1023 if some bins have a negative content some empty bins might be not painted.
1024 
1025 Combined with the option `COL`, the option `Z` allows to
1026 display the color palette defined by `gStyle->SetPalette()`.
1027 
1028 In the following example, the histogram has only positive bins; the empty
1029 bins (containing 0) are not drawn.
1030 
1031 Begin_Macro(source)
1032 {
1033  auto c1 = new TCanvas("c1","c1",600,400);
1034  auto hcol1 = new TH2F("hcol1","Option COLor example ",40,-4,4,40,-20,20);
1035  float px, py;
1036  for (Int_t i = 0; i < 25000; i++) {
1037  gRandom->Rannor(px,py);
1038  hcol1->Fill(px,5*py);
1039  }
1040  hcol1->Draw("COLZ");
1041 }
1042 End_Macro
1043 
1044 In the first plot of following example, the histogram has some negative bins;
1045 the empty bins (containing 0) are drawn. In some cases one wants to not draw
1046 empty bins (containing 0) of histograms having a negative minimum. The option
1047 `1`, used to produce the second plot in the following picture, allows to do that.
1048 
1049 Begin_Macro(source)
1050 {
1051  auto c1 = new TCanvas("c1","c1",600,600);
1052  c1->Divide(1,2);
1053  auto hcol23 = new TH2F("hcol23","Option COLZ example ",40,-4,4,40,-20,20);
1054  auto hcol24 = new TH2F("hcol24","Option COLZ1 example ",40,-4,4,40,-20,20);
1055  float px, py;
1056  for (Int_t i = 0; i < 25000; i++) {
1057  gRandom->Rannor(px,py);
1058  hcol23->Fill(px,5*py);
1059  hcol24->Fill(px,5*py);
1060  }
1061  hcol23->Fill(0.,0.,-200.);
1062  hcol24->Fill(0.,0.,-200.);
1063  c1->cd(1); hcol23->Draw("COLZ");
1064  c1->cd(2); hcol24->Draw("COLZ1");
1065 }
1066 End_Macro
1067 
1068 When the maximum of the histogram is set to a smaller value than the real maximum,
1069  the bins having a content between the new maximum and the real maximum are
1070 painted with the color corresponding to the new maximum.
1071 
1072 When the minimum of the histogram is set to a greater value than the real minimum,
1073  the bins having a value between the real minimum and the new minimum are not drawn
1074  unless the option `0` is set.
1075 
1076 The following example illustrates the option `0` combined with the option `COL`.
1077 
1078 Begin_Macro(source)
1079 {
1080  auto c1 = new TCanvas("c1","c1",600,600);
1081  c1->Divide(1,2);
1082  auto hcol21 = new TH2F("hcol21","Option COLZ",40,-4,4,40,-20,20);
1083  auto hcol22 = new TH2F("hcol22","Option COLZ0",40,-4,4,40,-20,20);
1084  float px, py;
1085  for (Int_t i = 0; i < 25000; i++) {
1086  gRandom->Rannor(px,py);
1087  hcol21->Fill(px,5*py);
1088  hcol22->Fill(px,5*py);
1089  }
1090  hcol21->SetBit(TH1::kNoStats);
1091  hcol22->SetBit(TH1::kNoStats);
1092  c1->cd(1); hcol21->Draw("COLZ");
1093  c1->cd(2); hcol22->Draw("COLZ0");
1094  hcol22->SetMaximum(100);
1095  hcol22->SetMinimum(40);
1096 }
1097 End_Macro
1098 
1099 \since **ROOT version 6.09/01:**
1100 
1101 When the option SAME (or "SAMES") is used with the option COL, the boxes' color
1102 are computing taking the previous plots into account. The range along the Z axis
1103 is imposed by the first plot (the one without option SAME); therefore the order
1104 in which the plots are done is relevant. Same as [in the `BOX` option](#HP13), one can use
1105 `SAME0` (or `SAMES0`) to opt out of this imposition.
1106 
1107 Begin_Macro(source)
1108 {
1109  auto c = new TCanvas("c","Example of col plots with option SAME",200,10,700,500);
1110  auto h1 = new TH2F("h1","h1",40,-3,3,40,-3,3);
1111  auto h2 = new TH2F("h2","h2",40,-3,3,40,-3,3);
1112  auto h3 = new TH2F("h3","h3",40,-3,3,40,-3,3);
1113  auto h4 = new TH2F("h4","h4",40,-3,3,40,-3,3);
1114  h1->SetBit(TH1::kNoStats);
1115  for (Int_t i=0;i<5000;i++) {
1116  double x,y;
1117  gRandom->Rannor(x,y);
1118  if(x>0 && y>0) h1->Fill(x,y,4);
1119  if(x<0 && y<0) h2->Fill(x,y,3);
1120  if(x>0 && y<0) h3->Fill(x,y,2);
1121  if(x<0 && y>0) h4->Fill(x,y,1);
1122  }
1123  h1->Draw("colz");
1124  h2->Draw("col same");
1125  h3->Draw("col same");
1126  h4->Draw("col same");
1127 }
1128 End_Macro
1129 
1130 The option `COL` can be combined with the option `POL`:
1131 
1132 Begin_Macro(source)
1133 {
1134  auto c1 = new TCanvas("c1","c1",600,400);
1135  auto hcol1 = new TH2F("hcol1","Option COLor combined with POL",40,-4,4,40,-4,4);
1136  float px, py;
1137  for (Int_t i = 0; i < 25000; i++) {
1138  gRandom->Rannor(px,py);
1139  hcol1->Fill(px,py);
1140  }
1141  hcol1->Draw("COLZPOL");
1142 }
1143 End_Macro
1144 
1145 \since **ROOT version 6.07/03:**
1146 
1147 A second rendering technique is also available with the COL2 and COLZ2 options.
1148 
1149 These options provide potential performance improvements compared to the standard
1150 COL option. The performance comparison of the COL2 to the COL option depends on
1151 the histogram and the size of the rendering region in the current pad. In general,
1152 a small (approx. less than 100 bins per axis), sparsely populated TH2 will render
1153 faster with the COL option.
1154 
1155 However, for larger histograms (approx. more than 100 bins per axis)
1156 that are not sparse, the COL2 option will provide up to 20 times performance improvements.
1157 For example, a 1000x1000 bin TH2 that is not sparse will render an order of magnitude
1158 faster with the COL2 option.
1159 
1160 The COL2 option will also scale its performance based on the size of the
1161 pixmap the histogram image is being rendered into. It also is much better optimized for
1162 sessions where the user is forwarding X11 windows through an `ssh` connection.
1163 
1164 For the most part, the COL2 and COLZ2 options are a drop in replacement to the COL
1165 and COLZ options. There is one major difference and that concerns the treatment of
1166 bins with zero content. The COL2 and COLZ2 options color these bins the color of zero.
1167 
1168 COL2 option renders the histogram as a bitmap. Therefore it cannot be saved in vector
1169 graphics file format like PostScript or PDF (an empty image will be generated). It can
1170 be saved only in bitmap files like PNG format for instance.
1171 
1172 
1173 ### <a name="HP140"></a> The CANDLE and VIOLIN options
1174 
1175 The mechanism behind Candle plots and Violin plots is very similar. Because of this they are
1176 implemented in the same class TCandle. The keywords CANDLE or VIOLIN will initiate the drawing of
1177 the corresponding plots. Followed by the keyword the user can select a plot direction (X or V for
1178 vertical projections, or Y or H for horizontal projections) and/or predefined definitions
1179 (1-6 for candles, 1-2 for violins). The order doesn't matter. Default is X and 1.
1180 
1181 Instead of using the predefined representations, the candle and violin parameters can be
1182 changed individually. In that case the option have the following form:
1183 
1184  CANDLEX(<option-string>)
1185  CANDLEY(<option-string>)
1186  VIOLINX(<option-string>)
1187  VIOLINY(<option-string>).
1188 
1189 All zeros at the beginning of `option-string` can be omitted.
1190 
1191 `option-string` consists eight values, defined as follow:
1192 
1193  "CANDLEX(zhpawMmb)"
1194 
1195 Where:
1196 
1197  - `b = 0`; no box drawn
1198  - `b = 1`; the box is drawn. As the candle-plot is also called a box-plot it
1199  makes sense in the very most cases to always draw the box
1200  - `b = 2`; draw a filled box with border
1201 
1202  - `m = 0`; no median drawn
1203  - `m = 1`; median is drawn as a line
1204  - `m = 2`; median is drawn with errors (notches)
1205  - `m = 3`; median is drawn as a circle
1206 
1207  - `M = 0`; no mean drawn
1208  - `M = 1`; mean is drawn as a dashed line
1209  - `M = 3`; mean is drawn as a circle
1210 
1211  - `w = 0`; no whisker drawn
1212  - `w = 1`; whisker is drawn to end of distribution.
1213  - `w = 2`; whisker is drawn to max 1.5*iqr
1214 
1215  - `a = 0`; no anchor drawn
1216  - `a = 1`; the anchors are drawn
1217 
1218  - `p = 0`; no points drawn
1219  - `p = 1`; only outliers are drawn
1220  - `p = 2`; all datapoints are drawn
1221  - `p = 3`: all datapoints are drawn scattered
1222 
1223  - `h = 0`; no histogram is drawn
1224  - `h = 1`; histogram at the left or bottom side is drawn
1225  - `h = 2`; histogram at the right or top side is drawn
1226  - `h = 3`; histogram at left and right or top and bottom (violin-style) is drawn
1227 
1228  - `z = 0`; no zero indicator line is drawn
1229  - `z = 1`; zero indicator line is drawn.
1230 
1231 As one can see all individual options for both candle and violin plots can be accessed by this
1232 mechanism. In deed the keywords CANDLE(<option-string>) and VIOLIN(<option-string>) have the same
1233 meaning. So you can parametrise an option-string for a candle plot and use the keywords VIOLIN and
1234 vice versa, if you wish.
1235 
1236 Using a logarithmic x- or y-axis is possible for candle and violin charts.
1237 
1238 \since **ROOT version 6.11/01**
1239 
1240 a logarithmic z-axis is possible, too but will only affect violin charts of course.
1241 
1242 #### <a name="HP140a"></a> The CANDLE option
1243 
1244 <a href="http://en.wikipedia.org/wiki/Box_plot">A Candle plot</a> (also known as
1245 a "box plot" or "whisker plot") was invented in 1977 by John Tukey. It is a convenient
1246 way to describe graphically a data distribution (D) with only five numbers:
1247 
1248  1. The minimum value of the distribution D (bottom or left whisker).
1249  2. The lower quartile (Q1): 25% of the data points in D are less than Q1 (bottom of the box).
1250  3. The median (M): 50% of the data points in D are less than M.
1251  4. The upper quartile (Q3): 75% of the data points in D are less than Q3 (top of the box).
1252  5. The maximum value of the distribution D (top or right whisker).
1253 
1254 In this implementation a TH2 is considered as a collection of TH1 along
1255 X (option `CANDLE` or `CANDLEX`) or Y (option `CANDLEY`).
1256 Each TH1 is represented as one candle.
1257 
1258 Begin_Macro(source)
1259 ../../../tutorials/hist/candleplotwhiskers.C
1260 End_Macro
1261 
1262 The candle reduces the information coming from a whole distribution into few values.
1263 Independently from the number of entries or the significance of the underlying distribution
1264 a candle will always look like a candle. So candle plots should be used carefully in
1265 particular with unknown distributions. The definition of a candle is based on
1266 __unbinned data__. Here, candles are created from binned data. Because of this, the
1267 deviation is connected to the bin width used. The calculation of the quantiles
1268 normally done on unbinned data also. Because data are binned, this will
1269 only work the best possible way within the resolution of one bin
1270 
1271 Because of all these facts one should take care that:
1272 
1273  - there are enough points per candle
1274  - the bin width is small enough (more bins will increase the maximum
1275  available resolution of the quantiles although there will be some
1276  bins with no entries)
1277  - never make a candle-plot if the underlying distribution is double-distributed
1278  - only create candles of distributions that are more-or-less gaussian (the
1279  MPV should be not too far away from the mean).
1280 
1281 #### What a candle is made of
1282 
1283 \since **ROOT version 6.07/05**
1284 
1285 ##### The box
1286 The box displays the position of the inter-quantile-range of the underlying
1287 distribution. The box contains 25% of the distribution below the median
1288 and 25% of the distribution above the median. If the underlying distribution is large
1289 enough and gaussian shaped the end-points of the box represent \f$ 0.6745\times\sigma \f$
1290 (Where \f$ \sigma \f$ is the standard deviation of the gaussian). The width and
1291 the position of the box can be modified by SetBarWidth() and SetBarOffset().
1292 The +-25% quantiles are calculated by the GetQuantiles() methods.
1293 
1294 \since **ROOT version 6.11/01**
1295 
1296 Using the static function TCandle::SetBoxRange(double) the box definition will be
1297 overwritten. E.g. using a box range of 0.68 will redefine the area of the lower box edge
1298 to the upper box edge in order to cover 68% of the distribution illustrated by that candle.
1299 The static function will affect all candle-charts in the running program.
1300 Default is 0.5.
1301 
1302 Using the static function TCandle::SetScaledCandle(bool) the width of the box (and the
1303 whole candle) can be influenced. Deactivated, the width is constant (to be set by
1304 SetBarWidth() ). Activated, the width of the boxes will be scaled to each other based on the
1305 amount of data in the corresponding candle, the maximum width can be influenced by
1306 SetBarWidth(). The static function will affect all candle-charts in the running program.
1307 Default is false. Scaling between multiple candle-charts (using "same" or THStack) is not
1308 supported, yet
1309 
1310 ##### The Median
1311 For a sorted list of numbers, the median is the value in the middle of the list.
1312 E.g. if a sorted list is made of five numbers "1,2,3,6,7" 3 will be the median
1313 because it is in the middle of the list. If the number of entries is even the
1314 average of the two values in the middle will be used. As histograms are binned
1315 data, the situation is a bit more complex. The following example shows this:
1316 
1317 ~~~ {.cpp}
1318 void quantiles() {
1319  auto h = new TH1I("h","h",10,0,10);
1320  //h->Fill(3);
1321  //h->Fill(3);
1322  h->Fill(4);
1323  h->Draw();
1324  double p = 0.;
1325  double q = 0.;
1326  h->GetQuantiles(1,&q,&p);
1327 
1328  cout << "Median is: " << q << std::endl;
1329 }
1330 ~~~
1331 
1332 Here the bin-width is 1.0. If the two Fill(3) are commented out, as there are currently,
1333 the example will return a calculated median of 4.5, because that's the bin center
1334 of the bin in which the value 4.0 has been dropped. If the two Fill(3) are not
1335 commented out, it will return 3.75, because the algorithm tries to evenly distribute
1336 the individual values of a bin with bin content > 0. It means the sorted list
1337 would be "3.25, 3.75, 4.5".
1338 
1339 The consequence is a median of 3.75. This shows how important it is to use a
1340 small enough bin-width when using candle-plots on binned data.
1341 If the distribution is large enough and gaussian shaped the median will be exactly
1342 equal to the mean.
1343 The median can be shown as a line or as a circle or not shown at all.
1344 
1345 In order to show the significance of the median notched candle plots apply a "notch" or
1346 narrowing of the box around the median. The significance is defined by
1347 \f$ 1.57\times\frac{iqr}{N} \f$ and will be represented as the size of the notch
1348 (where iqr is the size of the box and N is the number of entries of the whole
1349 distribution). Candle plots like these are usually called "notched candle plots".
1350 
1351 In case the significance of the median is greater that the size of the box, the
1352 box will have an unnatural shape. Usually it means the chart has not enough data,
1353 or that representing this uncertainty is not useful
1354 
1355 ##### The Mean
1356 The mean can be drawn as a dashed line or as a circle or not drawn at all.
1357 The mean is the arithmetic average of the values in the distribution.
1358 It is calculated using GetMean(). Because histograms are
1359 binned data, the mean value can differ from a calculation on the raw-data.
1360 If the distribution is large enough and gaussian shaped the mean will be
1361 exactly the median.
1362 
1363 ##### The Whiskers
1364 The whiskers represent the part of the distribution not covered by the box.
1365 The upper 25% and the lower 25% of the distribution are located within the whiskers.
1366 Two representations are available.
1367 
1368  - A simple one (using w=1) defining the lower whisker from the lowest data value
1369  to the bottom of the box, and the upper whisker from the top of the box to the
1370  highest data value. In this representation the whisker-lines are dashed.
1371  - A more complex one having a further restriction. The whiskers are still connected
1372  to the box but their length cannot exceed \f$ 1.5\times iqr \f$. So it might
1373  be that the outermost part of the underlying distribution will not be covered
1374  by the whiskers. Usually these missing parts will be represented by the outliers
1375  (see points). Of course the upper and the lower whisker may differ in length.
1376  In this representation the whiskers are drawn as solid lines.
1377 
1378 \since **ROOT version 6.11/01**
1379 
1380 Using the static function TCandle::SetWhiskerRange(double) the whisker definition w=1
1381 will be overwritten. E.g. using a whisker-range of 0.95 and w=1 will redefine the area of
1382 the lower whisker to the upper whisker in order to cover 95% of the distribution inside
1383 that candle. The static function will affect all candle-charts in the running program.
1384 Default is 1.
1385 
1386 If the distribution is large enough and gaussian shaped, the maximum length of
1387 the whisker will be located at \f$ \pm 2.698 \sigma \f$ (when using the
1388 1.5*iqr-definition (w=2), where \f$ \sigma \f$ is the standard deviation
1389 (see picture above). In that case 99.3% of the total distribution will be covered
1390 by the box and the whiskers, whereas 0.7% are represented by the outliers.
1391 
1392 ##### The Anchors
1393 The anchors have no special meaning in terms of statistical calculation. They mark
1394 the end of the whiskers and they have the width of the box. Both representation
1395 with and without anchors are common.
1396 
1397 ##### The Points
1398 Depending on the configuration the points can have different meanings:
1399  - If p=1 the points represent the outliers. If they are shown, it means
1400  some parts of the underlying distribution are not covered by the whiskers.
1401  This can only occur when the whiskers are set to option w=2. Here the whiskers
1402  can have a maximum length of \f$ 1.5 \times iqr \f$. So any points outside the
1403  whiskers will be drawn as outliers. The outliers will be represented by crosses.
1404  - If p=2 all points in the distribution will be painted as crosses. This is
1405  useful for small datasets only (up to 10 or 20 points per candle).
1406  The outliers are shown along the candle. Because the underlying distribution
1407  is binned, is frequently occurs that a bin contains more than one value.
1408  Because of this the points will be randomly scattered within their bin along
1409  the candle axis. If the bin content for a bin is exactly 1 (usually
1410  this happens for the outliers) if will be drawn in the middle of the bin along
1411  the candle axis. As the maximum number of points per candle is limited by kNMax/2
1412  on very large datasets scaling will be performed automatically. In that case one
1413  would loose all outliers because they have usually a bin content of 1 (and a
1414  bin content between 0 and 1 after the scaling). Because of this all bin contents
1415  between 0 and 1 - after the scaling - will be forced to be 1.
1416  - As the drawing of all values on large datasets can lead to big amounts of crosses,
1417  one can show all values as a scatter plot instead by choosing p=3. The points will be
1418  drawn as dots and will be scattered within the width of the candle. The color
1419  of the points will be the color of the candle-chart.
1420 
1421 ##### Other Options
1422 Is is possible to combine all options of candle and violin plots with each other. E.g. a box-plot
1423 with a histogram.
1424 
1425 #### How to use the candle-plots drawing option
1426 
1427 There are six predefined candle-plot representations:
1428 
1429  - "CANDLEX1": Standard candle (whiskers cover the whole distribution)
1430  - "CANDLEX2": Standard candle with better whisker definition + outliers.
1431  It is a good compromise
1432  - "CANDLEX3": Like candle2 but with a mean as a circle.
1433  It is easier to distinguish mean and median
1434  - "CANDLEX4": Like candle3 but showing the uncertainty of the median as well
1435  (notched candle plots).
1436  For bigger datasets per candle
1437  - "CANDLEX5": Like candle2 but showing all data points.
1438  For very small datasets
1439  - "CANDLEX6": Like candle2 but showing all datapoints scattered.
1440  For huge datasets
1441 
1442 
1443 The following picture shows how the six predefined representations look.
1444 
1445 Begin_Macro
1446 {
1447  auto c1 = new TCanvas("c1","c1",700,800);
1448  c1->Divide(2,3);
1449  gStyle->SetOptStat(kFALSE);
1450 
1451  auto hcandle = new TH2F("hcandle"," ",10,-4,4,40,-20,20);
1452  float px, py;
1453  for (Int_t i = 0; i < 15000; i++) {
1454  gRandom->Rannor(px,py);
1455  hcandle->Fill(px,5*py);
1456  }
1457  hcandle->SetMarkerSize(0.5);
1458 
1459  TH2F *h2;
1460  for (Int_t i=1; i<7; i++) {
1461  c1->cd(i);
1462  h2 = (TH2F*)hcandle->DrawClone(Form("CANDLE%d",i));
1463  h2->SetTitle(Form("CANDLE%d",i));
1464  }
1465 }
1466 End_Macro
1467 
1468 
1469 #### Example 1
1470 Box and improved whisker, no mean, no median, no anchor no outliers
1471 
1472  h1->Draw("CANDLEX(2001)");
1473 
1474 #### Example 2
1475 A Candle-definition like "CANDLEX2" (New standard candle with better whisker definition + outliers)
1476 
1477  h1->Draw("CANDLEX(112111)");
1478 
1479 #### Example 3
1480 The following example shows how several candle plots can be super-imposed using
1481 the option SAME. Note that the bar-width and bar-offset are active on candle plots.
1482 Also the color, the line width, the size of the points and so on can be changed by the
1483 standard attribute setting methods such as SetLineColor() SetLineWidth().
1484 
1485 Begin_Macro(source)
1486 ../../../tutorials/hist/candleplot.C
1487 End_Macro
1488 
1489 #### <a name="HP140b"></a> The VIOLIN option
1490 
1491 <a href="http://en.wikipedia.org/wiki/Violin_plot">A violin plot</a> is a candle plot
1492 that also encodes the pdf information at each point.
1493 
1494 
1495 Quartiles and mean are also represented at each point, with a marker
1496 and two lines.
1497 
1498 In this implementation a TH2 is considered as a collection of TH1 along
1499 X (option `VIOLIN` or `VIOLINX`) or Y (option `VIOLINY`).
1500 
1501 #### What a violin is made of
1502 
1503 \since **ROOT version 6.09/02**
1504 
1505 ##### The histogram
1506 The histogram is typically drawn to both directions with respect to the middle-line of the
1507 corresponding bin. This can be achieved by using h=3. It is possible to draw a histogram only to
1508 one side (h=1, or h=2).
1509 The maximum number of bins in the histogram is limited to 500, if the number of bins in the used
1510 histogram is higher it will be rebinned automatically. The maximum height of the histogram can
1511 be modified by using SetBarWidth() and the position can be changed with SetBarOffset().
1512 A solid fill style is recommended.
1513 
1514 \since **ROOT version 6.11/01**
1515 
1516 Using the static function TCandle::SetScaledViolin(bool) the height of the histogram or the
1517 violin can be influenced. Activated, the height of the bins of the individual violins will be
1518 scaled with respect to each other, the maximum height can be influenced by SetBarWidth().
1519 Deactivated, the height of the bin with the maximum content of each individual violin is
1520 set to a constant value using SetBarWidth(). The static function will affect all violin-charts
1521 in the running program. Default is true. Scaling between multiple violin-charts
1522 (using "same" or THStack) is not supported, yet.
1523 
1524 ##### The zero indicator line
1525 Typical for violin charts is a line in the background over the whole histogram indicating
1526 the bins with zero entries. The zero indicator line can be activated with z=1. The line color
1527 will always be the same as the fill-color of the histogram.
1528 
1529 ##### The Mean
1530 The Mean is illustrated with the same mechanism as used for candle plots. Usually a circle is used.
1531 
1532 ##### Whiskers
1533 The whiskers are illustrated by the same mechanism as used for candle plots. There is only one
1534 difference. When using the simple whisker definition (w=1) and the zero indicator line (z=1), then
1535 the whiskers will be forced to be solid (usually hashed)
1536 
1537 ##### Points
1538 The points are illustrated by the same mechanism as used for candle plots. E.g. VIOLIN2 uses
1539 better whisker definition (w=2) and outliers (p=1).
1540 
1541 ##### Other options
1542 It is possible to combine all options of candle or violin plots with each other. E.g. a violin plot
1543 including a box-plot.
1544 
1545 #### How to use the violin-plots drawing option
1546 
1547 There are two predefined violin-plot representations:
1548  - "VIOLINX1": Standard violin (histogram, mean, whisker over full distribution,
1549  zero indicator line)
1550  - "VIOLINX2": Line VIOLINX1 both with better whisker definition + outliers.
1551 
1552 A solid fill style is recommended for this plot (as opposed to a hollow or
1553 hashed style).
1554 
1555 Begin_Macro(source)
1556 {
1557  auto c1 = new TCanvas("c1","c1",600,400);
1558  Int_t nx(6), ny(40);
1559  double xmin(0.0), xmax(+6.0), ymin(0.0), ymax(+4.0);
1560  auto hviolin = new TH2F("hviolin", "Option VIOLIN example", nx, xmin, xmax, ny, ymin, ymax);
1561  TF1 f1("f1", "gaus", +0,0 +4.0);
1562  double x,y;
1563  for (Int_t iBin=1; iBin<hviolin->GetNbinsX(); ++iBin) {
1564  double xc = hviolin->GetXaxis()->GetBinCenter(iBin);
1565  f1.SetParameters(1, 2.0+TMath::Sin(1.0+xc), 0.2+0.1*(xc-xmin)/xmax);
1566  for(Int_t i=0; i<10000; ++i){
1567  x = xc;
1568  y = f1.GetRandom();
1569  hviolin->Fill(x, y);
1570  }
1571  }
1572  hviolin->SetFillColor(kGray);
1573  hviolin->SetMarkerStyle(20);
1574  hviolin->SetMarkerSize(0.5);
1575  hviolin->Draw("VIOLIN");
1576  c1->Update();
1577 }
1578 End_Macro
1579 
1580 The next example illustrates a time development of a certain value:
1581 
1582 Begin_Macro(source)
1583 ../../../tutorials/hist/candledecay.C
1584 End_Macro
1585 
1586 
1587 ### <a name="HP15"></a> The TEXT and TEXTnn Option
1588 
1589 
1590 For each bin the content is printed. The text attributes are:
1591 
1592 - text font = current TStyle font (`gStyle->SetTextFont()`).
1593 - text size = 0.02*padheight*markersize (if `h` is the histogram drawn
1594  with the option `TEXT` the marker size can be changed with
1595  `h->SetMarkerSize(markersize)`).
1596 - text color = marker color.
1597 
1598 By default the format `g` is used. This format can be redefined
1599 by calling `gStyle->SetPaintTextFormat()`.
1600 
1601 It is also possible to use `TEXTnn` in order to draw the text with
1602 the angle `nn` (`0 < nn < 90`).
1603 
1604 For 2D histograms the text is plotted in the center of each non empty cells.
1605 It is possible to plot empty cells by calling `gStyle->SetHistMinimumZero()`
1606 or providing MIN0 draw option. For 1D histogram the text is plotted at a y
1607 position equal to the bin content.
1608 
1609 For 2D histograms when the option "E" (errors) is combined with the option
1610 text ("TEXTE"), the error for each bin is also printed.
1611 
1612 Begin_Macro(source)
1613 {
1614  auto c01 = new TCanvas("c01","c01",700,400);
1615  c01->Divide(2,1);
1616  auto htext1 = new TH1F("htext1","Option TEXT on 1D histograms ",10,-4,4);
1617  auto htext2 = new TH2F("htext2","Option TEXT on 2D histograms ",10,-4,4,10,-20,20);
1618  float px, py;
1619  for (Int_t i = 0; i < 25000; i++) {
1620  gRandom->Rannor(px,py);
1621  htext1->Fill(px,0.1);
1622  htext2->Fill(px,5*py,0.1);
1623  }
1624  gStyle->SetPaintTextFormat("4.1f m");
1625  htext2->SetMarkerSize(1.8);
1626  c01->cd(1);
1627  htext2->Draw("TEXT45");
1628  c01->cd(2);
1629  htext1->Draw();
1630  htext1->Draw("HIST TEXT0 SAME");
1631 }
1632 End_Macro
1633 
1634 \since **ROOT version 6.07/07:**
1635 
1636 In case several histograms are drawn on top ot each other (using option `SAME`),
1637 the text can be shifted using `SetBarOffset()`. It specifies an offset for the
1638 text position in each cell, in percentage of the bin width.
1639 
1640 Begin_Macro(source)
1641 {
1642  auto c03 = new TCanvas("c03","c03",700,400);
1643  gStyle->SetOptStat(0);
1644  auto htext3 = new TH2F("htext3","Several 2D histograms drawn with option TEXT",10,-4,4,10,-20,20);
1645  auto htext4 = new TH2F("htext4","htext4",10,-4,4,10,-20,20);
1646  auto htext5 = new TH2F("htext5","htext5",10,-4,4,10,-20,20);
1647  float px, py;
1648  for (Int_t i = 0; i < 25000; i++) {
1649  gRandom->Rannor(px,py);
1650  htext3->Fill(4*px,20*py,0.1);
1651  htext4->Fill(4*px,20*py,0.5);
1652  htext5->Fill(4*px,20*py,1.0);
1653  }
1654  htext4->SetMarkerSize(1.8);
1655  htext5->SetMarkerSize(1.8);
1656  htext5->SetMarkerColor(kRed);
1657  htext3->Draw("COL");
1658  htext4->SetBarOffset(0.2);
1659  htext4->Draw("TEXT SAME");
1660  htext5->SetBarOffset(-0.2);
1661  htext5->Draw("TEXT SAME");
1662 }
1663 End_Macro
1664 
1665 In the case of profile histograms it is possible to print the number
1666 of entries instead of the bin content. It is enough to combine the
1667 option "E" (for entries) with the option "TEXT".
1668 
1669 Begin_Macro(source)
1670 {
1671  auto c02 = new TCanvas("c02","c02",700,400);
1672  c02->Divide(2,1);
1673  gStyle->SetPaintTextFormat("g");
1674 
1675  auto profile = new TProfile("profile","profile",10,0,10);
1676  profile->SetMarkerSize(2.2);
1677  profile->Fill(0.5,1);
1678  profile->Fill(1.5,2);
1679  profile->Fill(2.5,3);
1680  profile->Fill(3.5,4);
1681  profile->Fill(4.5,5);
1682  profile->Fill(5.5,5);
1683  profile->Fill(6.5,4);
1684  profile->Fill(7.5,3);
1685  profile->Fill(8.5,2);
1686  profile->Fill(9.5,1);
1687  c02->cd(1); profile->Draw("HIST TEXT0");
1688  c02->cd(2); profile->Draw("HIST TEXT0E");
1689 }
1690 End_Macro
1691 
1692 ### <a name="HP16"></a> The CONTour options
1693 
1694 
1695 The following contour options are supported:
1696 
1697 | Option | Description |
1698 |----------|-------------------------------------------------------------------|
1699 | "CONT" | Draw a contour plot (same as CONT0).|
1700 | "CONT0" | Draw a contour plot using surface colors to distinguish contours.|
1701 | "CONT1" | Draw a contour plot using the line colors to distinguish contours.|
1702 | "CONT2" | Draw a contour plot using the line styles to distinguish contours.|
1703 | "CONT3" | Draw a contour plot solid lines for all contours.|
1704 | "CONT4" | Draw a contour plot using surface colors (`SURF` option at theta = 0).|
1705 | "CONT5" | Draw a contour plot using Delaunay triangles.|
1706 
1707 
1708 
1709 The following example shows a 2D histogram plotted with the option
1710 `CONTZ`. The option `CONT` draws a contour plot using surface
1711 colors to distinguish contours. Combined with the option `CONT` (or
1712 `CONT0`), the option `Z` allows to display the color palette
1713 defined by `gStyle->SetPalette()`.
1714 
1715 Begin_Macro(source)
1716 {
1717  auto c1 = new TCanvas("c1","c1",600,400);
1718  auto hcontz = new TH2F("hcontz","Option CONTZ example ",40,-4,4,40,-20,20);
1719  float px, py;
1720  for (Int_t i = 0; i < 25000; i++) {
1721  gRandom->Rannor(px,py);
1722  hcontz->Fill(px-1,5*py);
1723  hcontz->Fill(2+0.5*px,2*py-10.,0.1);
1724  }
1725  hcontz->Draw("CONTZ");
1726 }
1727 End_Macro
1728 
1729 The following example shows a 2D histogram plotted with the option
1730 `CONT1Z`. The option `CONT1` draws a contour plot using the
1731 line colors to distinguish contours. Combined with the option `CONT1`,
1732 the option `Z` allows to display the color palette defined by
1733 `gStyle->SetPalette()`.
1734 
1735 Begin_Macro(source)
1736 {
1737  auto c1 = new TCanvas("c1","c1",600,400);
1738  auto hcont1 = new TH2F("hcont1","Option CONT1Z example ",40,-4,4,40,-20,20);
1739  float px, py;
1740  for (Int_t i = 0; i < 25000; i++) {
1741  gRandom->Rannor(px,py);
1742  hcont1->Fill(px-1,5*py);
1743  hcont1->Fill(2+0.5*px,2*py-10.,0.1);
1744  }
1745  hcont1->Draw("CONT1Z");
1746 }
1747 End_Macro
1748 
1749 The following example shows a 2D histogram plotted with the option
1750 `CONT2`. The option `CONT2` draws a contour plot using the
1751 line styles to distinguish contours.
1752 
1753 Begin_Macro(source)
1754 {
1755  auto c1 = new TCanvas("c1","c1",600,400);
1756  auto hcont2 = new TH2F("hcont2","Option CONT2 example ",40,-4,4,40,-20,20);
1757  float px, py;
1758  for (Int_t i = 0; i < 25000; i++) {
1759  gRandom->Rannor(px,py);
1760  hcont2->Fill(px-1,5*py);
1761  hcont2->Fill(2+0.5*px,2*py-10.,0.1);
1762  }
1763  hcont2->Draw("CONT2");
1764 }
1765 End_Macro
1766 
1767 The following example shows a 2D histogram plotted with the option
1768 `CONT3`. The option `CONT3` draws contour plot solid lines for
1769 all contours.
1770 
1771 Begin_Macro(source)
1772 {
1773  auto c1 = new TCanvas("c1","c1",600,400);
1774  auto hcont3 = new TH2F("hcont3","Option CONT3 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  hcont3->Fill(px-1,5*py);
1779  hcont3->Fill(2+0.5*px,2*py-10.,0.1);
1780  }
1781  hcont3->Draw("CONT3");
1782 }
1783 End_Macro
1784 
1785 The following example shows a 2D histogram plotted with the option
1786 `CONT4`. The option `CONT4` draws a contour plot using surface
1787 colors to distinguish contours (`SURF` option at theta = 0). Combined
1788 with the option `CONT` (or `CONT0`), the option `Z`
1789 allows to display the color palette defined by `gStyle->SetPalette()`.
1790 
1791 Begin_Macro(source)
1792 {
1793  auto c1 = new TCanvas("c1","c1",600,400);
1794  auto hcont4 = new TH2F("hcont4","Option CONT4Z 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  hcont4->Fill(px-1,5*py);
1799  hcont4->Fill(2+0.5*px,2*py-10.,0.1);
1800  }
1801  hcont4->Draw("CONT4Z");
1802 }
1803 End_Macro
1804 
1805 The default number of contour levels is 20 equidistant levels and can be changed
1806 with `TH1::SetContour()` or `TStyle::SetNumberContours()`.
1807 
1808 #### <a name="HP16a"></a> The LIST option
1809 
1810 When option `LIST` is specified together with option
1811 `CONT`, the points used to draw the contours are saved in
1812 `TGraph` objects:
1813 
1814  h->Draw("CONT LIST");
1815  gPad->Update();
1816 
1817 The contour are saved in `TGraph` objects once the pad is painted.
1818 Therefore to use this functionality in a macro, `gPad->Update()`
1819 should be performed after the histogram drawing. Once the list is
1820 built, the contours are accessible in the following way:
1821 
1822  TObjArray *contours = (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
1823  Int_t ncontours = contours->GetSize();
1824  TList *list = (TList*)contours->At(i);
1825 
1826 Where `i` is a contour number, and list contains a list of
1827 `TGraph` objects.
1828 For one given contour, more than one disjoint polyline may be generated.
1829 The number of TGraphs per contour is given by:
1830 
1831  list->GetSize();
1832 
1833 To access the first graph in the list one should do:
1834 
1835  TGraph *gr1 = (TGraph*)list->First();
1836 
1837 
1838 The following example (ContourList.C) shows how to use this functionality.
1839 
1840 Begin_Macro(source)
1841 ../../../tutorials/hist/ContourList.C
1842 End_Macro
1843 
1844 #### <a name="HP16b"></a> The AITOFF, MERCATOR, SINUSOIDAL and PARABOLIC options
1845 
1846 The following options select the `CONT4` option and are useful for
1847 sky maps or exposure maps (earth.C).
1848 
1849 | Option | Description |
1850 |--------------|---------------------------------------------------------------|
1851 | "AITOFF" | Draw a contour via an AITOFF projection.|
1852 | "MERCATOR" | Draw a contour via an Mercator projection.|
1853 | "SINUSOIDAL" | Draw a contour via an Sinusoidal projection.|
1854 | "PARABOLIC" | Draw a contour via an Parabolic projection.|
1855 
1856 Begin_Macro(source)
1857 ../../../tutorials/graphics/earth.C
1858 End_Macro
1859 
1860 
1861 ### <a name="HP17"></a> The LEGO options
1862 
1863 
1864 In a lego plot the cell contents are drawn as 3-d boxes. The height of each box
1865 is proportional to the cell content. The lego aspect is control with the
1866 following options:
1867 
1868 | Option | Description |
1869 |----------|-------------------------------------------------------------------|
1870 | "LEGO" | Draw a lego plot using the hidden lines removal technique.|
1871 | "LEGO1" | Draw a lego plot using the hidden surface removal technique.|
1872 | "LEGO2" | Draw a lego plot using colors to show the cell contents.|
1873 | "LEGO3" | Draw a lego plot with hidden surface removal, like LEGO1 but the border lines of each lego-bar are not drawn.|
1874 | "LEGO4" | Draw a lego plot with hidden surface removal, like LEGO1 but without the shadow effect on each lego-bar.|
1875 | "0" | When used with any LEGO option, the empty bins are not drawn.|
1876 
1877 
1878 See the limitations with [the option "SAME"](#HP060a).
1879 
1880 Line attributes can be used in lego plots to change the edges' style.
1881 
1882 The following example shows a 2D histogram plotted with the option
1883 `LEGO`. The option `LEGO` draws a lego plot using the hidden
1884 lines removal technique.
1885 
1886 Begin_Macro(source)
1887 {
1888  auto c2 = new TCanvas("c2","c2",600,400);
1889  auto hlego = new TH2F("hlego","Option LEGO example ",40,-4,4,40,-20,20);
1890  float px, py;
1891  for (Int_t i = 0; i < 25000; i++) {
1892  gRandom->Rannor(px,py);
1893  hlego->Fill(px-1,5*py);
1894  hlego->Fill(2+0.5*px,2*py-10.,0.1);
1895  }
1896  hlego->Draw("LEGO");
1897 }
1898 End_Macro
1899 
1900 The following example shows a 2D histogram plotted with the option
1901 `LEGO1`. The option `LEGO1` draws a lego plot using the
1902 hidden surface removal technique. Combined with any `LEGOn` option, the
1903 option `0` allows to not drawn the empty bins.
1904 
1905 Begin_Macro(source)
1906 {
1907  auto c2 = new TCanvas("c2","c2",600,400);
1908  auto hlego1 = new TH2F("hlego1","Option LEGO1 example (with option 0) ",40,-4,4,40,-20,20);
1909  float px, py;
1910  for (Int_t i = 0; i < 25000; i++) {
1911  gRandom->Rannor(px,py);
1912  hlego1->Fill(px-1,5*py);
1913  hlego1->Fill(2+0.5*px,2*py-10.,0.1);
1914  }
1915  hlego1->SetFillColor(kYellow);
1916  hlego1->Draw("LEGO1 0");
1917 }
1918 End_Macro
1919 
1920 The following example shows a 2D histogram plotted with the option
1921 `LEGO3`. Like the option `LEGO1`, the option `LEGO3`
1922 draws a lego plot using the hidden surface removal technique but doesn't draw
1923 the border lines of each individual lego-bar. This is very useful for histograms
1924 having many bins. With such histograms the option `LEGO1` gives a black
1925 image because of the border lines. This option also works with stacked legos.
1926 
1927 Begin_Macro(source)
1928 {
1929  auto c2 = new TCanvas("c2","c2",600,400);
1930  auto hlego3 = new TH2F("hlego3","Option LEGO3 example",40,-4,4,40,-20,20);
1931  float px, py;
1932  for (Int_t i = 0; i < 25000; i++) {
1933  gRandom->Rannor(px,py);
1934  hlego3->Fill(px-1,5*py);
1935  hlego3->Fill(2+0.5*px,2*py-10.,0.1);
1936  }
1937  hlego3->SetFillColor(kRed);
1938  hlego3->Draw("LEGO3");
1939 }
1940 End_Macro
1941 
1942 The following example shows a 2D histogram plotted with the option
1943 `LEGO2`. The option `LEGO2` draws a lego plot using colors to
1944 show the cell contents. Combined with the option `LEGO2`, the option
1945 `Z` allows to display the color palette defined by
1946 `gStyle->SetPalette()`.
1947 
1948 Begin_Macro(source)
1949 {
1950  auto c2 = new TCanvas("c2","c2",600,400);
1951  auto hlego2 = new TH2F("hlego2","Option LEGO2Z example ",40,-4,4,40,-20,20);
1952  float px, py;
1953  for (Int_t i = 0; i < 25000; i++) {
1954  gRandom->Rannor(px,py);
1955  hlego2->Fill(px-1,5*py);
1956  hlego2->Fill(2+0.5*px,2*py-10.,0.1);
1957  }
1958  hlego2->Draw("LEGO2Z");
1959 }
1960 End_Macro
1961 
1962 
1963 
1964 ### <a name="HP18"></a> The "SURFace" options
1965 
1966 
1967 In a surface plot, cell contents are represented as a mesh.
1968 The height of the mesh is proportional to the cell content.
1969 
1970 | Option | Description |
1971 |----------|-------------------------------------------------------------------|
1972 | "SURF" | Draw a surface plot using the hidden line removal technique.|
1973 | "SURF1" | Draw a surface plot using the hidden surface removal technique.|
1974 | "SURF2" | Draw a surface plot using colors to show the cell contents.|
1975 | "SURF3" | Same as `SURF` with an additional filled contour plot on top.|
1976 | "SURF4" | Draw a surface using the Gouraud shading technique.|
1977 | "SURF5" | Used with one of the options CYL, PSR and CYL this option allows to draw a a filled contour plot.|
1978 | "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.|
1979 | "SURF7" | Same as `SURF2` with an additional line contour plot on top.|
1980 
1981 
1982 
1983 See the limitations with [the option "SAME"](#HP060a).
1984 
1985 The following example shows a 2D histogram plotted with the option
1986 `SURF`. The option `SURF` draws a lego plot using the hidden
1987 lines removal technique.
1988 
1989 Begin_Macro(source)
1990 {
1991  auto c2 = new TCanvas("c2","c2",600,400);
1992  auto hsurf = new TH2F("hsurf","Option SURF example ",30,-4,4,30,-20,20);
1993  float px, py;
1994  for (Int_t i = 0; i < 25000; i++) {
1995  gRandom->Rannor(px,py);
1996  hsurf->Fill(px-1,5*py);
1997  hsurf->Fill(2+0.5*px,2*py-10.,0.1);
1998  }
1999  hsurf->Draw("SURF");
2000 }
2001 End_Macro
2002 
2003 The following example shows a 2D histogram plotted with the option
2004 `SURF1`. The option `SURF1` draws a surface plot using the
2005 hidden surface removal technique. Combined with the option `SURF1`,
2006 the option `Z` allows to display the color palette defined by
2007 `gStyle->SetPalette()`.
2008 
2009 Begin_Macro(source)
2010 {
2011  auto c2 = new TCanvas("c2","c2",600,400);
2012  auto hsurf1 = new TH2F("hsurf1","Option SURF1 example ",30,-4,4,30,-20,20);
2013  float px, py;
2014  for (Int_t i = 0; i < 25000; i++) {
2015  gRandom->Rannor(px,py);
2016  hsurf1->Fill(px-1,5*py);
2017  hsurf1->Fill(2+0.5*px,2*py-10.,0.1);
2018  }
2019  hsurf1->Draw("SURF1");
2020 }
2021 End_Macro
2022 
2023 The following example shows a 2D histogram plotted with the option
2024 `SURF2`. The option `SURF2` draws a surface plot using colors
2025 to show the cell contents. Combined with the option `SURF2`, the option
2026 `Z` allows to display the color palette defined by
2027 `gStyle->SetPalette()`.
2028 
2029 Begin_Macro(source)
2030 {
2031  auto c2 = new TCanvas("c2","c2",600,400);
2032  auto hsurf2 = new TH2F("hsurf2","Option SURF2 example ",30,-4,4,30,-20,20);
2033  float px, py;
2034  for (Int_t i = 0; i < 25000; i++) {
2035  gRandom->Rannor(px,py);
2036  hsurf2->Fill(px-1,5*py);
2037  hsurf2->Fill(2+0.5*px,2*py-10.,0.1);
2038  }
2039  hsurf2->Draw("SURF2");
2040 }
2041 End_Macro
2042 
2043 The following example shows a 2D histogram plotted with the option
2044 `SURF3`. The option `SURF3` draws a surface plot using the
2045 hidden line removal technique with, in addition, a filled contour view drawn on the
2046 top. Combined with the option `SURF3`, the option `Z` allows
2047 to display the color palette defined by `gStyle->SetPalette()`.
2048 
2049 Begin_Macro(source)
2050 {
2051  auto c2 = new TCanvas("c2","c2",600,400);
2052  auto hsurf3 = new TH2F("hsurf3","Option SURF3 example ",30,-4,4,30,-20,20);
2053  float px, py;
2054  for (Int_t i = 0; i < 25000; i++) {
2055  gRandom->Rannor(px,py);
2056  hsurf3->Fill(px-1,5*py);
2057  hsurf3->Fill(2+0.5*px,2*py-10.,0.1);
2058  }
2059  hsurf3->Draw("SURF3");
2060 }
2061 End_Macro
2062 
2063 The following example shows a 2D histogram plotted with the option
2064 `SURF4`. The option `SURF4` draws a surface using the Gouraud
2065 shading technique.
2066 
2067 Begin_Macro(source)
2068 {
2069  auto c2 = new TCanvas("c2","c2",600,400);
2070  auto hsurf4 = new TH2F("hsurf4","Option SURF4 example ",30,-4,4,30,-20,20);
2071  float px, py;
2072  for (Int_t i = 0; i < 25000; i++) {
2073  gRandom->Rannor(px,py);
2074  hsurf4->Fill(px-1,5*py);
2075  hsurf4->Fill(2+0.5*px,2*py-10.,0.1);
2076  }
2077  hsurf4->SetFillColor(kOrange);
2078  hsurf4->Draw("SURF4");
2079 }
2080 End_Macro
2081 
2082 The following example shows a 2D histogram plotted with the option
2083 `SURF5 CYL`. Combined with the option `SURF5`, the option
2084 `Z` allows to display the color palette defined by `gStyle->SetPalette()`.
2085 
2086 Begin_Macro(source)
2087 {
2088  auto c2 = new TCanvas("c2","c2",600,400);
2089  auto hsurf5 = new TH2F("hsurf4","Option SURF5 example ",30,-4,4,30,-20,20);
2090  float px, py;
2091  for (Int_t i = 0; i < 25000; i++) {
2092  gRandom->Rannor(px,py);
2093  hsurf5->Fill(px-1,5*py);
2094  hsurf5->Fill(2+0.5*px,2*py-10.,0.1);
2095  }
2096  hsurf5->Draw("SURF5 CYL");
2097 }
2098 End_Macro
2099 
2100 The following example shows a 2D histogram plotted with the option
2101 `SURF7`. The option `SURF7` draws a surface plot using the
2102 hidden surfaces removal technique with, in addition, a line contour view drawn on the
2103 top. Combined with the option `SURF7`, the option `Z` allows
2104 to display the color palette defined by `gStyle->SetPalette()`.
2105 
2106 Begin_Macro(source)
2107 {
2108  auto c2 = new TCanvas("c2","c2",600,400);
2109  auto hsurf7 = new TH2F("hsurf3","Option SURF7 example ",30,-4,4,30,-20,20);
2110  float px, py;
2111  for (Int_t i = 0; i < 25000; i++) {
2112  gRandom->Rannor(px,py);
2113  hsurf7->Fill(px-1,5*py);
2114  hsurf7->Fill(2+0.5*px,2*py-10.,0.1);
2115  }
2116  hsurf7->Draw("SURF7");
2117 }
2118 End_Macro
2119 
2120 As shown in the following example, when a contour plot is painted on top of a
2121 surface plot using the option `SAME`, the contours appear in 3D on the
2122 surface.
2123 
2124 Begin_Macro(source)
2125 {
2126  auto c20=new TCanvas("c20","c20",600,400);
2127  int NBins = 50;
2128  double d = 2;
2129  auto hsc = new TH2F("hsc", "Surface and contour with option SAME ", NBins, -d, d, NBins, -d, d);
2130  for (int bx = 1; bx <= NBins; ++bx) {
2131  for (int by = 1; by <= NBins; ++by) {
2132  double x = hsc->GetXaxis()->GetBinCenter(bx);
2133  double y = hsc->GetYaxis()->GetBinCenter(by);
2134  hsc->SetBinContent(bx, by, exp(-x*x)*exp(-y*y));
2135  }
2136  }
2137  hsc->Draw("surf2");
2138  hsc->Draw("CONT1 SAME");
2139 }
2140 End_Macro
2141 
2142 
2143 ### <a name="HP19"></a> Cylindrical, Polar, Spherical and PseudoRapidity/Phi options
2144 
2145 
2146 Legos and surfaces plots are represented by default in Cartesian coordinates.
2147 Combined with any `LEGOn` or `SURFn` options the following
2148 options allow to draw a lego or a surface in other coordinates systems.
2149 
2150 | Option | Description |
2151 |----------|-------------------------------------------------------------------|
2152 | "CYL" | Use Cylindrical coordinates. The X coordinate is mapped on the angle and the Y coordinate on the cylinder length.|
2153 | "POL" | Use Polar coordinates. The X coordinate is mapped on the angle and the Y coordinate on the radius.|
2154 | "SPH" | Use Spherical coordinates. The X coordinate is mapped on the latitude and the Y coordinate on the longitude.|
2155 | "PSR" | Use PseudoRapidity/Phi coordinates. The X coordinate is mapped on Phi.|
2156 
2157 
2158 
2159 <b>WARNING:</b> Axis are not drawn with these options.
2160 
2161 The following example shows the same histogram as a lego plot is the four
2162 different coordinates systems.
2163 
2164 Begin_Macro(source)
2165 {
2166  auto c3 = new TCanvas("c3","c3",600,400);
2167  c3->Divide(2,2);
2168  auto hlcc = new TH2F("hlcc","Cylindrical coordinates",20,-4,4,20,-20,20);
2169  float px, py;
2170  for (Int_t i = 0; i < 25000; i++) {
2171  gRandom->Rannor(px,py);
2172  hlcc->Fill(px-1,5*py);
2173  hlcc->Fill(2+0.5*px,2*py-10.,0.1);
2174  }
2175  hlcc->SetFillColor(kYellow);
2176  c3->cd(1); hlcc->Draw("LEGO1 CYL");
2177  c3->cd(2); auto hlpc = (TH2F*) hlcc->DrawClone("LEGO1 POL");
2178  hlpc->SetTitle("Polar coordinates");
2179  c3->cd(3); auto hlsc = (TH2F*) hlcc->DrawClone("LEGO1 SPH");
2180  hlsc->SetTitle("Spherical coordinates");
2181  c3->cd(4); auto hlprpc = (TH2F*) hlcc->DrawClone("LEGO1 PSR");
2182  hlprpc->SetTitle("PseudoRapidity/Phi coordinates");
2183 }
2184 End_Macro
2185 
2186 The following example shows the same histogram as a surface plot is the four different coordinates systems.
2187 
2188 Begin_Macro(source)
2189 {
2190  auto c4 = new TCanvas("c4","c4",600,400);
2191  c4->Divide(2,2);
2192  auto hscc = new TH2F("hscc","Cylindrical coordinates",20,-4,4,20,-20,20);
2193  float px, py;
2194  for (Int_t i = 0; i < 25000; i++) {
2195  gRandom->Rannor(px,py);
2196  hscc->Fill(px-1,5*py);
2197  hscc->Fill(2+0.5*px,2*py-10.,0.1);
2198  }
2199  c4->cd(1); hscc->Draw("SURF1 CYL");
2200  c4->cd(2); auto hspc = (TH2F*) hscc->DrawClone("SURF1 POL");
2201  hspc->SetTitle("Polar coordinates");
2202  c4->cd(3); auto hssc = (TH2F*) hscc->DrawClone("SURF1 SPH");
2203  hssc->SetTitle("Spherical coordinates");
2204  c4->cd(4); auto hsprpc = (TH2F*) hscc->DrawClone("SURF1 PSR");
2205  hsprpc->SetTitle("PseudoRapidity/Phi coordinates");
2206 }
2207 End_Macro
2208 
2209 
2210 ### <a name="HP20"></a> Base line for bar-charts and lego plots
2211 
2212 
2213 By default the base line used to draw the boxes for bar-charts and lego plots is
2214 the histogram minimum. It is possible to force this base line to be 0, using MIN0 draw
2215 option or with the command:
2216 
2217  gStyle->SetHistMinimumZero();
2218 
2219 Begin_Macro(source)
2220 {
2221  auto c5 = new TCanvas("c5","c5",700,400);
2222  c5->Divide(2,1);
2223  auto hz1 = new TH1F("hz1","Bar-chart drawn from 0",20,-3,3);
2224  auto hz2 = new TH2F("hz2","Lego plot drawn from 0",20,-3,3,20,-3,3);
2225  Int_t i;
2226  double x,y;
2227  hz1->SetFillColor(kBlue);
2228  hz2->SetFillColor(kBlue);
2229  for (i=0;i<10000;i++) {
2230  x = gRandom->Gaus(0,1);
2231  y = gRandom->Gaus(0,1);
2232  if (x>0) {
2233  hz1->Fill(x,1);
2234  hz2->Fill(x,y,1);
2235  } else {
2236  hz1->Fill(x,-1);
2237  hz2->Fill(x,y,-2);
2238  }
2239  }
2240  c5->cd(1); hz1->Draw("bar2 min0");
2241  c5->cd(2); hz2->Draw("lego1 min0");
2242 }
2243 End_Macro
2244 
2245 This option also works for horizontal plots. The example given in the section
2246 ["The bar chart option"](#HP100) appears as follow:
2247 
2248 Begin_Macro(source)
2249 {
2250  int i;
2251  const Int_t nx = 8;
2252  string os_X[nx] = {"8","32","128","512","2048","8192","32768","131072"};
2253  float d_35_0[nx] = {0.75, -3.30, -0.92, 0.10, 0.08, -1.69, -1.29, -2.37};
2254  float d_35_1[nx] = {1.01, -3.02, -0.65, 0.37, 0.34, -1.42, -1.02, -2.10};
2255 
2256  auto cbh = new TCanvas("cbh","cbh",400,600);
2257  cbh->SetGrid();
2258 
2259  auto h1bh = new TH1F("h1bh","Option HBAR centered on 0",nx,0,nx);
2260  h1bh->SetFillColor(4);
2261  h1bh->SetBarWidth(0.4);
2262  h1bh->SetBarOffset(0.1);
2263  h1bh->SetStats(0);
2264  h1bh->SetMinimum(-5);
2265  h1bh->SetMaximum(5);
2266 
2267  for (i=1; i<=nx; i++) {
2268  h1bh->Fill(os_X[i-1].c_str(), d_35_0[i-1]);
2269  h1bh->GetXaxis()->SetBinLabel(i,os_X[i-1].c_str());
2270  }
2271 
2272  h1bh->Draw("hbar min0");
2273 
2274  auto h2bh = new TH1F("h2bh","h2bh",nx,0,nx);
2275  h2bh->SetFillColor(38);
2276  h2bh->SetBarWidth(0.4);
2277  h2bh->SetBarOffset(0.5);
2278  h2bh->SetStats(0);
2279  for (i=1;i<=nx;i++) h2bh->Fill(os_X[i-1].c_str(), d_35_1[i-1]);
2280 
2281  h2bh->Draw("hbar min0 same");
2282 }
2283 End_Macro
2284 
2285 
2286 ### <a name="HP20a"></a> TH2Poly Drawing
2287 
2288 
2289 The following options are supported:
2290 
2291 | Option | Description |
2292 |----------|-------------------------------------------------------------------|
2293 | "SCAT" | Draw a scatter plot (default).|
2294 | "COL" | Draw a color plot. All the bins are painted even the empty bins.|
2295 | "COLZ" | Same as "COL". In addition the color palette is also drawn.|
2296 | "0" | When used with any COL options, the empty bins are not drawn.|
2297 | "TEXT" | Draw bin contents as text (format set via `gStyle->SetPaintTextFormat`).|
2298 | "TEXTN" | Draw bin names as text.|
2299 | "TEXTnn" | Draw bin contents as text at angle nn (0 < nn < 90).|
2300 | "L" | Draw the bins boundaries as lines. The lines attributes are the TGraphs ones.|
2301 | "P" | Draw the bins boundaries as markers. The markers attributes are the TGraphs ones.|
2302 | "F" | Draw the bins boundaries as filled polygons. The filled polygons attributes are the TGraphs ones.|
2303 
2304 
2305 
2306 `TH2Poly` can be drawn as a color plot (option COL). `TH2Poly` bins can have any
2307 shapes. The bins are defined as graphs. The following macro is a very simple
2308 example showing how to book a TH2Poly and draw it.
2309 
2310 Begin_Macro(source)
2311 {
2312  auto ch2p1 = new TCanvas("ch2p1","ch2p1",600,400);
2313  auto h2p = new TH2Poly();
2314  h2p->SetName("h2poly_name");
2315  h2p->SetTitle("h2poly_title");
2316  double px1[] = {0, 5, 6};
2317  double py1[] = {0, 0, 5};
2318  double px2[] = {0, -1, -1, 0};
2319  double py2[] = {0, 0, -1, 3};
2320  double px3[] = {4, 3, 0, 1, 2.4};
2321  double py3[] = {4, 3.7, 1, 3.7, 2.5};
2322  h2p->AddBin(3, px1, py1);
2323  h2p->AddBin(4, px2, py2);
2324  h2p->AddBin(5, px3, py3);
2325  h2p->Fill(0.1, 0.01, 3);
2326  h2p->Fill(-0.5, -0.5, 7);
2327  h2p->Fill(-0.7, -0.5, 1);
2328  h2p->Fill(1, 3, 1.5);
2329  double fx[] = {0.1, -0.5, -0.7, 1};
2330  double fy[] = {0.01, -0.5, -0.5, 3};
2331  double fw[] = {3, 1, 1, 1.5};
2332  h2p->FillN(4, fx, fy, fw);
2333  h2p->Draw("col");
2334 }
2335 End_Macro
2336 
2337 Rectangular bins are a frequent case. The special version of
2338 the `AddBin` method allows to define them more easily like
2339 shown in the following example (th2polyBoxes.C).
2340 
2341 Begin_Macro(source)
2342 ../../../tutorials/hist/th2polyBoxes.C
2343 End_Macro
2344 
2345 One `TH2Poly` bin can be a list of polygons. Such bins are defined
2346 by calling `AddBin` with a `TMultiGraph`. The following example
2347 shows a such case:
2348 
2349 Begin_Macro(source)
2350 {
2351  auto ch2p2 = new TCanvas("ch2p2","ch2p2",600,400);
2352 
2353  Int_t i, bin;
2354  const Int_t nx = 48;
2355  const char *states [nx] = {
2356  "alabama", "arizona", "arkansas", "california",
2357  "colorado", "connecticut", "delaware", "florida",
2358  "georgia", "idaho", "illinois", "indiana",
2359  "iowa", "kansas", "kentucky", "louisiana",
2360  "maine", "maryland", "massachusetts", "michigan",
2361  "minnesota", "mississippi", "missouri", "montana",
2362  "nebraska", "nevada", "new_hampshire", "new_jersey",
2363  "new_mexico", "new_york", "north_carolina", "north_dakota",
2364  "ohio", "oklahoma", "oregon", "pennsylvania",
2365  "rhode_island", "south_carolina", "south_dakota", "tennessee",
2366  "texas", "utah", "vermont", "virginia",
2367  "washington", "west_virginia", "wisconsin", "wyoming"
2368  };
2369  Double_t pop[nx] = {
2370  4708708, 6595778, 2889450, 36961664, 5024748, 3518288, 885122, 18537969,
2371  9829211, 1545801, 12910409, 6423113, 3007856, 2818747, 4314113, 4492076,
2372  1318301, 5699478, 6593587, 9969727, 5266214, 2951996, 5987580, 974989,
2373  1796619, 2643085, 1324575, 8707739, 2009671, 19541453, 9380884, 646844,
2374  11542645, 3687050, 3825657, 12604767, 1053209, 4561242, 812383, 6296254,
2375  24782302, 2784572, 621760, 7882590, 6664195, 1819777, 5654774, 544270
2376  };
2377 
2378  Double_t lon1 = -130;
2379  Double_t lon2 = -65;
2380  Double_t lat1 = 24;
2381  Double_t lat2 = 50;
2382  auto p = new TH2Poly("USA","USA Population",lon1,lon2,lat1,lat2);
2383 
2384  TFile::SetCacheFileDir(".");
2385  auto f = TFile::Open("http://root.cern.ch/files/usa.root", "CACHEREAD");
2386 
2387  TMultiGraph *mg;
2388  TKey *key;
2389  TIter nextkey(gDirectory->GetListOfKeys());
2390  while ((key = (TKey*)nextkey())) {
2391  TObject *obj = key->ReadObj();
2392  if (obj->InheritsFrom("TMultiGraph")) {
2393  mg = (TMultiGraph*)obj;
2394  bin = p->AddBin(mg);
2395  }
2396  }
2397 
2398  for (i=0; i<nx; i++) p->Fill(states[i], pop[i]);
2399 
2400  gStyle->SetOptStat(11);
2401  p->Draw("COLZ L");
2402 }
2403 End_Macro
2404 
2405 `TH2Poly` histograms can also be plotted using the GL interface using
2406 the option "GLLEGO".
2407 
2408 \since **ROOT version 6.09/01**
2409 
2410 In some cases it can be useful to not draw the empty bins. the option "0"
2411 combined with the option "COL" et COLZ allows to do that.
2412 
2413 Begin_Macro(source)
2414 {
2415  auto chc = new TCanvas("chc","chc",600,400);
2416 
2417  auto hc = new TH2Poly();
2418  hc->Honeycomb(0,0,.1,25,25);
2419  hc->SetName("hc");
2420  hc->SetTitle("Option COLZ 0");
2421  TRandom ran;
2422  for (int i = 0; i<300; i++) hc->Fill(ran.Gaus(2.,1), ran.Gaus(2.,1));
2423  hc->Draw("colz 0");
2424 }
2425 End_Macro
2426 
2427 ### <a name="HP21"></a> The SPEC option
2428 
2429 
2430 This option allows to use the `TSpectrum2Painter` tools. See the full
2431 documentation in `TSpectrum2Painter::PaintSpectrum`.
2432 
2433 
2434 ### <a name="HP22"></a> Option "Z" : Adding the color palette on the right side of the pad
2435 
2436 
2437 When this option is specified, a color palette with an axis indicating the value
2438 of the corresponding color is drawn on the right side of the picture. In case,
2439 not enough space is left, one can increase the size of the right margin by
2440 calling `TPad::SetRightMargin()`. The attributes used to display the
2441 palette axis values are taken from the Z axis of the object. For example, to
2442 set the labels size on the palette axis do:
2443 
2444  hist->GetZaxis()->SetLabelSize().
2445 
2446 <b>WARNING:</b> The palette axis is always drawn vertically.
2447 
2448 
2449 ### <a name="HP23"></a> Setting the color palette
2450 
2451 
2452 To change the color palette `TStyle::SetPalette` should be used, eg:
2453 
2454  gStyle->SetPalette(ncolors,colors);
2455 
2456 For example the option `COL` draws a 2D histogram with cells
2457 represented by a box filled with a color index which is a function
2458 of the cell content.
2459 If the cell content is N, the color index used will be the color number
2460 in `colors[N]`, etc. If the maximum cell content is greater than
2461 `ncolors`, all cell contents are scaled to `ncolors`.
2462 
2463 If ` ncolors <= 0`, a default palette (see below) of 50 colors is
2464 defined. This palette is recommended for pads, labels ...
2465 
2466 `if ncolors == 1 && colors == 0`, then a Pretty Palette with a
2467 Spectrum Violet->Red is created with 50 colors. That's the default rain bow
2468 palette.
2469 
2470 Other pre-defined palettes with 255 colors are available when `colors == 0`.
2471 The following value of `ncolors` give access to:
2472 
2473 
2474  if ncolors = 51 and colors=0, a Deep Sea palette is used.
2475  if ncolors = 52 and colors=0, a Grey Scale palette is used.
2476  if ncolors = 53 and colors=0, a Dark Body Radiator palette is used.
2477  if ncolors = 54 and colors=0, a two-color hue palette palette is used.(dark blue through neutral gray to bright yellow)
2478  if ncolors = 55 and colors=0, a Rain Bow palette is used.
2479  if ncolors = 56 and colors=0, an inverted Dark Body Radiator palette is used.
2480 
2481 
2482 If `ncolors > 0 && colors == 0`, the default palette is used with a maximum of ncolors.
2483 
2484 The default palette defines:
2485 
2486 - index 0 to 9 : shades of grey
2487 - index 10 to 19 : shades of brown
2488 - index 20 to 29 : shades of blue
2489 - index 30 to 39 : shades of red
2490 - index 40 to 49 : basic colors
2491 
2492 The color numbers specified in the palette can be viewed by selecting
2493 the item `colors` in the `VIEW` menu of the canvas tool bar.
2494 The red, green, and blue components of a color can be changed thanks to
2495 `TColor::SetRGB()`.
2496 
2497 \since **ROOT version 6.19/01**
2498 
2499 As default labels and ticks are drawn by `TGAxis` at equidistant (lin or log)
2500 points as controlled by SetNdivisions.
2501 If option "CJUST" is given labels and ticks are justified at the
2502 color boundaries defined by the contour levels.
2503 For more details see `TPaletteAxis`
2504 
2505 ### <a name="HP24"></a> Drawing a sub-range of a 2D histogram; the [cutg] option
2506 
2507 
2508 Using a `TCutG` object, it is possible to draw a sub-range of a 2D
2509 histogram. One must create a graphical cut (mouse or C++) and specify the name
2510 of the cut between `[]` in the `Draw()` option.
2511 For example (fit2a.C), with a `TCutG` named `cutg`, one can call:
2512 
2513  myhist->Draw("surf1 [cutg]");
2514 
2515 To invert the cut, it is enough to put a `-` in front of its name:
2516 
2517  myhist->Draw("surf1 [-cutg]");
2518 
2519 It is possible to apply several cuts (`,` means logical AND):
2520 
2521  myhist->Draw("surf1 [cutg1,cutg2]");
2522 
2523 Begin_Macro(source)
2524 ../../../tutorials/fit/fit2a.C
2525 End_Macro
2526 
2527 ### <a name="HP25"></a> Drawing options for 3D histograms
2528 
2529 
2530 | Option | Description |
2531 |----------|-------------------------------------------------------------------|
2532 | "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)`|
2533 | "BOX" | Draw a for each cell with volume proportional to the content's absolute value. An hidden line removal algorithm is used|
2534 | "BOX1" | Same as BOX but an hidden surface removal algorithm is used|
2535 | "BOX2" | The boxes' colors are picked in the current palette according to the bins' contents|
2536 | "BOX2Z" | Same as "BOX2". In addition the color palette is also drawn.|
2537 | "BOX3" | Same as BOX1, but the border lines of each lego-bar are not drawn.|
2538 
2539 Note that instead of `BOX` one can also use `LEGO`.
2540 
2541 By default, like 2D histograms, 3D histograms are drawn as scatter plots.
2542 
2543 The following example shows a 3D histogram plotted as a scatter plot.
2544 
2545 Begin_Macro(source)
2546 {
2547  auto c06 = new TCanvas("c06","c06",600,400);
2548  gStyle->SetOptStat(kFALSE);
2549  auto h3scat = new TH3F("h3scat","Option SCAT (default) ",15,-2,2,15,-2,2,15,0,4);
2550  double x, y, z;
2551  for (Int_t i=0;i<10000;i++) {
2552  gRandom->Rannor(x, y);
2553  z = x*x + y*y;
2554  h3scat->Fill(x,y,z);
2555  }
2556  h3scat->Draw();
2557 }
2558 End_Macro
2559 
2560 The following example shows a 3D histogram plotted with the option `BOX`.
2561 
2562 Begin_Macro(source)
2563 {
2564  auto c16 = new TCanvas("c16","c16",600,400);
2565  gStyle->SetOptStat(kFALSE);
2566  auto h3box = new TH3F("h3box","Option BOX",15,-2,2,15,-2,2,15,0,4);
2567  double x, y, z;
2568  for (Int_t i=0;i<10000;i++) {
2569  gRandom->Rannor(x, y);
2570  z = x*x + y*y;
2571  h3box->Fill(x,y,z);
2572  }
2573  h3box->Draw("BOX");
2574 }
2575 End_Macro
2576 
2577 The following example shows a 3D histogram plotted with the option `BOX1`.
2578 
2579 Begin_Macro(source)
2580 {
2581  auto c36 = new TCanvas("c36","c36",600,400);
2582  gStyle->SetOptStat(kFALSE);
2583  auto h3box = new TH3F("h3box","Option BOX1",10,-2.,2.,10,-2.,2.,10,-0.5,2.);
2584  double x, y, z;
2585  for (Int_t i=0;i<10000;i++) {
2586  gRandom->Rannor(x, y);
2587  z = abs(sin(x)/x + cos(y)*y);
2588  h3box->Fill(x,y,z);
2589  }
2590  h3box->SetFillColor(9);
2591  h3box->Draw("BOX1");
2592 }
2593 End_Macro
2594 
2595 The following example shows a 3D histogram plotted with the option `BOX2`.
2596 
2597 Begin_Macro(source)
2598 {
2599  auto c56 = new TCanvas("c56","c56",600,400);
2600  gStyle->SetOptStat(kFALSE);
2601  auto h3box = new TH3F("h3box","Option BOX2",10,-2.,2.,10,-2.,2.,10,-0.5,2.);
2602  double x, y, z;
2603  for (Int_t i=0;i<10000;i++) {
2604  gRandom->Rannor(x, y);
2605  z = abs(sin(x)/x + cos(y)*y);
2606  h3box->Fill(x,y,z);
2607  }
2608  h3box->Draw("BOX2 Z");
2609 }
2610 End_Macro
2611 
2612 The following example shows a 3D histogram plotted with the option `BOX3`.
2613 
2614 Begin_Macro(source)
2615 {
2616  auto c46 = new TCanvas("c46","c46",600,400);
2617  c46->SetFillColor(38);
2618  gStyle->SetOptStat(kFALSE);
2619  auto h3box = new TH3F("h3box","Option BOX3",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  h3box->Fill(x,y,z);
2625  }
2626  h3box->Draw("BOX3");
2627 }
2628 End_Macro
2629 
2630 For all the `BOX` options each bin is drawn as a 3D box with a volume proportional
2631 to the absolute value of the bin content. The bins with a negative content are
2632 drawn with a X on each face of the box as shown in the following example:
2633 
2634 Begin_Macro(source)
2635 {
2636  auto c = new TCanvas("c","c",600,400);
2637  gStyle->SetOptStat(kFALSE);
2638  auto h3box = new TH3F("h3box","Option BOX1 with negative bins",3, 0., 4., 3, 0.,4., 3, 0., 4.);
2639  h3box->Fill(0., 2., 2., 10.);
2640  h3box->Fill(2., 2., 2., 5.);
2641  h3box->Fill(2., 2., .5, 2.);
2642  h3box->Fill(2., 2., 3., -1.);
2643  h3box->Fill(3., 2., 2., -10.);
2644  h3box->SetFillColor(8);
2645  h3box->Draw("box1");
2646 }
2647 End_Macro
2648 
2649 The following example shows a 3D histogram plotted with the option `ISO`.
2650 
2651 Begin_Macro(source)
2652 {
2653  auto c26 = new TCanvas("c26","c26",600,400);
2654  gStyle->SetOptStat(kFALSE);
2655  auto h3iso = new TH3F("h3iso","Option ISO",15,-2,2,15,-2,2,15,0,4);
2656  double x, y, z;
2657  for (Int_t i=0;i<10000;i++) {
2658  gRandom->Rannor(x, y);
2659  z = x*x + y*y;
2660  h3iso->Fill(x,y,z);
2661  }
2662  h3iso->SetFillColor(kCyan);
2663  h3iso->Draw("ISO");
2664 }
2665 End_Macro
2666 
2667 
2668 ### <a name="HP26"></a> Drawing option for histograms' stacks
2669 
2670 
2671 Stacks of histograms are managed with the `THStack`. A `THStack`
2672 is a collection of `TH1` (or derived) objects. For painting only the
2673 `THStack` containing `TH1` only or
2674 `THStack` containing `TH2` only will be considered.
2675 
2676 By default, histograms are shown stacked:
2677 
2678 1. The first histogram is paint.
2679 2. The the sum of the first and second, etc...
2680 
2681 If the option `NOSTACK` is specified, the histograms are all paint in
2682 the same pad as if the option `SAME` had been specified. This allows to
2683 compute X and Y scales common to all the histograms, like
2684 `TMultiGraph` does for graphs.
2685 
2686 If the option `PADS` is specified, the current pad/canvas is
2687 subdivided into a number of pads equal to the number of histograms and each
2688 histogram is paint into a separate pad.
2689 
2690 The following example shows various types of stacks (hstack.C).
2691 
2692 Begin_Macro(source)
2693 ../../../tutorials/hist/hstack.C
2694 End_Macro
2695 
2696 The option `nostackb` allows to draw the histograms next to each
2697 other as bar charts:
2698 
2699 Begin_Macro(source)
2700 {
2701  auto cst0 = new TCanvas("cst0","cst0",600,400);
2702  auto hs = new THStack("hs","Stacked 1D histograms: option #font[82]{\"nostackb\"}");
2703 
2704  auto h1 = new TH1F("h1","h1",10,-4,4);
2705  h1->FillRandom("gaus",20000);
2706  h1->SetFillColor(kRed);
2707  hs->Add(h1);
2708 
2709  auto h2 = new TH1F("h2","h2",10,-4,4);
2710  h2->FillRandom("gaus",15000);
2711  h2->SetFillColor(kBlue);
2712  hs->Add(h2);
2713 
2714  auto h3 = new TH1F("h3","h3",10,-4,4);
2715  h3->FillRandom("gaus",10000);
2716  h3->SetFillColor(kGreen);
2717  hs->Add(h3);
2718 
2719  hs->Draw("nostackb");
2720  hs->GetXaxis()->SetNdivisions(-10);
2721  cst0->SetGridx();
2722 }
2723 End_Macro
2724 
2725 If at least one of the histograms in the stack has errors, the whole stack is
2726 visualized by default with error bars. To visualize it without errors the
2727 option `HIST` should be used.
2728 
2729 Begin_Macro(source)
2730 {
2731  auto cst1 = new TCanvas("cst1","cst1",700,400);
2732  cst1->Divide(2,1);
2733 
2734  auto hst11 = new TH1F("hst11", "", 20, -10, 10);
2735  hst11->Sumw2();
2736  hst11->FillRandom("gaus", 1000);
2737  hst11->SetFillColor(kViolet);
2738  hst11->SetLineColor(kViolet);
2739 
2740  auto hst12 = new TH1F("hst12", "", 20, -10, 10);
2741  hst12->FillRandom("gaus", 500);
2742  hst12->SetFillColor(kBlue);
2743  hst12->SetLineColor(kBlue);
2744 
2745  THStack st1("st1", "st1");
2746  st1.Add(hst11);
2747  st1.Add(hst12);
2748 
2749  cst1->cd(1); st1.Draw();
2750  cst1->cd(2); st1.Draw("hist");
2751 }
2752 End_Macro
2753 
2754 ### <a name="HP27"></a> Drawing of 3D implicit functions
2755 
2756 
2757 3D implicit functions (`TF3`) can be drawn as iso-surfaces.
2758 The implicit function f(x,y,z) = 0 is drawn in cartesian coordinates.
2759 In the following example the options "FB" and "BB" suppress the
2760 "Front Box" and "Back Box" around the plot.
2761 
2762 Begin_Macro(source)
2763 {
2764  auto c2 = new TCanvas("c2","c2",600,400);
2765  auto f3 = new TF3("f3","sin(x*x+y*y+z*z-36)",-2,2,-2,2,-2,2);
2766  f3->SetClippingBoxOn(0,0,0);
2767  f3->SetFillColor(30);
2768  f3->SetLineColor(15);
2769  f3->Draw("FBBB");
2770 }
2771 End_Macro
2772 
2773 
2774 ### <a name="HP28"></a> Associated functions drawing
2775 
2776 
2777 An associated function is created by `TH1::Fit`. More than on fitted
2778 function can be associated with one histogram (see `TH1::Fit`).
2779 
2780 A `TF1` object `f1` can be added to the list of associated
2781 functions of an histogram `h` without calling `TH1::Fit`
2782 simply doing:
2783 
2784  h->GetListOfFunctions()->Add(f1);
2785 
2786 or
2787 
2788  h->GetListOfFunctions()->Add(f1,someoption);
2789 
2790 To retrieve a function by name from this list, do:
2791 
2792  TF1 *f1 = (TF1*)h->GetListOfFunctions()->FindObject(name);
2793 
2794 or
2795 
2796  TF1 *f1 = h->GetFunction(name);
2797 
2798 Associated functions are automatically painted when an histogram is drawn.
2799 To avoid the painting of the associated functions the option `HIST`
2800 should be added to the list of the options used to paint the histogram.
2801 
2802 
2803 ### <a name="HP29"></a> Drawing using OpenGL
2804 
2805 
2806 The class `TGLHistPainter` allows to paint data set using the OpenGL 3D
2807 graphics library. The plotting options start with `GL` keyword.
2808 In addition, in order to inform canvases that OpenGL should be used to render
2809 3D representations, the following option should be set:
2810 
2811  gStyle->SetCanvasPreferGL(true);
2812 
2813 
2814 #### <a name="HP29a"></a> General information: plot types and supported options
2815 
2816 The following types of plots are provided:
2817 
2818 For lego plots the supported options are:
2819 
2820 | Option | Description |
2821 |----------|-------------------------------------------------------------------|
2822 | "GLLEGO" | Draw a lego plot. It works also for `TH2Poly`.|
2823 | "GLLEGO2"| Bins with color levels.|
2824 | "GLLEGO3"| Cylindrical bars.|
2825 
2826 
2827 
2828 Lego painter in cartesian supports logarithmic scales for X, Y, Z.
2829 In polar only Z axis can be logarithmic, in cylindrical only Y.
2830 
2831 For surface plots (`TF2` and `TH2`) the supported options are:
2832 
2833 | Option | Description |
2834 |-----------|------------------------------------------------------------------|
2835 | "GLSURF" | Draw a surface.|
2836 | "GLSURF1" | Surface with color levels|
2837 | "GLSURF2" | The same as "GLSURF1" but without polygon outlines.|
2838 | "GLSURF3" | Color level projection on top of plot (works only in cartesian coordinate system).|
2839 | "GLSURF4" | Same as "GLSURF" but without polygon outlines.|
2840 
2841 
2842 
2843 The surface painting in cartesian coordinates supports logarithmic scales along
2844 X, Y, Z axis. In polar coordinates only the Z axis can be logarithmic,
2845 in cylindrical coordinates only the Y axis.
2846 
2847 Additional options to SURF and LEGO - Coordinate systems:
2848 
2849 | Option | Description |
2850 |----------|-------------------------------------------------------------------|
2851 | " " | Default, cartesian coordinates system.|
2852 | "POL" | Polar coordinates system.|
2853 | "CYL" | Cylindrical coordinates system.|
2854 | "SPH" | Spherical coordinates system.|
2855 
2856 
2857 
2858 #### <a name="HP290"></a> TH3 as color boxes
2859 
2860 The supported option is:
2861 
2862 | Option | Description |
2863 |----------|-------------------------------------------------------------------|
2864 | "GLCOL" | H3 is drawn using semi-transparent colored boxes. See `$ROOTSYS/tutorials/gl/glvox1.C`.|
2865 
2866 
2867 
2868 #### <a name="HP29b"></a> TH3 as boxes (spheres)
2869 
2870 The supported options are:
2871 
2872 | Option | Description |
2873 |----------|-------------------------------------------------------------------|
2874 | "GLBOX" | TH3 as a set of boxes, size of box is proportional to bin content.|
2875 | "GLBOX1" | The same as "glbox", but spheres are drawn instead of boxes.|
2876 
2877 
2878 
2879 #### <a name="HP29c"></a> TH3 as iso-surface(s)
2880 
2881 The supported option is:
2882 
2883 | Option | Description |
2884 |----------|-------------------------------------------------------------------|
2885 | "GLISO" | TH3 is drawn using iso-surfaces.|
2886 
2887 
2888 
2889 #### <a name="HP29d"></a> TF3 (implicit function)
2890 
2891 The supported option is:
2892 
2893 | Option | Description |
2894 |----------|-------------------------------------------------------------------|
2895 | "GLTF3" | Draw a TF3.|
2896 
2897 
2898 
2899 #### <a name="HP29e"></a> Parametric surfaces
2900 
2901 `$ROOTSYS/tutorials/gl/glparametric.C` shows how to create parametric
2902 equations and visualize the surface.
2903 
2904 #### <a name="HP29f"></a> Interaction with the plots
2905 
2906 All the interactions are implemented via standard methods
2907 `DistancetoPrimitive()` and `ExecuteEvent()`. That's why all the
2908 interactions with the OpenGL plots are possible only when the mouse cursor is
2909 in the plot's area (the plot's area is the part of a the pad occupied by
2910 gl-produced picture). If the mouse cursor is not above gl-picture, the standard
2911 pad interaction is performed.
2912 
2913 #### <a name="HP29g"></a> Selectable parts
2914 
2915 Different parts of the plot can be selected:
2916 
2917 - xoz, yoz, xoy back planes: When such a plane selected, it's highlighted in green
2918  if the dynamic slicing by this plane is supported, and it's highlighted in red,
2919  if the dynamic slicing is not supported.
2920 - The plot itself:
2921  On surfaces, the selected surface is outlined in red. (TF3 and
2922  ISO are not outlined). On lego plots, the selected bin is
2923  highlighted. The bin number and content are displayed in pad's
2924  status bar. In box plots, the box or sphere is highlighted and
2925  the bin info is displayed in pad's status bar.
2926 
2927 
2928 #### <a name="HP29h"></a> Rotation and zooming
2929 
2930 
2931 - Rotation:
2932  When the plot is selected, it can be rotated by pressing and
2933  holding the left mouse button and move the cursor.
2934 - Zoom/Unzoom:
2935  Mouse wheel or 'j', 'J', 'k', 'K' keys.
2936 
2937 
2938 #### <a name="HP29i"></a> Panning
2939 
2940 The selected plot can be moved in a pad's area by pressing and
2941 holding the left mouse button and the shift key.
2942 
2943 #### <a name="HP29j"></a> Box cut
2944 
2945 Surface, iso, box, TF3 and parametric painters support box cut by
2946 pressing the 'c' or 'C' key when the mouse cursor is in a plot's
2947 area. That will display a transparent box, cutting away part of the
2948 surface (or boxes) in order to show internal part of plot. This box
2949 can be moved inside the plot's area (the full size of the box is
2950 equal to the plot's surrounding box) by selecting one of the box
2951 cut axes and pressing the left mouse button to move it.
2952 
2953 #### <a name="HP29k"></a> Plot specific interactions (dynamic slicing etc.)
2954 
2955 Currently, all gl-plots support some form of slicing. When back plane
2956 is selected (and if it's highlighted in green) you can press and hold
2957 left mouse button and shift key and move this back plane inside
2958 plot's area, creating the slice. During this "slicing" plot becomes
2959 semi-transparent. To remove all slices (and projected curves for
2960 surfaces) double click with left mouse button in a plot's area.
2961 
2962 #### <a name="HP29l"></a> Surface with option "GLSURF"
2963 
2964 The surface profile is displayed on the slicing plane.
2965 The profile projection is drawn on the back plane
2966 by pressing `'p'` or `'P'` key.
2967 
2968 #### <a name="HP29m"></a> TF3
2969 
2970 The contour plot is drawn on the slicing plane. For TF3 the color
2971 scheme can be changed by pressing 's' or 'S'.
2972 
2973 #### <a name="HP29n"></a> Box
2974 
2975 The contour plot corresponding to slice plane position is drawn in real time.
2976 
2977 #### <a name="HP29o"></a> Iso
2978 
2979 Slicing is similar to "GLBOX" option.
2980 
2981 #### <a name="HP29p"></a> Parametric plot
2982 
2983 No slicing. Additional keys: 's' or 'S' to change color scheme -
2984 about 20 color schemes supported ('s' for "scheme"); 'l' or 'L' to
2985 increase number of polygons ('l' for "level" of details), 'w' or 'W'
2986 to show outlines ('w' for "wireframe").
2987 
2988 #### <a name="HP30"></a> Highlight mode for histogram
2989 
2990 \since **ROOT version 6.15/01**
2991 
2992 \image html hlHisto3_top.gif "Highlight mode"
2993 
2994 Highlight mode is implemented for `TH1` (and for `TGraph`) class. When
2995 highlight mode is on, mouse movement over the bin will be represented
2996 graphically. Bin will be highlighted as "bin box" (presented by box
2997 object). Moreover, any highlight (change of bin) emits signal
2998 `TCanvas::Highlighted()` which allows the user to react and call their own
2999 function. For a better understanding see also the tutorials
3000 `$ROOTSYS/tutorials/hist/hlHisto*.C` files.
3001 
3002 Highlight mode is switched on/off by `TH1::SetHighlight()` function
3003 or interactively from `TH1` context menu. `TH1::IsHighlight()` to verify
3004 whether the highlight mode enabled or disabled, default it is disabled.
3005 
3006 ~~~ {.cpp}
3007  root [0] .x $ROOTSYS/tutorials/hsimple.C
3008  root [1] hpx->SetHighlight(kTRUE) // or interactively from TH1 context menu
3009  root [2] hpx->IsHighlight()
3010  (bool) true
3011 ~~~
3012 
3013 \image html hlsimple_nofun.gif "Highlight mode for histogram"
3014 
3015 #### <a name="HP30a"></a> Highlight mode and user function
3016 
3017 The user can use (connect) `TCanvas::Highlighted()` signal, which is always
3018 emitted if there is a highlight bin and call user function via signal
3019 and slot communication mechanism. `TCanvas::Highlighted()` is similar
3020 `TCanvas::Picked()`
3021 
3022 - when selected object (histogram as a whole) is different from previous
3023 then emit `Picked()` signal
3024 - when selected (highlighted) bin from histogram is different from previous
3025 then emit `Highlighted()` signal
3026 
3027 Any user function (or functions) has to be defined
3028 `UserFunction(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)`.
3029 In example (see below) has name `PrintInfo()`. All parameters of user
3030 function are taken from
3031 
3032  void TCanvas::Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
3033 
3034 - `pad` is pointer to pad with highlighted histogram
3035 - `obj` is pointer to highlighted histogram
3036 - `x` is highlighted x bin for 1D histogram
3037 - `y` is highlighted y bin for 2D histogram (for 1D histogram not in use)
3038 
3039 Example how to create a connection from any `TCanvas` object to a user
3040 `UserFunction()` slot (see also `TQObject::Connect()` for additional info)
3041 
3042  TQObject::Connect("TCanvas", "Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)",
3043  0, 0, "UserFunction(TVirtualPad*,TObject*,Int_t,Int_t)");
3044 
3045 or use non-static "simplified" function
3046 `TCanvas::HighlightConnect(const char *slot)`
3047 
3048  c1->HighlightConnect("UserFunction(TVirtualPad*,TObject*,Int_t,Int_t)");
3049 
3050 NOTE the signal and slot string must have a form
3051 "(TVirtualPad*,TObject*,Int_t,Int_t)"
3052 
3053  root [0] .x $ROOTSYS/tutorials/hsimple.C
3054  root [1] hpx->SetHighlight(kTRUE)
3055  root [2] .x hlprint.C
3056 
3057 file `hlprint.C`
3058 ~~~ {.cpp}
3059 void PrintInfo(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
3060 {
3061  auto h = (TH1F *)obj;
3062  if (!h->IsHighlight()) // after highlight disabled
3063  h->SetTitle("highlight disable");
3064  else
3065  h->SetTitle(TString::Format("bin[%03d] (%5.2f) content %g", x,
3066  h->GetBinCenter(x), h->GetBinContent(x)));
3067  pad->Update();
3068 }
3069 
3070 void hlprint()
3071 {
3072  if (!gPad) return;
3073  gPad->GetCanvas()->HighlightConnect("PrintInfo(TVirtualPad*,TObject*,Int_t,Int_t)");
3074 }
3075 ~~~
3076 
3077 \image html hlsimple.gif "Highlight mode and simple user function"
3078 
3079 For more complex demo please see for example `$ROOTSYS/tutorials/tree/temperature.C` file.
3080 
3081 */
3082 
3083 TH1 *gCurrentHist = 0;
3084 
3085 Hoption_t Hoption;
3086 Hparam_t Hparam;
3087 
3088 const Int_t kNMAX = 2000;
3089 
3090 const Int_t kMAXCONTOUR = 104;
3091 const UInt_t kCannotRotate = BIT(11);
3092 
3093 static TBox *gXHighlightBox = 0; // highlight X box
3094 static TBox *gYHighlightBox = 0; // highlight Y box
3095 
3096 static TString gStringEntries;
3097 static TString gStringMean;
3098 static TString gStringMeanX;
3099 static TString gStringMeanY;
3100 static TString gStringMeanZ;
3101 static TString gStringStdDev;
3102 static TString gStringStdDevX;
3103 static TString gStringStdDevY;
3104 static TString gStringStdDevZ;
3105 static TString gStringUnderflow;
3106 static TString gStringOverflow;
3107 static TString gStringIntegral;
3108 static TString gStringIntegralBinWidth;
3109 static TString gStringSkewness;
3110 static TString gStringSkewnessX;
3111 static TString gStringSkewnessY;
3112 static TString gStringSkewnessZ;
3113 static TString gStringKurtosis;
3114 static TString gStringKurtosisX;
3115 static TString gStringKurtosisY;
3116 static TString gStringKurtosisZ;
3117 
3118 ClassImp(THistPainter);
3119 
3120 ////////////////////////////////////////////////////////////////////////////////
3121 /// Default constructor.
3122 
3123 THistPainter::THistPainter()
3124 {
3125 
3126  fH = 0;
3127  fXaxis = 0;
3128  fYaxis = 0;
3129  fZaxis = 0;
3130  fFunctions = 0;
3131  fXbuf = 0;
3132  fYbuf = 0;
3133  fNcuts = 0;
3134  fStack = 0;
3135  fLego = 0;
3136  fPie = 0;
3137  fGraph2DPainter = 0;
3138  fShowProjection = 0;
3139  fShowOption = "";
3140  for (int i=0; i<kMaxCuts; i++) {
3141  fCuts[i] = 0;
3142  fCutsOpt[i] = 0;
3143  }
3144  fXHighlightBin = -1;
3145  fYHighlightBin = -1;
3146 
3147  gStringEntries = gEnv->GetValue("Hist.Stats.Entries", "Entries");
3148  gStringMean = gEnv->GetValue("Hist.Stats.Mean", "Mean");
3149  gStringMeanX = gEnv->GetValue("Hist.Stats.MeanX", "Mean x");
3150  gStringMeanY = gEnv->GetValue("Hist.Stats.MeanY", "Mean y");
3151  gStringMeanZ = gEnv->GetValue("Hist.Stats.MeanZ", "Mean z");
3152  gStringStdDev = gEnv->GetValue("Hist.Stats.StdDev", "Std Dev");
3153  gStringStdDevX = gEnv->GetValue("Hist.Stats.StdDevX", "Std Dev x");
3154  gStringStdDevY = gEnv->GetValue("Hist.Stats.StdDevY", "Std Dev y");
3155  gStringStdDevZ = gEnv->GetValue("Hist.Stats.StdDevZ", "Std Dev z");
3156  gStringUnderflow = gEnv->GetValue("Hist.Stats.Underflow", "Underflow");
3157  gStringOverflow = gEnv->GetValue("Hist.Stats.Overflow", "Overflow");
3158  gStringIntegral = gEnv->GetValue("Hist.Stats.Integral", "Integral");
3159  gStringIntegralBinWidth = gEnv->GetValue("Hist.Stats.IntegralBinWidth", "Integral(w)");
3160  gStringSkewness = gEnv->GetValue("Hist.Stats.Skewness", "Skewness");
3161  gStringSkewnessX = gEnv->GetValue("Hist.Stats.SkewnessX", "Skewness x");
3162  gStringSkewnessY = gEnv->GetValue("Hist.Stats.SkewnessY", "Skewness y");
3163  gStringSkewnessZ = gEnv->GetValue("Hist.Stats.SkewnessZ", "Skewness z");
3164  gStringKurtosis = gEnv->GetValue("Hist.Stats.Kurtosis", "Kurtosis");
3165  gStringKurtosisX = gEnv->GetValue("Hist.Stats.KurtosisX", "Kurtosis x");
3166  gStringKurtosisY = gEnv->GetValue("Hist.Stats.KurtosisY", "Kurtosis y");
3167  gStringKurtosisZ = gEnv->GetValue("Hist.Stats.KurtosisZ", "Kurtosis z");
3168 }
3169 
3170 ////////////////////////////////////////////////////////////////////////////////
3171 /// Default destructor.
3172 
3173 THistPainter::~THistPainter()
3174 {
3175 }
3176 
3177 ////////////////////////////////////////////////////////////////////////////////
3178 /// Compute the distance from the point px,py to a line.
3179 ///
3180 /// Compute the closest distance of approach from point px,py to elements of
3181 /// an histogram. The distance is computed in pixels units.
3182 ///
3183 /// Algorithm: Currently, this simple model computes the distance from the mouse
3184 /// to the histogram contour only.
3185 
3186 Int_t THistPainter::DistancetoPrimitive(Int_t px, Int_t py)
3187 {
3188 
3189  Double_t defaultLabelSize = 0.04; // See TAttAxis.h for source of this value
3190 
3191  const Int_t big = 9999;
3192  const Int_t kMaxDiff = 7;
3193 
3194  if (fPie) return fPie->DistancetoPrimitive(px, py);
3195 
3196  Double_t x = gPad->AbsPixeltoX(px);
3197  Double_t x1 = gPad->AbsPixeltoX(px+1);
3198 
3199  Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin());
3200  Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin());
3201  Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax());
3202  Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax());
3203  Int_t curdist = big;
3204  Int_t yxaxis, dyaxis,xyaxis, dxaxis;
3205  Bool_t dsame;
3206  TObject *PadPointer = gPad->GetPadPointer();
3207  if (!PadPointer) return 0;
3208  TString doption = PadPointer->GetDrawOption();
3209  Double_t factor = 1;
3210  if (fH->GetNormFactor() != 0) {
3211  factor = fH->GetNormFactor()/fH->GetSumOfWeights();
3212  }
3213  // return if point is not in the histogram area
3214 
3215  // If a 3D view exists, check distance to axis
3216  TView *view = gPad->GetView();
3217  Int_t d1,d2,d3;
3218  if (view && Hoption.Contour != 14) {
3219  Double_t ratio;
3220  d3 = view->GetDistancetoAxis(3, px, py, ratio);
3221  if (d3 <= kMaxDiff) {gPad->SetSelected(fZaxis); return 0;}
3222  d1 = view->GetDistancetoAxis(1, px, py, ratio);
3223  if (d1 <= kMaxDiff) {gPad->SetSelected(fXaxis); return 0;}
3224  d2 = view->GetDistancetoAxis(2, px, py, ratio);
3225  if (d2 <= kMaxDiff) {gPad->SetSelected(fYaxis); return 0;}
3226  if ( px > puxmin && px < puxmax && py > puymax && py < puymin) curdist = 1;
3227  goto FUNCTIONS;
3228  }
3229  // check if point is close to an axis
3230  doption.ToLower();
3231  dsame = kFALSE;
3232  if (doption.Contains("same")) dsame = kTRUE;
3233 
3234  dyaxis = Int_t(2*(puymin-puymax)*TMath::Max(Double_t(fYaxis->GetLabelSize()), defaultLabelSize));
3235  if (doption.Contains("y+")) {
3236  xyaxis = puxmax + Int_t((puxmax-puxmin)*fYaxis->GetLabelOffset());
3237  if (px <= xyaxis+dyaxis && px >= xyaxis && py >puymax && py < puymin) {
3238  if (!dsame) {
3239  if (gPad->IsVertical()) gPad->SetSelected(fYaxis);
3240  else gPad->SetSelected(fXaxis);
3241  return 0;
3242  }
3243  }
3244  } else {
3245  xyaxis = puxmin - Int_t((puxmax-puxmin)*fYaxis->GetLabelOffset());
3246  if (px >= xyaxis-dyaxis && px <= xyaxis && py >puymax && py < puymin) {
3247  if (!dsame) {
3248  if (gPad->IsVertical()) gPad->SetSelected(fYaxis);
3249  else gPad->SetSelected(fXaxis);
3250  return 0;
3251  }
3252  }
3253  }
3254 
3255  dxaxis = Int_t((puymin-puymax)*TMath::Max(Double_t(fXaxis->GetLabelSize()), defaultLabelSize));
3256  if (doption.Contains("x+")) {
3257  yxaxis = puymax - Int_t((puymin-puymax)*fXaxis->GetLabelOffset());
3258  if (py >= yxaxis-dxaxis && py <= yxaxis && px <puxmax && px > puxmin) {
3259  if (!dsame) {
3260  if (gPad->IsVertical()) gPad->SetSelected(fXaxis);
3261  else gPad->SetSelected(fYaxis);
3262  return 0;
3263  }
3264  }
3265  } else {
3266  yxaxis = puymin + Int_t((puymin-puymax)*fXaxis->GetLabelOffset());
3267  if (yxaxis < puymin) yxaxis = puymin;
3268  if (py <= yxaxis+dxaxis && py >= yxaxis && px <puxmax && px > puxmin) {
3269  if (!dsame) {
3270  if (gPad->IsVertical()) gPad->SetSelected(fXaxis);
3271  else gPad->SetSelected(fYaxis);
3272  return 0;
3273  }
3274  }
3275  }
3276 
3277  if (fH->IsHighlight()) { // only if highlight is enable
3278  if ((px > puxmin) && (py < puymin) && (px < puxmax) && (py > puymax))
3279  HighlightBin(px, py);
3280  }
3281 
3282  // if object is 2D or 3D return this object
3283  if (fH->GetDimension() == 2) {
3284  if (fH->InheritsFrom(TH2Poly::Class())) {
3285  TH2Poly *th2 = (TH2Poly*)fH;
3286  Double_t xmin, ymin, xmax, ymax;
3287  gPad->GetRangeAxis(xmin, ymin, xmax, ymax);
3288  Double_t pxu = gPad->AbsPixeltoX(px);
3289  Double_t pyu = gPad->AbsPixeltoY(py);
3290  if ((pxu>xmax) || (pxu < xmin) || (pyu>ymax) || (pyu < ymin)) {
3291  curdist = big;
3292  goto FUNCTIONS;
3293  } else {
3294  Int_t bin = th2->FindBin(pxu, pyu);
3295  if (bin>0) curdist = 1;
3296  else curdist = big;
3297  goto FUNCTIONS;
3298  }
3299  }
3300  Int_t delta2 = 5; //Give a margin of delta2 pixels to be in the 2-d area
3301  if ( px > puxmin + delta2
3302  && px < puxmax - delta2
3303  && py > puymax + delta2
3304  && py < puymin - delta2) {curdist =1; goto FUNCTIONS;}
3305  }
3306 
3307  // point is inside histogram area. Find channel number
3308  if (gPad->IsVertical()) {
3309  Int_t bin = fXaxis->FindFixBin(gPad->PadtoX(x));
3310  Int_t binsup = fXaxis->FindFixBin(gPad->PadtoX(x1));
3311  Double_t binval = factor*fH->GetBinContent(bin);
3312  Int_t pybin = gPad->YtoAbsPixel(gPad->YtoPad(binval));
3313  if (binval == 0 && pybin < puymin) pybin = 10000;
3314  // special case if more than one bin for the pixel
3315  if (binsup-bin>1) {
3316  Double_t binvalmin, binvalmax;
3317  binvalmin=binval;
3318  binvalmax=binval;
3319  for (Int_t ibin=bin+1; ibin<binsup; ibin++) {
3320  Double_t binvaltmp = factor*fH->GetBinContent(ibin);
3321  if (binvalmin>binvaltmp) binvalmin=binvaltmp;
3322  if (binvalmax<binvaltmp) binvalmax=binvaltmp;
3323  }
3324  Int_t pybinmin = gPad->YtoAbsPixel(gPad->YtoPad(binvalmax));
3325  Int_t pybinmax = gPad->YtoAbsPixel(gPad->YtoPad(binvalmin));
3326  if (py<pybinmax+kMaxDiff/2 && py>pybinmin-kMaxDiff/2) pybin = py;
3327  }
3328  if (bin != binsup) { // Mouse on bin border
3329  Double_t binsupval = factor*fH->GetBinContent(binsup);
3330  Int_t pybinsub = gPad->YtoAbsPixel(gPad->YtoPad(binsupval));
3331  if (py <= TMath::Max(pybinsub,pybin) && py >= TMath::Min(pybinsub,pybin) && pybin != 10000) return 0;
3332  }
3333  if (TMath::Abs(py - pybin) <= kMaxDiff) return TMath::Abs(py - pybin);
3334  } else {
3335  Double_t y = gPad->AbsPixeltoY(py);
3336  Double_t y1 = gPad->AbsPixeltoY(py+1);
3337  Int_t bin = fXaxis->FindFixBin(gPad->PadtoY(y));
3338  Int_t binsup = fXaxis->FindFixBin(gPad->PadtoY(y1));
3339  Double_t binval = factor*fH->GetBinContent(bin);
3340  Int_t pxbin = gPad->XtoAbsPixel(gPad->XtoPad(binval));
3341  if (binval == 0 && pxbin > puxmin) pxbin = 10000;
3342  // special case if more than one bin for the pixel
3343  if (binsup-bin>1) {
3344  Double_t binvalmin, binvalmax;
3345  binvalmin=binval;
3346  binvalmax=binval;
3347  for (Int_t ibin=bin+1; ibin<binsup; ibin++) {
3348  Double_t binvaltmp = factor*fH->GetBinContent(ibin);
3349  if (binvalmin>binvaltmp) binvalmin=binvaltmp;
3350  if (binvalmax<binvaltmp) binvalmax=binvaltmp;
3351  }
3352  Int_t pxbinmin = gPad->XtoAbsPixel(gPad->XtoPad(binvalmax));
3353  Int_t pxbinmax = gPad->XtoAbsPixel(gPad->XtoPad(binvalmin));
3354  if (px<pxbinmax+kMaxDiff/2 && px>pxbinmin-kMaxDiff/2) pxbin = px;
3355  }
3356  if (TMath::Abs(px - pxbin) <= kMaxDiff) return TMath::Abs(px - pxbin);
3357  }
3358  // Loop on the list of associated functions and user objects
3359 FUNCTIONS:
3360  TObject *f;
3361  TIter next(fFunctions);
3362  while ((f = (TObject*) next())) {
3363  Int_t dist;
3364  if (f->InheritsFrom(TF1::Class())) dist = f->DistancetoPrimitive(-px,py);
3365  else dist = f->DistancetoPrimitive(px,py);
3366  if (dist < kMaxDiff) {gPad->SetSelected(f); return dist;}
3367  }
3368  return curdist;
3369 }
3370 
3371 ////////////////////////////////////////////////////////////////////////////////
3372 /// Display a panel with all histogram drawing options.
3373 
3374 void THistPainter::DrawPanel()
3375 {
3376 
3377  gCurrentHist = fH;
3378  if (!gPad) {
3379  Error("DrawPanel", "need to draw histogram first");
3380  return;
3381  }
3382  TVirtualPadEditor *editor = TVirtualPadEditor::GetPadEditor();
3383  editor->Show();
3384  gROOT->ProcessLine(Form("((TCanvas*)0x%lx)->Selected((TVirtualPad*)0x%lx,(TObject*)0x%lx,1)",
3385  (ULong_t)gPad->GetCanvas(), (ULong_t)gPad, (ULong_t)fH));
3386 }
3387 
3388 ////////////////////////////////////////////////////////////////////////////////
3389 /// Execute the actions corresponding to `event`.
3390 ///
3391 /// This function is called when a histogram is clicked with the locator at
3392 /// the pixel position px,py.
3393 
3394 void THistPainter::ExecuteEvent(Int_t event, Int_t px, Int_t py)
3395 {
3396 
3397  if (!gPad) return;
3398 
3399  static Int_t bin, px1, py1, px2, py2, pyold;
3400  static TBox *zoombox;
3401  Double_t zbx1,zbx2,zby1,zby2;
3402 
3403  Int_t bin1, bin2;
3404  Double_t xlow, xup, ylow, binval, x, baroffset, barwidth, binwidth;
3405  Bool_t opaque = gPad->OpaqueMoving();
3406 
3407  if (!gPad->IsEditable()) return;
3408 
3409  if (fPie) {
3410  fPie->ExecuteEvent(event, px, py);
3411  return;
3412  }
3413  // come here if we have a lego/surface in the pad
3414  TView *view = gPad->GetView();
3415 
3416  if (!fShowProjection && view && view->TestBit(kCannotRotate) == 0) {
3417  view->ExecuteRotateView(event, px, py);
3418  return;
3419  }
3420 
3421  TAxis *xaxis = fH->GetXaxis();
3422  TAxis *yaxis = fH->GetYaxis();
3423  Int_t dimension = fH->GetDimension();
3424 
3425  // In case of option SAME the axis must be the ones of the first drawn histogram
3426  TString IsSame = fH->GetDrawOption();
3427  IsSame.ToLower();
3428  if (IsSame.Index("same")>=0) {
3429  TH1 *h1;
3430  TIter next(gPad->GetListOfPrimitives());
3431  while ((h1 = (TH1 *)next())) {
3432  if (!h1->InheritsFrom(TH1::Class())) continue;
3433  xaxis = h1->GetXaxis();
3434  yaxis = h1->GetYaxis();
3435  break;
3436  }
3437  }
3438 
3439  Double_t factor = 1;
3440  if (fH->GetNormFactor() != 0) {
3441  factor = fH->GetNormFactor()/fH->GetSumOfWeights();
3442  }
3443 
3444  switch (event) {
3445 
3446  case kButton1Down:
3447 
3448  if (!opaque) gVirtualX->SetLineColor(-1);
3449  fH->TAttLine::Modify();
3450 
3451  if (opaque && dimension ==2) {
3452  zbx1 = gPad->AbsPixeltoX(px);
3453  zbx2 = gPad->AbsPixeltoX(px);
3454  zby1 = gPad->AbsPixeltoY(py);
3455  zby2 = gPad->AbsPixeltoY(py);
3456  px1 = px;
3457  py1 = py;
3458  if (gPad->GetLogx()) {
3459  zbx1 = TMath::Power(10,zbx1);
3460  zbx2 = TMath::Power(10,zbx2);
3461  }
3462  if (gPad->GetLogy()) {
3463  zby1 = TMath::Power(10,zby1);
3464  zby2 = TMath::Power(10,zby2);
3465  }
3466  zoombox = new TBox(zbx1, zby1, zbx2, zby2);
3467  Int_t ci = TColor::GetColor("#7d7dff");
3468  TColor *zoomcolor = gROOT->GetColor(ci);
3469  if (!TCanvas::SupportAlpha() || !zoomcolor) zoombox->SetFillStyle(3002);
3470  else zoomcolor->SetAlpha(0.5);
3471  zoombox->SetFillColor(ci);
3472  zoombox->Draw();
3473  gPad->Modified();
3474  gPad->Update();
3475  }
3476  // No break !!!
3477 
3478  case kMouseMotion:
3479 
3480  if (fShowProjection) {ShowProjection3(px,py); break;}
3481 
3482  gPad->SetCursor(kPointer);
3483  if (dimension ==1) {
3484  if (Hoption.Bar) {
3485  baroffset = fH->GetBarOffset();
3486  barwidth = fH->GetBarWidth();
3487  } else {
3488  baroffset = 0;
3489  barwidth = 1;
3490  }
3491  x = gPad->AbsPixeltoX(px);
3492  bin = fXaxis->FindFixBin(gPad->PadtoX(x));
3493  binwidth = fXaxis->GetBinWidth(bin);
3494  xlow = gPad->XtoPad(fXaxis->GetBinLowEdge(bin) + baroffset*binwidth);
3495  xup = gPad->XtoPad(xlow + barwidth*binwidth);
3496  ylow = gPad->GetUymin();
3497  px1 = gPad->XtoAbsPixel(xlow);
3498  px2 = gPad->XtoAbsPixel(xup);
3499  py1 = gPad->YtoAbsPixel(ylow);
3500  py2 = py;
3501  pyold = py;
3502  if (gROOT->GetEditHistograms()) gPad->SetCursor(kArrowVer);
3503  }
3504 
3505  break;
3506 
3507  case kButton1Motion:
3508 
3509  if (dimension ==1) {
3510  if (gROOT->GetEditHistograms()) {
3511  if (!opaque) {
3512  gVirtualX->DrawBox(px1, py1, px2, py2,TVirtualX::kHollow); // Draw the old box
3513  py2 += py - pyold;
3514  gVirtualX->DrawBox(px1, py1, px2, py2,TVirtualX::kHollow); // Draw the new box
3515  pyold = py;
3516  } else {
3517  py2 += py - pyold;
3518  pyold = py;
3519  binval = gPad->PadtoY(gPad->AbsPixeltoY(py2))/factor;
3520  fH->SetBinContent(bin,binval);
3521  gPad->Modified(kTRUE);
3522  }
3523  }
3524  }
3525 
3526  if (opaque && dimension ==2) {
3527  if (TMath::Abs(px1-px)>5 && TMath::Abs(py1-py)>5) {
3528  zbx2 = gPad->AbsPixeltoX(px);
3529  zby2 = gPad->AbsPixeltoY(py);
3530  if (gPad->GetLogx()) zbx2 = TMath::Power(10,zbx2);
3531  if (gPad->GetLogy()) zby2 = TMath::Power(10,zby2);
3532  zoombox->SetX2(zbx2);
3533  zoombox->SetY2(zby2);
3534  gPad->Modified();
3535  gPad->Update();
3536  }
3537  }
3538 
3539  break;
3540 
3541  case kWheelUp:
3542 
3543  if (dimension ==2) {
3544  bin1 = xaxis->GetFirst()+1;
3545  bin2 = xaxis->GetLast()-1;
3546  bin1 = TMath::Max(bin1, 1);
3547  bin2 = TMath::Min(bin2, xaxis->GetNbins());
3548  if (bin2>bin1) xaxis->SetRange(bin1,bin2);
3549  bin1 = yaxis->GetFirst()+1;
3550  bin2 = yaxis->GetLast()-1;
3551  bin1 = TMath::Max(bin1, 1);
3552  bin2 = TMath::Min(bin2, yaxis->GetNbins());
3553  if (bin2>bin1) yaxis->SetRange(bin1,bin2);
3554  }
3555  gPad->Modified();
3556  gPad->Update();
3557 
3558  break;
3559 
3560  case kWheelDown:
3561 
3562  if (dimension == 2) {
3563  bin1 = xaxis->GetFirst()-1;
3564  bin2 = xaxis->GetLast()+1;
3565  bin1 = TMath::Max(bin1, 1);
3566  bin2 = TMath::Min(bin2, xaxis->GetNbins());
3567  if (bin2>bin1) xaxis->SetRange(bin1,bin2);
3568  bin1 = yaxis->GetFirst()-1;
3569  bin2 = yaxis->GetLast()+1;
3570  bin1 = TMath::Max(bin1, 1);
3571  bin2 = TMath::Min(bin2, yaxis->GetNbins());
3572  if (bin2>bin1) yaxis->SetRange(bin1,bin2);
3573  }
3574  gPad->Modified();
3575  gPad->Update();
3576 
3577  break;
3578 
3579  case kButton1Up:
3580  if (dimension ==1) {
3581  if (gROOT->GetEditHistograms()) {
3582  binval = gPad->PadtoY(gPad->AbsPixeltoY(py2))/factor;
3583  fH->SetBinContent(bin,binval);
3584  PaintInit(); // recalculate Hparam structure and recalculate range
3585  }
3586 
3587  // might resize pad pixmap so should be called before any paint routine
3588  RecalculateRange();
3589  }
3590  if (opaque && dimension ==2) {
3591  if (zoombox) {
3592  Double_t x1 = TMath::Min(zoombox->GetX1(), zoombox->GetX2());
3593  Double_t x2 = TMath::Max(zoombox->GetX1(), zoombox->GetX2());
3594  Double_t y1 = TMath::Min(zoombox->GetY1(), zoombox->GetY2());
3595  Double_t y2 = TMath::Max(zoombox->GetY1(), zoombox->GetY2());
3596  x1 = TMath::Max(x1,xaxis->GetXmin());
3597  x2 = TMath::Min(x2,xaxis->GetXmax());
3598  y1 = TMath::Max(y1,yaxis->GetXmin());
3599  y2 = TMath::Min(y2,yaxis->GetXmax());
3600  if (x1<x2 && y1<y2) {
3601  xaxis->SetRangeUser(x1, x2);
3602  yaxis->SetRangeUser(y1, y2);
3603  }
3604  zoombox->Delete();
3605  zoombox = 0;
3606  }
3607  }
3608  gPad->Modified(kTRUE);
3609  if (opaque) gVirtualX->SetLineColor(-1);
3610 
3611  break;
3612 
3613  case kButton1Locate:
3614 
3615  ExecuteEvent(kButton1Down, px, py);
3616 
3617  while (1) {
3618  px = py = 0;
3619  event = gVirtualX->RequestLocator(1, 1, px, py);
3620 
3621  ExecuteEvent(kButton1Motion, px, py);
3622 
3623  if (event != -1) { // button is released
3624  ExecuteEvent(kButton1Up, px, py);
3625  return;
3626  }
3627  }
3628  }
3629 }
3630 
3631 ////////////////////////////////////////////////////////////////////////////////
3632 /// Get a contour (as a list of TGraphs) using the Delaunay triangulation.
3633 
3634 TList *THistPainter::GetContourList(Double_t contour) const
3635 {
3636 
3637 
3638 
3639  // Check if fH contains a TGraphDelaunay2D
3640  TList *hl = fH->GetListOfFunctions();
3641  TGraphDelaunay2D *dt = (TGraphDelaunay2D*)hl->FindObject("TGraphDelaunay2D");
3642  // try with the old painter
3643  TGraphDelaunay *dtOld = nullptr;
3644  if (!dt) dtOld = (TGraphDelaunay*)hl->FindObject("TGraphDelaunay");
3645 
3646  if (!dt && !dtOld) return nullptr;
3647 
3648  gCurrentHist = fH;
3649 
3650  if (!fGraph2DPainter) {
3651  if (dt) ((THistPainter*)this)->fGraph2DPainter = new TGraph2DPainter(dt);
3652  else ((THistPainter*)this)->fGraph2DPainter = new TGraph2DPainter(dtOld);
3653  }
3654 
3655  return fGraph2DPainter->GetContourList(contour);
3656 }
3657 
3658 ////////////////////////////////////////////////////////////////////////////////
3659 /// Display the histogram info (bin number, contents, integral up to bin
3660 /// corresponding to cursor position px,py.
3661 
3662 char *THistPainter::GetObjectInfo(Int_t px, Int_t py) const
3663 {
3664 
3665  if (!gPad) return (char*)"";
3666 
3667  Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
3668  Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
3669  Double_t x1 = gPad->PadtoX(gPad->AbsPixeltoX(px+1));
3670  TString drawOption = fH->GetDrawOption();
3671  drawOption.ToLower();
3672  Double_t xmin, xmax, uxmin,uxmax;
3673  Double_t ymin, ymax, uymin,uymax;
3674  if (fH->GetDimension() == 2) {
3675  if (gPad->GetView() || drawOption.Index("cont") >= 0) {
3676  uxmin=gPad->GetUxmin();
3677  uxmax=gPad->GetUxmax();
3678  xmin = fXaxis->GetBinLowEdge(fXaxis->GetFirst());
3679  xmax = fXaxis->GetBinUpEdge(fXaxis->GetLast());
3680  x = xmin +(xmax-xmin)*(x-uxmin)/(uxmax-uxmin);
3681  uymin=gPad->GetUymin();
3682  uymax=gPad->GetUymax();
3683  ymin = fYaxis->GetBinLowEdge(fYaxis->GetFirst());
3684  ymax = fYaxis->GetBinUpEdge(fYaxis->GetLast());
3685  y = ymin +(ymax-ymin)*(y-uymin)/(uymax-uymin);
3686  }
3687  }
3688  Int_t binx,biny,binmin=0,binx1;
3689  if (gPad->IsVertical()) {
3690  binx = fXaxis->FindFixBin(x);
3691  if (drawOption.Index("same") >= 0) {
3692  TH1 *h1;
3693  TIter next(gPad->GetListOfPrimitives());
3694  while ((h1 = (TH1 *)next())) {
3695  if (!h1->InheritsFrom(TH1::Class())) continue;
3696  binmin = h1->GetXaxis()->GetFirst();
3697  break;
3698  }
3699  } else {
3700  binmin = fXaxis->GetFirst();
3701  }
3702  binx1 = fXaxis->FindFixBin(x1);
3703  // special case if more than 1 bin in x per pixel
3704  if (binx1-binx>1 && fH->GetDimension() == 1) {
3705  Double_t binval=fH->GetBinContent(binx);
3706  Int_t binnear=binx;
3707  for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
3708  Double_t binvaltmp = fH->GetBinContent(ibin);
3709  if (TMath::Abs(y-binvaltmp) < TMath::Abs(y-binval)) {
3710  binval=binvaltmp;
3711  binnear=ibin;
3712  }
3713  }
3714  binx = binnear;
3715  }
3716  } else {
3717  x1 = gPad->PadtoY(gPad->AbsPixeltoY(py+1));
3718  binx = fXaxis->FindFixBin(y);
3719  if (drawOption.Index("same") >= 0) {
3720  TH1 *h1;
3721  TIter next(gPad->GetListOfPrimitives());
3722  while ((h1 = (TH1 *)next())) {
3723  if (!h1->InheritsFrom(TH1::Class())) continue;
3724  binmin = h1->GetXaxis()->GetFirst();
3725  break;
3726  }
3727  } else {
3728  binmin = fXaxis->GetFirst();
3729  }
3730  binx1 = fXaxis->FindFixBin(x1);
3731  // special case if more than 1 bin in x per pixel
3732  if (binx1-binx>1 && fH->GetDimension() == 1) {
3733  Double_t binval=fH->GetBinContent(binx);
3734  Int_t binnear=binx;
3735  for (Int_t ibin=binx+1; ibin<binx1; ibin++) {
3736  Double_t binvaltmp = fH->GetBinContent(ibin);
3737  if (TMath::Abs(x-binvaltmp) < TMath::Abs(x-binval)) {
3738  binval=binvaltmp;
3739  binnear=ibin;
3740  }
3741  }
3742  binx = binnear;
3743  }
3744  }
3745  if (fH->GetDimension() == 1) {
3746  if (fH->InheritsFrom(TProfile::Class())) {
3747  TProfile *tp = (TProfile*)fH;
3748  fObjectInfo.Form("(x=%g, y=%g, binx=%d, binc=%g, bine=%g, binn=%d)",
3749  x, y, binx, fH->GetBinContent(binx), fH->GetBinError(binx),
3750  (Int_t) tp->GetBinEntries(binx));
3751  }
3752  else {
3753  Double_t integ = 0;
3754  for (Int_t bin=binmin;bin<=binx;bin++) {integ += fH->GetBinContent(bin);}
3755  fObjectInfo.Form("(x=%g, y=%g, binx=%d, binc=%g, Sum=%g)",
3756  x,y,binx,fH->GetBinContent(binx),integ);
3757  }
3758  } else if (fH->GetDimension() == 2) {
3759  if (fH->InheritsFrom(TH2Poly::Class())) {
3760  TH2Poly *th2 = (TH2Poly*)fH;
3761  biny = th2->FindBin(x,y);
3762  fObjectInfo.Form("%s (x=%g, y=%g, bin=%d, binc=%g)",
3763  th2->GetBinTitle(biny),x,y,biny,th2->GetBinContent(biny));
3764  }
3765  else if (fH->InheritsFrom(TProfile2D::Class())) {
3766  TProfile2D *tp = (TProfile2D*)fH;
3767  biny = fYaxis->FindFixBin(y);
3768  Int_t bin = fH->GetBin(binx,biny);
3769  fObjectInfo.Form("(x=%g, y=%g, binx=%d, biny=%d, binc=%g, bine=%g, binn=%d)",
3770  x, y, binx, biny, fH->GetBinContent(bin),
3771  fH->GetBinError(bin), (Int_t) tp->GetBinEntries(bin));
3772  } else {
3773  biny = fYaxis->FindFixBin(y);
3774  fObjectInfo.Form("(x=%g, y=%g, binx=%d, biny=%d, binc=%g bine=%g)",
3775  x,y,binx,biny,fH->GetBinContent(binx,biny),
3776  fH->GetBinError(binx,biny));
3777  }
3778  } else {
3779  // 3d case: retrieving the x,y,z bin is not yet implemented
3780  // print just the x,y info
3781  fObjectInfo.Form("(x=%g, y=%g)",x,y);
3782  }
3783 
3784  return (char *)fObjectInfo.Data();
3785 }
3786 
3787 ////////////////////////////////////////////////////////////////////////////////
3788 /// Set highlight (enable/disable) mode for fH
3789 
3790 void THistPainter::SetHighlight()
3791 {
3792  if (fH->IsHighlight()) return;
3793 
3794  fXHighlightBin = -1;
3795  fYHighlightBin = -1;
3796  // delete previous highlight box
3797  if (gXHighlightBox) { gXHighlightBox->Delete(); gXHighlightBox = 0; }
3798  if (gYHighlightBox) { gYHighlightBox->Delete(); gYHighlightBox = 0; }
3799  // emit Highlighted() signal (user can check on disabled)
3800  if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, fH, fXHighlightBin, fYHighlightBin);
3801 }
3802 
3803 ////////////////////////////////////////////////////////////////////////////////
3804 /// Check on highlight bin
3805 
3806 void THistPainter::HighlightBin(Int_t px, Int_t py)
3807 {
3808  // call from DistancetoPrimitive (only if highlight is enable)
3809 
3810  Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
3811  Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
3812  Int_t binx = fXaxis->FindFixBin(x);
3813  Int_t biny = fYaxis->FindFixBin(y);
3814  if (!gPad->IsVertical()) binx = fXaxis->FindFixBin(y);
3815 
3816  Bool_t changedBin = kFALSE;
3817  if (binx != fXHighlightBin) {
3818  fXHighlightBin = binx;
3819  changedBin = kTRUE;
3820  } else if (fH->GetDimension() == 1) return;
3821  if (biny != fYHighlightBin) {
3822  fYHighlightBin = biny;
3823  changedBin = kTRUE;
3824  }
3825  if (!changedBin) return;
3826 
3827  // Info("HighlightBin", "histo: %p '%s'\txbin: %d, ybin: %d",
3828  // (void *)fH, fH->GetName(), fXHighlightBin, fYHighlightBin);
3829 
3830  // paint highlight bin as box (recursive calls PaintHighlightBin)
3831  gPad->Modified(kTRUE);
3832  gPad->Update();
3833 
3834  // emit Highlighted() signal
3835  if (gPad->GetCanvas()) gPad->GetCanvas()->Highlighted(gPad, fH, fXHighlightBin, fYHighlightBin);
3836 }
3837 
3838 ////////////////////////////////////////////////////////////////////////////////
3839 /// Paint highlight bin as TBox object
3840 
3841 void THistPainter::PaintHighlightBin(Option_t * /*option*/)
3842 {
3843  // call from PaintTitle
3844 
3845  if (!fH->IsHighlight()) return;
3846 
3847  Double_t uxmin = gPad->GetUxmin();
3848  Double_t uxmax = gPad->GetUxmax();
3849  Double_t uymin = gPad->GetUymin();
3850  Double_t uymax = gPad->GetUymax();
3851  if (gPad->GetLogx()) {
3852  uxmin = TMath::Power(10.0, uxmin);
3853  uxmax = TMath::Power(10.0, uxmax);
3854  }
3855  if (gPad->GetLogy()) {
3856  uymin = TMath::Power(10.0, uymin);
3857  uymax = TMath::Power(10.0, uymax);
3858  }
3859 
3860  // testing specific possibility (after zoom, draw with "same", log, etc.)
3861  Double_t hcenter;
3862  if (gPad->IsVertical()) {
3863  hcenter = fXaxis->GetBinCenter(fXHighlightBin);
3864  if ((hcenter < uxmin) || (hcenter > uxmax)) return;
3865  } else {
3866  hcenter = fYaxis->GetBinCenter(fXHighlightBin);
3867  if ((hcenter < uymin) || (hcenter > uymax)) return;
3868  }
3869  if (fH->GetDimension() == 2) {
3870  hcenter = fYaxis->GetBinCenter(fYHighlightBin);
3871  if ((hcenter < uymin) || (hcenter > uymax)) return;
3872  }
3873 
3874  // paint X highlight bin (for 1D or 2D)
3875  Double_t hbx1, hbx2, hby1, hby2;
3876  if (gPad->IsVertical()) {
3877  hbx1 = fXaxis->GetBinLowEdge(fXHighlightBin);
3878  hbx2 = fXaxis->GetBinUpEdge(fXHighlightBin);
3879  hby1 = uymin;
3880  hby2 = uymax;
3881  } else {
3882  hbx1 = uxmin;
3883  hbx2 = uxmax;
3884  hby1 = fYaxis->GetBinLowEdge(fXHighlightBin);
3885  hby2 = fYaxis->GetBinUpEdge(fXHighlightBin);
3886  }
3887 
3888  if (!gXHighlightBox) {
3889  gXHighlightBox = new TBox(hbx1, hby1, hbx2, hby2);
3890  gXHighlightBox->SetBit(kCannotPick);
3891  gXHighlightBox->SetFillColor(TColor::GetColor("#9797ff"));
3892  if (!TCanvas::SupportAlpha()) gXHighlightBox->SetFillStyle(3001);
3893  else gROOT->GetColor(gXHighlightBox->GetFillColor())->SetAlpha(0.5);
3894  }
3895  gXHighlightBox->SetX1(hbx1);
3896  gXHighlightBox->SetX2(hbx2);
3897  gXHighlightBox->SetY1(hby1);
3898  gXHighlightBox->SetY2(hby2);
3899  gXHighlightBox->Paint();
3900 
3901  // Info("PaintHighlightBin", "histo: %p '%s'\txbin: %d, ybin: %d",
3902  // (void *)fH, fH->GetName(), fXHighlightBin, fYHighlightBin);
3903 
3904  // paint Y highlight bin (only for 2D)
3905  if (fH->GetDimension() != 2) return;
3906  hbx1 = uxmin;
3907  hbx2 = uxmax;
3908  hby1 = fYaxis->GetBinLowEdge(fYHighlightBin);
3909  hby2 = fYaxis->GetBinUpEdge(fYHighlightBin);
3910 
3911  if (!gYHighlightBox) {
3912  gYHighlightBox = new TBox(hbx1, hby1, hbx2, hby2);
3913  gYHighlightBox->SetBit(kCannotPick);
3914  gYHighlightBox->SetFillColor(gXHighlightBox->GetFillColor());
3915  gYHighlightBox->SetFillStyle(gXHighlightBox->GetFillStyle());
3916  }
3917  gYHighlightBox->SetX1(hbx1);
3918  gYHighlightBox->SetX2(hbx2);
3919  gYHighlightBox->SetY1(hby1);
3920  gYHighlightBox->SetY2(hby2);
3921  gYHighlightBox->Paint();
3922 }
3923 
3924 ////////////////////////////////////////////////////////////////////////////////
3925 /// Return `kTRUE` if the cell `ix`, `iy` is inside one of the graphical cuts.
3926 
3927 Bool_t THistPainter::IsInside(Int_t ix, Int_t iy)
3928 {
3929 
3930  for (Int_t i=0;i<fNcuts;i++) {
3931  Double_t x = fXaxis->GetBinCenter(ix);
3932  Double_t y = fYaxis->GetBinCenter(iy);
3933  if (fCutsOpt[i] > 0) {
3934  if (!fCuts[i]->IsInside(x,y)) return kFALSE;
3935  } else {
3936  if (fCuts[i]->IsInside(x,y)) return kFALSE;
3937  }
3938  }
3939  return kTRUE;
3940 }
3941 
3942 ////////////////////////////////////////////////////////////////////////////////
3943 /// Return `kTRUE` if the point `x`, `y` is inside one of the graphical cuts.
3944 
3945 Bool_t THistPainter::IsInside(Double_t x, Double_t y)
3946 {
3947 
3948  for (Int_t i=0;i<fNcuts;i++) {
3949  if (fCutsOpt[i] > 0) {
3950  if (!fCuts[i]->IsInside(x,y)) return kFALSE;
3951  } else {
3952  if (fCuts[i]->IsInside(x,y)) return kFALSE;
3953  }
3954  }
3955  return kTRUE;
3956 }
3957 
3958 ////////////////////////////////////////////////////////////////////////////////
3959 /// Decode string `choptin` and fill Hoption structure.
3960 
3961 Int_t THistPainter::MakeChopt(Option_t *choptin)
3962 {
3963 
3964  char *l;
3965  char chopt[128];
3966  Int_t nch = strlen(choptin);
3967  strlcpy(chopt,choptin,128);
3968  Int_t hdim = fH->GetDimension();
3969 
3970  Hoption.Axis = Hoption.Bar = Hoption.Curve = Hoption.Error = 0;
3971  Hoption.Hist = Hoption.Line = Hoption.Mark = Hoption.Fill = 0;
3972  Hoption.Same = Hoption.Func = Hoption.Scat = 0;
3973  Hoption.Star = Hoption.Arrow = Hoption.Box = Hoption.Text = 0;
3974  Hoption.Char = Hoption.Color = Hoption.Contour = Hoption.Logx = 0;
3975  Hoption.Logy = Hoption.Logz = Hoption.Lego = Hoption.Surf = 0;
3976  Hoption.Off = Hoption.Tri = Hoption.Proj = Hoption.AxisPos = 0;
3977  Hoption.Spec = Hoption.Pie = Hoption.Candle = 0;
3978 
3979  // special 2D options
3980  Hoption.List = 0;
3981  Hoption.Zscale = 0;
3982  Hoption.FrontBox = 1;
3983  Hoption.BackBox = 1;
3984  Hoption.System = kCARTESIAN;
3985 
3986  Hoption.Zero = 0;
3987 
3988  Hoption.MinimumZero = gStyle->GetHistMinimumZero() ? 1 : 0;
3989 
3990  //check for graphical cuts
3991  MakeCuts(chopt);
3992 
3993  for (Int_t i=0;i<nch;i++) chopt[i] = toupper(chopt[i]);
3994  if (hdim > 1) Hoption.Scat = 1;
3995  if (!nch) Hoption.Hist = 1;
3996  if (fFunctions->First()) Hoption.Func = 1;
3997  if (fH->GetSumw2N() && hdim == 1) Hoption.Error = 2;
3998 
3999  char *l1 = strstr(chopt,"PFC"); // Automatic Fill Color
4000  char *l2 = strstr(chopt,"PLC"); // Automatic Line Color
4001  char *l3 = strstr(chopt,"PMC"); // Automatic Marker Color
4002  if (l1 || l2 || l3) {
4003  Int_t i = gPad->NextPaletteColor();
4004  if (l1) {memcpy(l1," ",3); fH->SetFillColor(i);}
4005  if (l2) {memcpy(l2," ",3); fH->SetLineColor(i);}
4006  if (l3) {memcpy(l3," ",3); fH->SetMarkerColor(i);}
4007  Hoption.Hist = 1; // Make sure something is drawn in case there is no drawing option specified.
4008  }
4009 
4010  l = strstr(chopt,"MIN0");
4011  if (l) {
4012  Hoption.MinimumZero = 1;
4013  memcpy(l," ",4);
4014  }
4015 
4016  l = strstr(chopt,"SPEC");
4017  if (l) {
4018  Hoption.Scat = 0;
4019  memcpy(l," ",4);
4020  Int_t bs=0;
4021  l = strstr(chopt,"BF(");
4022  if (l) {
4023  if (sscanf(&l[3],"%d",&bs) > 0) {
4024  Int_t i=0;
4025  while (l[i]!=')') {
4026  l[i] = ' ';
4027  i++;
4028  }
4029  l[i] = ' ';
4030  }
4031  }
4032  Hoption.Spec = TMath::Max(1600,bs);
4033  return 1;
4034  }
4035 
4036  l = strstr(chopt,"GL");
4037  if (l) {
4038  memcpy(l," ",2);
4039  }
4040  l = strstr(chopt,"X+");
4041  if (l) {
4042  Hoption.AxisPos = 10;
4043  memcpy(l," ",2);
4044  }
4045  l = strstr(chopt,"Y+");
4046  if (l) {
4047  Hoption.AxisPos += 1;
4048  memcpy(l," ",2);
4049  }
4050  if ((Hoption.AxisPos == 10 || Hoption.AxisPos == 1) && (nch == 2)) Hoption.Hist = 1;
4051  if (Hoption.AxisPos == 11 && nch == 4) Hoption.Hist = 1;
4052 
4053  l = strstr(chopt,"SAMES");
4054  if (l) {
4055  if (nch == 5) Hoption.Hist = 1;
4056  Hoption.Same = 2;
4057  memcpy(l," ",5);
4058  if (l[5] == '0') { Hoption.Same += 10; l[5] = ' '; }
4059  }
4060  l = strstr(chopt,"SAME");
4061  if (l) {
4062  if (nch == 4) Hoption.Hist = 1;
4063  Hoption.Same = 1;
4064  memcpy(l," ",4);
4065  if (l[4] == '0') { Hoption.Same += 10; l[4] = ' '; }
4066  }
4067 
4068  l = strstr(chopt,"PIE");
4069  if (l) {
4070  Hoption.Pie = 1;
4071  memcpy(l," ",3);
4072  }
4073 
4074 
4075  l = strstr(chopt,"CANDLE");
4076  if (l) {
4077  TCandle candle;
4078  Hoption.Candle = candle.ParseOption(l);
4079  Hoption.Scat = 0;
4080  }
4081 
4082  l = strstr(chopt,"VIOLIN");
4083  if (l) {
4084  TCandle candle;
4085  Hoption.Candle = candle.ParseOption(l);
4086  Hoption.Scat = 0;
4087  }
4088 
4089  l = strstr(chopt,"LEGO");
4090  if (l) {
4091  Hoption.Scat = 0;
4092  Hoption.Lego = 1; memcpy(l," ",4);
4093  if (l[4] == '1') { Hoption.Lego = 11; l[4] = ' '; }
4094  if (l[4] == '2') { Hoption.Lego = 12; l[4] = ' '; }
4095  if (l[4] == '3') { Hoption.Lego = 13; l[4] = ' '; }
4096  if (l[4] == '4') { Hoption.Lego = 14; l[4] = ' '; }
4097  if (l[4] == '9') { Hoption.Lego = 19; l[4] = ' '; }
4098  l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4099  l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4100  l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4101  }
4102 
4103  l = strstr(chopt,"SURF");
4104  if (l) {
4105  Hoption.Scat = 0;
4106  Hoption.Surf = 1; memcpy(l," ",4);
4107  if (l[4] == '1') { Hoption.Surf = 11; l[4] = ' '; }
4108  if (l[4] == '2') { Hoption.Surf = 12; l[4] = ' '; }
4109  if (l[4] == '3') { Hoption.Surf = 13; l[4] = ' '; }
4110  if (l[4] == '4') { Hoption.Surf = 14; l[4] = ' '; }
4111  if (l[4] == '5') { Hoption.Surf = 15; l[4] = ' '; }
4112  if (l[4] == '6') { Hoption.Surf = 16; l[4] = ' '; }
4113  if (l[4] == '7') { Hoption.Surf = 17; l[4] = ' '; }
4114  l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4115  l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4116  }
4117 
4118  l = strstr(chopt,"TF3");
4119  if (l) {
4120  l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4121  l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4122  }
4123 
4124  l = strstr(chopt,"ISO");
4125  if (l) {
4126  l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4127  l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4128  }
4129 
4130  l = strstr(chopt,"LIST"); if (l) { Hoption.List = 1; memcpy(l," ",4);}
4131 
4132  l = strstr(chopt,"CONT");
4133  if (l) {
4134  memcpy(l," ",4);
4135  if (hdim>1) {
4136  Hoption.Scat = 0;
4137  Hoption.Contour = 1;
4138  if (l[4] == '1') { Hoption.Contour = 11; l[4] = ' '; }
4139  if (l[4] == '2') { Hoption.Contour = 12; l[4] = ' '; }
4140  if (l[4] == '3') { Hoption.Contour = 13; l[4] = ' '; }
4141  if (l[4] == '4') { Hoption.Contour = 14; l[4] = ' '; }
4142  if (l[4] == '5') { Hoption.Contour = 15; l[4] = ' '; }
4143  } else {
4144  Hoption.Hist = 1;
4145  }
4146  }
4147  l = strstr(chopt,"HBAR");
4148  if (l) {
4149  Hoption.Hist = 0;
4150  Hoption.Bar = 20; memcpy(l," ",4);
4151  if (l[4] == '1') { Hoption.Bar = 21; l[4] = ' '; }
4152  if (l[4] == '2') { Hoption.Bar = 22; l[4] = ' '; }
4153  if (l[4] == '3') { Hoption.Bar = 23; l[4] = ' '; }
4154  if (l[4] == '4') { Hoption.Bar = 24; l[4] = ' '; }
4155  }
4156  l = strstr(chopt,"BAR");
4157  if (l) {
4158  Hoption.Hist = 0;
4159  Hoption.Bar = 10; memcpy(l," ",3);
4160  if (l[3] == '1') { Hoption.Bar = 11; l[3] = ' '; }
4161  if (l[3] == '2') { Hoption.Bar = 12; l[3] = ' '; }
4162  if (l[3] == '3') { Hoption.Bar = 13; l[3] = ' '; }
4163  if (l[3] == '4') { Hoption.Bar = 14; l[3] = ' '; }
4164  }
4165 
4166  l = strstr(chopt,"ARR" );
4167  if (l) {
4168  memcpy(l," ", 3);
4169  if (hdim>1) {
4170  Hoption.Arrow = 1;
4171  Hoption.Scat = 0;
4172  l = strstr(chopt,"COL"); if (l) { Hoption.Arrow = 2; memcpy(l," ",3); }
4173  l = strstr(chopt,"Z"); if (l) { Hoption.Zscale = 1; memcpy(l," ",1); }
4174  } else {
4175  Hoption.Hist = 1;
4176  }
4177  }
4178  l = strstr(chopt,"BOX" );
4179  if (l) {
4180  memcpy(l," ", 3);
4181  if (hdim>1) {
4182  Hoption.Scat = 0;
4183  Hoption.Box = 1;
4184  if (l[3] == '1') { Hoption.Box = 11; l[3] = ' '; }
4185  if (l[3] == '2') { Hoption.Box = 12; l[3] = ' '; }
4186  if (l[3] == '3') { Hoption.Box = 13; l[3] = ' '; }
4187  } else {
4188  Hoption.Hist = 1;
4189  }
4190  }
4191  l = strstr(chopt,"COLZ");
4192  if (l) {
4193  memcpy(l," ",4);
4194  if (hdim>1) {
4195  Hoption.Color = 1;
4196  Hoption.Scat = 0;
4197  Hoption.Zscale = 1;
4198  if (l[4] == '2') { Hoption.Color = 3; l[4] = ' '; }
4199  l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4200  l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); }
4201  } else {
4202  Hoption.Hist = 1;
4203  }
4204  }
4205  l = strstr(chopt,"COL" );
4206  if (l) {
4207  memcpy(l," ", 3);
4208  if (hdim>1) {
4209  Hoption.Color = 1;
4210  Hoption.Scat = 0;
4211  if (l[3] == '2') { Hoption.Color = 3; l[3] = ' '; }
4212  l = strstr(chopt,"0"); if (l) { Hoption.Zero = 1; memcpy(l," ",1); }
4213  l = strstr(chopt,"1"); if (l) { Hoption.Color = 2; memcpy(l," ",1); }
4214  } else {
4215  Hoption.Hist = 1;
4216  }
4217  }
4218  l = strstr(chopt,"CHAR"); if (l) { Hoption.Char = 1; memcpy(l," ",4); Hoption.Scat = 0; }
4219  l = strstr(chopt,"FUNC"); if (l) { Hoption.Func = 2; memcpy(l," ",4); Hoption.Hist = 0; }
4220  l = strstr(chopt,"HIST"); if (l) { Hoption.Hist = 2; memcpy(l," ",4); Hoption.Func = 0; Hoption.Error = 0;}
4221  l = strstr(chopt,"AXIS"); if (l) { Hoption.Axis = 1; memcpy(l," ",4); }
4222  l = strstr(chopt,"AXIG"); if (l) { Hoption.Axis = 2; memcpy(l," ",4); }
4223  l = strstr(chopt,"SCAT"); if (l) { Hoption.Scat = 1; memcpy(l," ",4); }
4224  l = strstr(chopt,"TEXT");
4225  if (l) {
4226  Int_t angle;
4227  if (sscanf(&l[4],"%d",&angle) > 0) {
4228  if (angle < 0) angle=0;
4229  if (angle > 90) angle=90;
4230  Hoption.Text = 1000+angle;
4231  } else {
4232  Hoption.Text = 1;
4233  }
4234  memcpy(l," ", 4);
4235  l = strstr(chopt,"N");
4236  if (l && fH->InheritsFrom(TH2Poly::Class())) Hoption.Text += 3000;
4237  Hoption.Scat = 0;
4238  }
4239  l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; memcpy(l," ",3); }
4240  l = strstr(chopt,"CYL"); if (l) { Hoption.System = kCYLINDRICAL; memcpy(l," ",3); }
4241  l = strstr(chopt,"SPH"); if (l) { Hoption.System = kSPHERICAL; memcpy(l," ",3); }
4242  l = strstr(chopt,"PSR"); if (l) { Hoption.System = kRAPIDITY; memcpy(l," ",3); }
4243 
4244  l = strstr(chopt,"TRI");
4245  if (l) {
4246  Hoption.Scat = 0;
4247  Hoption.Color = 0;
4248  Hoption.Tri = 1; memcpy(l," ",3);
4249  l = strstr(chopt,"FB"); if (l) { Hoption.FrontBox = 0; memcpy(l," ",2); }
4250  l = strstr(chopt,"BB"); if (l) { Hoption.BackBox = 0; memcpy(l," ",2); }
4251  l = strstr(chopt,"ERR"); if (l) memcpy(l," ",3);
4252  }
4253 
4254  l = strstr(chopt,"AITOFF");
4255  if (l) {
4256  Hoption.Proj = 1; memcpy(l," ",6); //Aitoff projection
4257  }
4258  l = strstr(chopt,"MERCATOR");
4259  if (l) {
4260  Hoption.Proj = 2; memcpy(l," ",8); //Mercator projection
4261  }
4262  l = strstr(chopt,"SINUSOIDAL");
4263  if (l) {
4264  Hoption.Proj = 3; memcpy(l," ",10); //Sinusoidal projection
4265  }
4266  l = strstr(chopt,"PARABOLIC");
4267  if (l) {
4268  Hoption.Proj = 4; memcpy(l," ",9); //Parabolic projection
4269  }
4270  if (Hoption.Proj > 0) {
4271  Hoption.Scat = 0;
4272  Hoption.Contour = 14;
4273  }
4274 
4275  if (strstr(chopt,"A")) Hoption.Axis = -1;
4276  if (strstr(chopt,"B")) Hoption.Bar = 1;
4277  if (strstr(chopt,"C") && !strstr(chopt,"CJUST")) { Hoption.Curve =1; Hoption.Hist = -1;}
4278  if (strstr(chopt,"F")) Hoption.Fill =1;
4279  if (strstr(chopt,"][")) {Hoption.Off =1; Hoption.Hist =1;}
4280  if (strstr(chopt,"F2")) Hoption.Fill =2;
4281  if (strstr(chopt,"L")) { Hoption.Line =1; Hoption.Hist = -1;}
4282  if (strstr(chopt,"P")) { Hoption.Mark =1; Hoption.Hist = -1;}
4283  if (strstr(chopt,"Z")) Hoption.Zscale =1;
4284  if (strstr(chopt,"*")) Hoption.Star =1;
4285  if (strstr(chopt,"H")) Hoption.Hist =2;
4286  if (strstr(chopt,"P0")) Hoption.Mark =10;
4287 
4288  if (fH->InheritsFrom(TH2Poly::Class())) {
4289  if (Hoption.Fill+Hoption.Line+Hoption.Mark != 0 ) Hoption.Scat = 0;
4290  }
4291 
4292  if (strstr(chopt,"E")) {
4293  if (hdim == 1) {
4294  Hoption.Error = 1;
4295  if (strstr(chopt,"E0")) Hoption.Error = 10;
4296  if (strstr(chopt,"E1")) Hoption.Error = 11;
4297  if (strstr(chopt,"E2")) Hoption.Error = 12;
4298  if (strstr(chopt,"E3")) Hoption.Error = 13;
4299  if (strstr(chopt,"E4")) Hoption.Error = 14;
4300  if (strstr(chopt,"E5")) Hoption.Error = 15;
4301  if (strstr(chopt,"E6")) Hoption.Error = 16;
4302  if (strstr(chopt,"X0")) {
4303  if (Hoption.Error == 1) Hoption.Error += 20;
4304  Hoption.Error += 10;
4305  }
4306  if (Hoption.Text && fH->InheritsFrom(TProfile::Class())) {
4307  Hoption.Text += 2000;
4308  Hoption.Error = 0;
4309  }
4310  } else {
4311  if (Hoption.Error == 0) {
4312  Hoption.Error = 100;
4313  Hoption.Scat = 0;
4314  }
4315  if (Hoption.Text) {
4316  Hoption.Text += 2000;
4317  Hoption.Error = 0;
4318  }
4319  }
4320  }
4321 
4322  if (Hoption.Surf == 15) {
4323  if (Hoption.System == kPOLAR || Hoption.System == kCARTESIAN) {
4324  Hoption.Surf = 13;
4325  Warning("MakeChopt","option SURF5 is not supported in Cartesian and Polar modes");
4326  }
4327  }
4328 
4329  // Copy options from current style
4330  Hoption.Logx = gPad->GetLogx();
4331  Hoption.Logy = gPad->GetLogy();
4332  Hoption.Logz = gPad->GetLogz();
4333 
4334  // Check options incompatibilities
4335  if (Hoption.Bar == 1) Hoption.Hist = -1;
4336  return 1;
4337 }
4338 
4339 ////////////////////////////////////////////////////////////////////////////////
4340 /// Decode string `choptin` and fill Graphical cuts structure.
4341 
4342 Int_t THistPainter::MakeCuts(char *choptin)
4343 {
4344 
4345  fNcuts = 0;
4346  char *left = (char*)strchr(choptin,'[');
4347  if (!left) return 0;
4348  char *right = (char*)strchr(choptin,']');
4349  if (!right) return 0;
4350  Int_t nch = right-left;
4351  if (nch < 2) return 0;
4352  char *cuts = left+1;
4353  *right = 0;
4354  char *comma, *minus;
4355  Int_t i;
4356  while (1) {
4357  comma = strchr(cuts,',');
4358  if (comma) *comma = 0;
4359  minus = strchr(cuts,'-');
4360  if (minus) cuts = minus+1;
4361  while (*cuts == ' ') cuts++;
4362  Int_t nc = strlen(cuts);
4363  while (cuts[nc-1] == ' ') {cuts[nc-1] = 0; nc--;}
4364  TIter next(gROOT->GetListOfSpecials());
4365  TCutG *cut=0;
4366  TObject *obj;
4367  while ((obj = next())) {
4368  if (!obj->InheritsFrom(TCutG::Class())) continue;
4369  if (strcmp(obj->GetName(),cuts)) continue;
4370  cut = (TCutG*)obj;
4371  break;
4372  }
4373  if (cut) {
4374  fCuts[fNcuts] = cut;
4375  fCutsOpt[fNcuts] = 1;
4376  if (minus) fCutsOpt[fNcuts] = -1;
4377  fNcuts++;
4378  }
4379  if (!comma) break;
4380  cuts = comma+1;
4381  }
4382  for (i=0;i<=nch;i++) left[i] = ' ';
4383  return fNcuts;
4384 }
4385 
4386 ////////////////////////////////////////////////////////////////////////////////
4387 /// [Control routine to paint any kind of histograms](#HP00)
4388 
4389 void THistPainter::Paint(Option_t *option)
4390 {
4391 
4392  if (fH->GetBuffer()) fH->BufferEmpty(-1);
4393 
4394  //For iOS: put the histogram on the top of stack of pickable objects.
4395  const TPickerStackGuard topPush(fH);
4396 
4397  gPad->SetVertical(kTRUE);
4398 
4399  TH1 *oldhist = gCurrentHist;
4400  gCurrentHist = fH;
4401  TH1 *hsave = fH;
4402  Double_t minsav = fH->GetMinimumStored();
4403 
4404  if (!MakeChopt(option)) return; //check options and fill Hoption structure
4405 
4406  // Paint using TSpectrum2Painter
4407  if (Hoption.Spec) {
4408  if (!TableInit()) return;
4409  if (!TClass::GetClass("TSpectrum2Painter")) gSystem->Load("libSpectrumPainter");
4410  gROOT->ProcessLineFast(Form("TSpectrum2Painter::PaintSpectrum((TH2F*)0x%lx,\"%s\",%d)",
4411  (ULong_t)fH, option, Hoption.Spec));
4412  return;
4413  }
4414 
4415  if (Hoption.Pie) {
4416  if (fH->GetDimension() == 1) {
4417  if (!fPie) fPie = new TPie(fH);
4418  fPie->Paint(option);
4419  } else {
4420  Error("Paint", "Option PIE is for 1D histograms only");
4421  }
4422  return;
4423  } else {
4424  if (fPie) delete fPie;
4425  fPie = 0;
4426  }
4427 
4428  fXbuf = new Double_t[kNMAX];
4429  fYbuf = new Double_t[kNMAX];
4430  if (fH->GetDimension() > 2) {
4431  PaintH3(option);
4432  fH->SetMinimum(minsav);
4433  if (Hoption.Func) {
4434  Hoption_t hoptsave = Hoption;
4435  Hparam_t hparsave = Hparam;
4436  PaintFunction(option);
4437  SetHistogram(hsave);
4438  Hoption = hoptsave;
4439  Hparam = hparsave;
4440  }
4441  gCurrentHist = oldhist;
4442  delete [] fXbuf; delete [] fYbuf;
4443  return;
4444  }
4445  TView *view = gPad->GetView();
4446  if (view) {
4447  if (!Hoption.Lego && !Hoption.Surf && !Hoption.Tri) {
4448  delete view;
4449  gPad->SetView(0);
4450  }
4451  }
4452  if (fH->GetDimension() > 1 || Hoption.Lego || Hoption.Surf) {
4453  // In case of 1D histogram, Z axis becomes Y axis.
4454  Int_t logysav=0, logzsav=0;
4455  if (fH->GetDimension() == 1) {
4456  logysav = Hoption.Logy;
4457  logzsav = Hoption.Logz;
4458  Hoption.Logz = 0;
4459  if (Hoption.Logy) {
4460  Hoption.Logz = 1;
4461  Hoption.Logy = 0;
4462  }
4463  }
4464  PaintTable(option);
4465  if (Hoption.Func) {
4466  Hoption_t hoptsave = Hoption;
4467  Hparam_t hparsave = Hparam;
4468  PaintFunction(option);
4469  SetHistogram(hsave);
4470  Hoption = hoptsave;
4471  Hparam = hparsave;
4472  }
4473  fH->SetMinimum(minsav);
4474  gCurrentHist = oldhist;
4475  delete [] fXbuf; delete [] fYbuf;
4476  if (fH->GetDimension() == 1) {
4477  Hoption.Logy = logysav;
4478  Hoption.Logz = logzsav;
4479  }
4480  return;
4481  }
4482 
4483  if (Hoption.Bar >= 20) {
4484  PaintBarH(option);
4485  delete [] fXbuf; delete [] fYbuf;
4486  return;
4487  }
4488 
4489  // fill Hparam structure with histo parameters
4490  if (!PaintInit()) {
4491  delete [] fXbuf; delete [] fYbuf;
4492  return;
4493  }
4494 
4495  // Picture surround (if new page) and page number (if requested).
4496  // Histogram surround (if not option "Same").
4497  PaintFrame();
4498 
4499  // Paint histogram axis only
4500  Bool_t gridx = gPad->GetGridx();
4501  Bool_t gridy = gPad->GetGridy();
4502  if (Hoption.Axis > 0) {
4503  if (Hoption.Axis > 1) PaintAxis(kTRUE); //axis with grid
4504  else {
4505  if (gridx) gPad->SetGridx(0);
4506  if (gridy) gPad->SetGridy(0);
4507  PaintAxis(kFALSE);
4508  if (gridx) gPad->SetGridx(1);
4509  if (gridy) gPad->SetGridy(1);
4510  }
4511  if ((Hoption.Same%10) ==1) Hoption.Same += 1;
4512  goto paintstat;
4513  }
4514  if (gridx || gridy) PaintAxis(kTRUE); // Draw the grid only
4515 
4516  // test for options BAR or HBAR
4517  if (Hoption.Bar >= 10) {
4518  PaintBar(option);
4519  }
4520 
4521  // do not draw histogram if error bars required
4522  if (!Hoption.Error) {
4523  if (Hoption.Hist && Hoption.Bar<10) PaintHist(option);
4524  }
4525 
4526  // test for error bars or option E
4527  if (Hoption.Error) {
4528  PaintErrors(option);
4529  if (Hoption.Hist == 2) PaintHist(option);
4530  }
4531 
4532  if (Hoption.Text) PaintText(option);
4533 
4534  // test for associated function
4535  if (Hoption.Func) {
4536  Hoption_t hoptsave = Hoption;
4537  Hparam_t hparsave = Hparam;
4538  PaintFunction(option);
4539  SetHistogram(hsave);
4540  Hoption = hoptsave;
4541  Hparam = hparsave;
4542  }
4543 
4544  if (gridx) gPad->SetGridx(0);
4545  if (gridy) gPad->SetGridy(0);
4546  PaintAxis(kFALSE);
4547  if (gridx) gPad->SetGridx(1);
4548  if (gridy) gPad->SetGridy(1);
4549 
4550  PaintTitle(); // Draw histogram title
4551 
4552  // Draw box with histogram statistics and/or fit parameters
4553 paintstat:
4554  if ((Hoption.Same%10) != 1 && !fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
4555  TIter next(fFunctions);
4556  TObject *obj = 0;
4557  while ((obj = next())) {
4558  if (obj->InheritsFrom(TF1::Class())) break;
4559  obj = 0;
4560  }
4561 
4562  //Stat is painted twice (first, it will be in canvas' list of primitives),
4563  //second, it will be here, this is not required on iOS.
4564  //Condition is ALWAYS true on a platform different from iOS.
4565  if (!gPad->PadInSelectionMode() && !gPad->PadInHighlightMode())
4566  PaintStat(gStyle->GetOptStat(),(TF1*)obj);
4567  }
4568  fH->SetMinimum(minsav);
4569  gCurrentHist = oldhist;
4570  delete [] fXbuf; fXbuf = 0;
4571  delete [] fYbuf; fYbuf = 0;
4572 
4573 }
4574 
4575 ////////////////////////////////////////////////////////////////////////////////
4576 /// [Control function to draw a table as an arrow plot](#HP12)
4577 
4578 void THistPainter::PaintArrows(Option_t *)
4579 {
4580  Double_t xk, xstep, yk, ystep;
4581  Double_t dx, dy, x1, x2, y1, y2, xc, yc, dxn, dyn;
4582  Int_t ncx = Hparam.xlast - Hparam.xfirst + 1;
4583  Int_t ncy = Hparam.ylast - Hparam.yfirst + 1;
4584  Double_t xrg = gPad->GetUxmin();
4585  Double_t yrg = gPad->GetUymin();
4586  Double_t xln = gPad->GetUxmax() - xrg;
4587  Double_t yln = gPad->GetUymax() - yrg;
4588  Double_t cx = (xln/Double_t(ncx) -0.03)/2;
4589  Double_t cy = (yln/Double_t(ncy) -0.03)/2;
4590  Double_t dn = 1.E-30;
4591 
4592  auto arrow = new TArrow();
4593  arrow->SetAngle(30);
4594  arrow->SetFillStyle(1001);
4595  arrow->SetFillColor(fH->GetLineColor());
4596  arrow->SetLineColor(fH->GetLineColor());
4597  arrow->SetLineWidth(fH->GetLineWidth());
4598 
4599  // Initialize the levels on the Z axis
4600  Int_t ncolors=0, ndivz=0;
4601  Double_t scale=0.;
4602  if (Hoption.Arrow>1) {
4603  ncolors = gStyle->GetNumberOfColors();
4604  Int_t ndiv = fH->GetContour();
4605  if (ndiv == 0 ) {
4606  ndiv = gStyle->GetNumberContours();
4607  fH->SetContour(ndiv);
4608  }
4609  ndivz = TMath::Abs(ndiv);
4610  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ndiv);
4611  scale = ndivz/(fH->GetMaximum()-fH->GetMinimum());
4612  }
4613 
4614  for (Int_t id=1;id<=2;id++) {
4615  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
4616  yk = fYaxis->GetBinLowEdge(j);
4617  ystep = fYaxis->GetBinWidth(j);
4618  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
4619  xk = fXaxis->GetBinLowEdge(i);
4620  xstep = fXaxis->GetBinWidth(i);
4621  if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
4622  if (i == Hparam.xfirst) {
4623  dx = fH->GetBinContent(i+1, j) - fH->GetBinContent(i, j);
4624  } else if (i == Hparam.xlast) {
4625  dx = fH->GetBinContent(i, j) - fH->GetBinContent(i-1, j);
4626  } else {
4627  dx = 0.5*(fH->GetBinContent(i+1, j) - fH->GetBinContent(i-1, j));
4628  }
4629  if (j == Hparam.yfirst) {
4630  dy = fH->GetBinContent(i, j+1) - fH->GetBinContent(i, j);
4631  } else if (j == Hparam.ylast) {
4632  dy = fH->GetBinContent(i, j) - fH->GetBinContent(i, j-1);
4633  } else {
4634  dy = 0.5*(fH->GetBinContent(i, j+1) - fH->GetBinContent(i, j-1));
4635  }
4636  if (id == 1) {
4637  dn = TMath::Max(dn, TMath::Abs(dx));
4638  dn = TMath::Max(dn, TMath::Abs(dy));
4639  } else if (id == 2) {
4640  xc = xrg + xln*(Double_t(i - Hparam.xfirst+1)-0.5)/Double_t(ncx);
4641  dxn = cx*dx/dn;
4642  x1 = xc - dxn;
4643  x2 = xc + dxn;
4644  yc = yrg + yln*(Double_t(j - Hparam.yfirst+1)-0.5)/Double_t(ncy);
4645  dyn = cy*dy/dn;
4646  y1 = yc - dyn;
4647  y2 = yc + dyn;
4648  if (Hoption.Arrow>1) {
4649  int color = Int_t(0.01+(fH->GetBinContent(i, j)-fH->GetMinimum())*scale);
4650  Int_t theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz));
4651  if (theColor > ncolors-1) theColor = ncolors-1;
4652  arrow->SetFillColor(gStyle->GetColorPalette(theColor));
4653  arrow->SetLineColor(gStyle->GetColorPalette(theColor));
4654  }
4655  if (TMath::Abs(x2-x1) > 0. || TMath::Abs(y2-y1) > 0.) {
4656  arrow->PaintArrow(x1, y1, x2, y2, 0.015, "|>");
4657  } else {
4658  arrow->PaintArrow(x1, y1, x2, y2, 0.005, "|>");
4659  }
4660  }
4661  }
4662  }
4663  }
4664 
4665  if (Hoption.Zscale) PaintPalette();
4666 }
4667 
4668 ////////////////////////////////////////////////////////////////////////////////
4669 /// Draw axis (2D case) of an histogram.
4670 ///
4671 /// If `drawGridOnly` is `TRUE`, only the grid is painted (if needed). This allows
4672 /// to draw the grid and the axis separately. In `THistPainter::Paint` this
4673 /// feature is used to make sure that the grid is drawn in the background and
4674 /// the axis tick marks in the foreground of the pad.
4675 
4676 void THistPainter::PaintAxis(Bool_t drawGridOnly)
4677 {
4678 
4679  //On iOS, grid should not be pickable and can not be highlighted.
4680  //Condition is never true on a platform different from iOS.
4681  if (drawGridOnly && (gPad->PadInHighlightMode() || gPad->PadInSelectionMode()))
4682  return;
4683 
4684  if (Hoption.Axis == -1) return;
4685  if (Hoption.Same && Hoption.Axis <= 0) return;
4686 
4687  // Repainting alphanumeric labels axis on a plot done with
4688  // the option HBAR (horizontal) needs some adjustments.
4689  TAxis *xaxis = 0;
4690  TAxis *yaxis = 0;
4691  if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
4692  if (fXaxis->GetLabels() || fYaxis->GetLabels()) { // One axis has alphanumeric labels
4693  TIter next(gPad->GetListOfPrimitives());
4694  TObject *obj;
4695  // Check if the first TH1 of THStack in the pad is drawn with the option HBAR
4696  while ((obj = next())) {
4697  if (!obj->InheritsFrom(TH1::Class()) &&
4698  !obj->InheritsFrom(THStack::Class())) continue;
4699  TString opt = obj->GetDrawOption();
4700  opt.ToLower();
4701  // if drawn with HBAR, the axis should be inverted and the pad set to horizontal
4702  if (strstr(opt,"hbar")) {
4703  gPad->SetVertical(kFALSE);
4704  xaxis = fXaxis;
4705  yaxis = fYaxis;
4706  if (!strcmp(xaxis->GetName(),"xaxis")) {
4707  fXaxis = yaxis;
4708  fYaxis = xaxis;
4709  }
4710  }
4711  break;
4712  }
4713  }
4714  }
4715 
4716  static char chopt[10] = "";
4717  Double_t gridl = 0;
4718  Int_t ndiv, ndivx, ndivy, nx1, nx2, ndivsave;
4719  Int_t useHparam = 0;
4720  Double_t umin, umax, uminsave, umaxsave;
4721  Short_t xAxisPos = Hoption.AxisPos/10;
4722  Short_t yAxisPos = Hoption.AxisPos - 10*xAxisPos;
4723 
4724  Double_t axmin = gPad->GetUxmin();
4725  Double_t axmax = gPad->GetUxmax();
4726  Double_t aymin = gPad->GetUymin();
4727  Double_t aymax = gPad->GetUymax();
4728  char *cw = 0;
4729  TGaxis axis;
4730 
4731  // In case of option 'cont4' or in case of option 'same' over a 'cont4 plot'
4732  // Hparam must be use for the axis limits.
4733  if (Hoption.Contour == 14) useHparam = 1;
4734  if (Hoption.Same) {
4735  TObject *obj;
4736  TIter next(gPad->GetListOfPrimitives());
4737  while ((obj=next())) {
4738  if (strstr(obj->GetDrawOption(),"cont4")) {
4739  useHparam = 1;
4740  break;
4741  }
4742  }
4743  }
4744 
4745  // Paint X axis
4746 
4747  //To make X-axis selectable on iOS device.
4748  if (gPad->PadInSelectionMode())
4749  gPad->PushSelectableObject(fXaxis);
4750 
4751  //This condition is ALWAYS true, unless it works on iOS (can be false on iOS).
4752  if (gPad->PadInSelectionMode() || !gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && gPad->GetSelected() == fXaxis)) {
4753  ndivx = fXaxis->GetNdivisions();
4754  if (ndivx > 1000) {
4755  nx2 = ndivx/100;
4756  nx1 = TMath::Max(1, ndivx%100);
4757  ndivx = 100*nx2 + Int_t(Float_t(nx1)*gPad->GetAbsWNDC());
4758  }
4759  axis.SetTextAngle(0);
4760  axis.ImportAxisAttributes(fXaxis);
4761 
4762  chopt[0] = 0;
4763  strlcat(chopt, "SDH",10);
4764  if (ndivx < 0) strlcat(chopt, "N",10);
4765  if (gPad->GetGridx()) {
4766  gridl = (aymax-aymin)/(gPad->GetY2() - gPad->GetY1());
4767  strlcat(chopt, "W",10);
4768  }
4769 
4770  // Define X-Axis limits
4771  if (Hoption.Logx) {
4772  strlcat(chopt, "G",10);
4773  ndiv = TMath::Abs(ndivx);
4774  if (useHparam) {
4775  umin = TMath::Power(10,Hparam.xmin);
4776  umax = TMath::Power(10,Hparam.xmax);
4777  } else {
4778  umin = TMath::Power(10,axmin);
4779  umax = TMath::Power(10,axmax);
4780  }
4781  } else {
4782  ndiv = TMath::Abs(ndivx);
4783  if (useHparam) {
4784  umin = Hparam.xmin;
4785  umax = Hparam.xmax;
4786  } else {
4787  umin = axmin;
4788  umax = axmax;
4789  }
4790  }
4791 
4792  // Display axis as time
4793  if (fXaxis->GetTimeDisplay()) {
4794  strlcat(chopt,"t",10);
4795  if (strlen(fXaxis->GetTimeFormatOnly()) == 0) {
4796  axis.SetTimeFormat(fXaxis->ChooseTimeFormat(Hparam.xmax-Hparam.xmin));
4797  }
4798  }
4799 
4800  // The main X axis can be on the bottom or on the top of the pad
4801  Double_t xAxisYPos1, xAxisYPos2;
4802  if (xAxisPos == 1) {
4803  // Main X axis top
4804  xAxisYPos1 = aymax;
4805  xAxisYPos2 = aymin;
4806  } else {
4807  // Main X axis bottom
4808  xAxisYPos1 = aymin;
4809  xAxisYPos2 = aymax;
4810  }
4811 
4812  // Paint the main X axis (always)
4813  uminsave = umin;
4814  umaxsave = umax;
4815  ndivsave = ndiv;
4816  axis.SetOption(chopt);
4817  if (xAxisPos) {
4818  strlcat(chopt, "-",10);
4819  gridl = -gridl;
4820  }
4821  if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
4822  axis.SetLabelSize(0.);
4823  axis.SetTitle("");
4824  }
4825  axis.PaintAxis(axmin, xAxisYPos1,
4826  axmax, xAxisYPos1,
4827  umin, umax, ndiv, chopt, gridl, drawGridOnly);
4828 
4829  // Paint additional X axis (if needed)
4830  // On iOS, this additional X axis is neither pickable, nor highlighted.
4831  // Additional checks PadInSelectionMode etc. does not effect non-iOS platform.
4832  if (gPad->GetTickx() && !gPad->PadInSelectionMode() && !gPad->PadInHighlightMode()) {
4833  if (xAxisPos) {
4834  cw=strstr(chopt,"-");
4835  *cw='z';
4836  } else {
4837  strlcat(chopt, "-",10);
4838  }
4839  if (gPad->GetTickx() < 2) strlcat(chopt, "U",10);
4840  if ((cw=strstr(chopt,"W"))) *cw='z';
4841  axis.SetTitle("");
4842  axis.PaintAxis(axmin, xAxisYPos2,
4843  axmax, xAxisYPos2,
4844  uminsave, umaxsave, ndivsave, chopt, gridl, drawGridOnly);
4845  }
4846  }//End of "if pad in selection mode etc".
4847 
4848  // Paint Y axis
4849  //On iOS, Y axis must pushed into the stack of selectable objects.
4850  if (gPad->PadInSelectionMode())
4851  gPad->PushSelectableObject(fYaxis);
4852 
4853  //This conditions is ALWAYS true on a platform, different from iOS (on iOS can be true, can be false).
4854  if (gPad->PadInSelectionMode() || !gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && gPad->GetSelected() == fYaxis)) {
4855  ndivy = fYaxis->GetNdivisions();
4856  axis.ImportAxisAttributes(fYaxis);
4857 
4858  chopt[0] = 0;
4859  strlcat(chopt, "SDH",10);
4860  if (ndivy < 0) strlcat(chopt, "N",10);
4861  if (gPad->GetGridy()) {
4862  gridl = (axmax-axmin)/(gPad->GetX2() - gPad->GetX1());
4863  strlcat(chopt, "W",10);
4864  }
4865 
4866  // Define Y-Axis limits
4867  if (Hoption.Logy) {
4868  strlcat(chopt, "G",10);
4869  ndiv = TMath::Abs(ndivy);
4870  if (useHparam) {
4871  umin = TMath::Power(10,Hparam.ymin);
4872  umax = TMath::Power(10,Hparam.ymax);
4873  } else {
4874  umin = TMath::Power(10,aymin);
4875  umax = TMath::Power(10,aymax);
4876  }
4877  } else {
4878  ndiv = TMath::Abs(ndivy);
4879  if (useHparam) {
4880  umin = Hparam.ymin;
4881  umax = Hparam.ymax;
4882  } else {
4883  umin = aymin;
4884  umax = aymax;
4885  }
4886  }
4887 
4888  // Display axis as time
4889  if (fYaxis->GetTimeDisplay()) {
4890  strlcat(chopt,"t",10);
4891  if (strlen(fYaxis->GetTimeFormatOnly()) == 0) {
4892  axis.SetTimeFormat(fYaxis->ChooseTimeFormat(Hparam.ymax-Hparam.ymin));
4893  }
4894  }
4895 
4896  // The main Y axis can be on the left or on the right of the pad
4897  Double_t yAxisXPos1, yAxisXPos2;
4898  if (yAxisPos == 1) {
4899  // Main Y axis left
4900  yAxisXPos1 = axmax;
4901  yAxisXPos2 = axmin;
4902  } else {
4903  // Main Y axis right
4904  yAxisXPos1 = axmin;
4905  yAxisXPos2 = axmax;
4906  }
4907 
4908  // Paint the main Y axis (always)
4909  uminsave = umin;
4910  umaxsave = umax;
4911  ndivsave = ndiv;
4912  axis.SetOption(chopt);
4913  if (yAxisPos) {
4914  strlcat(chopt, "+L",10);
4915  gridl = -gridl;
4916  }
4917  if (Hoption.Same && Hoption.Axis) { // Axis repainted (TPad::RedrawAxis)
4918  axis.SetLabelSize(0.);
4919  axis.SetTitle("");
4920  }
4921  axis.PaintAxis(yAxisXPos1, aymin,
4922  yAxisXPos1, aymax,
4923  umin, umax, ndiv, chopt, gridl, drawGridOnly);
4924 
4925  // Paint the additional Y axis (if needed)
4926  // Additional checks for pad mode are required on iOS: this "second" axis is
4927  // neither pickable, nor highlighted. Additional checks have no effect on non-iOS platform.
4928  if (gPad->GetTicky() && !gPad->PadInSelectionMode() && !gPad->PadInHighlightMode()) {
4929  if (gPad->GetTicky() < 2) {
4930  strlcat(chopt, "U",10);
4931  axis.SetTickSize(-fYaxis->GetTickLength());
4932  } else {
4933  strlcat(chopt, "+L",10);
4934  }
4935  if ((cw=strstr(chopt,"W"))) *cw='z';
4936  axis.SetTitle("");
4937  axis.PaintAxis(yAxisXPos2, aymin,
4938  yAxisXPos2, aymax,
4939  uminsave, umaxsave, ndivsave, chopt, gridl, drawGridOnly);
4940  }
4941  }//End of "if pad is in selection mode etc."
4942 
4943  // Reset the axis if they have been inverted in case of option HBAR
4944  if (xaxis) {
4945  fXaxis = xaxis;
4946  fYaxis = yaxis;
4947  }
4948 }
4949 
4950 ////////////////////////////////////////////////////////////////////////////////
4951 /// [Draw a bar-chart in a normal pad.](#HP10)
4952 
4953 void THistPainter::PaintBar(Option_t *)
4954 {
4955 
4956  Int_t bar = Hoption.Bar - 10;
4957  Double_t xmin,xmax,ymin,ymax,umin,umax,w,y;
4958  Double_t offset = fH->GetBarOffset();
4959  Double_t width = fH->GetBarWidth();
4960  TBox box;
4961  Int_t hcolor = fH->GetFillColor();
4962  if (hcolor == gPad->GetFrameFillColor()) ++hcolor;
4963  Int_t hstyle = fH->GetFillStyle();
4964  box.SetFillColor(hcolor);
4965  box.SetFillStyle(hstyle);
4966  box.SetLineStyle(fH->GetLineStyle());
4967  box.SetLineColor(fH->GetLineColor());
4968  box.SetLineWidth(fH->GetLineWidth());
4969  for (Int_t bin=fXaxis->GetFirst();bin<=fXaxis->GetLast();bin++) {
4970  y = fH->GetBinContent(bin);
4971  xmin = gPad->XtoPad(fXaxis->GetBinLowEdge(bin));
4972  xmax = gPad->XtoPad(fXaxis->GetBinUpEdge(bin));
4973  ymin = gPad->GetUymin();
4974  ymax = gPad->YtoPad(y);
4975  if (ymax < gPad->GetUymin()) continue;
4976  if (ymax > gPad->GetUymax()) ymax = gPad->GetUymax();
4977  if (ymin < gPad->GetUymin()) ymin = gPad->GetUymin();
4978  if (Hoption.MinimumZero && ymin < 0)
4979  ymin=TMath::Min(0.,gPad->GetUymax());
4980  w = (xmax-xmin)*width;
4981  xmin += offset*(xmax-xmin);
4982  xmax = xmin + w;
4983  if (bar < 1) {
4984  box.PaintBox(xmin,ymin,xmax,ymax);
4985  } else {
4986  umin = xmin + bar*(xmax-xmin)/10.;
4987  umax = xmax - bar*(xmax-xmin)/10.;
4988  //box.SetFillColor(hcolor+150); //bright
4989  box.SetFillColor(TColor::GetColorBright(hcolor)); //bright
4990  box.PaintBox(xmin,ymin,umin,ymax);
4991  box.SetFillColor(hcolor);
4992  box.PaintBox(umin,ymin,umax,ymax);
4993  box.SetFillColor(TColor::GetColorDark(hcolor)); //dark
4994  box.PaintBox(umax,ymin,xmax,ymax);
4995  }
4996  }
4997 }
4998 
4999 ////////////////////////////////////////////////////////////////////////////////
5000 /// [Draw a bar char in a rotated pad (X vertical, Y horizontal)](#HP10)
5001 
5002 void THistPainter::PaintBarH(Option_t *)
5003 {
5004 
5005  gPad->SetVertical(kFALSE);
5006 
5007  PaintInitH();
5008 
5009  TAxis *xaxis = fXaxis;
5010  TAxis *yaxis = fYaxis;
5011  if (!strcmp(xaxis->GetName(),"xaxis")) {
5012  fXaxis = yaxis;
5013  fYaxis = xaxis;
5014  }
5015 
5016  PaintFrame();
5017  PaintAxis(kFALSE);
5018 
5019  Int_t bar = Hoption.Bar - 20;
5020  Double_t xmin,xmax,ymin,ymax,umin,umax,w;
5021  Double_t offset = fH->GetBarOffset();
5022  Double_t width = fH->GetBarWidth();
5023  TBox box;
5024  Int_t hcolor = fH->GetFillColor();
5025  if (hcolor == gPad->GetFrameFillColor()) ++hcolor;
5026  Int_t hstyle = fH->GetFillStyle();
5027  box.SetFillColor(hcolor);
5028  box.SetFillStyle(hstyle);
5029  box.SetLineStyle(fH->GetLineStyle());
5030  box.SetLineColor(fH->GetLineColor());
5031  box.SetLineWidth(fH->GetLineWidth());
5032  for (Int_t bin=fYaxis->GetFirst();bin<=fYaxis->GetLast();bin++) {
5033  ymin = gPad->YtoPad(fYaxis->GetBinLowEdge(bin));
5034  ymax = gPad->YtoPad(fYaxis->GetBinUpEdge(bin));
5035  xmin = gPad->GetUxmin();
5036  xmax = gPad->XtoPad(fH->GetBinContent(bin));
5037  if (xmax < gPad->GetUxmin()) continue;
5038  if (xmax > gPad->GetUxmax()) xmax = gPad->GetUxmax();
5039  if (xmin < gPad->GetUxmin()) xmin = gPad->GetUxmin();
5040  if (Hoption.MinimumZero && xmin < 0)
5041  xmin=TMath::Min(0.,gPad->GetUxmax());
5042  w = (ymax-ymin)*width;
5043  ymin += offset*(ymax-ymin);
5044  ymax = ymin + w;
5045  if (bar < 1) {
5046  box.PaintBox(xmin,ymin,xmax,ymax);
5047  } else {
5048  umin = ymin + bar*(ymax-ymin)/10.;
5049  umax = ymax - bar*(ymax-ymin)/10.;
5050  box.SetFillColor(TColor::GetColorDark(hcolor)); //dark
5051  box.PaintBox(xmin,ymin,xmax,umin);
5052  box.SetFillColor(hcolor);
5053  box.PaintBox(xmin,umin,xmax,umax);
5054  box.SetFillColor(TColor::GetColorBright(hcolor)); //bright
5055  box.PaintBox(xmin,umax,xmax,ymax);
5056  }
5057  }
5058 
5059  PaintTitle();
5060 
5061  // Draw box with histogram statistics and/or fit parameters
5062  if ((Hoption.Same%10) != 1 && !fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
5063  TIter next(fFunctions);
5064  TObject *obj = 0;
5065  while ((obj = next())) {
5066  if (obj->InheritsFrom(TF1::Class())) break;
5067  obj = 0;
5068  }
5069  PaintStat(gStyle->GetOptStat(),(TF1*)obj);
5070  }
5071 
5072  fXaxis = xaxis;
5073  fYaxis = yaxis;
5074 }
5075 
5076 ////////////////////////////////////////////////////////////////////////////////
5077 /// [Control function to draw a 2D histogram as a box plot](#HP13)
5078 
5079 void THistPainter::PaintBoxes(Option_t *)
5080 {
5081 
5082  Style_t fillsav = fH->GetFillStyle();
5083  Style_t colsav = fH->GetFillColor();
5084  if (fH->GetFillColor() == 0) fH->SetFillStyle(0);
5085  if (Hoption.Box == 11) fH->SetFillStyle(1001);
5086  fH->TAttLine::Modify();
5087  fH->TAttFill::Modify();
5088 
5089  Double_t z, xk,xstep, yk, ystep, xcent, ycent, xlow, xup, ylow, yup;
5090  Double_t ux1 = gPad->PixeltoX(1);
5091  Double_t ux0 = gPad->PixeltoX(0);
5092  Double_t uy1 = gPad->PixeltoY(1);
5093  Double_t uy0 = gPad->PixeltoY(0);
5094  Double_t dxmin = 0.51*(gPad->PadtoX(ux1)-gPad->PadtoX(ux0));
5095  Double_t dymin = 0.51*(gPad->PadtoY(uy0)-gPad->PadtoY(uy1));
5096 
5097  Double_t zmin = TMath::Max(fH->GetMinimum(),0.);
5098  Double_t zmax = TMath::Max(TMath::Abs(fH->GetMaximum()),
5099  TMath::Abs(fH->GetMinimum()));
5100  Double_t zminlin = zmin, zmaxlin = zmax;
5101 
5102  // In case of option SAME, zmin and zmax values are taken from the
5103  // first plotted 2D histogram.
5104  if (Hoption.Same > 0 && Hoption.Same < 10) {
5105  TH2 *h2;
5106  TIter next(gPad->GetListOfPrimitives());
5107  while ((h2 = (TH2 *)next())) {
5108  if (!h2->InheritsFrom(TH2::Class())) continue;
5109  zmin = TMath::Max(h2->GetMinimum(), 0.);
5110  zmax = TMath::Max(TMath::Abs(h2->GetMaximum()),
5111  TMath::Abs(h2->GetMinimum()));
5112  zminlin = zmin;
5113  zmaxlin = zmax;
5114  if (Hoption.Logz) {
5115  if (zmin <= 0) {
5116  zmin = TMath::Log10(zmax*0.001);
5117  } else {
5118  zmin = TMath::Log10(zmin);
5119  }
5120  zmax = TMath::Log10(zmax);
5121  }
5122  break;
5123  }
5124  } else {
5125  if (Hoption.Logz) {
5126  if (zmin > 0) {
5127  zmin = TMath::Log10(zmin);
5128  zmax = TMath::Log10(zmax);
5129  } else {
5130  return;
5131  }
5132  }
5133  }
5134 
5135  Double_t zratio, dz = zmax - zmin;
5136  Bool_t kZminNeg = kFALSE;
5137  if (fH->GetMinimum()<0) kZminNeg = kTRUE;
5138  Bool_t kZNeg = kFALSE;
5139 
5140  // Define the dark and light colors the "button style" boxes.
5141  Color_t color = fH->GetFillColor();
5142  Color_t light=0, dark=0;
5143  if (Hoption.Box == 11) {
5144  light = TColor::GetColorBright(color);
5145  dark = TColor::GetColorDark(color);
5146  }
5147 
5148  // Loop over all the bins and draw the boxes
5149  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
5150  yk = fYaxis->GetBinLowEdge(j);
5151  ystep = fYaxis->GetBinWidth(j);
5152  ycent = 0.5*ystep;
5153  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
5154  Int_t bin = j*(fXaxis->GetNbins()+2) + i;
5155  xk = fXaxis->GetBinLowEdge(i);
5156  xstep = fXaxis->GetBinWidth(i);
5157  if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
5158  xcent = 0.5*xstep;
5159  z = Hparam.factor*fH->GetBinContent(bin);
5160  kZNeg = kFALSE;
5161 
5162  if (TMath::Abs(z) < zminlin) continue; // Can be the case with ...
5163  if (TMath::Abs(z) > zmaxlin) z = zmaxlin; // ... option Same
5164  if (kZminNeg && z==0) continue; // Do not draw empty bins if case of histo with netgative bins.
5165 
5166  if (z < 0) {
5167  if (Hoption.Logz) continue;
5168  z = -z;
5169  kZNeg = kTRUE;
5170  }
5171  if (Hoption.Logz) {
5172  if (z != 0) z = TMath::Log10(z);
5173  else z = zmin;
5174  }
5175 
5176  if (dz == 0) continue;
5177  zratio = TMath::Sqrt((z-zmin)/dz);
5178  if (zratio == 0) continue;
5179 
5180  xup = xcent*zratio + xk + xcent;
5181  xlow = 2*(xk + xcent) - xup;
5182  if (xup-xlow < dxmin) xup = xlow+dxmin;
5183  if (Hoption.Logx) {
5184  if (xup > 0) xup = TMath::Log10(xup);
5185  else continue;
5186  if (xlow > 0) xlow = TMath::Log10(xlow);
5187  else continue;
5188  }
5189 
5190  yup = ycent*zratio + yk + ycent;
5191  ylow = 2*(yk + ycent) - yup;
5192  if (yup-ylow < dymin) yup = ylow+dymin;
5193  if (Hoption.Logy) {
5194  if (yup > 0) yup = TMath::Log10(yup);
5195  else continue;
5196  if (ylow > 0) ylow = TMath::Log10(ylow);
5197  else continue;
5198  }
5199 
5200  xlow = TMath::Max(xlow, gPad->GetUxmin());
5201  ylow = TMath::Max(ylow, gPad->GetUymin());
5202  xup = TMath::Min(xup , gPad->GetUxmax());
5203  yup = TMath::Min(yup , gPad->GetUymax());
5204 
5205  if (xlow >= xup) continue;
5206  if (ylow >= yup) continue;
5207 
5208  if (Hoption.Box == 1) {
5209  fH->SetFillColor(color);
5210  fH->TAttFill::Modify();
5211  gPad->PaintBox(xlow, ylow, xup, yup);
5212  if (kZNeg) {
5213  gPad->PaintLine(xlow, ylow, xup, yup);
5214  gPad->PaintLine(xlow, yup, xup, ylow);
5215  }
5216  } else if (Hoption.Box == 11) {
5217  // Draw the center of the box
5218  fH->SetFillColor(color);
5219  fH->TAttFill::Modify();
5220  gPad->PaintBox(xlow, ylow, xup, yup);
5221 
5222  // Draw top&left part of the box
5223  Double_t x[7], y[7];
5224  Double_t bwidth = 0.1;
5225  x[0] = xlow; y[0] = ylow;
5226  x[1] = xlow + bwidth*(xup-xlow); y[1] = ylow + bwidth*(yup-ylow);
5227  x[2] = x[1]; y[2] = yup - bwidth*(yup-ylow);
5228  x[3] = xup - bwidth*(xup-xlow); y[3] = y[2];
5229  x[4] = xup; y[4] = yup;
5230  x[5] = xlow; y[5] = yup;
5231  x[6] = xlow; y[6] = ylow;
5232  if (kZNeg) fH->SetFillColor(dark);
5233  else fH->SetFillColor(light);
5234  fH->TAttFill::Modify();
5235  gPad->PaintFillArea(7, x, y);
5236 
5237  // Draw bottom&right part of the box
5238  x[0] = xlow; y[0] = ylow;
5239  x[1] = xlow + bwidth*(xup-xlow); y[1] = ylow + bwidth*(yup-ylow);
5240  x[2] = xup - bwidth*(xup-xlow); y[2] = y[1];
5241  x[3] = x[2]; y[3] = yup - bwidth*(yup-ylow);
5242  x[4] = xup; y[4] = yup;
5243  x[5] = xup; y[5] = ylow;
5244  x[6] = xlow; y[6] = ylow;
5245  if (kZNeg) fH->SetFillColor(light);
5246  else fH->SetFillColor(dark);
5247  fH->TAttFill::Modify();
5248  gPad->PaintFillArea(7, x, y);
5249  }
5250  }
5251  }
5252 
5253  if (Hoption.Zscale) PaintPalette();
5254  fH->SetFillStyle(fillsav);
5255  fH->SetFillColor(colsav);
5256  fH->TAttFill::Modify();
5257 }
5258 
5259 
5260 
5261 ////////////////////////////////////////////////////////////////////////////////
5262 /// [Control function to draw a 2D histogram as a candle (box) plot or violin plot](#HP14)
5263 
5264 void THistPainter::PaintCandlePlot(Option_t *)
5265 {
5266  TH1D *hproj;
5267  TH2D *h2 = (TH2D*)fH;
5268 
5269  TCandle myCandle;
5270  myCandle.SetOption((TCandle::CandleOption)Hoption.Candle);
5271  myCandle.SetMarkerColor(fH->GetLineColor());
5272  myCandle.SetLineColor(fH->GetLineColor());
5273  myCandle.SetLineWidth(fH->GetLineWidth());
5274  myCandle.SetFillColor(fH->GetFillColor());
5275  myCandle.SetFillStyle(fH->GetFillStyle());
5276  myCandle.SetMarkerSize(fH->GetMarkerSize());
5277  myCandle.SetMarkerStyle(fH->GetMarkerStyle());
5278  myCandle.SetLog(Hoption.Logx,Hoption.Logy, Hoption.Logz);
5279 
5280  Bool_t swapXY = myCandle.IsHorizontal();
5281  const Double_t standardCandleWidth = 0.66;
5282  const Double_t standardHistoWidth = 0.8;
5283 
5284  double allMaxContent = h2->GetBinContent(h2->GetMaximumBin());
5285  double allMaxIntegral = 0;
5286 
5287  if (!swapXY) { // Vertical candle
5288  //Determining the slice with the maximum content
5289  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast; i++) {
5290  hproj = h2->ProjectionY("_px", i, i);
5291  if (hproj->Integral() > allMaxIntegral) allMaxIntegral = hproj->Integral();
5292  }
5293  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast; i++) {
5294  Double_t binPosX = fXaxis->GetBinLowEdge(i);
5295  Double_t binWidth = fXaxis->GetBinWidth(i);
5296  hproj = h2->ProjectionY("_px", i, i);
5297  if (hproj->GetEntries() !=0) {
5298  Double_t candleWidth = fH->GetBarWidth();
5299  Double_t offset = fH->GetBarOffset()*binWidth;
5300  double myMaxContent = hproj->GetBinContent(hproj->GetMaximumBin());
5301  double myIntegral = hproj->Integral();
5302  Double_t histoWidth = candleWidth;
5303  if (candleWidth > 0.999 && candleWidth < 1.001) {
5304  candleWidth = standardCandleWidth;
5305  histoWidth = standardHistoWidth;
5306  }
5307  if (Hoption.Logz && myMaxContent > 0) {
5308  histoWidth *= myMaxContent/TMath::Log10(myMaxContent);
5309  if (myCandle.IsViolinScaled() && myMaxContent > 0 && allMaxContent > 0) histoWidth *= TMath::Log10(myMaxContent)/TMath::Log10(allMaxContent);
5310  } else if (myCandle.IsViolinScaled()) histoWidth *= myMaxContent/allMaxContent;
5311  if (myCandle.IsCandleScaled()) candleWidth *= myIntegral/allMaxIntegral;
5312 
5313  myCandle.SetAxisPosition(binPosX+binWidth/2. + offset);
5314  myCandle.SetCandleWidth(candleWidth*binWidth);
5315  myCandle.SetHistoWidth(histoWidth*binWidth);
5316  myCandle.SetHistogram(hproj);
5317  myCandle.Paint();
5318  }
5319  }
5320  } else { // Horizontal candle
5321  //Determining the slice with the maximum content
5322  for (Int_t i=Hparam.yfirst; i<=Hparam.ylast; i++) {
5323  hproj = h2->ProjectionX("_py", i, i);
5324  if (hproj->Integral() > allMaxIntegral) allMaxIntegral = hproj->Integral();
5325  }
5326  for (Int_t i=Hparam.yfirst; i<=Hparam.ylast; i++) {
5327  Double_t binPosY = fYaxis->GetBinLowEdge(i);
5328  Double_t binWidth = fYaxis->GetBinWidth(i);
5329  hproj = h2->ProjectionX("_py", i, i);
5330  if (hproj->GetEntries() !=0) {
5331  Double_t candleWidth = fH->GetBarWidth();
5332  Double_t offset = fH->GetBarOffset()*binWidth;
5333  double myMaxContent = hproj->GetBinContent(hproj->GetMaximumBin());
5334  double myIntegral = hproj->Integral();
5335  Double_t histoWidth = candleWidth;
5336  if (candleWidth > 0.999 && candleWidth < 1.001) {
5337  candleWidth = standardCandleWidth;
5338  histoWidth = standardHistoWidth;
5339  }
5340  if (Hoption.Logz && myMaxContent > 0) {
5341  histoWidth *= myMaxContent/TMath::Log10(myMaxContent);
5342  if (myCandle.IsViolinScaled() && myMaxContent > 0 && allMaxContent > 0) histoWidth *= TMath::Log10(myMaxContent)/TMath::Log10(allMaxContent);
5343  } else if (myCandle.IsViolinScaled()) histoWidth *= myMaxContent/allMaxContent;
5344  if (myCandle.IsCandleScaled()) candleWidth *= myIntegral/allMaxIntegral;
5345 
5346  myCandle.SetAxisPosition(binPosY+binWidth/2. + offset);
5347  myCandle.SetCandleWidth(candleWidth*binWidth);
5348  myCandle.SetHistoWidth(histoWidth*binWidth);
5349  myCandle.SetHistogram(hproj);
5350  myCandle.Paint();
5351  }
5352  }
5353  }
5354 }
5355 
5356 
5357 
5358 ////////////////////////////////////////////////////////////////////////////////
5359 /// Returns the rendering regions for an axis to use in the COL2 option
5360 ///
5361 /// The algorithm analyses the size of the axis compared to the size of
5362 /// the rendering region. It figures out the boundaries to use for each color
5363 /// of the rendering region. Only one axis is computed here.
5364 ///
5365 /// This allows for a single computation of the boundaries before iterating
5366 /// through all of the bins.
5367 ///
5368 /// \param pAxis the axis to consider
5369 /// \param nPixels the number of pixels to render axis into
5370 /// \param isLog whether the axis is log scale
5371 
5372 std::vector<THistRenderingRegion>
5373 THistPainter::ComputeRenderingRegions(TAxis* pAxis, Int_t nPixels, Bool_t isLog)
5374 {
5375  std::vector<THistRenderingRegion> regions;
5376 
5377  enum STRATEGY { Bins, Pixels } strategy;
5378 
5379  Int_t nBins = (pAxis->GetLast() - pAxis->GetFirst() + 1);
5380 
5381  if (nBins >= nPixels) {
5382  // more bins than pixels... we should loop over pixels and sample
5383  strategy = Pixels;
5384  } else {
5385  // fewer bins than pixels... we should loop over bins
5386  strategy = Bins;
5387  }
5388 
5389  if (isLog) {
5390 
5391  Double_t xMin = pAxis->GetBinLowEdge(pAxis->GetFirst());
5392  Int_t binOffset=0;
5393  while (xMin <= 0 && ((pAxis->GetFirst()+binOffset) != pAxis->GetLast()) ) {
5394  binOffset++;
5395  xMin = pAxis->GetBinLowEdge(pAxis->GetFirst()+binOffset);
5396  }
5397  if (xMin <= 0) {
5398  // this should cause an error if we have
5399  return regions;
5400  }
5401  Double_t xMax = pAxis->GetBinUpEdge(pAxis->GetLast());
5402 
5403  if (strategy == Bins) {
5404  // logarithmic plot. we find the pixel for the bin
5405  // pixel = eta * log10(V) - alpha
5406  // where eta = nPixels/(log10(Vmax)-log10(Vmin))
5407  // and alpha = nPixels*log10(Vmin)/(log10(Vmax)-log10(Vmin))
5408  // and V is axis value
5409  Double_t eta = (nPixels-1.0)/(TMath::Log10(xMax) - TMath::Log10(xMin));
5410  Double_t offset = -1.0 * eta * TMath::Log10(xMin);
5411 
5412  for (Int_t bin=pAxis->GetFirst()+binOffset; bin<=pAxis->GetLast(); bin++) {
5413 
5414  // linear plot. we simply need to find the appropriate bin
5415  // for the
5416  Double_t xLowValue = pAxis->GetBinLowEdge(bin);
5417  Double_t xUpValue = pAxis->GetBinUpEdge(bin);
5418  Int_t xPx0 = eta*TMath::Log10(xLowValue)+ offset;
5419  Int_t xPx1 = eta*TMath::Log10(xUpValue) + offset;
5420  THistRenderingRegion region = {std::make_pair(xPx0, xPx1),
5421  std::make_pair(bin, bin+1)};
5422  regions.push_back(region);
5423  }
5424 
5425  } else {
5426 
5427  // loop over pixels
5428 
5429  Double_t beta = (TMath::Log10(xMax) - TMath::Log10(xMin))/(nPixels-1.0);
5430 
5431  for (Int_t pixelIndex=0; pixelIndex<(nPixels-1); pixelIndex++) {
5432  // linear plot
5433  Int_t binLow = pAxis->FindBin(xMin*TMath::Power(10.0, beta*pixelIndex));
5434  Int_t binHigh = pAxis->FindBin(xMin*TMath::Power(10.0, beta*(pixelIndex+1)));
5435  THistRenderingRegion region = { std::make_pair(pixelIndex, pixelIndex+1),
5436  std::make_pair(binLow, binHigh)};
5437  regions.push_back(region);
5438  }
5439  }
5440  } else {
5441  // standard linear plot
5442 
5443  if (strategy == Bins) {
5444  // loop over bins
5445  for (Int_t bin=pAxis->GetFirst(); bin<=pAxis->GetLast(); bin++) {
5446 
5447  // linear plot. we simply need to find the appropriate bin
5448  // for the
5449  Int_t xPx0 = ((bin - pAxis->GetFirst()) * nPixels)/nBins;
5450  Int_t xPx1 = xPx0 + nPixels/nBins;
5451 
5452  // make sure we don't compute beyond our bounds
5453  if (xPx1>= nPixels) xPx1 = nPixels-1;
5454 
5455  THistRenderingRegion region = {std::make_pair(xPx0, xPx1),
5456  std::make_pair(bin, bin+1)};
5457  regions.push_back(region);
5458  }
5459  } else {
5460  // loop over pixels
5461  for (Int_t pixelIndex=0; pixelIndex<nPixels-1; pixelIndex++) {
5462  // linear plot
5463  Int_t binLow = (nBins*pixelIndex)/nPixels + pAxis->GetFirst();
5464  Int_t binHigh = binLow + nBins/nPixels;
5465  THistRenderingRegion region = { std::make_pair(pixelIndex, pixelIndex+1),
5466  std::make_pair(binLow, binHigh)};
5467  regions.push_back(region);
5468  }
5469  }
5470  }
5471 
5472  return regions;
5473 }
5474 
5475 ////////////////////////////////////////////////////////////////////////////////
5476 /// [Rendering scheme for the COL2 and COLZ2 options] (#HP14)
5477 
5478 void THistPainter::PaintColorLevelsFast(Option_t*)
5479 {
5480 
5481  if (Hoption.System != kCARTESIAN) {
5482  Error("THistPainter::PaintColorLevelsFast(Option_t*)",
5483  "Only cartesian coordinates supported by 'COL2' option. Using 'COL' option instead.");
5484  PaintColorLevels(nullptr);
5485  return;
5486  }
5487 
5488  Double_t z;
5489 
5490  // Use existing max or min values. If either is already set
5491  // the appropriate value to use.
5492  Double_t zmin = fH->GetMinimumStored();
5493  Double_t zmax = fH->GetMaximumStored();
5494  Double_t originalZMin = zmin;
5495  Double_t originalZMax = zmax;
5496  if ((zmin == -1111) && (zmax == -1111)) {
5497  fH->GetMinimumAndMaximum(zmin, zmax);
5498  fH->SetMinimum(zmin);
5499  fH->SetMaximum(zmax);
5500  } else if (zmin == -1111) {
5501  zmin = fH->GetMinimum();
5502  fH->SetMinimum(zmin);
5503  } else if (zmax == -1111) {
5504  zmax = fH->GetMaximum();
5505  fH->SetMaximum(zmax);
5506  }
5507 
5508  Double_t dz = zmax - zmin;
5509  if (dz <= 0) { // Histogram filled with a constant value
5510  zmax += 0.1*TMath::Abs(zmax);
5511  zmin -= 0.1*TMath::Abs(zmin);
5512  dz = zmax - zmin;
5513  }
5514 
5515  if (Hoption.Logz) {
5516  if (zmin > 0) {
5517  zmin = TMath::Log10(zmin);
5518  zmax = TMath::Log10(zmax);
5519  dz = zmax - zmin;
5520  } else {
5521  Error("THistPainter::PaintColorLevelsFast(Option_t*)",
5522  "Cannot plot logz because bin content is less than 0.");
5523  return;
5524  }
5525  }
5526 
5527  // Initialize the levels on the Z axis
5528  Int_t ndiv = fH->GetContour();
5529  if (ndiv == 0 ) {
5530  ndiv = gStyle->GetNumberContours();
5531  fH->SetContour(ndiv);
5532  }
5533  std::vector<Double_t> colorBounds(ndiv);
5534  std::vector<Double_t> contours(ndiv, 0);
5535  if (fH->TestBit(TH1::kUserContour) == 0) {
5536  fH->SetContour(ndiv);
5537  } else {
5538  fH->GetContour(contours.data());
5539  }
5540 
5541  Double_t step = 1.0/ndiv;
5542  for (Int_t i=0; i<ndiv; ++i) {
5543  colorBounds[i] = step*i;
5544  }
5545 
5546  auto pFrame = gPad->GetFrame();
5547  Int_t px0 = gPad->XtoPixel(pFrame->GetX1());
5548  Int_t px1 = gPad->XtoPixel(pFrame->GetX2());
5549  Int_t py0 = gPad->YtoPixel(pFrame->GetY1());
5550  Int_t py1 = gPad->YtoPixel(pFrame->GetY2());
5551  Int_t nXPixels = px1-px0;
5552  Int_t nYPixels = py0-py1; // y=0 is at the top of the screen
5553 
5554  std::vector<Double_t> buffer(nXPixels*nYPixels, 0);
5555 
5556  auto xRegions = ComputeRenderingRegions(fXaxis, nXPixels, Hoption.Logx);
5557  auto yRegions = ComputeRenderingRegions(fYaxis, nYPixels, Hoption.Logy);
5558  if (xRegions.size() == 0 || yRegions.size() == 0) {
5559  Error("THistPainter::PaintColorLevelFast(Option_t*)",
5560  "Encountered error while computing rendering regions.");
5561  return;
5562  }
5563 
5564  Bool_t minExists = kFALSE;
5565  Bool_t maxExists = kFALSE;
5566  Double_t minValue = 1.;
5567  Double_t maxValue = 0.;
5568  for (auto& yRegion : yRegions) {
5569  for (auto& xRegion : xRegions ) {
5570 
5571  const auto& xBinRange = xRegion.fBinRange;
5572  const auto& yBinRange = yRegion.fBinRange;
5573 
5574  // sample the range
5575  z = fH->GetBinContent(xBinRange.second-1, yBinRange.second-1);
5576 
5577  if (Hoption.Logz) {
5578  if (z > 0) z = TMath::Log10(z);
5579  else z = zmin;
5580  }
5581 
5582  // obey the user's max and min values if they were set
5583  if (z > zmax) z = zmax;
5584  if (z < zmin) z = zmin;
5585 
5586  if (fH->TestBit(TH1::kUserContour) == 1) {
5587  // contours are absolute values
5588  auto index = TMath::BinarySearch(contours.size(), contours.data(), z);
5589  z = colorBounds[index];
5590  } else {
5591  Int_t index = 0;
5592  if (dz != 0) {
5593  index = 0.001 + ((z - zmin)/dz)*ndiv;
5594  }
5595 
5596  if (index == static_cast<Int_t>(colorBounds.size())) {
5597  index--;
5598  }
5599 
5600  // Do a little bookkeeping to use later for getting libAfterImage to produce
5601  // the correct colors
5602  if (index == 0) {
5603  minExists = kTRUE;
5604  } else if (index == static_cast<Int_t>(colorBounds.size()-1)) {
5605  maxExists = kTRUE;
5606  }
5607 
5608  z = colorBounds[index];
5609 
5610  if (z < minValue) {
5611  minValue = z;
5612  }
5613  if (z > maxValue) {
5614  maxValue = z;
5615  }
5616  }
5617 
5618  // fill in the actual pixels
5619  const auto& xPixelRange = xRegion.fPixelRange;
5620  const auto& yPixelRange = yRegion.fPixelRange;
5621  for (Int_t xPx = xPixelRange.first; xPx <= xPixelRange.second; ++xPx) {
5622  for (Int_t yPx = yPixelRange.first; yPx <= yPixelRange.second; ++yPx) {
5623  Int_t pixel = yPx*nXPixels + xPx;
5624  buffer[pixel] = z;
5625  }
5626  }
5627  } // end px loop
5628  } // end py loop
5629 
5630  // This is a bit of a hack to ensure that we span the entire color range and
5631  // don't screw up the colors for a sparse histogram. No one will notice that I set a
5632  // single pixel on the edge of the image to a different color. This is even more
5633  // true because the chosen pixels will be covered by the axis.
5634  if (minValue != maxValue) {
5635  if ( !minExists) {
5636  buffer.front() = 0;
5637  }
5638 
5639  if ( !maxExists) {
5640  buffer[buffer.size()-nXPixels] = 0.95;
5641  }
5642  }
5643 
5644  // Generate the TImage
5645  TImagePalette* pPalette = TImagePalette::CreateCOLPalette(ndiv);
5646  TImage* pImage = TImage::Create();
5647  pImage->SetImageQuality(TAttImage::kImgBest);
5648  pImage->SetImage(buffer.data(), nXPixels, nYPixels, pPalette);
5649  delete pPalette;
5650 
5651  Window_t wid = static_cast<Window_t>(gVirtualX->GetWindowID(gPad->GetPixmapID()));
5652  pImage->PaintImage(wid, px0, py1, 0, 0, nXPixels, nYPixels);
5653  delete pImage;
5654 
5655  if (Hoption.Zscale) PaintPalette();
5656 
5657  // Reset the maximum and minimum values to their original values
5658  // when this function was called. If we don't do this, an initial
5659  // value of -1111 will be replaced with the true max or min values.
5660  fH->SetMinimum(originalZMin);
5661  fH->SetMaximum(originalZMax);
5662 }
5663 
5664 ////////////////////////////////////////////////////////////////////////////////
5665 /// [Control function to draw a 2D histogram as a color plot.](#HP14)
5666 
5667 void THistPainter::PaintColorLevels(Option_t*)
5668 {
5669  Double_t z, zc, xk, xstep, yk, ystep, xlow, xup, ylow, yup;
5670 
5671  Double_t zmin = fH->GetMinimum();
5672  Double_t zmax = fH->GetMaximum();
5673 
5674  Double_t dz = zmax - zmin;
5675  if (dz <= 0) { // Histogram filled with a constant value
5676  zmax += 0.1*TMath::Abs(zmax);
5677  zmin -= 0.1*TMath::Abs(zmin);
5678  dz = zmax - zmin;
5679  }
5680 
5681  // In case of option SAME, zmin and zmax values are taken from the
5682  // first plotted 2D histogram.
5683  if (Hoption.Same > 0 && Hoption.Same < 10) {
5684  TH2 *h2;
5685  TIter next(gPad->GetListOfPrimitives());
5686  while ((h2 = (TH2 *)next())) {
5687  if (!h2->InheritsFrom(TH2::Class())) continue;
5688  zmin = h2->GetMinimum();
5689  zmax = h2->GetMaximum();
5690  fH->SetMinimum(zmin);
5691  fH->SetMaximum(zmax);
5692  if (Hoption.Logz) {
5693  if (zmin <= 0) {
5694  zmin = TMath::Log10(zmax*0.001);
5695  } else {
5696  zmin = TMath::Log10(zmin);
5697  }
5698  zmax = TMath::Log10(zmax);
5699  }
5700  dz = zmax - zmin;
5701  break;
5702  }
5703  } else {
5704  if (Hoption.Logz) {
5705  if (zmin > 0) {
5706  zmin = TMath::Log10(zmin);
5707  zmax = TMath::Log10(zmax);
5708  dz = zmax - zmin;
5709  } else {
5710  return;
5711  }
5712  }
5713  }
5714 
5715  Style_t fillsav = fH->GetFillStyle();
5716  Style_t colsav = fH->GetFillColor();
5717  fH->SetFillStyle(1001);
5718  fH->TAttFill::Modify();
5719 
5720  // Initialize the levels on the Z axis
5721  Int_t ncolors = gStyle->GetNumberOfColors();
5722  Int_t ndiv = fH->GetContour();
5723  if (ndiv == 0 ) {
5724  ndiv = gStyle->GetNumberContours();
5725  fH->SetContour(ndiv);
5726  }
5727  Int_t ndivz = TMath::Abs(ndiv);
5728  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ndiv);
5729  Double_t scale = ndivz/dz;
5730 
5731  Int_t color;
5732  TProfile2D* prof2d = dynamic_cast<TProfile2D*>(fH);
5733  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
5734  yk = fYaxis->GetBinLowEdge(j);
5735  ystep = fYaxis->GetBinWidth(j);
5736  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
5737  Int_t bin = j*(fXaxis->GetNbins()+2) + i;
5738  xk = fXaxis->GetBinLowEdge(i);
5739  xstep = fXaxis->GetBinWidth(i);
5740  if (Hoption.System == kPOLAR && xk<0) xk= 2*TMath::Pi()+xk;
5741  if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
5742  z = fH->GetBinContent(bin);
5743  // if fH is a profile histogram do not draw empty bins
5744  if (prof2d) {
5745  const Double_t binEntries = prof2d->GetBinEntries(bin);
5746  if (binEntries == 0)
5747  continue;
5748  } else {
5749  // don't draw the empty bins for non-profile histograms
5750  // with positive content
5751  if (z == 0) {
5752  if (zmin >= 0 || Hoption.Logz) continue;
5753  if (Hoption.Color == 2) continue;
5754  }
5755  }
5756 
5757  if (Hoption.Logz) {
5758  if (z > 0) z = TMath::Log10(z);
5759  else z = zmin;
5760  }
5761  if (z < zmin && !Hoption.Zero) continue;
5762  xup = xk + xstep;
5763  xlow = xk;
5764  if (Hoption.Logx) {
5765  if (xup > 0) xup = TMath::Log10(xup);
5766  else continue;
5767  if (xlow > 0) xlow = TMath::Log10(xlow);
5768  else continue;
5769  }
5770  yup = yk + ystep;
5771  ylow = yk;
5772  if (Hoption.System != kPOLAR) {
5773  if (Hoption.Logy) {
5774  if (yup > 0) yup = TMath::Log10(yup);
5775  else continue;
5776  if (ylow > 0) ylow = TMath::Log10(ylow);
5777  else continue;
5778  }
5779  if (xup < gPad->GetUxmin()) continue;
5780  if (yup < gPad->GetUymin()) continue;
5781  if (xlow > gPad->GetUxmax()) continue;
5782  if (ylow > gPad->GetUymax()) continue;
5783  if (xlow < gPad->GetUxmin()) xlow = gPad->GetUxmin();
5784  if (ylow < gPad->GetUymin()) ylow = gPad->GetUymin();
5785  if (xup > gPad->GetUxmax()) xup = gPad->GetUxmax();
5786  if (yup > gPad->GetUymax()) yup = gPad->GetUymax();
5787  }
5788 
5789  if (fH->TestBit(TH1::kUserContour)) {
5790  zc = fH->GetContourLevelPad(0);
5791  if (z < zc) continue;
5792  color = -1;
5793  for (Int_t k=0; k<ndiv; k++) {
5794  zc = fH->GetContourLevelPad(k);
5795  if (z < zc) {
5796  continue;
5797  } else {
5798  color++;
5799  }
5800  }
5801  } else {
5802  color = Int_t(0.01+(z-zmin)*scale);
5803  }
5804 
5805  Int_t theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz));
5806  if (theColor > ncolors-1) theColor = ncolors-1;
5807  fH->SetFillColor(gStyle->GetColorPalette(theColor));
5808  fH->TAttFill::Modify();
5809  if (Hoption.System != kPOLAR) {
5810  gPad->PaintBox(xlow, ylow, xup, yup);
5811  } else {
5812  TCrown crown(0,0,ylow,yup,xlow*TMath::RadToDeg(),xup*TMath::RadToDeg());
5813  crown.SetFillColor(gStyle->GetColorPalette(theColor));
5814  crown.Paint();
5815  }
5816  }
5817  }
5818 
5819  if (Hoption.Zscale) PaintPalette();
5820 
5821  fH->SetFillStyle(fillsav);
5822  fH->SetFillColor(colsav);
5823  fH->TAttFill::Modify();
5824 
5825 }
5826 
5827 ////////////////////////////////////////////////////////////////////////////////
5828 /// [Control function to draw a 2D histogram as a contour plot.](#HP16)
5829 
5830 void THistPainter::PaintContour(Option_t *option)
5831 {
5832 
5833  Int_t i, j, count, ncontour, icol, n, lj, m, ix, jx, ljfill;
5834  Int_t itars, mode, ir[4];
5835  Double_t xsave, ysave, thesave,phisave,x[4], y[4], zc[4];
5836 
5837  if (Hoption.Contour == 14) {
5838  Hoption.Surf = 12;
5839  Hoption.Axis = 1;
5840  thesave = gPad->GetTheta();
5841  phisave = gPad->GetPhi();
5842  gPad->SetPhi(0.);
5843  gPad->SetTheta(90.);
5844  PaintSurface(option);
5845  gPad->SetPhi(phisave);
5846  gPad->SetTheta(thesave);
5847  TView *view = gPad->GetView();
5848  if (view) view->SetBit(kCannotRotate); //tested in ExecuteEvent
5849  PaintAxis();
5850  return;
5851  }
5852 
5853  if (Hoption.Same) {
5854  // If the contour is painted on a 3d plot, the contour lines are
5855  // paint in 3d too.
5856  TObject *obj;
5857  TIter next(gPad->GetListOfPrimitives());
5858  while ((obj=next())) {
5859  if (strstr(obj->GetDrawOption(),"surf") ||
5860  strstr(obj->GetDrawOption(),"lego") ||
5861  strstr(obj->GetDrawOption(),"tri")) {
5862  Hoption.Surf = 16;
5863  PaintSurface(option);
5864  return;
5865  }
5866  }
5867  }
5868 
5869  if (Hoption.Contour == 15) {
5870  TGraphDelaunay2D *dt = nullptr;
5871  TGraphDelaunay *dtOld = nullptr;
5872  TList *hl = fH->GetListOfFunctions();
5873  dt = (TGraphDelaunay2D*)hl->FindObject("TGraphDelaunay2D");
5874  if (!dt) dtOld = (TGraphDelaunay*)hl->FindObject("TGraphDelaunay");
5875  if (!dt && !dtOld) return;
5876  if (!fGraph2DPainter) {
5877  if (dt) fGraph2DPainter = new TGraph2DPainter(dt);
5878  else fGraph2DPainter = new TGraph2DPainter(dtOld);
5879  }
5880  fGraph2DPainter->Paint(option);
5881  return;
5882  }
5883 
5884  gPad->SetBit(TGraph::kClipFrame);
5885 
5886  Double_t *levels = new Double_t[2*kMAXCONTOUR];
5887  Double_t *xarr = new Double_t[2*kMAXCONTOUR];
5888  Double_t *yarr = new Double_t[2*kMAXCONTOUR];
5889  Int_t *itarr = new Int_t[2*kMAXCONTOUR];
5890 
5891  Int_t npmax = 0;
5892  for (i=0;i<2*kMAXCONTOUR;i++) itarr[i] = 0;
5893 
5894  ncontour = fH->GetContour();
5895  if (ncontour == 0) {
5896  ncontour = gStyle->GetNumberContours();
5897  fH->SetContour(ncontour);
5898  }
5899  if (ncontour > kMAXCONTOUR) {
5900  Warning("PaintContour", "maximum number of contours is %d, asked for %d",
5901  kMAXCONTOUR, ncontour);
5902  ncontour = kMAXCONTOUR-1;
5903  }
5904  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ncontour);
5905 
5906  for (i=0;i<ncontour;i++) levels[i] = fH->GetContourLevelPad(i);
5907  Int_t linesav = fH->GetLineStyle();
5908  Int_t colorsav = fH->GetLineColor();
5909  Int_t fillsav = fH->GetFillColor();
5910  if (Hoption.Contour == 13) {
5911  fH->TAttLine::Modify();
5912  }
5913 
5914  TPolyLine **polys = 0;
5915  TPolyLine *poly=0;
5916  TObjArray *contours = 0;
5917  TList *list = 0;
5918  TGraph *graph = 0;
5919  Int_t *np = 0;
5920  if (Hoption.Contour == 1) {
5921  np = new Int_t[ncontour];
5922  for (i=0;i<ncontour;i++) np[i] = 0;
5923  polys = new TPolyLine*[ncontour];
5924  for (i=0;i<ncontour;i++) {
5925  polys[i] = new TPolyLine(100);
5926  }
5927  if (Hoption.List == 1) {
5928  contours = (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
5929  if (contours) {
5930  gROOT->GetListOfSpecials()->Remove(contours);
5931  count = contours->GetSize();
5932  for (i=0;i<count;i++) {
5933  list = (TList*)contours->At(i);
5934  if (list) list->Delete();
5935  }
5936  }
5937  contours = new TObjArray(ncontour);
5938  contours->SetName("contours");
5939  gROOT->GetListOfSpecials()->Add(contours);
5940  for (i=0;i<ncontour;i++) {
5941  list = new TList();
5942  contours->Add(list);
5943  }
5944  }
5945  }
5946  Int_t theColor;
5947  Int_t ncolors = gStyle->GetNumberOfColors();
5948  Int_t ndivz = TMath::Abs(ncontour);
5949 
5950  Int_t k,ipoly;
5951  for (j=Hparam.yfirst; j<Hparam.ylast; j++) {
5952  y[0] = fYaxis->GetBinCenter(j);
5953  y[1] = y[0];
5954  y[2] = fYaxis->GetBinCenter(j+1);
5955  y[3] = y[2];
5956  for (i=Hparam.xfirst; i<Hparam.xlast; i++) {
5957  zc[0] = fH->GetBinContent(i, j);
5958  zc[1] = fH->GetBinContent(i+1, j);
5959  zc[2] = fH->GetBinContent(i+1, j+1);
5960  zc[3] = fH->GetBinContent(i, j+1);
5961  if (!IsInside(fXaxis->GetBinCenter(i),fYaxis->GetBinCenter(j))) continue;
5962  if (Hoption.Logz) {
5963  if (zc[0] > 0) zc[0] = TMath::Log10(zc[0]);
5964  else zc[0] = Hparam.zmin;
5965  if (zc[1] > 0) zc[1] = TMath::Log10(zc[1]);
5966  else zc[1] = Hparam.zmin;
5967  if (zc[2] > 0) zc[2] = TMath::Log10(zc[2]);
5968  else zc[2] = Hparam.zmin;
5969  if (zc[3] > 0) zc[3] = TMath::Log10(zc[3]);
5970  else zc[3] = Hparam.zmin;
5971  }
5972  for (k=0;k<4;k++) {
5973  ir[k] = TMath::BinarySearch(ncontour,levels,zc[k]);
5974  }
5975  if (ir[0] != ir[1] || ir[1] != ir[2] || ir[2] != ir[3] || ir[3] != ir[0]) {
5976  x[0] = fXaxis->GetBinCenter(i);
5977  x[3] = x[0];
5978  x[1] = fXaxis->GetBinCenter(i+1);
5979  x[2] = x[1];
5980  if (zc[0] <= zc[1]) n = 0; else n = 1;
5981  if (zc[2] <= zc[3]) m = 2; else m = 3;
5982  if (zc[n] > zc[m]) n = m;
5983  n++;
5984  lj=1;
5985  for (ix=1;ix<=4;ix++) {
5986  m = n%4 + 1;
5987  ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],zc[m-1],
5988  ir[m-1],x[m-1],y[m-1],&xarr[lj-1],&yarr[lj-1],&itarr[lj-1], levels);
5989  lj += 2*ljfill;
5990  n = m;
5991  }
5992 
5993  if (zc[0] <= zc[1]) n = 0; else n = 1;
5994  if (zc[2] <= zc[3]) m = 2; else m = 3;
5995  if (zc[n] > zc[m]) n = m;
5996  n++;
5997  lj=2;
5998  for (ix=1;ix<=4;ix++) {
5999  if (n == 1) m = 4;
6000  else m = n-1;
6001  ljfill = PaintContourLine(zc[n-1],ir[n-1],x[n-1],y[n-1],zc[m-1],
6002  ir[m-1],x[m-1],y[m-1],&xarr[lj-1],&yarr[lj-1],&itarr[lj-1], levels);
6003  lj += 2*ljfill;
6004  n = m;
6005  }
6006 
6007  // Re-order endpoints
6008 
6009  count = 0;
6010  for (ix=1; ix<=lj-5; ix +=2) {
6011  //count = 0;
6012  while (itarr[ix-1] != itarr[ix]) {
6013  xsave = xarr[ix];
6014  ysave = yarr[ix];
6015  itars = itarr[ix];
6016  for (jx=ix; jx<=lj-5; jx +=2) {
6017  xarr[jx] = xarr[jx+2];
6018  yarr[jx] = yarr[jx+2];
6019  itarr[jx] = itarr[jx+2];
6020  }
6021  xarr[lj-3] = xsave;
6022  yarr[lj-3] = ysave;
6023  itarr[lj-3] = itars;
6024  if (count > 100) break;
6025  count++;
6026  }
6027  }
6028 
6029  if (count > 100) continue;
6030  for (ix=1; ix<=lj-2; ix +=2) {
6031  theColor = Int_t((itarr[ix-1]+0.99)*Float_t(ncolors)/Float_t(ndivz));
6032  icol = gStyle->GetColorPalette(theColor);
6033  if (Hoption.Contour == 11) {
6034  fH->SetLineColor(icol);
6035  }
6036  if (Hoption.Contour == 12) {
6037  mode = icol%5;
6038  if (mode == 0) mode = 5;
6039  fH->SetLineStyle(mode);
6040  }
6041  if (Hoption.Contour != 1) {
6042  fH->TAttLine::Modify();
6043  gPad->PaintPolyLine(2,&xarr[ix-1],&yarr[ix-1]);
6044  continue;
6045  }
6046 
6047  ipoly = itarr[ix-1];
6048  if (ipoly >=0 && ipoly <ncontour) {
6049  poly = polys[ipoly];
6050  poly->SetPoint(np[ipoly] ,xarr[ix-1],yarr[ix-1]);
6051  poly->SetPoint(np[ipoly]+1,xarr[ix], yarr[ix]);
6052  np[ipoly] += 2;
6053  if (npmax < np[ipoly]) npmax = np[ipoly];
6054  }
6055  }
6056  } // end of if (ir[0]
6057  } //end of for (i
6058  } //end of for (j
6059 
6060  Double_t xmin,ymin;
6061  Double_t *xp, *yp;
6062  Int_t nadd,iminus,iplus;
6063  Double_t *xx, *yy;
6064  Int_t istart;
6065  Int_t first = ncontour;
6066  Int_t *polysort = 0;
6067  Int_t contListNb;
6068  if (Hoption.Contour != 1) goto theEND;
6069 
6070  //The 2 points line generated above are now sorted/merged to generate
6071  //a list of consecutive points.
6072  // If the option "List" has been specified, the list of points is saved
6073  // in the form of TGraph objects in the ROOT list of special objects.
6074  xmin = gPad->GetUxmin();
6075  ymin = gPad->GetUymin();
6076  xp = new Double_t[2*npmax];
6077  yp = new Double_t[2*npmax];
6078  polysort = new Int_t[ncontour];
6079  //find first positive contour
6080  for (ipoly=0;ipoly<ncontour;ipoly++) {
6081  if (levels[ipoly] >= 0) {first = ipoly; break;}
6082  }
6083  //store negative contours from 0 to minimum, then all positive contours
6084  k = 0;
6085  for (ipoly=first-1;ipoly>=0;ipoly--) {polysort[k] = ipoly; k++;}
6086  for (ipoly=first;ipoly<ncontour;ipoly++) {polysort[k] = ipoly; k++;}
6087  // we can now draw sorted contours
6088  contListNb = 0;
6089  fH->SetFillStyle(1001);
6090  for (k=0;k<ncontour;k++) {
6091  ipoly = polysort[k];
6092  if (np[ipoly] == 0) continue;
6093  if (Hoption.List) list = (TList*)contours->At(contListNb);
6094  contListNb++;
6095  poly = polys[ipoly];
6096  xx = poly->GetX();
6097  yy = poly->GetY();
6098  istart = 0;
6099  while (1) {
6100  iminus = npmax;
6101  iplus = iminus+1;
6102  xp[iminus]= xx[istart]; yp[iminus] = yy[istart];
6103  xp[iplus] = xx[istart+1]; yp[iplus] = yy[istart+1];
6104  xx[istart] = xmin; yy[istart] = ymin;
6105  xx[istart+1] = xmin; yy[istart+1] = ymin;
6106  while (1) {
6107  nadd = 0;
6108  for (i=2;i<np[ipoly];i+=2) {
6109  if ((iplus < 2*npmax-1) && (xx[i] == xp[iplus]) && (yy[i] == yp[iplus])) {
6110  iplus++;
6111  xp[iplus] = xx[i+1]; yp[iplus] = yy[i+1];
6112  xx[i] = xmin; yy[i] = ymin;
6113  xx[i+1] = xmin; yy[i+1] = ymin;
6114  nadd++;
6115  }
6116  if ((iminus > 0) && (xx[i+1] == xp[iminus]) && (yy[i+1] == yp[iminus])) {
6117  iminus--;
6118  xp[iminus] = xx[i]; yp[iminus] = yy[i];
6119  xx[i] = xmin; yy[i] = ymin;
6120  xx[i+1] = xmin; yy[i+1] = ymin;
6121  nadd++;
6122  }
6123  }
6124  if (nadd == 0) break;
6125  }
6126  theColor = Int_t((ipoly+0.99)*Float_t(ncolors)/Float_t(ndivz));
6127  icol = gStyle->GetColorPalette(theColor);
6128  if (ndivz > 1) fH->SetFillColor(icol);
6129  fH->TAttFill::Modify();
6130  gPad->PaintFillArea(iplus-iminus+1,&xp[iminus],&yp[iminus]);
6131  if (Hoption.List) {
6132  graph = new TGraph(iplus-iminus+1,&xp[iminus],&yp[iminus]);
6133  graph->SetFillColor(icol);
6134  graph->SetLineWidth(fH->GetLineWidth());
6135  list->Add(graph);
6136  }
6137  //check if more points are left
6138  istart = 0;
6139  for (i=2;i<np[ipoly];i+=2) {
6140  if (xx[i] != xmin && yy[i] != ymin) {
6141  istart = i;
6142  break;
6143  }
6144  }
6145  if (istart == 0) break;
6146  }
6147  }
6148 
6149  for (i=0;i<ncontour;i++) delete polys[i];
6150  delete [] polys;
6151  delete [] xp;
6152  delete [] yp;
6153  delete [] polysort;
6154 
6155 theEND:
6156  gPad->ResetBit(TGraph::kClipFrame);
6157  if (Hoption.Zscale) PaintPalette();
6158  fH->SetLineStyle(linesav);
6159  fH->SetLineColor(colorsav);
6160  fH->SetFillColor(fillsav);
6161  if (np) delete [] np;
6162  delete [] xarr;
6163  delete [] yarr;
6164  delete [] itarr;
6165  delete [] levels;
6166 }
6167 
6168 ////////////////////////////////////////////////////////////////////////////////
6169 /// Fill the matrix `xarr` and `yarr` for Contour Plot.
6170 
6171 Int_t THistPainter::PaintContourLine(Double_t elev1, Int_t icont1, Double_t x1, Double_t y1,
6172  Double_t elev2, Int_t icont2, Double_t x2, Double_t y2,
6173  Double_t *xarr, Double_t *yarr, Int_t *itarr, Double_t *levels)
6174 {
6175 
6176  Bool_t vert;
6177  Double_t tlen, tdif, elev, diff, pdif, xlen;
6178  Int_t n, i, icount;
6179 
6180  if (x1 == x2) {
6181  vert = kTRUE;
6182  tlen = y2 - y1;
6183  } else {
6184  vert = kFALSE;
6185  tlen = x2 - x1;
6186  }
6187 
6188  n = icont1 +1;
6189  tdif = elev2 - elev1;
6190  i = 0;
6191  icount = 0;
6192  while (n <= icont2 && i <= kMAXCONTOUR/2 -3) {
6193  //elev = fH->GetContourLevel(n);
6194  elev = levels[n];
6195  diff = elev - elev1;
6196  pdif = diff/tdif;
6197  xlen = tlen*pdif;
6198  if (vert) {
6199  if (Hoption.Logx)
6200  xarr[i] = TMath::Log10(x1);
6201  else
6202  xarr[i] = x1;
6203  if (Hoption.Logy)
6204  yarr[i] = TMath::Log10(y1 + xlen);
6205  else
6206  yarr[i] = y1 + xlen;
6207  } else {
6208  if (Hoption.Logx)
6209  xarr[i] = TMath::Log10(x1 + xlen);
6210  else
6211  xarr[i] = x1 + xlen;
6212  if (Hoption.Logy)
6213  yarr[i] = TMath::Log10(y1);
6214  else
6215  yarr[i] = y1;
6216  }
6217  itarr[i] = n;
6218  icount++;
6219  i +=2;
6220  n++;
6221  }
6222  return icount;
6223 }
6224 
6225 ////////////////////////////////////////////////////////////////////////////////
6226 /// [Draw 1D histograms error bars.](#HP09)
6227 
6228 void THistPainter::PaintErrors(Option_t *)
6229 {
6230 
6231  // On iOS, we do not highlight histogram, if it's not picked at the moment
6232  // (but part of histogram (axis or pavestat) was picked, that's why this code
6233  // is called at all. This conditional statement never executes on non-iOS platform.
6234  if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH) return;
6235 
6236  const Int_t kBASEMARKER=8;
6237  Double_t xp, yp, ex1, ex2, ey1, ey2;
6238  Double_t delta;
6239  Double_t s2x, s2y, bxsize, bysize, symbolsize, xerror, sbase;
6240  Double_t xi1, xi2, xi3, xi4, yi1, yi2, yi3, yi4;
6241  Double_t xmin, xmax, ymin, ymax;
6242  Double_t logxmin = 0;
6243  Double_t logymin = 0;
6244  Double_t offset = 0.;
6245  Double_t width = 0.;
6246  Int_t i, k, npoints, first, last, fixbin;
6247  Int_t if1 = 0;
6248  Int_t if2 = 0;
6249  Int_t drawmarker, errormarker;
6250  Int_t option0, option1, option2, option3, option4, optionE, optionEX0, optionI0;
6251 
6252  Double_t *xline = 0;
6253  Double_t *yline = 0;
6254  option0 = option1 = option2 = option3 = option4 = optionE = optionEX0 = optionI0 = 0;
6255  if (Int_t(Hoption.Error/10) == 2) {optionEX0 = 1; Hoption.Error -= 10;}
6256  if (Hoption.Error == 31) {optionEX0 = 1; Hoption.Error = 1;}
6257  if (Hoption.Error == 10) option0 = 1;
6258  if (Hoption.Error == 11) option1 = 1;
6259  if (Hoption.Error == 12) option2 = 1;
6260  if (Hoption.Error == 13) option3 = 1;
6261  if (Hoption.Error == 14) {option4 = 1; option3 = 1;}
6262  if (Hoption.Error == 15) {optionI0 = 1; option3 = 1;}
6263  if (Hoption.Error == 16) {optionI0 = 1; option4 = 1; option3 = 1;}
6264  if (option2+option3 == 0) optionE = 1;
6265  if (Hoption.Error == 0) optionE = 0;
6266  if (fXaxis->GetXbins()->fN) fixbin = 0;
6267  else fixbin = 1;
6268 
6269  offset = fH->GetBarOffset();
6270  width = fH->GetBarWidth();
6271 
6272  errormarker = fH->GetMarkerStyle();
6273  if (optionEX0) {
6274  xerror = 0;
6275  } else {
6276  xerror = gStyle->GetErrorX();
6277  }
6278  symbolsize = fH->GetMarkerSize();
6279  if (errormarker == 1) symbolsize = 0.01;
6280  sbase = symbolsize*kBASEMARKER;
6281  // set the graphics attributes
6282 
6283  fH->TAttLine::Modify();
6284  fH->TAttFill::Modify();
6285  fH->TAttMarker::Modify();
6286 
6287  // set the first and last bin
6288 
6289  Double_t factor = Hparam.factor;
6290  first = Hparam.xfirst;
6291  last = Hparam.xlast;
6292  npoints = last - first +1;
6293  xmin = gPad->GetUxmin();
6294  xmax = gPad->GetUxmax();
6295  ymin = gPad->GetUymin();
6296  ymax = gPad->GetUymax();
6297 
6298 
6299  if (option3) {
6300  xline = new Double_t[2*npoints];
6301  yline = new Double_t[2*npoints];
6302  if (!xline || !yline) {
6303  Error("PaintErrors", "too many points, out of memory");
6304  return;
6305  }
6306  if1 = 1;
6307  if2 = 2*npoints;
6308  }
6309 
6310  // compute the offset of the error bars due to the symbol size
6311  s2x = gPad->PixeltoX(Int_t(0.5*sbase)) - gPad->PixeltoX(0);
6312  s2y =-gPad->PixeltoY(Int_t(0.5*sbase)) + gPad->PixeltoY(0);
6313 
6314  // compute size of the lines at the end of the error bars
6315  Int_t dxend = Int_t(gStyle->GetEndErrorSize());
6316  bxsize = gPad->PixeltoX(dxend) - gPad->PixeltoX(0);
6317  bysize =-gPad->PixeltoY(dxend) + gPad->PixeltoY(0);
6318 
6319 
6320  if (fixbin) {
6321  if (Hoption.Logx) xp = TMath::Power(10,Hparam.xmin) + 0.5*Hparam.xbinsize;
6322  else xp = Hparam.xmin + 0.5*Hparam.xbinsize;
6323  } else {
6324  delta = fH->GetBinWidth(first);
6325  xp = fH->GetBinLowEdge(first) + 0.5*delta;
6326  }
6327 
6328  // if errormarker = 0 or symbolsize = 0. no symbol is drawn
6329  if (Hoption.Logx) logxmin = TMath::Power(10,Hparam.xmin);
6330  if (Hoption.Logy) logymin = TMath::Power(10,Hparam.ymin);
6331 
6332  // ---------------------- Loop over the points---------------------
6333  for (k=first; k<=last; k++) {
6334 
6335  // get the data
6336  // xp = X position of the current point
6337  // yp = Y position of the current point
6338  // ex1 = Low X error
6339  // ex2 = Up X error
6340  // ey1 = Low Y error
6341  // ey2 = Up Y error
6342  // (xi,yi) = Error bars coordinates
6343 
6344  // apply offset on errors for bar histograms
6345  Double_t xminTmp = gPad->XtoPad(fXaxis->GetBinLowEdge(k));
6346  Double_t xmaxTmp = gPad->XtoPad(fXaxis->GetBinUpEdge(k));
6347  Double_t w = (xmaxTmp-xminTmp)*width;
6348  xminTmp += offset*(xmaxTmp-xminTmp);
6349  xmaxTmp = xminTmp + w;
6350  xp = (xminTmp+xmaxTmp)/2.;
6351 
6352  if (Hoption.Logx) {
6353  if (xp <= 0) goto L30;
6354  if (xp < logxmin) goto L30;
6355  if (xp > TMath::Power(10,xmax)) break;
6356  } else {
6357  if (xp < xmin) goto L30;
6358  if (xp > xmax) break;
6359  }
6360  yp = factor*fH->GetBinContent(k);
6361  if (optionI0 && yp==0) goto L30;
6362  if (fixbin) {
6363  ex1 = xerror*Hparam.xbinsize;
6364  } else {
6365  delta = fH->GetBinWidth(k);
6366  ex1 = xerror*delta;
6367  }
6368  if (fH->GetBinErrorOption() == TH1::kNormal) {
6369  ey1 = factor*fH->GetBinError(k);
6370  ey2 = ey1;
6371  } else {
6372  ey1 = factor*fH->GetBinErrorLow(k);
6373  ey2 = factor*fH->GetBinErrorUp(k);
6374  }
6375  ex2 = ex1;
6376 
6377  xi4 = xp;
6378  xi3 = xp;
6379  xi2 = xp + ex2;
6380  xi1 = xp - ex1;
6381 
6382  yi1 = yp;
6383  yi2 = yp;
6384  yi3 = yp - ey1;
6385  yi4 = yp + ey2;
6386 
6387  // take the LOG if necessary
6388  if (Hoption.Logx) {
6389  xi1 = TMath::Log10(TMath::Max(xi1,logxmin));
6390  xi2 = TMath::Log10(TMath::Max(xi2,logxmin));
6391  xi3 = TMath::Log10(TMath::Max(xi3,logxmin));
6392  xi4 = TMath::Log10(TMath::Max(xi4,logxmin));
6393  }
6394  if (Hoption.Logy) {
6395  yi1 = TMath::Log10(TMath::Max(yi1,logymin));
6396  yi2 = TMath::Log10(TMath::Max(yi2,logymin));
6397  yi3 = TMath::Log10(TMath::Max(yi3,logymin));
6398  yi4 = TMath::Log10(TMath::Max(yi4,logymin));
6399  }
6400 
6401  // test if error bars are not outside the limits
6402  // otherwise they are truncated
6403 
6404  xi1 = TMath::Max(xi1,xmin);
6405  xi2 = TMath::Min(xi2,xmax);
6406  yi3 = TMath::Max(yi3,ymin);
6407  yi4 = TMath::Min(yi4,ymax);
6408 
6409  // test if the marker is on the frame limits. If "Yes", the
6410  // marker will not be drawn and the error bars will be readjusted.
6411 
6412  drawmarker = kTRUE;
6413  if (!option0 && !option3) {
6414  if (Hoption.Logy && yp < logymin) goto L30;
6415  if (yi1 < ymin || yi1 > ymax) goto L30;
6416  if (Hoption.Error != 0 && yp == 0 && ey1 <= 0) drawmarker = kFALSE;
6417  }
6418  if (!symbolsize || !errormarker) drawmarker = kFALSE;
6419 
6420  // draw the error rectangles
6421  if (option2) gPad->PaintBox(xi1,yi3,xi2,yi4);
6422 
6423  // keep points for fill area drawing
6424  if (option3) {
6425  xline[if1-1] = xi3;
6426  xline[if2-1] = xi3;
6427  yline[if1-1] = yi4;
6428  yline[if2-1] = yi3;
6429  if1++;
6430  if2--;
6431  }
6432 
6433  // draw the error bars
6434  if (Hoption.Logy && yp < logymin) drawmarker = kFALSE;
6435  if (optionE && drawmarker) {
6436  if ((yi3 < yi1 - s2y) && (yi3 < ymax)) gPad->PaintLine(xi3,yi3,xi4,TMath::Min(yi1 - s2y,ymax));
6437  if ((yi1 + s2y < yi4) && (yi4 > ymin)) gPad->PaintLine(xi3,TMath::Max(yi1 + s2y, ymin),xi4,yi4);
6438  // don't duplicate the horizontal line
6439  if (Hoption.Hist != 2) {
6440  if (yi1<ymax && yi1>ymin) {
6441  if (xi1 < xi3 - s2x) gPad->PaintLine(xi1,yi1,xi3 - s2x,yi2);
6442  if (xi3 + s2x < xi2) gPad->PaintLine(xi3 + s2x,yi1,xi2,yi2);
6443  }
6444  }
6445  }
6446  if (optionE && !drawmarker && (ey1 != 0 || ey2 !=0)) {
6447  if ((yi3 < yi1) && (yi3 < ymax)) gPad->PaintLine(xi3,yi3,xi4,TMath::Min(yi1,ymax));
6448  if ((yi1 < yi4) && (yi4 > ymin)) gPad->PaintLine(xi3,TMath::Max(yi1,ymin),xi4,yi4);
6449  // don't duplicate the horizontal line
6450  if (Hoption.Hist != 2) {
6451  if (yi1<ymax && yi1>ymin) {
6452  if (xi1 < xi3) gPad->PaintLine(xi1,yi1,xi3,yi2);
6453  if (xi3 < xi2) gPad->PaintLine(xi3,yi1,xi2,yi2);
6454  }
6455  }
6456  }
6457 
6458  // draw line at the end of the error bars
6459 
6460  if (option1 && drawmarker) {
6461  if (yi3 < yi1-s2y) gPad->PaintLine(xi3 - bxsize,yi3,xi3 + bxsize,yi3);
6462  if (yi4 > yi1+s2y) gPad->PaintLine(xi3 - bxsize,yi4,xi3 + bxsize,yi4);
6463  if (xi1 < xi3-s2x) gPad->PaintLine(xi1,yi1 - bysize,xi1,yi1 + bysize);
6464  if (xi2 > xi3+s2x) gPad->PaintLine(xi2,yi1 - bysize,xi2,yi1 + bysize);
6465  }
6466 
6467  // draw the marker
6468 
6469  if (drawmarker) gPad->PaintPolyMarker(1, &xi3, &yi1);
6470 
6471 L30:
6472  if (fixbin) xp += Hparam.xbinsize;
6473  else {
6474  if (k < last) {
6475  delta = fH->GetBinWidth(k+1);
6476  xp = fH->GetBinLowEdge(k+1) + 0.5*delta;
6477  }
6478  }
6479  } //end of for loop
6480 
6481  // draw the filled area
6482 
6483  if (option3) {
6484  TGraph graph;
6485  graph.SetLineStyle(fH->GetLineStyle());
6486  graph.SetLineColor(fH->GetLineColor());
6487  graph.SetLineWidth(fH->GetLineWidth());
6488  graph.SetFillStyle(fH->GetFillStyle());
6489  graph.SetFillColor(fH->GetFillColor());
6490  Int_t logx = gPad->GetLogx();
6491  Int_t logy = gPad->GetLogy();
6492  gPad->SetLogx(0);
6493  gPad->SetLogy(0);
6494 
6495  // In some cases the number of points in the fill area is smaller than
6496  // 2*npoints. In such cases the array xline and yline must be arranged
6497  // before being plotted. The next loop does that.
6498  if (if2 > npoints) {
6499  for (i=1; i<if1; i++) {
6500  xline[if1-2+i] = xline[if2-1+i];
6501  yline[if1-2+i] = yline[if2-1+i];
6502  }
6503  npoints = if1-1;
6504  }
6505  if (option4) graph.PaintGraph(2*npoints,xline,yline,"FC");
6506  else graph.PaintGraph(2*npoints,xline,yline,"F");
6507  gPad->SetLogx(logx);
6508  gPad->SetLogy(logy);
6509  delete [] xline;
6510  delete [] yline;
6511  }
6512 }
6513 
6514 ////////////////////////////////////////////////////////////////////////////////
6515 /// Draw 2D histograms errors.
6516 
6517 void THistPainter::Paint2DErrors(Option_t *)
6518 {
6519 
6520  fH->TAttMarker::Modify();
6521  fH->TAttLine::Modify();
6522 
6523  // Define the 3D view
6524  fXbuf[0] = Hparam.xmin;
6525  fYbuf[0] = Hparam.xmax;
6526  fXbuf[1] = Hparam.ymin;
6527  fYbuf[1] = Hparam.ymax;
6528  fXbuf[2] = Hparam.zmin;
6529  fYbuf[2] = Hparam.zmax*(1. + gStyle->GetHistTopMargin());
6530  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
6531  TView *view = gPad->GetView();
6532  if (!view) {
6533  Error("Paint2DErrors", "no TView in current pad");
6534  return;
6535  }
6536  Double_t thedeg = 90 - gPad->GetTheta();
6537  Double_t phideg = -90 - gPad->GetPhi();
6538  Double_t psideg = view->GetPsi();
6539  Int_t irep;
6540  view->SetView(phideg, thedeg, psideg, irep);
6541 
6542  // Set color/style for back box
6543  fLego->SetFillStyle(gPad->GetFrameFillStyle());
6544  fLego->SetFillColor(gPad->GetFrameFillColor());
6545  fLego->TAttFill::Modify();
6546  Int_t backcolor = gPad->GetFrameFillColor();
6547  if (Hoption.System != kCARTESIAN) backcolor = 0;
6548  view->PadRange(backcolor);
6549  fLego->SetFillStyle(fH->GetFillStyle());
6550  fLego->SetFillColor(fH->GetFillColor());
6551  fLego->TAttFill::Modify();
6552 
6553  // Paint the Back Box if needed
6554  if (Hoption.BackBox && !Hoption.Same && !Hoption.Lego && !Hoption.Surf) {
6555  fLego->InitMoveScreen(-1.1,1.1);
6556  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
6557  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
6558  fLego->BackBox(90);
6559  }
6560 
6561  // Paint the Errors
6562  Double_t x, ex, x1, x2;
6563  Double_t y, ey, y1, y2;
6564  Double_t z, ez1, ez2, z1, z2;
6565  Double_t temp1[3],temp2[3];
6566  Double_t xyerror;
6567  if (Hoption.Error == 110) {
6568  xyerror = 0;
6569  } else {
6570  xyerror = gStyle->GetErrorX();
6571  }
6572 
6573  Double_t xk, xstep, yk, ystep;
6574  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
6575  y = fYaxis->GetBinCenter(j);
6576  ey = fYaxis->GetBinWidth(j)*xyerror;
6577  y1 = y-ey;
6578  y2 = y+ey;
6579  if (Hoption.Logy) {
6580  if (y > 0) y = TMath::Log10(y);
6581  else continue;
6582  if (y1 > 0) y1 = TMath::Log10(y1);
6583  else y1 = Hparam.ymin;
6584  if (y2 > 0) y2 = TMath::Log10(y2);
6585  else y2 = Hparam.ymin;
6586  }
6587  yk = fYaxis->GetBinLowEdge(j);
6588  ystep = fYaxis->GetBinWidth(j);
6589  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
6590  xk = fXaxis->GetBinLowEdge(i);
6591  xstep = fXaxis->GetBinWidth(i);
6592  if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
6593  Int_t bin = fH->GetBin(i,j);
6594  x = fXaxis->GetBinCenter(i);
6595  ex = fXaxis->GetBinWidth(i)*xyerror;
6596  x1 = x-ex;
6597  x2 = x+ex;
6598  if (Hoption.Logx) {
6599  if (x > 0) x = TMath::Log10(x);
6600  else continue;
6601  if (x1 > 0) x1 = TMath::Log10(x1);
6602  else x1 = Hparam.xmin;
6603  if (x2 > 0) x2 = TMath::Log10(x2);
6604  else x2 = Hparam.xmin;
6605  }
6606  z = fH->GetBinContent(bin);
6607  if (fH->GetBinErrorOption() == TH1::kNormal) {
6608  ez1 = fH->GetBinError(bin);
6609  ez2 = ez1;
6610  }
6611  else {
6612  ez1 = fH->GetBinErrorLow(bin);
6613  ez2 = fH->GetBinErrorUp(bin);
6614  }
6615  z1 = z - ez1;
6616  z2 = z + ez2;
6617  if (Hoption.Logz) {
6618  if (z > 0) z = TMath::Log10(z);
6619  else z = Hparam.zmin;
6620  if (z1 > 0) z1 = TMath::Log10(z1);
6621  else z1 = Hparam.zmin;
6622  if (z2 > 0) z2 = TMath::Log10(z2);
6623  else z2 = Hparam.zmin;
6624 
6625  }
6626  if (z <= Hparam.zmin) continue;
6627  if (z > Hparam.zmax) z = Hparam.zmax;
6628 
6629  temp1[0] = x1;
6630  temp1[1] = y;
6631  temp1[2] = z;
6632  temp2[0] = x2;
6633  temp2[1] = y;
6634  temp2[2] = z;
6635  gPad->PaintLine3D(temp1, temp2);
6636  temp1[0] = x;
6637  temp1[1] = y1;
6638  temp1[2] = z;
6639  temp2[0] = x;
6640  temp2[1] = y2;
6641  temp2[2] = z;
6642  gPad->PaintLine3D(temp1, temp2);
6643  temp1[0] = x;
6644  temp1[1] = y;
6645  temp1[2] = z1;
6646  temp2[0] = x;
6647  temp2[1] = y;
6648  temp2[2] = z2;
6649  gPad->PaintLine3D(temp1, temp2);
6650  temp1[0] = x;
6651  temp1[1] = y;
6652  temp1[2] = z;
6653  view->WCtoNDC(temp1, &temp2[0]);
6654  gPad->PaintPolyMarker(1, &temp2[0], &temp2[1]);
6655  }
6656  }
6657 
6658  // Paint the Front Box if needed
6659  if (Hoption.FrontBox) {
6660  fLego->InitMoveScreen(-1.1,1.1);
6661  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
6662  fLego->FrontBox(90);
6663  }
6664 
6665  // Paint the Axis if needed
6666  if (!Hoption.Axis && !Hoption.Same && !Hoption.Lego && !Hoption.Surf) {
6667  TGaxis *axis = new TGaxis();
6668  PaintLegoAxis(axis, 90);
6669  delete axis;
6670  }
6671 
6672  delete fLego; fLego = 0;
6673 }
6674 
6675 ////////////////////////////////////////////////////////////////////////////////
6676 /// Calculate range and clear pad (canvas).
6677 
6678 void THistPainter::PaintFrame()
6679 {
6680 
6681  if (Hoption.Same) return;
6682 
6683  RecalculateRange();
6684 
6685  if (Hoption.Lego || Hoption.Surf || Hoption.Tri ||
6686  Hoption.Contour == 14 || Hoption.Error >= 100) {
6687  TObject *frame = gPad->FindObject("TFrame");
6688  if (frame) gPad->GetListOfPrimitives()->Remove(frame);
6689  return;
6690  }
6691 
6692  //The next statement is always executed on non-iOS platform,
6693  //on iOS depends on pad mode.
6694  if (!gPad->PadInSelectionMode() && !gPad->PadInHighlightMode())
6695  gPad->PaintPadFrame(Hparam.xmin,Hparam.ymin,Hparam.xmax,Hparam.ymax);
6696 }
6697 
6698 ////////////////////////////////////////////////////////////////////////////////
6699 /// [Paint functions associated to an histogram.](#HP28")
6700 
6701 void THistPainter::PaintFunction(Option_t *)
6702 {
6703 
6704  TObjOptLink *lnk = (TObjOptLink*)fFunctions->FirstLink();
6705  TObject *obj;
6706 
6707  while (lnk) {
6708  obj = lnk->GetObject();
6709  TVirtualPad *padsave = gPad;
6710  if (obj->InheritsFrom(TF2::Class())) {
6711  if (obj->TestBit(TF2::kNotDraw) == 0) {
6712  if (Hoption.Lego || Hoption.Surf || Hoption.Error >= 100) {
6713  TF2 *f2 = (TF2*)obj;
6714  f2->SetMinimum(fH->GetMinimum());
6715  f2->SetMaximum(fH->GetMaximum());
6716  f2->SetRange(fH->GetXaxis()->GetXmin(), fH->GetYaxis()->GetXmin(), fH->GetXaxis()->GetXmax(), fH->GetYaxis()->GetXmax() );
6717  f2->Paint("surf same");
6718  } else {
6719  obj->Paint("cont3 same");
6720  }
6721  }
6722  } else if (obj->InheritsFrom(TF1::Class())) {
6723  if (obj->TestBit(TF1::kNotDraw) == 0) obj->Paint("lsame");
6724  } else {
6725  //Let's make this 'function' selectable on iOS device (for example, it can be TPaveStat).
6726  gPad->PushSelectableObject(obj);
6727 
6728  //The next statement is ALWAYS executed on non-iOS platform, on iOS it depends on pad's mode
6729  //and picked object.
6730  if (!gPad->PadInHighlightMode() || (gPad->PadInHighlightMode() && obj == gPad->GetSelected()))
6731  obj->Paint(lnk->GetOption());
6732  }
6733  lnk = (TObjOptLink*)lnk->Next();
6734  padsave->cd();
6735  }
6736 }
6737 
6738 ////////////////////////////////////////////////////////////////////////////////
6739 /// [Control routine to draw 1D histograms](#HP01b)
6740 
6741 void THistPainter::PaintHist(Option_t *)
6742 {
6743 
6744  //On iOS: do not highlight hist, if part of it was selected.
6745  //Never executes on non-iOS platform.
6746  if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH)
6747  return;
6748 
6749  static char chopth[17];
6750 
6751  Int_t htype, oldhtype;
6752  Int_t i, j, first, last, nbins, fixbin;
6753  Double_t c1, yb;
6754  yb = 0;
6755 
6756  strlcpy(chopth, " ",17);
6757 
6758  Double_t ymin = Hparam.ymin;
6759  Double_t ymax = Hparam.ymax;
6760  Double_t baroffset = fH->GetBarOffset();
6761  Double_t barwidth = fH->GetBarWidth();
6762  Double_t baroffsetsave = gStyle->GetBarOffset();
6763  Double_t barwidthsave = gStyle->GetBarWidth();
6764  gStyle->SetBarOffset(baroffset);
6765  gStyle->SetBarWidth(barwidth);
6766 
6767  // Create "LIFE" structure to keep current histogram status
6768 
6769  first = Hparam.xfirst;
6770  last = Hparam.xlast;
6771  nbins = last - first + 1;
6772 
6773  Double_t *keepx = 0;
6774  Double_t *keepy = 0;
6775  if (fXaxis->GetXbins()->fN) fixbin = 0;
6776  else fixbin = 1;
6777  if (fixbin) keepx = new Double_t[2];
6778  else keepx = new Double_t[nbins+1];
6779  keepy = new Double_t[nbins];
6780  Double_t logymin = 0;
6781  if (Hoption.Logy) logymin = TMath::Power(10,ymin);
6782 
6783  // Loop on histogram bins
6784 
6785  for (j=first; j<=last;j++) {
6786  c1 = Hparam.factor*fH->GetBinContent(j);
6787  if (TMath::Abs(ymax-ymin) > 0) {
6788  if (Hoption.Logy) yb = TMath::Log10(TMath::Max(c1,.1*logymin));
6789  else yb = c1;
6790  }
6791  if (!Hoption.Line) {
6792  yb = TMath::Max(yb, ymin);
6793  yb = TMath::Min(yb, ymax);
6794  }
6795  keepy[j-first] = yb;
6796  }
6797 
6798  // Draw histogram according to value of FillStyle and FillColor
6799 
6800  if (fixbin) { keepx[0] = Hparam.xmin; keepx[1] = Hparam.xmax; }
6801  else {
6802  for (i=0; i<nbins; i++) keepx[i] = fXaxis->GetBinLowEdge(i+first);
6803  keepx[nbins] = fXaxis->GetBinUpEdge(nbins-1+first);
6804  }
6805 
6806  // Prepare Fill area (systematic with option "Bar").
6807 
6808  oldhtype = fH->GetFillStyle();
6809  htype = oldhtype;
6810  if (Hoption.Bar) {
6811  if (htype == 0 || htype == 1000) htype = 1001;
6812  }
6813 
6814  Width_t lw = (Width_t)fH->GetLineWidth();
6815 
6816  // Code option for GrapHist
6817 
6818  if (Hoption.Line) chopth[0] = 'L';
6819  if (Hoption.Star) chopth[1] = '*';
6820  if (Hoption.Mark) chopth[2] = 'P';
6821  if (Hoption.Mark == 10) chopth[3] = '0';
6822  if (Hoption.Line || Hoption.Curve || Hoption.Hist || Hoption.Bar) {
6823  if (Hoption.Curve) chopth[3] = 'C';
6824  if (Hoption.Hist > 0) chopth[4] = 'H';
6825  else if (Hoption.Bar) chopth[5] = 'B';
6826  if (fH->GetFillColor() && htype) {
6827  if (Hoption.Logy) {
6828  chopth[6] = '1';
6829  }
6830  if (Hoption.Hist > 0 || Hoption.Curve || Hoption.Line) {
6831  chopth[7] = 'F';
6832  }
6833  }
6834  }
6835  if (!fixbin && strlen(chopth)) {
6836  chopth[8] = 'N';
6837  }
6838 
6839  if (Hoption.Fill == 2) chopth[13] = '2';
6840 
6841  // Option LOGX
6842 
6843  if (Hoption.Logx) {
6844  chopth[9] = 'G';
6845  chopth[10] = 'X';
6846  if (fixbin) {
6847  keepx[0] = TMath::Power(10,keepx[0]);
6848  keepx[1] = TMath::Power(10,keepx[1]);
6849  }
6850  }
6851 
6852  if (Hoption.Off) {
6853  chopth[11] = ']';
6854  chopth[12] = '[';
6855  }
6856 
6857  // Draw the histogram
6858 
6859  TGraph graph;
6860  graph.SetLineWidth(lw);
6861  graph.SetLineStyle(fH->GetLineStyle());
6862  graph.SetLineColor(fH->GetLineColor());
6863  graph.SetFillStyle(htype);
6864  graph.SetFillColor(fH->GetFillColor());
6865  graph.SetMarkerStyle(fH->GetMarkerStyle());
6866  graph.SetMarkerSize(fH->GetMarkerSize());
6867  graph.SetMarkerColor(fH->GetMarkerColor());
6868  if (!Hoption.Same) graph.ResetBit(TGraph::kClipFrame);
6869 
6870  graph.PaintGrapHist(nbins, keepx, keepy ,chopth);
6871 
6872  delete [] keepx;
6873  delete [] keepy;
6874  gStyle->SetBarOffset(baroffsetsave);
6875  gStyle->SetBarWidth(barwidthsave);
6876 
6877  htype=oldhtype;
6878 }
6879 
6880 ////////////////////////////////////////////////////////////////////////////////
6881 /// [Control function to draw a 3D histograms.](#HP01d)
6882 
6883 void THistPainter::PaintH3(Option_t *option)
6884 {
6885 
6886  char *cmd;
6887  TString opt = option;
6888  opt.ToLower();
6889  Int_t irep;
6890 
6891  if (Hoption.Box || Hoption.Lego) {
6892  if (Hoption.Box == 11 || Hoption.Lego == 11) {
6893  PaintH3Box(1);
6894  } else if (Hoption.Box == 12 || Hoption.Lego == 12) {
6895  PaintH3Box(2);
6896  } else if (Hoption.Box == 13 || Hoption.Lego == 13) {
6897  PaintH3Box(3);
6898  } else {
6899  PaintH3BoxRaster();
6900  }
6901  return;
6902  } else if (strstr(opt,"iso")) {
6903  PaintH3Iso();
6904  return;
6905  } else if (strstr(opt,"tf3")) {
6906  PaintTF3();
6907  return;
6908  } else {
6909  cmd = Form("TPolyMarker3D::PaintH3((TH1 *)0x%lx,\"%s\");",(Long_t)fH,option);
6910  }
6911 
6912  if (strstr(opt,"fb")) Hoption.FrontBox = 0;
6913  if (strstr(opt,"bb")) Hoption.BackBox = 0;
6914 
6915  TView *view = gPad->GetView();
6916  if (!view) return;
6917  Double_t thedeg = 90 - gPad->GetTheta();
6918  Double_t phideg = -90 - gPad->GetPhi();
6919  Double_t psideg = view->GetPsi();
6920  view->SetView(phideg, thedeg, psideg, irep);
6921 
6922  // Paint the data
6923  gROOT->ProcessLine(cmd);
6924 
6925  if (Hoption.Same) return;
6926 
6927  // Draw axis
6928  view->SetOutlineToCube();
6929  TSeqCollection *ol = view->GetOutline();
6930  if (ol && Hoption.BackBox && Hoption.FrontBox) ol->Paint(option);
6931  Hoption.System = kCARTESIAN;
6932  TGaxis *axis = new TGaxis();
6933  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
6934  delete axis;
6935 
6936  // Draw palette. In case of 4D plot with TTree::Draw() the palette should
6937  // be painted with the option colz.
6938  if (fH->GetDrawOption() && strstr(opt,"colz")) {
6939  Int_t ndiv = fH->GetContour();
6940  if (ndiv == 0 ) {
6941  ndiv = gStyle->GetNumberContours();
6942  fH->SetContour(ndiv);
6943  }
6944  PaintPalette();
6945  }
6946 
6947  // Draw title
6948  PaintTitle();
6949 
6950  //Draw stats and fit results
6951  TF1 *fit = 0;
6952  TIter next(fFunctions);
6953  TObject *obj;
6954  while ((obj = next())) {
6955  if (obj->InheritsFrom(TF1::Class())) {
6956  fit = (TF1*)obj;
6957  break;
6958  }
6959  }
6960  if ((Hoption.Same%10) != 1) {
6961  if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
6962  PaintStat3(gStyle->GetOptStat(),fit);
6963  }
6964  }
6965 
6966 }
6967 
6968 ////////////////////////////////////////////////////////////////////////////////
6969 /// Compute histogram parameters used by the drawing routines.
6970 
6971 Int_t THistPainter::PaintInit()
6972 {
6973 
6974  if (fH->GetDimension() > 1 || Hoption.Lego || Hoption.Surf) return 1;
6975 
6976  Int_t i;
6977  static const char *where = "PaintInit";
6978  Double_t yMARGIN = gStyle->GetHistTopMargin();
6979  Int_t maximum = 0;
6980  Int_t minimum = 0;
6981  if (fH->GetMaximumStored() != -1111) maximum = 1;
6982  if (fH->GetMinimumStored() != -1111) minimum = 1;
6983 
6984  // Compute X axis parameters
6985 
6986  Int_t last = fXaxis->GetLast();
6987  Int_t first = fXaxis->GetFirst();
6988  Hparam.xlowedge = fXaxis->GetBinLowEdge(first);
6989  Hparam.xbinsize = fXaxis->GetBinWidth(first);
6990  Hparam.xlast = last;
6991  Hparam.xfirst = first;
6992  Hparam.xmin = Hparam.xlowedge;
6993  Hparam.xmax = fXaxis->GetBinLowEdge(last)+fXaxis->GetBinWidth(last);
6994 
6995  // if log scale in X, replace xmin,max by the log
6996  if (Hoption.Logx) {
6997  if (Hparam.xmax<=0) {
6998  Error(where, "cannot set X axis to log scale");
6999  return 0;
7000  }
7001  if (Hparam.xlowedge <=0 ) {
7002  if (Hoption.Same) {
7003  Hparam.xlowedge = TMath::Power(10, gPad->GetUxmin());
7004  } else {
7005  for (i=first; i<=last; i++) {
7006  Double_t binLow = fXaxis->GetBinLowEdge(i);
7007  if (binLow>0) {
7008  Hparam.xlowedge = binLow;
7009  break;
7010  }
7011  if (binLow == 0 && fH->GetBinContent(i) !=0) {
7012  Hparam.xlowedge = fXaxis->GetBinUpEdge(i)*0.001;
7013  break;
7014  }
7015  }
7016  if (Hparam.xlowedge<=0) {
7017  Error(where, "cannot set X axis to log scale");
7018  return 0;
7019  }
7020  }
7021  Hparam.xmin = Hparam.xlowedge;
7022  }
7023  Hparam.xfirst= fXaxis->FindFixBin(Hparam.xmin);
7024  Hparam.xlast = fXaxis->FindFixBin(Hparam.xmax);
7025  Hparam.xmin = TMath::Log10(Hparam.xmin);
7026  Hparam.xmax = TMath::Log10(Hparam.xmax);
7027  if (Hparam.xlast > last) Hparam.xlast = last;
7028  if (Hparam.xfirst < first) Hparam.xfirst = first;
7029  }
7030 
7031  // Compute Y axis parameters
7032  Double_t bigp = TMath::Power(10,32);
7033  Double_t ymax = -bigp;
7034  Double_t ymin = bigp;
7035  Double_t c1, e1;
7036  Double_t xv[1];
7037  Double_t fval;
7038  TObject *f;
7039  TF1 *f1;
7040  Double_t allchan = 0;
7041  Int_t nonNullErrors = 0;
7042  TIter next(fFunctions);
7043  for (i=first; i<=last;i++) {
7044  c1 = fH->GetBinContent(i);
7045  ymax = TMath::Max(ymax,c1);
7046  if (Hoption.Logy) {
7047  if (c1 > 0) ymin = TMath::Min(ymin,c1);
7048  } else {
7049  ymin = TMath::Min(ymin,c1);
7050  }
7051  if (Hoption.Error) {
7052  if (fH->GetBinErrorOption() == TH1::kNormal)
7053  e1 = fH->GetBinError(i);
7054  else
7055  e1 = fH->GetBinErrorUp(i);
7056  if (e1 > 0) nonNullErrors++;
7057  ymax = TMath::Max(ymax,c1+e1);
7058  if (fH->GetBinErrorOption() != TH1::kNormal)
7059  e1 = fH->GetBinErrorLow(i);
7060 
7061  if (Hoption.Logy) {
7062  if (c1-e1>0.01*TMath::Abs(c1)) ymin = TMath::Min(ymin,c1-e1);
7063  } else {
7064  ymin = TMath::Min(ymin,c1-e1);
7065  }
7066  }
7067  if (Hoption.Func) {
7068  xv[0] = fXaxis->GetBinCenter(i);
7069  while ((f = (TObject*) next())) {
7070  if (f->IsA() == TF1::Class()) {
7071  f1 = (TF1*)f;
7072  if (xv[0] < f1->GetXmin() || xv[0] > f1->GetXmax()) continue;
7073  fval = f1->Eval(xv[0],0,0);
7074  if (f1->GetMaximumStored() != -1111) fval = TMath::Min(f1->GetMaximumStored(), fval);
7075  ymax = TMath::Max(ymax,fval);
7076  if (Hoption.Logy) {
7077  if (c1 > 0 && fval > 0.3*c1) ymin = TMath::Min(ymin,fval);
7078  }
7079  }
7080  }
7081  next.Reset();
7082  }
7083  allchan += c1;
7084  }
7085  if (!nonNullErrors) {
7086  if (Hoption.Error) {
7087  if (!Hoption.Mark && !Hoption.Line && !Hoption.Star && !Hoption.Curve) Hoption.Hist = 2;
7088  Hoption.Error=0;
7089  }
7090  }
7091 
7092 
7093  // Take into account maximum , minimum
7094 
7095  if (Hoption.Logy && ymin <= 0) {
7096  if (ymax >= 1) ymin = TMath::Max(.005,ymax*1e-10);
7097  else ymin = 0.001*ymax;
7098  }
7099 
7100  Double_t xm = ymin;
7101  if (maximum) ymax = fH->GetMaximumStored();
7102  if (minimum) xm = fH->GetMinimumStored();
7103  if (Hoption.Logy && xm < 0) {
7104  Error(where, "log scale requested with a negative argument (%f)", xm);
7105  return 0;
7106  } else if (Hoption.Logy && xm>=0 && ymax==0) { // empty histogram in log scale
7107  ymin = 0.01;
7108  ymax = 10.;
7109  } else {
7110  ymin = xm;
7111  }
7112 
7113  if (ymin >= ymax) {
7114  if (Hoption.Logy) {
7115  if (ymax > 0) ymin = 0.001*ymax;
7116  else {
7117  if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", ymax);
7118  return 0;
7119  }
7120  }
7121  else {
7122  if (ymin > 0) {
7123  ymin = 0;
7124  ymax *= 2;
7125  } else if (ymin < 0) {
7126  ymax = 0;
7127  ymin *= 2;
7128  } else {
7129  ymin = 0;
7130  ymax = 1;
7131  }
7132  }
7133  }
7134 
7135  // In some cases, mainly because of precision issues, ymin and ymax could almost equal.
7136  if (TMath::AreEqualRel(ymin,ymax,1E-15)) {
7137  ymin = ymin*(1-1E-14);
7138  ymax = ymax*(1+1E-14);
7139  }
7140 
7141  // take into account normalization factor
7142  Hparam.allchan = allchan;
7143  Double_t factor = allchan;
7144  if (fH->GetNormFactor() > 0) factor = fH->GetNormFactor();
7145  if (allchan) factor /= allchan;
7146  if (factor == 0) factor = 1;
7147  Hparam.factor = factor;
7148  ymax = factor*ymax;
7149  ymin = factor*ymin;
7150  //just in case the norm factor is negative
7151  // this may happen with a positive norm factor and a negative integral !
7152  if (ymax < ymin) {
7153  Double_t temp = ymax;
7154  ymax = ymin;
7155  ymin = temp;
7156  }
7157 
7158  // For log scales, histogram coordinates are LOG10(ymin) and
7159  // LOG10(ymax). Final adjustment (if not option "Same"
7160  // or "+" for ymax) of ymax and ymin for logarithmic scale, if
7161  // Maximum and Minimum are not defined.
7162  if (Hoption.Logy) {
7163  if (ymin <=0 || ymax <=0) {
7164  Error(where, "Cannot set Y axis to log scale");
7165  return 0;
7166  }
7167  ymin = TMath::Log10(ymin);
7168  if (!minimum) ymin += TMath::Log10(0.5);
7169  ymax = TMath::Log10(ymax);
7170  if (!maximum) ymax += TMath::Log10(2*(0.9/0.95));
7171  if (!Hoption.Same) {
7172  Hparam.ymin = ymin;
7173  Hparam.ymax = ymax;
7174  }
7175  return 1;
7176  }
7177 
7178  // final adjustment of ymin for linear scale.
7179  // if minimum is not set , then ymin is set to zero if >0
7180  // or to ymin - margin if <0.
7181  if (!minimum) {
7182  if (Hoption.MinimumZero) {
7183  if (ymin >= 0) ymin = 0;
7184  else ymin -= yMARGIN*(ymax-ymin);
7185  } else {
7186  Double_t dymin = yMARGIN*(ymax-ymin);
7187  if (ymin >= 0 && (ymin-dymin <= 0)) ymin = 0;
7188  else ymin -= dymin;
7189  }
7190  }
7191 
7192  // final adjustment of YMAXI for linear scale (if not option "Same"):
7193  // decrease histogram height to MAX% of allowed height if HMAXIM
7194  // has not been called.
7195  if (!maximum) {
7196  ymax += yMARGIN*(ymax-ymin);
7197  }
7198 
7199  Hparam.ymin = ymin;
7200  Hparam.ymax = ymax;
7201  return 1;
7202 }
7203 
7204 ////////////////////////////////////////////////////////////////////////////////
7205 /// Compute histogram parameters used by the drawing routines for a rotated pad.
7206 
7207 Int_t THistPainter::PaintInitH()
7208 {
7209 
7210  static const char *where = "PaintInitH";
7211  Double_t yMARGIN = gStyle->GetHistTopMargin();
7212  Int_t maximum = 0;
7213  Int_t minimum = 0;
7214  if (fH->GetMaximumStored() != -1111) maximum = 1;
7215  if (fH->GetMinimumStored() != -1111) minimum = 1;
7216 
7217  // Compute X axis parameters
7218 
7219  Int_t last = fXaxis->GetLast();
7220  Int_t first = fXaxis->GetFirst();
7221  Hparam.xlowedge = fXaxis->GetBinLowEdge(first);
7222  Hparam.xbinsize = fXaxis->GetBinWidth(first);
7223  Hparam.xlast = last;
7224  Hparam.xfirst = first;
7225  Hparam.ymin = Hparam.xlowedge;
7226  Hparam.ymax = fXaxis->GetBinLowEdge(last)+fXaxis->GetBinWidth(last);
7227 
7228  // if log scale in Y, replace ymin,max by the log
7229  if (Hoption.Logy) {
7230  if (Hparam.xlowedge <=0 ) {
7231  Hparam.xlowedge = 0.1*Hparam.xbinsize;
7232  Hparam.ymin = Hparam.xlowedge;
7233  }
7234  if (Hparam.ymin <=0 || Hparam.ymax <=0) {
7235  Error(where, "cannot set Y axis to log scale");
7236  return 0;
7237  }
7238  Hparam.xfirst= fXaxis->FindFixBin(Hparam.ymin);
7239  Hparam.xlast = fXaxis->FindFixBin(Hparam.ymax);
7240  Hparam.ymin = TMath::Log10(Hparam.ymin);
7241  Hparam.ymax = TMath::Log10(Hparam.ymax);
7242  if (Hparam.xlast > last) Hparam.xlast = last;
7243  }
7244 
7245  // Compute Y axis parameters
7246  Double_t bigp = TMath::Power(10,32);
7247  Double_t xmax = -bigp;
7248  Double_t xmin = bigp;
7249  Double_t c1, e1;
7250  Double_t xv[1];
7251  Double_t fval;
7252  Int_t i;
7253  TObject *f;
7254  TF1 *f1;
7255  Double_t allchan = 0;
7256  TIter next(fFunctions);
7257  for (i=first; i<=last;i++) {
7258  c1 = fH->GetBinContent(i);
7259  xmax = TMath::Max(xmax,c1);
7260  xmin = TMath::Min(xmin,c1);
7261  if (Hoption.Error) {
7262  e1 = fH->GetBinError(i);
7263  xmax = TMath::Max(xmax,c1+e1);
7264  xmin = TMath::Min(xmin,c1-e1);
7265  }
7266  if (Hoption.Func) {
7267  xv[0] = fXaxis->GetBinCenter(i);
7268  while ((f = (TObject*) next())) {
7269  if (f->IsA() == TF1::Class()) {
7270  f1 = (TF1*)f;
7271  if (xv[0] < f1->GetXmin() || xv[0] > f1->GetXmax()) continue;
7272  fval = f1->Eval(xv[0],0,0);
7273  xmax = TMath::Max(xmax,fval);
7274  if (Hoption.Logy) {
7275  if (fval > 0.3*c1) xmin = TMath::Min(xmin,fval);
7276  }
7277  }
7278  }
7279  next.Reset();
7280  }
7281  allchan += c1;
7282  }
7283 
7284  // Take into account maximum , minimum
7285 
7286  if (Hoption.Logx && xmin <= 0) {
7287  if (xmax >= 1) xmin = TMath::Max(.5,xmax*1e-10);
7288  else xmin = 0.001*xmax;
7289  }
7290  Double_t xm = xmin;
7291  if (maximum) xmax = fH->GetMaximumStored();
7292  if (minimum) xm = fH->GetMinimumStored();
7293  if (Hoption.Logx && xm <= 0) {
7294  Error(where, "log scale requested with zero or negative argument (%f)", xm);
7295  return 0;
7296  }
7297  else xmin = xm;
7298  if (xmin >= xmax) {
7299  if (Hoption.Logx) {
7300  if (xmax > 0) xmin = 0.001*xmax;
7301  else {
7302  if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", xmax);
7303  return 0;
7304  }
7305  }
7306  else {
7307  if (xmin > 0) {
7308  xmin = 0;
7309  xmax *= 2;
7310  } else if (xmin < 0) {
7311  xmax = 0;
7312  xmin *= 2;
7313  } else {
7314  xmin = -1;
7315  xmax = 1;
7316  }
7317  }
7318  }
7319 
7320  // take into account normalization factor
7321  Hparam.allchan = allchan;
7322  Double_t factor = allchan;
7323  if (fH->GetNormFactor() > 0) factor = fH->GetNormFactor();
7324  if (allchan) factor /= allchan;
7325  if (factor == 0) factor = 1;
7326  Hparam.factor = factor;
7327  xmax = factor*xmax;
7328  xmin = factor*xmin;
7329 
7330  // For log scales, histogram coordinates are LOG10(ymin) and
7331  // LOG10(ymax). Final adjustment (if not option "Same"
7332  // or "+" for ymax) of ymax and ymin for logarithmic scale, if
7333  // Maximum and Minimum are not defined.
7334  if (Hoption.Logx) {
7335  if (xmin <=0 || xmax <=0) {
7336  Error(where, "Cannot set Y axis to log scale");
7337  return 0;
7338  }
7339  xmin = TMath::Log10(xmin);
7340  if (!minimum) xmin += TMath::Log10(0.5);
7341  xmax = TMath::Log10(xmax);
7342  if (!maximum) xmax += TMath::Log10(2*(0.9/0.95));
7343  if (!Hoption.Same) {
7344  Hparam.xmin = xmin;
7345  Hparam.xmax = xmax;
7346  }
7347  return 1;
7348  }
7349 
7350  // final adjustment of ymin for linear scale.
7351  // if minimum is not set , then ymin is set to zero if >0
7352  // or to ymin - margin if <0.
7353  if (!minimum) {
7354  if (xmin >= 0) xmin = 0;
7355  else xmin -= yMARGIN*(xmax-xmin);
7356  }
7357 
7358  // final adjustment of YMAXI for linear scale (if not option "Same"):
7359  // decrease histogram height to MAX% of allowed height if HMAXIM
7360  // has not been called.
7361  if (!maximum) {
7362  xmax += yMARGIN*(xmax-xmin);
7363  }
7364  Hparam.xmin = xmin;
7365  Hparam.xmax = xmax;
7366  return 1;
7367 }
7368 
7369 ////////////////////////////////////////////////////////////////////////////////
7370 /// [Control function to draw a 3D histogram with boxes.](#HP25)
7371 
7372 void THistPainter::PaintH3Box(Int_t iopt)
7373 {
7374  // Predefined box structure
7375  Double_t wxyz[8][3] = { {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1},
7376  {-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1} };
7377  Int_t iface[6][4] = { {0,3,2,1}, {4,5,6,7},
7378  {0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7} };
7379 
7380  // Define dimensions of world space
7381  TGaxis *axis = new TGaxis();
7382  TAxis *xaxis = fH->GetXaxis();
7383  TAxis *yaxis = fH->GetYaxis();
7384  TAxis *zaxis = fH->GetZaxis();
7385 
7386  fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
7387  fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
7388  fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
7389  fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
7390  fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
7391  fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
7392 
7393  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
7394 
7395  // Set view
7396  TView *view = gPad->GetView();
7397  if (!view) {
7398  Error("PaintH3", "no TView in current pad");
7399  return;
7400  }
7401  Double_t thedeg = 90 - gPad->GetTheta();
7402  Double_t phideg = -90 - gPad->GetPhi();
7403  Double_t psideg = view->GetPsi();
7404  Int_t irep;
7405  view->SetView(phideg, thedeg, psideg, irep);
7406 
7407  Int_t backcolor = gPad->GetFrameFillColor();
7408  view->PadRange(backcolor);
7409 
7410  // Draw back surfaces of frame box
7411  fLego->InitMoveScreen(-1.1,1.1);
7412  if (Hoption.BackBox) {
7413  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
7414  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
7415  fLego->BackBox(90);
7416  }
7417 
7418  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode1);
7419 
7420  // Define order of drawing
7421  Double_t *tnorm = view->GetTnorm();
7422  if (!tnorm) return;
7423  Int_t incrx = (tnorm[ 8] < 0.) ? -1 : +1;
7424  Int_t incry = (tnorm[ 9] < 0.) ? -1 : +1;
7425  Int_t incrz = (tnorm[10] < 0.) ? -1 : +1;
7426  Int_t ix1 = (incrx == +1) ? xaxis->GetFirst() : xaxis->GetLast();
7427  Int_t iy1 = (incry == +1) ? yaxis->GetFirst() : yaxis->GetLast();
7428  Int_t iz1 = (incrz == +1) ? zaxis->GetFirst() : zaxis->GetLast();
7429  Int_t ix2 = (incrx == +1) ? xaxis->GetLast() : xaxis->GetFirst();
7430  Int_t iy2 = (incry == +1) ? yaxis->GetLast() : yaxis->GetFirst();
7431  Int_t iz2 = (incrz == +1) ? zaxis->GetLast() : zaxis->GetFirst();
7432 
7433  // Set graphic attributes (colour, style, etc.)
7434  Style_t fillsav = fH->GetFillStyle();
7435  Style_t colsav = fH->GetFillColor();
7436  Style_t coldark = TColor::GetColorDark(colsav);
7437  Style_t colbright = TColor::GetColorBright(colsav);
7438 
7439  fH->SetFillStyle(1001);
7440  fH->TAttFill::Modify();
7441  fH->TAttLine::Modify();
7442  Int_t ncolors = gStyle->GetNumberOfColors();
7443  Int_t theColor;
7444 
7445  // Create bin boxes and draw
7446  Double_t wmin = TMath::Max(fH->GetMinimum(),0.);
7447  Double_t wmax = TMath::Max(TMath::Abs(fH->GetMaximum()),
7448  TMath::Abs(fH->GetMinimum()));
7449 
7450  Double_t pmin[3], pmax[3], sxyz[8][3];
7451  for (Int_t ix = ix1; ix !=ix2+incrx; ix += incrx) {
7452  pmin[0] = xaxis->GetBinLowEdge(ix);
7453  pmax[0] = xaxis->GetBinUpEdge(ix);
7454  for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
7455  pmin[1] = yaxis->GetBinLowEdge(iy);
7456  pmax[1] = yaxis->GetBinUpEdge(iy);
7457  for (Int_t iz = iz1; iz != iz2+incrz; iz += incrz) {
7458  pmin[2] = zaxis->GetBinLowEdge(iz);
7459  pmax[2] = zaxis->GetBinUpEdge(iz);
7460  Double_t w = fH->GetBinContent(fH->GetBin(ix,iy,iz));
7461  Bool_t neg = kFALSE;
7462  Int_t n = 5;
7463  if (w<0) {
7464  w = -w;
7465  neg = kTRUE;
7466  }
7467  if (w < wmin) continue;
7468  if (w > wmax) w = wmax;
7469  Double_t scale = (TMath::Power((w-wmin)/(wmax-wmin),1./3.))/2.;
7470  if (scale == 0) continue;
7471  for (Int_t i=0; i<3; ++i) {
7472  Double_t c = (pmax[i] + pmin[i])*0.5;
7473  Double_t d = (pmax[i] - pmin[i])*scale;
7474  for (Int_t k=0; k<8; ++k) { // set bin box vertices
7475  sxyz[k][i] = wxyz[k][i]*d + c;
7476  }
7477  }
7478  for (Int_t k=0; k<8; ++k) { // transform to normalized space
7479  view->WCtoNDC(&sxyz[k][0],&sxyz[k][0]);
7480  }
7481  Double_t x[8], y[8]; // draw bin box faces
7482  for (Int_t k=0; k<6; ++k) {
7483  for (Int_t i=0; i<4; ++i) {
7484  Int_t iv = iface[k][i];
7485  x[i] = sxyz[iv][0];
7486  y[i] = sxyz[iv][1];
7487  }
7488  x[4] = x[0] ; y[4] = y[0];
7489  if (neg) {
7490  x[5] = x[2] ; y[5] = y[2];
7491  x[6] = x[3] ; y[6] = y[3];
7492  x[7] = x[1] ; y[7] = y[1];
7493  n = 8;
7494  } else {
7495  n = 5;
7496  }
7497  Double_t z = (x[2]-x[0])*(y[3]-y[1]) - (y[2]-y[0])*(x[3]-x[1]);
7498  if (z <= 0.) continue;
7499  if (iopt == 2) {
7500  theColor = ncolors*((w-wmin)/(wmax-wmin)) -1;
7501  fH->SetFillColor(gStyle->GetColorPalette(theColor));
7502  } else {
7503  if (k == 3 || k == 5) {
7504  fH->SetFillColor(coldark);
7505  } else if (k == 0 || k == 1) {
7506  fH->SetFillColor(colbright);
7507  } else {
7508  fH->SetFillColor(colsav);
7509  }
7510  }
7511  fH->TAttFill::Modify();
7512  gPad->PaintFillArea(4, x, y);
7513  if (iopt != 3)gPad->PaintPolyLine(n, x, y);
7514  }
7515  }
7516  }
7517  }
7518 
7519  // Draw front surfaces of frame box
7520  if (Hoption.FrontBox) fLego->FrontBox(90);
7521 
7522  // Draw axis and title
7523  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
7524  PaintTitle();
7525 
7526  // Draw palette. if needed.
7527  if (Hoption.Zscale) {
7528  Int_t ndiv = fH->GetContour();
7529  if (ndiv == 0 ) {
7530  ndiv = gStyle->GetNumberContours();
7531  fH->SetContour(ndiv);
7532  }
7533  PaintPalette();
7534  }
7535 
7536  delete axis;
7537  delete fLego; fLego = 0;
7538 
7539  fH->SetFillStyle(fillsav);
7540  fH->SetFillColor(colsav);
7541  fH->TAttFill::Modify();
7542 }
7543 
7544 ////////////////////////////////////////////////////////////////////////////////
7545 /// [Control function to draw a 3D histogram with boxes.](#HP25)
7546 
7547 void THistPainter::PaintH3BoxRaster()
7548 {
7549  // Predefined box structure
7550  Double_t wxyz[8][3] = {
7551  {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1}, // bottom vertices
7552  {-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1} // top vertices
7553  };
7554  Int_t iface[6][4] = {
7555  {0,3,2,1}, {4,5,6,7}, // bottom and top faces
7556  {0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7} // side faces
7557  };
7558  Double_t normal[6][3] = {
7559  {0,0,-1}, {0,0,1}, // Z-, Z+
7560  {0,-1,0}, {1,0,0}, {0,1,0}, {-1,0,0} // Y-, X+, Y+, X-
7561  };
7562 
7563  // Define dimensions of world space
7564  TGaxis *axis = new TGaxis();
7565  TAxis *xaxis = fH->GetXaxis();
7566  TAxis *yaxis = fH->GetYaxis();
7567  TAxis *zaxis = fH->GetZaxis();
7568 
7569  fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
7570  fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
7571  fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
7572  fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
7573  fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
7574  fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
7575 
7576  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
7577 
7578  // Set view
7579  TView *view = gPad->GetView();
7580  if (!view) {
7581  Error("PaintH3", "no TView in current pad");
7582  return;
7583  }
7584  Double_t thedeg = 90 - gPad->GetTheta();
7585  Double_t phideg = -90 - gPad->GetPhi();
7586  Double_t psideg = view->GetPsi();
7587  Int_t irep;
7588  view->SetView(phideg, thedeg, psideg, irep);
7589 
7590  Int_t backcolor = gPad->GetFrameFillColor();
7591  view->PadRange(backcolor);
7592 
7593  // Draw front surfaces of frame box
7594  if (Hoption.FrontBox) {
7595  fLego->InitMoveScreen(-1.1,1.1);
7596  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
7597  }
7598 
7599  // Initialize hidden line removal algorithm "raster screen"
7600  fLego->InitRaster(-1.1,-1.1,1.1,1.1,1000,800);
7601 
7602  // Define order of drawing
7603  Double_t *tnorm = view->GetTnorm();
7604  if (!tnorm) return;
7605  Int_t incrx = (tnorm[ 8] < 0.) ? +1 : -1;
7606  Int_t incry = (tnorm[ 9] < 0.) ? +1 : -1;
7607  Int_t incrz = (tnorm[10] < 0.) ? +1 : -1;
7608  Int_t ix1 = (incrx == +1) ? xaxis->GetFirst() : xaxis->GetLast();
7609  Int_t iy1 = (incry == +1) ? yaxis->GetFirst() : yaxis->GetLast();
7610  Int_t iz1 = (incrz == +1) ? zaxis->GetFirst() : zaxis->GetLast();
7611  Int_t ix2 = (incrx == +1) ? xaxis->GetLast() : xaxis->GetFirst();
7612  Int_t iy2 = (incry == +1) ? yaxis->GetLast() : yaxis->GetFirst();
7613  Int_t iz2 = (incrz == +1) ? zaxis->GetLast() : zaxis->GetFirst();
7614 
7615  // Set line attributes (colour, style, etc.)
7616  fH->TAttLine::Modify();
7617 
7618  // Create bin boxes and draw
7619  const Int_t NTMAX = 100;
7620  Double_t tt[NTMAX][2];
7621  Double_t wmin = TMath::Max(fH->GetMinimum(),0.);
7622  Double_t wmax = TMath::Max(TMath::Abs(fH->GetMaximum()),
7623  TMath::Abs(fH->GetMinimum()));
7624  Double_t pmin[3], pmax[3], sxyz[8][3], pp[4][2];
7625  for (Int_t ix = ix1; ix !=ix2+incrx; ix += incrx) {
7626  pmin[0] = xaxis->GetBinLowEdge(ix);
7627  pmax[0] = xaxis->GetBinUpEdge(ix);
7628  for (Int_t iy = iy1; iy != iy2+incry; iy += incry) {
7629  pmin[1] = yaxis->GetBinLowEdge(iy);
7630  pmax[1] = yaxis->GetBinUpEdge(iy);
7631  for (Int_t iz = iz1; iz != iz2+incrz; iz += incrz) {
7632  pmin[2] = zaxis->GetBinLowEdge(iz);
7633  pmax[2] = zaxis->GetBinUpEdge(iz);
7634  Double_t w = fH->GetBinContent(fH->GetBin(ix,iy,iz));
7635  Bool_t neg = kFALSE;
7636  if (w<0) {
7637  w = -w;
7638  neg = kTRUE;
7639  }
7640  if (w < wmin) continue;
7641  if (w > wmax) w = wmax;
7642  Double_t scale = (TMath::Power((w-wmin)/(wmax-wmin),1./3.))/2.;
7643  if (scale == 0) continue;
7644  for (Int_t i=0; i<3; ++i) {
7645  Double_t c = (pmax[i] + pmin[i])*0.5;
7646  Double_t d = (pmax[i] - pmin[i])*scale;
7647  for (Int_t k=0; k<8; ++k) { // set bin box vertices
7648  sxyz[k][i] = wxyz[k][i]*d + c;
7649  }
7650  }
7651  for (Int_t k=0; k<8; ++k) { // transform to normalized space
7652  view->WCtoNDC(&sxyz[k][0],&sxyz[k][0]);
7653  }
7654  for (Int_t k=0; k<6; ++k) { // draw box faces
7655  Double_t zn;
7656  view->FindNormal(normal[k][0], normal[k][1], normal[k][2], zn);
7657  if (zn <= 0) continue;
7658  for (Int_t i=0; i<4; ++i) {
7659  Int_t ip = iface[k][i];
7660  pp[i][0] = sxyz[ip][0];
7661  pp[i][1] = sxyz[ip][1];
7662  }
7663  for (Int_t i=0; i<4; ++i) {
7664  Int_t i1 = i;
7665  Int_t i2 = (i == 3) ? 0 : i + 1;
7666  Int_t nt;
7667  fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
7668  Double_t xdel = pp[i2][0] - pp[i1][0];
7669  Double_t ydel = pp[i2][1] - pp[i1][1];
7670  Double_t x[2], y[2];
7671  for (Int_t it = 0; it < nt; ++it) {
7672  x[0] = pp[i1][0] + xdel*tt[it][0];
7673  y[0] = pp[i1][1] + ydel*tt[it][0];
7674  x[1] = pp[i1][0] + xdel*tt[it][1];
7675  y[1] = pp[i1][1] + ydel*tt[it][1];
7676  gPad->PaintPolyLine(2, x, y);
7677  }
7678  }
7679  if (neg) {
7680  Int_t i1 = 0;
7681  Int_t i2 = 2;
7682  Int_t nt;
7683  fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
7684  Double_t xdel = pp[i2][0] - pp[i1][0];
7685  Double_t ydel = pp[i2][1] - pp[i1][1];
7686  Double_t x[2], y[2];
7687  for (Int_t it = 0; it < nt; ++it) {
7688  x[0] = pp[i1][0] + xdel*tt[it][0];
7689  y[0] = pp[i1][1] + ydel*tt[it][0];
7690  x[1] = pp[i1][0] + xdel*tt[it][1];
7691  y[1] = pp[i1][1] + ydel*tt[it][1];
7692  gPad->PaintPolyLine(2, x, y);
7693  }
7694  i1 = 1;
7695  i2 = 3;
7696  fLego->FindVisibleLine(&pp[i1][0], &pp[i2][0], NTMAX, nt, &tt[0][0]);
7697  xdel = pp[i2][0] - pp[i1][0];
7698  ydel = pp[i2][1] - pp[i1][1];
7699  for (Int_t it = 0; it < nt; ++it) {
7700  x[0] = pp[i1][0] + xdel*tt[it][0];
7701  y[0] = pp[i1][1] + ydel*tt[it][0];
7702  x[1] = pp[i1][0] + xdel*tt[it][1];
7703  y[1] = pp[i1][1] + ydel*tt[it][1];
7704  gPad->PaintPolyLine(2, x, y);
7705  }
7706  }
7707  fLego->FillPolygonBorder(4, &pp[0][0]); // update raster screen
7708  }
7709  }
7710  }
7711  }
7712 
7713  // Draw frame box
7714  if (Hoption.BackBox) {
7715  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
7716  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceRaster1);
7717  fLego->BackBox(90);
7718  }
7719 
7720  if (Hoption.FrontBox) fLego->FrontBox(90);
7721 
7722  // Draw axis and title
7723  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
7724  PaintTitle();
7725 
7726  delete axis;
7727  delete fLego; fLego = 0;
7728 }
7729 
7730 ////////////////////////////////////////////////////////////////////////////////
7731 /// [Control function to draw a 3D histogram with Iso Surfaces.](#HP25)
7732 
7733 void THistPainter::PaintH3Iso()
7734 {
7735 
7736  const Double_t ydiff = 1;
7737  const Double_t yligh1 = 10;
7738  const Double_t qa = 0.15;
7739  const Double_t qd = 0.15;
7740  const Double_t qs = 0.8;
7741  Double_t fmin, fmax;
7742  Int_t i, irep;
7743  Int_t nbcol = 28;
7744  Int_t icol1 = 201;
7745  Int_t ic1 = icol1;
7746  Int_t ic2 = ic1+nbcol;
7747  Int_t ic3 = ic2+nbcol;
7748 
7749  TGaxis *axis = new TGaxis();
7750  TAxis *xaxis = fH->GetXaxis();
7751  TAxis *yaxis = fH->GetYaxis();
7752  TAxis *zaxis = fH->GetZaxis();
7753 
7754  Int_t nx = fH->GetNbinsX();
7755  Int_t ny = fH->GetNbinsY();
7756  Int_t nz = fH->GetNbinsZ();
7757 
7758  Double_t *x = new Double_t[nx];
7759  Double_t *y = new Double_t[ny];
7760  Double_t *z = new Double_t[nz];
7761 
7762  for (i=0; i<nx; i++) x[i] = xaxis->GetBinCenter(i+1);
7763  for (i=0; i<ny; i++) y[i] = yaxis->GetBinCenter(i+1);
7764  for (i=0; i<nz; i++) z[i] = zaxis->GetBinCenter(i+1);
7765 
7766  fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
7767  fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
7768  fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
7769  fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
7770  fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
7771  fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
7772 
7773  Double_t s[3];
7774  s[0] = fH->GetSumOfWeights()/(fH->GetNbinsX()*fH->GetNbinsY()*fH->GetNbinsZ());
7775  s[1] = 0.5*s[0];
7776  s[2] = 1.5*s[0];
7777 
7778  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
7779 
7780  TView *view = gPad->GetView();
7781  if (!view) {
7782  Error("PaintH3Iso", "no TView in current pad");
7783  delete [] x;
7784  delete [] y;
7785  delete [] z;
7786  return;
7787  }
7788  Double_t thedeg = 90 - gPad->GetTheta();
7789  Double_t phideg = -90 - gPad->GetPhi();
7790  Double_t psideg = view->GetPsi();
7791  view->SetView(phideg, thedeg, psideg, irep);
7792 
7793  Int_t backcolor = gPad->GetFrameFillColor();
7794  if (Hoption.System != kCARTESIAN) backcolor = 0;
7795  view->PadRange(backcolor);
7796 
7797  Double_t dcol = 0.5/Double_t(nbcol);
7798  TColor *colref = gROOT->GetColor(fH->GetFillColor());
7799  if (!colref) {
7800  delete [] x;
7801  delete [] y;
7802  delete [] z;
7803  return;
7804  }
7805  Float_t r, g, b, hue, light, satur;
7806  colref->GetRGB(r,g,b);
7807  TColor::RGBtoHLS(r,g,b,hue,light,satur);
7808  TColor *acol;
7809  for (Int_t col=0;col<nbcol;col++) {
7810  acol = gROOT->GetColor(col+icol1);
7811  TColor::HLStoRGB(hue, .4+col*dcol, satur, r, g, b);
7812  if (acol) acol->SetRGB(r, g, b);
7813  }
7814 
7815  fLego->InitMoveScreen(-1.1,1.1);
7816 
7817  if (Hoption.BackBox) {
7818  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
7819  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
7820  fLego->BackBox(90);
7821  }
7822 
7823  fLego->LightSource(0, ydiff, 0, 0, 0, irep);
7824  fLego->LightSource(1, yligh1, 1, 1, 1, irep);
7825  fLego->SurfaceProperty(qa, qd, qs, 1, irep);
7826  fmin = ydiff*qa;
7827  fmax = ydiff*qa + (yligh1+0.1)*(qd+qs);
7828  fLego->SetIsoSurfaceParameters(fmin, fmax, nbcol, ic1, ic2, ic3);
7829 
7830  fLego->IsoSurface(1, s, nx, ny, nz, x, y, z, "BF");
7831 
7832  if (Hoption.FrontBox) {
7833  fLego->InitMoveScreen(-1.1,1.1);
7834  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
7835  fLego->FrontBox(90);
7836  }
7837  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
7838 
7839  PaintTitle();
7840 
7841  delete axis;
7842  delete fLego; fLego = 0;
7843  delete [] x;
7844  delete [] y;
7845  delete [] z;
7846 }
7847 
7848 ////////////////////////////////////////////////////////////////////////////////
7849 /// [Control function to draw a 2D histogram as a lego plot.](#HP17)
7850 
7851 void THistPainter::PaintLego(Option_t *)
7852 {
7853 
7854  Int_t raster = 1;
7855  if (Hparam.zmin == 0 && Hparam.zmax == 0) {Hparam.zmin = -1; Hparam.zmax = 1;}
7856  Int_t nx = Hparam.xlast - Hparam.xfirst + 1;
7857  Int_t ny = Hparam.ylast - Hparam.yfirst + 1;
7858  Double_t zmin = Hparam.zmin;
7859  Double_t zmax = Hparam.zmax;
7860  Double_t xlab1 = Hparam.xmin;
7861  Double_t xlab2 = Hparam.xmax;
7862  Double_t ylab1 = Hparam.ymin;
7863  Double_t ylab2 = Hparam.ymax;
7864  Double_t dangle = 10*3.141592/180; //Delta angle for Rapidity option
7865  Double_t deltaz = TMath::Abs(zmin);
7866  if (deltaz == 0) deltaz = 1;
7867  if (zmin >= zmax) {
7868  zmin -= 0.5*deltaz;
7869  zmax += 0.5*deltaz;
7870  }
7871  Double_t z1c = zmin;
7872  Double_t z2c = zmin + (zmax-zmin)*(1+gStyle->GetHistTopMargin());
7873 
7874  // Compute the lego limits and instantiate a lego object
7875  fXbuf[0] = -1;
7876  fYbuf[0] = 1;
7877  fXbuf[1] = -1;
7878  fYbuf[1] = 1;
7879  if (Hoption.System == kPOLAR) {
7880  fXbuf[2] = z1c;
7881  fYbuf[2] = z2c;
7882  } else if (Hoption.System == kCYLINDRICAL) {
7883  if (Hoption.Logy) {
7884  if (ylab1 > 0) fXbuf[2] = TMath::Log10(ylab1);
7885  else fXbuf[2] = 0;
7886  if (ylab2 > 0) fYbuf[2] = TMath::Log10(ylab2);
7887  else fYbuf[2] = 0;
7888  } else {
7889  fXbuf[2] = ylab1;
7890  fYbuf[2] = ylab2;
7891  }
7892  z1c = 0; z2c = 1;
7893  } else if (Hoption.System == kSPHERICAL) {
7894  fXbuf[2] = -1;
7895  fYbuf[2] = 1;
7896  z1c = 0; z2c = 1;
7897  } else if (Hoption.System == kRAPIDITY) {
7898  fXbuf[2] = -1/TMath::Tan(dangle);
7899  fYbuf[2] = 1/TMath::Tan(dangle);
7900  } else {
7901  fXbuf[0] = xlab1;
7902  fYbuf[0] = xlab2;
7903  fXbuf[1] = ylab1;
7904  fYbuf[1] = ylab2;
7905  fXbuf[2] = z1c;
7906  fYbuf[2] = z2c;
7907  raster = 0;
7908  }
7909 
7910  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf, Hoption.System);
7911 
7912  Int_t nids = -1;
7913  TH1 * hid = NULL;
7914  Color_t colormain = -1, colordark = -1;
7915  Bool_t drawShadowsInLego1 = kTRUE;
7916 
7917  // LEGO3 is like LEGO1 except that the black lines around each lego are not drawn.
7918  if (Hoption.Lego == 13) {
7919  Hoption.Lego = 11;
7920  fLego->SetMesh(0);
7921  }
7922  // LEGO4 is like LEGO1 except no shadows are drawn.
7923  if (Hoption.Lego == 14) {
7924  Hoption.Lego = 11;
7925  drawShadowsInLego1 = kFALSE;
7926  }
7927 
7928  // Create axis object
7929 
7930  TGaxis *axis = new TGaxis();
7931 
7932  // Initialize the levels on the Z axis
7933  Int_t ndiv = fH->GetContour();
7934  if (ndiv == 0 ) {
7935  ndiv = gStyle->GetNumberContours();
7936  fH->SetContour(ndiv);
7937  }
7938  Int_t ndivz = TMath::Abs(ndiv);
7939  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ndiv);
7940 
7941  // Initialize colors
7942  if (!fStack) {
7943  fLego->SetEdgeAtt(fH->GetLineColor(),fH->GetLineStyle(),fH->GetLineWidth(),0);
7944  } else {
7945  for (Int_t id=0;id<=fStack->GetSize();id++) {
7946  hid = (TH1*)fStack->At((id==0)?id:id-1);
7947  fLego->SetEdgeAtt(hid->GetLineColor(),hid->GetLineStyle(),hid->GetLineWidth(),id);
7948  }
7949  }
7950 
7951  if (Hoption.Lego == 11) {
7952  nids = 1;
7953  if (fStack) nids = fStack->GetSize();
7954  hid = fH;
7955  for (Int_t id=0;id<=nids;id++) {
7956  if (id > 0 && fStack) hid = (TH1*)fStack->At(id-1);
7957  colormain = hid->GetFillColor();
7958  if (colormain == 1) colormain = 17; //avoid drawing with black
7959  if (drawShadowsInLego1) colordark = TColor::GetColorDark(colormain);
7960  else colordark = colormain;
7961  fLego->SetColorMain(colormain,id);
7962  fLego->SetColorDark(colordark,id);
7963  if (id <= 1) fLego->SetColorMain(colormain,-1); // Set Bottom color
7964  if (id == nids) fLego->SetColorMain(colormain,99); // Set Top color
7965  }
7966  }
7967 
7968  // Now ready to draw the lego plot
7969  Int_t irep = 0;
7970 
7971  TView *view = gPad->GetView();
7972  if (!view) {
7973  Error("PaintLego", "no TView in current pad");
7974  return;
7975  }
7976 
7977  Double_t thedeg = 90 - gPad->GetTheta();
7978  Double_t phideg = -90 - gPad->GetPhi();
7979  Double_t psideg = view->GetPsi();
7980  view->SetView(phideg, thedeg, psideg, irep);
7981 
7982  fLego->SetLineColor(kBlack); // zgrid color for lego1 & lego2
7983  fLego->SetFillStyle(fH->GetFillStyle());
7984 
7985  // Set color/style for back box
7986  fLego->SetFillStyle(gPad->GetFrameFillStyle());
7987  fLego->SetFillColor(gPad->GetFrameFillColor());
7988  fLego->TAttFill::Modify();
7989 
7990  Int_t backcolor = gPad->GetFrameFillColor();
7991  if (Hoption.System != kCARTESIAN) backcolor = 0;
7992  view->PadRange(backcolor);
7993 
7994  fLego->SetFillStyle(fH->GetFillStyle());
7995  fLego->SetFillColor(fH->GetFillColor());
7996  fLego->TAttFill::Modify();
7997 
7998  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
7999 
8000  if (raster) fLego->InitRaster(-1.1,-1.1,1.1,1.1,1000,800);
8001  else fLego->InitMoveScreen(-1.1,1.1);
8002 
8003  if (Hoption.Lego == 19) {
8004  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
8005  if (Hoption.BackBox) fLego->BackBox(90);
8006  if (Hoption.FrontBox) fLego->FrontBox(90);
8007  if (!Hoption.Axis) PaintLegoAxis(axis, 90);
8008  return;
8009  }
8010 
8011  if (Hoption.Lego == 11 || Hoption.Lego == 12) {
8012  if (Hoption.System == kCARTESIAN && Hoption.BackBox) {
8013  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
8014  fLego->BackBox(90);
8015  }
8016  }
8017 
8018  if (Hoption.Lego == 12) DefineColorLevels(ndivz);
8019 
8020  fLego->SetLegoFunction(&TPainter3dAlgorithms::LegoFunction);
8021  if (Hoption.Lego == 1) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceRaster2);
8022  if (Hoption.Lego == 11) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode3);
8023  if (Hoption.Lego == 12) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode2);
8024  if (Hoption.System == kPOLAR) {
8025  if (Hoption.Lego == 1) fLego->LegoPolar(1,nx,ny,"FB");
8026  if (Hoption.Lego == 11) fLego->LegoPolar(1,nx,ny,"BF");
8027  if (Hoption.Lego == 12) fLego->LegoPolar(1,nx,ny,"BF");
8028  } else if (Hoption.System == kCYLINDRICAL) {
8029  if (Hoption.Lego == 1) fLego->LegoCylindrical(1,nx,ny,"FB");
8030  if (Hoption.Lego == 11) fLego->LegoCylindrical(1,nx,ny,"BF");
8031  if (Hoption.Lego == 12) fLego->LegoCylindrical(1,nx,ny,"BF");
8032  } else if (Hoption.System == kSPHERICAL) {
8033  if (Hoption.Lego == 1) fLego->LegoSpherical(0,1,nx,ny,"FB");
8034  if (Hoption.Lego == 11) fLego->LegoSpherical(0,1,nx,ny,"BF");
8035  if (Hoption.Lego == 12) fLego->LegoSpherical(0,1,nx,ny,"BF");
8036  } else if (Hoption.System == kRAPIDITY) {
8037  if (Hoption.Lego == 1) fLego->LegoSpherical(1,1,nx,ny,"FB");
8038  if (Hoption.Lego == 11) fLego->LegoSpherical(1,1,nx,ny,"BF");
8039  if (Hoption.Lego == 12) fLego->LegoSpherical(1,1,nx,ny,"BF");
8040  } else {
8041  if (Hoption.Lego == 1) {
8042  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
8043  fLego->LegoCartesian(90,nx,ny,"FB");}
8044  if (Hoption.Lego == 11) fLego->LegoCartesian(90,nx,ny,"BF");
8045  if (Hoption.Lego == 12) fLego->LegoCartesian(90,nx,ny,"BF");
8046  }
8047 
8048  if (Hoption.Lego == 1 || Hoption.Lego == 11) {
8049  if (Hoption.System == kCARTESIAN && Hoption.BackBox) {
8050  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
8051  fLego->BackBox(90);
8052  }
8053  }
8054  if (Hoption.System == kCARTESIAN) {
8055  fLego->InitMoveScreen(-1.1,1.1);
8056  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
8057  if (Hoption.FrontBox) fLego->FrontBox(90);
8058  }
8059  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
8060  if (Hoption.Zscale) PaintPalette();
8061  delete axis;
8062  delete fLego; fLego = 0;
8063 }
8064 
8065 ////////////////////////////////////////////////////////////////////////////////
8066 /// Draw the axis for legos and surface plots.
8067 
8068 void THistPainter::PaintLegoAxis(TGaxis *axis, Double_t ang)
8069 {
8070 
8071  static Double_t epsil = 0.001;
8072 
8073  Double_t cosa, sina;
8074  Double_t bmin, bmax;
8075  Double_t r[24] /* was [3][8] */;
8076  Int_t ndivx, ndivy, ndivz, i;
8077  Double_t x1[3], x2[3], y1[3], y2[3], z1[3], z2[3], av[24] /* was [3][8] */;
8078  static char chopax[8], chopay[8], chopaz[8];
8079  Int_t ix1, ix2, iy1, iy2, iz1, iz2;
8080  Double_t rad;
8081 
8082  TView *view = gPad->GetView();
8083  if (!view) {
8084  Error("PaintLegoAxis", "no TView in current pad");
8085  return;
8086  }
8087 
8088  // In polar coordinates, draw a short line going from the external circle
8089  // corresponding to r = 1 up to r = 1.1
8090  if (Hoption.System == kPOLAR) {
8091  r[0] = 1;
8092  r[1] = 0;
8093  r[2] = 0;
8094  view->WCtoNDC(r, x1);
8095  r[0] = 1.1;
8096  r[1] = 0;
8097  r[2] = 0;
8098  view->WCtoNDC(r, x2);
8099  gPad->PaintLine(x1[0],x1[1],x2[0],x2[1]);
8100  return;
8101  }
8102 
8103  if (Hoption.System != kCARTESIAN) return;
8104 
8105  rad = TMath::ATan(1.) * 4. /180.;
8106  cosa = TMath::Cos(ang*rad);
8107  sina = TMath::Sin(ang*rad);
8108 
8109  view->AxisVertex(ang, av, ix1, ix2, iy1, iy2, iz1, iz2);
8110  for (i = 1; i <= 8; ++i) {
8111  r[i*3 - 3] = av[i*3 - 3] + av[i*3 - 2]*cosa;
8112  r[i*3 - 2] = av[i*3 - 2]*sina;
8113  r[i*3 - 1] = av[i*3 - 1];
8114  }
8115 
8116  view->WCtoNDC(&r[ix1*3 - 3], x1);
8117  view->WCtoNDC(&r[ix2*3 - 3], x2);
8118  view->WCtoNDC(&r[iy1*3 - 3], y1);
8119  view->WCtoNDC(&r[iy2*3 - 3], y2);
8120  view->WCtoNDC(&r[iz1*3 - 3], z1);
8121  view->WCtoNDC(&r[iz2*3 - 3], z2);
8122 
8123  view->SetAxisNDC(x1, x2, y1, y2, z1, z2);
8124 
8125  Double_t *rmin = view->GetRmin();
8126  Double_t *rmax = view->GetRmax();
8127  if (!rmin || !rmax) return;
8128 
8129  // Initialize the axis options
8130  if (x1[0] > x2[0]) strlcpy(chopax, "SDH=+",8);
8131  else strlcpy(chopax, "SDH=-",8);
8132  if (y1[0] > y2[0]) strlcpy(chopay, "SDH=+",8);
8133  else strlcpy(chopay, "SDH=-",8);
8134  if (z2[1] > z1[1]) strlcpy(chopaz, "SDH=+",8);
8135  else strlcpy(chopaz, "SDH=-",8);
8136 
8137  // Option LOG is required ?
8138  if (Hoption.Logx) strlcat(chopax,"G",8);
8139  if (Hoption.Logy) strlcat(chopay,"G",8);
8140  if (Hoption.Logz) strlcat(chopaz,"G",8);
8141 
8142  // Initialize the number of divisions. If the
8143  // number of divisions is negative, option 'N' is required.
8144  ndivx = fXaxis->GetNdivisions();
8145  ndivy = fYaxis->GetNdivisions();
8146  ndivz = fZaxis->GetNdivisions();
8147  if (ndivx < 0) {
8148  ndivx = TMath::Abs(ndivx);
8149  strlcat(chopax, "N",8);
8150  }
8151  if (ndivy < 0) {
8152  ndivy = TMath::Abs(ndivy);
8153  strlcat(chopay, "N",8);
8154  }
8155  if (ndivz < 0) {
8156  ndivz = TMath::Abs(ndivz);
8157  strlcat(chopaz, "N",8);
8158  }
8159 
8160  // Set Axis attributes.
8161  // The variable SCALE rescales the VSIZ
8162  // in order to have the same label size for all angles.
8163 
8164  axis->SetLineWidth(1);
8165 
8166  // X axis drawing
8167  if (TMath::Abs(x1[0] - x2[0]) >= epsil || TMath::Abs(x1[1] - x2[1]) > epsil) {
8168  axis->ImportAxisAttributes(fXaxis);
8169  axis->SetLabelOffset(fXaxis->GetLabelOffset()+fXaxis->GetTickLength());
8170  if (Hoption.Logx && !fH->InheritsFrom(TH3::Class())) {
8171  bmin = TMath::Power(10, rmin[0]);
8172  bmax = TMath::Power(10, rmax[0]);
8173  } else {
8174  bmin = rmin[0];
8175  bmax = rmax[0];
8176  }
8177  // Option time display is required ?
8178  if (fXaxis->GetTimeDisplay()) {
8179  strlcat(chopax,"t",8);
8180  if (strlen(fXaxis->GetTimeFormatOnly()) == 0) {
8181  axis->SetTimeFormat(fXaxis->ChooseTimeFormat(bmax-bmin));
8182  } else {
8183  axis->SetTimeFormat(fXaxis->GetTimeFormat());
8184  }
8185  }
8186  axis->SetOption(chopax);
8187  axis->PaintAxis(x1[0], x1[1], x2[0], x2[1], bmin, bmax, ndivx, chopax);
8188  }
8189 
8190  // Y axis drawing
8191  if (TMath::Abs(y1[0] - y2[0]) >= epsil || TMath::Abs(y1[1] - y2[1]) > epsil) {
8192  axis->ImportAxisAttributes(fYaxis);
8193  axis->SetLabelOffset(fYaxis->GetLabelOffset()+fYaxis->GetTickLength());
8194  if (fYaxis->GetTitleOffset() == 0) axis->SetTitleOffset(1.5);
8195 
8196  if (fH->GetDimension() < 2) {
8197  strlcpy(chopay, "V=+UN",8);
8198  ndivy = 0;
8199  }
8200  if (TMath::Abs(y1[0] - y2[0]) < epsil) {
8201  y2[0] = y1[0];
8202  }
8203  if (Hoption.Logy && !fH->InheritsFrom(TH3::Class())) {
8204  bmin = TMath::Power(10, rmin[1]);
8205  bmax = TMath::Power(10, rmax[1]);
8206  } else {
8207  bmin = rmin[1];
8208  bmax = rmax[1];
8209  }
8210  // Option time display is required ?
8211  if (fYaxis->GetTimeDisplay()) {
8212  strlcat(chopay,"t",8);
8213  if (strlen(fYaxis->GetTimeFormatOnly()) == 0) {
8214  axis->SetTimeFormat(fYaxis->ChooseTimeFormat(bmax-bmin));
8215  } else {
8216  axis->SetTimeFormat(fYaxis->GetTimeFormat());
8217  }
8218  }
8219  axis->SetOption(chopay);
8220  axis->PaintAxis(y1[0], y1[1], y2[0], y2[1], bmin, bmax, ndivy, chopay);
8221  }
8222 
8223  // Z axis drawing
8224  if (TMath::Abs(z1[0] - z2[0]) >= 100*epsil || TMath::Abs(z1[1] - z2[1]) > 100*epsil) {
8225  axis->ImportAxisAttributes(fZaxis);
8226  if (Hoption.Logz && !fH->InheritsFrom(TH3::Class())) {
8227  bmin = TMath::Power(10, rmin[2]);
8228  bmax = TMath::Power(10, rmax[2]);
8229  } else {
8230  bmin = rmin[2];
8231  bmax = rmax[2];
8232  }
8233  // Option time display is required ?
8234  if (fZaxis->GetTimeDisplay()) {
8235  strlcat(chopaz,"t",8);
8236  if (strlen(fZaxis->GetTimeFormatOnly()) == 0) {
8237  axis->SetTimeFormat(fZaxis->ChooseTimeFormat(bmax-bmin));
8238  } else {
8239  axis->SetTimeFormat(fZaxis->GetTimeFormat());
8240  }
8241  }
8242  axis->SetOption(chopaz);
8243  axis->PaintAxis(z1[0], z1[1], z2[0], z2[1], bmin, bmax, ndivz, chopaz);
8244  }
8245 
8246  //fH->SetLineStyle(1); /// otherwise fEdgeStyle[i] gets overwritten!
8247 }
8248 
8249 ////////////////////////////////////////////////////////////////////////////////
8250 /// [Paint the color palette on the right side of the pad.](#HP22)
8251 
8252 void THistPainter::PaintPalette()
8253 {
8254 
8255  TPaletteAxis *palette = (TPaletteAxis*)fFunctions->FindObject("palette");
8256  TView *view = gPad->GetView();
8257  if (palette) {
8258  if (view) {
8259  if (!palette->TestBit(TPaletteAxis::kHasView)) {
8260  fFunctions->Remove(palette);
8261  delete palette; palette = 0;
8262  }
8263  } else {
8264  if (palette->TestBit(TPaletteAxis::kHasView)) {
8265  fFunctions->Remove(palette);
8266  delete palette; palette = 0;
8267  }
8268  }
8269  // make sure the histogram member of the palette is setup correctly. It may not be after a Clone()
8270  if (palette && !palette->GetHistogram()) palette->SetHistogram(fH);
8271  }
8272 
8273  if (!palette) {
8274  Double_t xup = gPad->GetUxmax();
8275  Double_t x2 = gPad->PadtoX(gPad->GetX2());
8276  Double_t ymin = gPad->PadtoY(gPad->GetUymin());
8277  Double_t ymax = gPad->PadtoY(gPad->GetUymax());
8278  Double_t xr = 0.05*(gPad->GetX2() - gPad->GetX1());
8279  Double_t xmin = gPad->PadtoX(xup +0.1*xr);
8280  Double_t xmax = gPad->PadtoX(xup + xr);
8281  if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr);
8282  palette = new TPaletteAxis(xmin,ymin,xmax,ymax,fH);
8283  fFunctions->AddFirst(palette);
8284  palette->Paint();
8285  }
8286 }
8287 
8288 ////////////////////////////////////////////////////////////////////////////////
8289 /// [Control function to draw a 2D histogram as a scatter plot.](#HP11)
8290 
8291 void THistPainter::PaintScatterPlot(Option_t *option)
8292 {
8293 
8294  fH->TAttMarker::Modify();
8295 
8296  Int_t k, marker;
8297  Double_t dz, z, xk,xstep, yk, ystep;
8298  Double_t scale = 1;
8299  Bool_t ltest = kFALSE;
8300  Double_t zmax = fH->GetMaximum();
8301  Double_t zmin = fH->GetMinimum();
8302  if (zmin == 0 && zmax == 0) return;
8303  if (zmin == zmax) {
8304  zmax += 0.1*TMath::Abs(zmax);
8305  zmin -= 0.1*TMath::Abs(zmin);
8306  }
8307  Int_t ncells = (Hparam.ylast-Hparam.yfirst)*(Hparam.xlast-Hparam.xfirst);
8308  if (Hoption.Logz) {
8309  if (zmin > 0) zmin = TMath::Log10(zmin);
8310  else zmin = 0;
8311  if (zmax > 0) zmax = TMath::Log10(zmax);
8312  else zmax = 0;
8313  if (zmin == 0 && zmax == 0) return;
8314  dz = zmax - zmin;
8315  scale = 100/dz;
8316  if (ncells > 10000) scale /= 5;
8317  ltest = kTRUE;
8318  } else {
8319  dz = zmax - zmin;
8320  if (dz >= kNMAX || zmax < 1) {
8321  scale = (kNMAX-1)/dz;
8322  if (ncells > 10000) scale /= 5;
8323  ltest = kTRUE;
8324  }
8325  }
8326  if (fH->GetMinimumStored() == -1111) {
8327  Double_t yMARGIN = gStyle->GetHistTopMargin();
8328  if (Hoption.MinimumZero) {
8329  if (zmin >= 0) zmin = 0;
8330  else zmin -= yMARGIN*(zmax-zmin);
8331  } else {
8332  Double_t dzmin = yMARGIN*(zmax-zmin);
8333  if (zmin >= 0 && (zmin-dzmin <= 0)) zmin = 0;
8334  else zmin -= dzmin;
8335  }
8336  }
8337 
8338  TString opt = option;
8339  opt.ToLower();
8340  if (opt.Contains("scat=")) {
8341  char optscat[100];
8342  strlcpy(optscat,opt.Data(),100);
8343  char *oscat = strstr(optscat,"scat=");
8344  char *blank = strstr(oscat," "); if (blank) *blank = 0;
8345  sscanf(oscat+5,"%lg",&scale);
8346  }
8347  // use an independent instance of a random generator
8348  // instead of gRandom to avoid conflicts and
8349  // to get same random numbers when drawing the same histogram
8350  TRandom2 random;
8351  marker=0;
8352  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
8353  yk = fYaxis->GetBinLowEdge(j);
8354  ystep = fYaxis->GetBinWidth(j);
8355  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
8356  Int_t bin = j*(fXaxis->GetNbins()+2) + i;
8357  xk = fXaxis->GetBinLowEdge(i);
8358  xstep = fXaxis->GetBinWidth(i);
8359  if (!IsInside(xk+0.5*xstep,yk+0.5*ystep)) continue;
8360  z = fH->GetBinContent(bin);
8361  if (z < zmin) z = zmin;
8362  if (z > zmax) z = zmax;
8363  if (Hoption.Logz) {
8364  if (z > 0) z = TMath::Log10(z) - zmin;
8365  } else {
8366  z -= zmin;
8367  }
8368  if (z <= 0) continue;
8369  k = Int_t(z*scale);
8370  if (ltest) k++;
8371  if (k > 0) {
8372  for (Int_t loop=0; loop<k; loop++) {
8373  if (k+marker >= kNMAX) {
8374  gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
8375  marker=0;
8376  }
8377  fXbuf[marker] = (random.Rndm()*xstep) + xk;
8378  fYbuf[marker] = (random.Rndm()*ystep) + yk;
8379  if (Hoption.Logx) {
8380  if (fXbuf[marker] > 0) fXbuf[marker] = TMath::Log10(fXbuf[marker]);
8381  else break;
8382  }
8383  if (Hoption.Logy) {
8384  if (fYbuf[marker] > 0) fYbuf[marker] = TMath::Log10(fYbuf[marker]);
8385  else break;
8386  }
8387  if (fXbuf[marker] < gPad->GetUxmin()) break;
8388  if (fYbuf[marker] < gPad->GetUymin()) break;
8389  if (fXbuf[marker] > gPad->GetUxmax()) break;
8390  if (fYbuf[marker] > gPad->GetUymax()) break;
8391  marker++;
8392  }
8393  }
8394  }
8395  }
8396  if (marker > 0) gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
8397 
8398  if (Hoption.Zscale) PaintPalette();
8399 }
8400 
8401 ////////////////////////////////////////////////////////////////////////////////
8402 /// Static function to paint special objects like vectors and matrices.
8403 /// This function is called via `gROOT->ProcessLine` to paint these objects
8404 /// without having a direct dependency of the graphics or histogramming
8405 /// system.
8406 
8407 void THistPainter::PaintSpecialObjects(const TObject *obj, Option_t *option)
8408 {
8409 
8410  if (!obj) return;
8411  Bool_t status = TH1::AddDirectoryStatus();
8412  TH1::AddDirectory(kFALSE);
8413 
8414  if (obj->InheritsFrom(TMatrixFBase::Class())) {
8415  // case TMatrixF
8416  TH2F *R__TMatrixFBase = new TH2F((TMatrixFBase &)*obj);
8417  R__TMatrixFBase->SetBit(kCanDelete);
8418  R__TMatrixFBase->Draw(option);
8419 
8420  } else if (obj->InheritsFrom(TMatrixDBase::Class())) {
8421  // case TMatrixD
8422  TH2D *R__TMatrixDBase = new TH2D((TMatrixDBase &)*obj);
8423  R__TMatrixDBase->SetBit(kCanDelete);
8424  R__TMatrixDBase->Draw(option);
8425 
8426  } else if (obj->InheritsFrom(TVectorF::Class())) {
8427  //case TVectorF
8428  TH1F *R__TVectorF = new TH1F((TVectorF &)*obj);
8429  R__TVectorF->SetBit(kCanDelete);
8430  R__TVectorF->Draw(option);
8431 
8432  } else if (obj->InheritsFrom(TVectorD::Class())) {
8433  //case TVectorD
8434  TH1D *R__TVectorD = new TH1D((TVectorD &)*obj);
8435  R__TVectorD->SetBit(kCanDelete);
8436  R__TVectorD->Draw(option);
8437  }
8438 
8439  TH1::AddDirectory(status);
8440 }
8441 
8442 ////////////////////////////////////////////////////////////////////////////////
8443 /// [Draw the statistics box for 1D and profile histograms.](#HP07)
8444 
8445 void THistPainter::PaintStat(Int_t dostat, TF1 *fit)
8446 {
8447 
8448  TString tt, tf;
8449  Int_t dofit;
8450  TPaveStats *stats = 0;
8451  TIter next(fFunctions);
8452  TObject *obj;
8453  while ((obj = next())) {
8454  if (obj->InheritsFrom(TPaveStats::Class())) {
8455  stats = (TPaveStats*)obj;
8456  break;
8457  }
8458  }
8459 
8460  if (stats && dostat) {
8461  dofit = stats->GetOptFit();
8462  dostat = stats->GetOptStat();
8463  } else {
8464  dofit = gStyle->GetOptFit();
8465  }
8466  if (!dofit) fit = 0;
8467  if (dofit == 1) dofit = 111;
8468  if (dostat == 1) dostat = 1111;
8469  Int_t print_name = dostat%10;
8470  Int_t print_entries = (dostat/10)%10;
8471  Int_t print_mean = (dostat/100)%10;
8472  Int_t print_stddev = (dostat/1000)%10;
8473  Int_t print_under = (dostat/10000)%10;
8474  Int_t print_over = (dostat/100000)%10;
8475  Int_t print_integral= (dostat/1000000)%10;
8476  Int_t print_skew = (dostat/10000000)%10;
8477  Int_t print_kurt = (dostat/100000000)%10;
8478  Int_t nlines = print_name + print_entries + print_mean + print_stddev +
8479  print_under + print_over + print_integral +
8480  print_skew + print_kurt;
8481  Int_t print_fval = dofit%10;
8482  Int_t print_ferrors = (dofit/10)%10;
8483  Int_t print_fchi2 = (dofit/100)%10;
8484  Int_t print_fprob = (dofit/1000)%10;
8485  Int_t nlinesf = print_fval + print_fchi2 + print_fprob;
8486  if (fit) {
8487  if (print_fval < 2) nlinesf += fit->GetNumberFreeParameters();
8488  else nlinesf += fit->GetNpar();
8489  }
8490  if (fH->InheritsFrom(TProfile::Class())) nlinesf += print_mean + print_stddev;
8491 
8492  // Pavetext with statistics
8493  Bool_t done = kFALSE;
8494  if (!dostat && !fit) {
8495  if (stats) { fFunctions->Remove(stats); delete stats;}
8496  return;
8497  }
8498  Double_t statw = gStyle->GetStatW();
8499  if (fit) statw = 1.8*gStyle->GetStatW();
8500  Double_t stath = (nlines+nlinesf)*gStyle->GetStatFontSize();
8501  if (stath <= 0 || 3 == (gStyle->GetStatFont()%10)) {
8502  stath = 0.25*(nlines+nlinesf)*gStyle->GetStatH();
8503  }
8504  if (stats) {
8505  stats->Clear();
8506  done = kTRUE;
8507  } else {
8508  stats = new TPaveStats(
8509  gStyle->GetStatX()-statw,
8510  gStyle->GetStatY()-stath,
8511  gStyle->GetStatX(),
8512  gStyle->GetStatY(),"brNDC");
8513 
8514  stats->SetParent(fH);
8515  stats->SetOptFit(dofit);
8516  stats->SetOptStat(dostat);
8517  stats->SetFillColor(gStyle->GetStatColor());
8518  stats->SetFillStyle(gStyle->GetStatStyle());
8519  stats->SetBorderSize(gStyle->GetStatBorderSize());
8520  stats->SetTextFont(gStyle->GetStatFont());
8521  if (gStyle->GetStatFont()%10 > 2)
8522  stats->SetTextSize(gStyle->GetStatFontSize());
8523  stats->SetFitFormat(gStyle->GetFitFormat());
8524  stats->SetStatFormat(gStyle->GetStatFormat());
8525  stats->SetName("stats");
8526 
8527  stats->SetTextColor(gStyle->GetStatTextColor());
8528  stats->SetTextAlign(12);
8529  stats->SetBit(kCanDelete);
8530  stats->SetBit(kMustCleanup);
8531  }
8532  if (print_name) stats->AddText(fH->GetName());
8533  if (print_entries) {
8534  if (fH->GetEntries() < 1e7) tt.Form("%s = %-7d",gStringEntries.Data(),Int_t(fH->GetEntries()+0.5));
8535  else tt.Form("%s = %14.7g",gStringEntries.Data(),Float_t(fH->GetEntries()));
8536  stats->AddText(tt.Data());
8537  }
8538  if (print_mean) {
8539  if (print_mean == 1) {
8540  tf.Form("%s = %s%s",gStringMean.Data(),"%",stats->GetStatFormat());
8541  tt.Form(tf.Data(),fH->GetMean(1));
8542  } else {
8543  tf.Form("%s = %s%s #pm %s%s",gStringMean.Data(),"%",stats->GetStatFormat()
8544  ,"%",stats->GetStatFormat());
8545  tt.Form(tf.Data(),fH->GetMean(1),fH->GetMeanError(1));
8546  }
8547  stats->AddText(tt.Data());
8548  if (fH->InheritsFrom(TProfile::Class())) {
8549  if (print_mean == 1) {
8550  tf.Form("%s = %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat());
8551  tt.Form(tf.Data(),fH->GetMean(2));
8552  } else {
8553  tf.Form("%s = %s%s #pm %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat()
8554  ,"%",stats->GetStatFormat());
8555  tt.Form(tf.Data(),fH->GetMean(2),fH->GetMeanError(2));
8556  }
8557  stats->AddText(tt.Data());
8558  }
8559  }
8560  if (print_stddev) {
8561  if (print_stddev == 1) {
8562  tf.Form("%s = %s%s",gStringStdDev.Data(),"%",stats->GetStatFormat());
8563  tt.Form(tf.Data(),fH->GetStdDev(1));
8564  } else {
8565  tf.Form("%s = %s%s #pm %s%s",gStringStdDev.Data(),"%",stats->GetStatFormat()
8566  ,"%",stats->GetStatFormat());
8567  tt.Form(tf.Data(),fH->GetStdDev(1),fH->GetStdDevError(1));
8568  }
8569  stats->AddText(tt.Data());
8570  if (fH->InheritsFrom(TProfile::Class())) {
8571  if (print_stddev == 1) {
8572  tf.Form("%s = %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat());
8573  tt.Form(tf.Data(),fH->GetStdDev(2));
8574  } else {
8575  tf.Form("%s = %s%s #pm %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat()
8576  ,"%",stats->GetStatFormat());
8577  tt.Form(tf.Data(),fH->GetStdDev(2),fH->GetStdDevError(2));
8578  }
8579  stats->AddText(tt.Data());
8580  }
8581  }
8582  if (print_under) {
8583  tf.Form("%s = %s%s",gStringUnderflow.Data(),"%",stats->GetStatFormat());
8584  tt.Form(tf.Data(),fH->GetBinContent(0));
8585  stats->AddText(tt.Data());
8586  }
8587  if (print_over) {
8588  tf.Form("%s = %s%s",gStringOverflow.Data(),"%",stats->GetStatFormat());
8589  tt.Form(tf.Data(),fH->GetBinContent(fXaxis->GetNbins()+1));
8590  stats->AddText(tt.Data());
8591  }
8592  if (print_integral) {
8593  if (print_integral == 1) {
8594  tf.Form("%s = %s%s",gStringIntegral.Data(),"%",stats->GetStatFormat());
8595  tt.Form(tf.Data(),fH->Integral());
8596  } else {
8597  tf.Form("%s = %s%s",gStringIntegralBinWidth.Data(),"%",stats->GetStatFormat());
8598  tt.Form(tf.Data(),fH->Integral("width"));
8599  }
8600  stats->AddText(tt.Data());
8601  }
8602  if (print_skew) {
8603  if (print_skew == 1) {
8604  tf.Form("%s = %s%s",gStringSkewness.Data(),"%",stats->GetStatFormat());
8605  tt.Form(tf.Data(),fH->GetSkewness(1));
8606  } else {
8607  tf.Form("%s = %s%s #pm %s%s",gStringSkewness.Data(),"%",stats->GetStatFormat()
8608  ,"%",stats->GetStatFormat());
8609  tt.Form(tf.Data(),fH->GetSkewness(1),fH->GetSkewness(11));
8610  }
8611  stats->AddText(tt.Data());
8612  }
8613  if (print_kurt) {
8614  if (print_kurt == 1) {
8615  tf.Form("%s = %s%s",gStringKurtosis.Data(),"%",stats->GetStatFormat());
8616  tt.Form(tf.Data(),fH->GetKurtosis(1));
8617  } else {
8618  tf.Form("%s = %s%s #pm %s%s",gStringKurtosis.Data(),"%",stats->GetStatFormat()
8619  ,"%",stats->GetStatFormat());
8620  tt.Form(tf.Data(),fH->GetKurtosis(1),fH->GetKurtosis(11));
8621  }
8622  stats->AddText(tt.Data());
8623  }
8624 
8625  // Draw Fit parameters
8626  if (fit) {
8627  Int_t ndf = fit->GetNDF();
8628  tf.Form("#chi^{2} / ndf = %s%s / %d","%",stats->GetFitFormat(),ndf);
8629  tt.Form(tf.Data(),(Float_t)fit->GetChisquare());
8630  if (print_fchi2) stats->AddText(tt.Data());
8631  if (print_fprob) {
8632  tf.Form("Prob = %s%s","%",stats->GetFitFormat());
8633  tt.Form(tf.Data(),(Float_t)TMath::Prob(fit->GetChisquare(),ndf));
8634  stats->AddText(tt.Data());
8635  }
8636  if (print_fval || print_ferrors) {
8637  Double_t parmin,parmax;
8638  for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
8639  fit->GetParLimits(ipar,parmin,parmax);
8640  if (print_fval < 2 && parmin*parmax != 0 && parmin >= parmax) continue;
8641  if (print_ferrors) {
8642  tf.Form("%-8s = %s%s #pm %s ", fit->GetParName(ipar), "%",stats->GetFitFormat(),
8643  GetBestFormat(fit->GetParameter(ipar), fit->GetParError(ipar), stats->GetFitFormat()));
8644  tt.Form(tf.Data(),(Float_t)fit->GetParameter(ipar)
8645  ,(Float_t)fit->GetParError(ipar));
8646  } else {
8647  tf.Form("%-8s = %s%s ",fit->GetParName(ipar), "%",stats->GetFitFormat());
8648  tt.Form(tf.Data(),(Float_t)fit->GetParameter(ipar));
8649  }
8650  stats->AddText(tt.Data());
8651  }
8652  }
8653  }
8654 
8655  if (!done) fFunctions->Add(stats);
8656  stats->Paint();
8657 }
8658 
8659 ////////////////////////////////////////////////////////////////////////////////
8660 /// [Draw the statistics box for 2D histograms.](#HP07)
8661 
8662 void THistPainter::PaintStat2(Int_t dostat, TF1 *fit)
8663 {
8664 
8665  if (fH->GetDimension() != 2) return;
8666  TH2 *h2 = (TH2*)fH;
8667 
8668  TString tt, tf;
8669  Int_t dofit;
8670  TPaveStats *stats = 0;
8671  TIter next(fFunctions);
8672  TObject *obj;
8673  while ((obj = next())) {
8674  if (obj->InheritsFrom(TPaveStats::Class())) {
8675  stats = (TPaveStats*)obj;
8676  break;
8677  }
8678  }
8679  if (stats && dostat) {
8680  dofit = stats->GetOptFit();
8681  dostat = stats->GetOptStat();
8682  } else {
8683  dofit = gStyle->GetOptFit();
8684  }
8685  if (dostat == 1) dostat = 1111;
8686  Int_t print_name = dostat%10;
8687  Int_t print_entries = (dostat/10)%10;
8688  Int_t print_mean = (dostat/100)%10;
8689  Int_t print_stddev = (dostat/1000)%10;
8690  Int_t print_under = (dostat/10000)%10;
8691  Int_t print_over = (dostat/100000)%10;
8692  Int_t print_integral= (dostat/1000000)%10;
8693  Int_t print_skew = (dostat/10000000)%10;
8694  Int_t print_kurt = (dostat/100000000)%10;
8695  Int_t nlines = print_name + print_entries + 2*print_mean + 2*print_stddev + print_integral;
8696  if (print_under || print_over) nlines += 3;
8697 
8698  // Pavetext with statistics
8699  if (!gStyle->GetOptFit()) fit = 0;
8700  Bool_t done = kFALSE;
8701  if (!dostat && !fit) {
8702  if (stats) { fFunctions->Remove(stats); delete stats;}
8703  return;
8704  }
8705  Double_t statw = gStyle->GetStatW();
8706  if (fit) statw = 1.8*gStyle->GetStatW();
8707  Double_t stath = nlines*gStyle->GetStatFontSize();
8708  if (stath <= 0 || 3 == (gStyle->GetStatFont()%10)) {
8709  stath = 0.25*nlines*gStyle->GetStatH();
8710  }
8711  if (fit) stath += gStyle->GetStatH();
8712  if (stats) {
8713  stats->Clear();
8714  done = kTRUE;
8715  } else {
8716  stats = new TPaveStats(
8717  gStyle->GetStatX()-statw,
8718  gStyle->GetStatY()-stath,
8719  gStyle->GetStatX(),
8720  gStyle->GetStatY(),"brNDC");
8721 
8722  stats->SetParent(fH);
8723  stats->SetOptFit(dofit);
8724  stats->SetOptStat(dostat);
8725  stats->SetFillColor(gStyle->GetStatColor());
8726  stats->SetFillStyle(gStyle->GetStatStyle());
8727  stats->SetBorderSize(gStyle->GetStatBorderSize());
8728  stats->SetName("stats");
8729 
8730  stats->SetTextColor(gStyle->GetStatTextColor());
8731  stats->SetTextAlign(12);
8732  stats->SetTextFont(gStyle->GetStatFont());
8733  if (gStyle->GetStatFont()%10 > 2)
8734  stats->SetTextSize(gStyle->GetStatFontSize());
8735  stats->SetFitFormat(gStyle->GetFitFormat());
8736  stats->SetStatFormat(gStyle->GetStatFormat());
8737  stats->SetBit(kCanDelete);
8738  stats->SetBit(kMustCleanup);
8739  }
8740  if (print_name) stats->AddText(h2->GetName());
8741  if (print_entries) {
8742  if (h2->GetEntries() < 1e7) tt.Form("%s = %-7d",gStringEntries.Data(),Int_t(h2->GetEntries()+0.5));
8743  else tt.Form("%s = %14.7g",gStringEntries.Data(),Float_t(h2->GetEntries()));
8744  stats->AddText(tt.Data());
8745  }
8746  if (print_mean) {
8747  if (print_mean == 1) {
8748  tf.Form("%s = %s%s",gStringMeanX.Data(),"%",stats->GetStatFormat());
8749  tt.Form(tf.Data(),h2->GetMean(1));
8750  stats->AddText(tt.Data());
8751  tf.Form("%s = %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat());
8752  tt.Form(tf.Data(),h2->GetMean(2));
8753  stats->AddText(tt.Data());
8754  } else {
8755  tf.Form("%s = %s%s #pm %s%s",gStringMeanX.Data(),"%",stats->GetStatFormat()
8756  ,"%",stats->GetStatFormat());
8757  tt.Form(tf.Data(),h2->GetMean(1),h2->GetMeanError(1));
8758  stats->AddText(tt.Data());
8759  tf.Form("%s = %s%s #pm %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat()
8760  ,"%",stats->GetStatFormat());
8761  tt.Form(tf.Data(),h2->GetMean(2),h2->GetMeanError(2));
8762  stats->AddText(tt.Data());
8763  }
8764  }
8765  if (print_stddev) {
8766  if (print_stddev == 1) {
8767  tf.Form("%s = %s%s",gStringStdDevX.Data(),"%",stats->GetStatFormat());
8768  tt.Form(tf.Data(),h2->GetStdDev(1));
8769  stats->AddText(tt.Data());
8770  tf.Form("%s = %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat());
8771  tt.Form(tf.Data(),h2->GetStdDev(2));
8772  stats->AddText(tt.Data());
8773  } else {
8774  tf.Form("%s = %s%s #pm %s%s",gStringStdDevX.Data(),"%",stats->GetStatFormat()
8775  ,"%",stats->GetStatFormat());
8776  tt.Form(tf.Data(),h2->GetStdDev(1),h2->GetStdDevError(1));
8777  stats->AddText(tt.Data());
8778  tf.Form("%s = %s%s #pm %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat()
8779  ,"%",stats->GetStatFormat());
8780  tt.Form(tf.Data(),h2->GetStdDev(2),h2->GetStdDevError(2));
8781  stats->AddText(tt.Data());
8782  }
8783  }
8784  if (print_integral) {
8785  tf.Form("%s = %s%s",gStringIntegral.Data(),"%",stats->GetStatFormat());
8786  tt.Form(tf.Data(),fH->Integral());
8787  stats->AddText(tt.Data());
8788  }
8789  if (print_skew) {
8790  if (print_skew == 1) {
8791  tf.Form("%s = %s%s",gStringSkewnessX.Data(),"%",stats->GetStatFormat());
8792  tt.Form(tf.Data(),h2->GetSkewness(1));
8793  stats->AddText(tt.Data());
8794  tf.Form("%s = %s%s",gStringSkewnessY.Data(),"%",stats->GetStatFormat());
8795  tt.Form(tf.Data(),h2->GetSkewness(2));
8796  stats->AddText(tt.Data());
8797  } else {
8798  tf.Form("%s = %s%s #pm %s%s",gStringSkewnessX.Data(),"%",stats->GetStatFormat()
8799  ,"%",stats->GetStatFormat());
8800  tt.Form(tf.Data(),h2->GetSkewness(1),h2->GetSkewness(11));
8801  stats->AddText(tt.Data());
8802  tf.Form("%s = %s%s #pm %s%s",gStringSkewnessY.Data(),"%",stats->GetStatFormat()
8803  ,"%",stats->GetStatFormat());
8804  tt.Form(tf.Data(),h2->GetSkewness(2),h2->GetSkewness(12));
8805  stats->AddText(tt.Data());
8806  }
8807  }
8808  if (print_kurt) {
8809  if (print_kurt == 1) {
8810  tf.Form("%s = %s%s",gStringKurtosisX.Data(),"%",stats->GetStatFormat());
8811  tt.Form(tf.Data(),h2->GetKurtosis(1));
8812  stats->AddText(tt.Data());
8813  tf.Form("%s = %s%s",gStringKurtosisY.Data(),"%",stats->GetStatFormat());
8814  tt.Form(tf.Data(),h2->GetKurtosis(2));
8815  stats->AddText(tt.Data());
8816  } else {
8817  tf.Form("%s = %s%s #pm %s%s",gStringKurtosisX.Data(),"%",stats->GetStatFormat()
8818  ,"%",stats->GetStatFormat());
8819  tt.Form(tf.Data(),h2->GetKurtosis(1),h2->GetKurtosis(11));
8820  stats->AddText(tt.Data());
8821  tf.Form("%s = %s%s #pm %s%s",gStringKurtosisY.Data(),"%",stats->GetStatFormat()
8822  ,"%",stats->GetStatFormat());
8823  tt.Form(tf.Data(),h2->GetKurtosis(2),h2->GetKurtosis(12));
8824  stats->AddText(tt.Data());
8825  }
8826  }
8827  if (print_under || print_over) {
8828  //get 3*3 under/overflows for 2d hist
8829  Double_t unov[9];
8830 
8831  Int_t cellsX = h2->GetXaxis()->GetNbins() + 1;
8832  Int_t cellsY = h2->GetYaxis()->GetNbins() + 1;
8833  Int_t firstX = std::max(1, h2->GetXaxis()->GetFirst());
8834  Int_t firstY = std::max(1, h2->GetYaxis()->GetFirst());
8835  Int_t lastX = std::min(h2->GetXaxis()->GetLast(), h2->GetXaxis()->GetNbins());
8836  Int_t lastY = std::min(h2->GetYaxis()->GetLast(), h2->GetYaxis()->GetNbins());
8837 
8838  unov[0] = h2->Integral( 0, firstX-1, lastY+1, cellsY );
8839  unov[1] = h2->Integral(firstX , lastX , lastY+1, cellsY );
8840  unov[2] = h2->Integral(lastX+1, cellsX , lastY+1, cellsY );
8841  unov[3] = h2->Integral( 0, firstX-1, firstY , lastY );
8842  unov[4] = h2->Integral(firstX , lastX , firstY , lastY );
8843  unov[5] = h2->Integral(lastX+1, cellsX , firstY , lastY );
8844  unov[6] = h2->Integral( 0, firstX-1, 0, firstY-1);
8845  unov[7] = h2->Integral(firstX, lastX, 0, firstY-1);
8846  unov[8] = h2->Integral(lastX+1, cellsX , 0, firstY-1);
8847 
8848  tt.Form(" %7d|%7d|%7d\n", (Int_t)unov[0], (Int_t)unov[1], (Int_t)unov[2]);
8849  stats->AddText(tt.Data());
8850  if (TMath::Abs(unov[4]) < 1.e7)
8851  tt.Form(" %7d|%7d|%7d\n", (Int_t)unov[3], (Int_t)unov[4], (Int_t)unov[5]);
8852  else
8853  tt.Form(" %7d|%14.7g|%7d\n", (Int_t)unov[3], (Float_t)unov[4], (Int_t)unov[5]);
8854  stats->AddText(tt.Data());
8855  tt.Form(" %7d|%7d|%7d\n", (Int_t)unov[6], (Int_t)unov[7], (Int_t)unov[8]);
8856  stats->AddText(tt.Data());
8857  }
8858 
8859  // Draw Fit parameters
8860  if (fit) {
8861  Int_t ndf = fit->GetNDF();
8862  tt.Form("#chi^{2} / ndf = %6.4g / %d",(Float_t)fit->GetChisquare(),ndf);
8863  stats->AddText(tt.Data());
8864  for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
8865  tt.Form("%-8s = %5.4g #pm %5.4g ",fit->GetParName(ipar)
8866  ,(Float_t)fit->GetParameter(ipar)
8867  ,(Float_t)fit->GetParError(ipar));
8868  stats->AddText(tt.Data());
8869  }
8870  }
8871 
8872  if (!done) fFunctions->Add(stats);
8873  stats->Paint();
8874 }
8875 
8876 ////////////////////////////////////////////////////////////////////////////////
8877 /// [Draw the statistics box for 3D histograms.](#HP07)
8878 
8879 void THistPainter::PaintStat3(Int_t dostat, TF1 *fit)
8880 {
8881 
8882  if (fH->GetDimension() != 3) return;
8883  TH3 *h3 = (TH3*)fH;
8884 
8885  TString tt, tf;
8886  Int_t dofit;
8887  TPaveStats *stats = 0;
8888  TIter next(fFunctions);
8889  TObject *obj;
8890  while ((obj = next())) {
8891  if (obj->InheritsFrom(TPaveStats::Class())) {
8892  stats = (TPaveStats*)obj;
8893  break;
8894  }
8895  }
8896  if (stats && dostat) {
8897  dofit = stats->GetOptFit();
8898  dostat = stats->GetOptStat();
8899  } else {
8900  dofit = gStyle->GetOptFit();
8901  }
8902  if (dostat == 1) dostat = 1111;
8903  Int_t print_name = dostat%10;
8904  Int_t print_entries = (dostat/10)%10;
8905  Int_t print_mean = (dostat/100)%10;
8906  Int_t print_stddev = (dostat/1000)%10;
8907  Int_t print_under = (dostat/10000)%10;
8908  Int_t print_over = (dostat/100000)%10;
8909  Int_t print_integral= (dostat/1000000)%10;
8910  Int_t print_skew = (dostat/10000000)%10;
8911  Int_t print_kurt = (dostat/100000000)%10;
8912  Int_t nlines = print_name + print_entries + 3*print_mean + 3*print_stddev + print_integral;
8913  if (print_under || print_over) nlines += 3;
8914 
8915  // Pavetext with statistics
8916  if (!gStyle->GetOptFit()) fit = 0;
8917  Bool_t done = kFALSE;
8918  if (!dostat && !fit) {
8919  if (stats) { fFunctions->Remove(stats); delete stats;}
8920  return;
8921  }
8922  Double_t statw = gStyle->GetStatW();
8923  if (fit) statw = 1.8*gStyle->GetStatW();
8924  Double_t stath = nlines*gStyle->GetStatFontSize();
8925  if (stath <= 0 || 3 == (gStyle->GetStatFont()%10)) {
8926  stath = 0.25*nlines*gStyle->GetStatH();
8927  }
8928  if (fit) stath += gStyle->GetStatH();
8929  if (stats) {
8930  stats->Clear();
8931  done = kTRUE;
8932  } else {
8933  stats = new TPaveStats(
8934  gStyle->GetStatX()-statw,
8935  gStyle->GetStatY()-stath,
8936  gStyle->GetStatX(),
8937  gStyle->GetStatY(),"brNDC");
8938 
8939  stats->SetParent(fH);
8940  stats->SetOptFit(dofit);
8941  stats->SetOptStat(dostat);
8942  stats->SetFillColor(gStyle->GetStatColor());
8943  stats->SetFillStyle(gStyle->GetStatStyle());
8944  stats->SetBorderSize(gStyle->GetStatBorderSize());
8945  stats->SetName("stats");
8946 
8947  stats->SetTextColor(gStyle->GetStatTextColor());
8948  stats->SetTextAlign(12);
8949  stats->SetTextFont(gStyle->GetStatFont());
8950  stats->SetFitFormat(gStyle->GetFitFormat());
8951  stats->SetStatFormat(gStyle->GetStatFormat());
8952  stats->SetBit(kCanDelete);
8953  stats->SetBit(kMustCleanup);
8954  }
8955  if (print_name) stats->AddText(h3->GetName());
8956  if (print_entries) {
8957  if (h3->GetEntries() < 1e7) tt.Form("%s = %-7d",gStringEntries.Data(),Int_t(h3->GetEntries()+0.5));
8958  else tt.Form("%s = %14.7g",gStringEntries.Data(),Float_t(h3->GetEntries()+0.5));
8959  stats->AddText(tt.Data());
8960  }
8961  if (print_mean) {
8962  if (print_mean == 1) {
8963  tf.Form("%s = %s%s",gStringMeanX.Data(),"%",stats->GetStatFormat());
8964  tt.Form(tf.Data(),h3->GetMean(1));
8965  stats->AddText(tt.Data());
8966  tf.Form("%s = %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat());
8967  tt.Form(tf.Data(),h3->GetMean(2));
8968  stats->AddText(tt.Data());
8969  tf.Form("%s = %s%s",gStringMeanZ.Data(),"%",stats->GetStatFormat());
8970  tt.Form(tf.Data(),h3->GetMean(3));
8971  stats->AddText(tt.Data());
8972  } else {
8973  tf.Form("%s = %s%s #pm %s%s",gStringMeanX.Data(),"%",stats->GetStatFormat()
8974  ,"%",stats->GetStatFormat());
8975  tt.Form(tf.Data(),h3->GetMean(1),h3->GetMeanError(1));
8976  stats->AddText(tt.Data());
8977  tf.Form("%s = %s%s #pm %s%s",gStringMeanY.Data(),"%",stats->GetStatFormat()
8978  ,"%",stats->GetStatFormat());
8979  tt.Form(tf.Data(),h3->GetMean(2),h3->GetMeanError(2));
8980  stats->AddText(tt.Data());
8981  tf.Form("%s = %s%s #pm %s%s",gStringMeanZ.Data(),"%",stats->GetStatFormat()
8982  ,"%",stats->GetStatFormat());
8983  tt.Form(tf.Data(),h3->GetMean(3),h3->GetMeanError(3));
8984  stats->AddText(tt.Data());
8985  }
8986  }
8987  if (print_stddev) {
8988  if (print_stddev == 1) {
8989  tf.Form("%s = %s%s",gStringStdDevX.Data(),"%",stats->GetStatFormat());
8990  tt.Form(tf.Data(),h3->GetStdDev(1));
8991  stats->AddText(tt.Data());
8992  tf.Form("%s = %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat());
8993  tt.Form(tf.Data(),h3->GetStdDev(2));
8994  stats->AddText(tt.Data());
8995  tf.Form("%s = %s%s",gStringStdDevZ.Data(),"%",stats->GetStatFormat());
8996  tt.Form(tf.Data(),h3->GetStdDev(3));
8997  stats->AddText(tt.Data());
8998  } else {
8999  tf.Form("%s = %s%s #pm %s%s",gStringStdDevX.Data(),"%",stats->GetStatFormat()
9000  ,"%",stats->GetStatFormat());
9001  tt.Form(tf.Data(),h3->GetStdDev(1),h3->GetStdDevError(1));
9002  stats->AddText(tt.Data());
9003  tf.Form("%s = %s%s #pm %s%s",gStringStdDevY.Data(),"%",stats->GetStatFormat()
9004  ,"%",stats->GetStatFormat());
9005  tt.Form(tf.Data(),h3->GetStdDev(2),h3->GetStdDevError(2));
9006  stats->AddText(tt.Data());
9007  tf.Form("%s = %s%s #pm %s%s",gStringStdDevZ.Data(),"%",stats->GetStatFormat()
9008  ,"%",stats->GetStatFormat());
9009  tt.Form(tf.Data(),h3->GetStdDev(3),h3->GetStdDevError(3));
9010  stats->AddText(tt.Data());
9011  }
9012  }
9013  if (print_integral) {
9014  tt.Form("%s = %6.4g",gStringIntegral.Data(),h3->Integral());
9015  stats->AddText(tt.Data());
9016  }
9017  if (print_skew) {
9018  if (print_skew == 1) {
9019  tf.Form("%s = %s%s",gStringSkewnessX.Data(),"%",stats->GetStatFormat());
9020  tt.Form(tf.Data(),h3->GetSkewness(1));
9021  stats->AddText(tt.Data());
9022  tf.Form("%s = %s%s",gStringSkewnessY.Data(),"%",stats->GetStatFormat());
9023  tt.Form(tf.Data(),h3->GetSkewness(2));
9024  stats->AddText(tt.Data());
9025  tf.Form("%s = %s%s",gStringSkewnessZ.Data(),"%",stats->GetStatFormat());
9026  tt.Form(tf.Data(),h3->GetSkewness(3));
9027  stats->AddText(tt.Data());
9028  } else {
9029  tf.Form("%s = %s%s #pm %s%s",gStringSkewnessX.Data(),"%",stats->GetStatFormat()
9030  ,"%",stats->GetStatFormat());
9031  tt.Form(tf.Data(),h3->GetSkewness(1),h3->GetSkewness(11));
9032  stats->AddText(tt.Data());
9033  tf.Form("%s = %s%s #pm %s%s",gStringSkewnessY.Data(),"%",stats->GetStatFormat()
9034  ,"%",stats->GetStatFormat());
9035  tt.Form(tf.Data(),h3->GetSkewness(2),h3->GetSkewness(12));
9036  stats->AddText(tt.Data());
9037  tf.Form("%s = %s%s #pm %s%s",gStringSkewnessZ.Data(),"%",stats->GetStatFormat()
9038  ,"%",stats->GetStatFormat());
9039  tt.Form(tf.Data(),h3->GetSkewness(3),h3->GetSkewness(13));
9040  stats->AddText(tt.Data());
9041  }
9042  }
9043  if (print_kurt) {
9044  if (print_kurt == 1) {
9045  tf.Form("%s = %s%s",gStringKurtosisX.Data(),"%",stats->GetStatFormat());
9046  tt.Form(tf.Data(),h3->GetKurtosis(1));
9047  stats->AddText(tt.Data());
9048  tf.Form("%s = %s%s",gStringKurtosisY.Data(),"%",stats->GetStatFormat());
9049  tt.Form(tf.Data(),h3->GetKurtosis(2));
9050  stats->AddText(tt.Data());
9051  tf.Form("%s = %s%s",gStringKurtosisZ.Data(),"%",stats->GetStatFormat());
9052  tt.Form(tf.Data(),h3->GetKurtosis(3));
9053  stats->AddText(tt.Data());
9054  } else {
9055  tf.Form("%s = %s%s #pm %s%s",gStringKurtosisX.Data(),"%",stats->GetStatFormat()
9056  ,"%",stats->GetStatFormat());
9057  tt.Form(tf.Data(),h3->GetKurtosis(1),h3->GetKurtosis(11));
9058  stats->AddText(tt.Data());
9059  tf.Form("%s = %s%s #pm %s%s",gStringKurtosisY.Data(),"%",stats->GetStatFormat()
9060  ,"%",stats->GetStatFormat());
9061  tt.Form(tf.Data(),h3->GetKurtosis(2),h3->GetKurtosis(12));
9062  stats->AddText(tt.Data());
9063  tf.Form("%s = %s%s #pm %s%s",gStringKurtosisZ.Data(),"%",stats->GetStatFormat()
9064  ,"%",stats->GetStatFormat());
9065  tt.Form(tf.Data(),h3->GetKurtosis(3),h3->GetKurtosis(13));
9066  stats->AddText(tt.Data());
9067  }
9068  }
9069  if (print_under || print_over) {
9070  // no underflow - overflow printing for a 3D histogram
9071  // one would need a 3D table
9072  }
9073 
9074  // Draw Fit parameters
9075  if (fit) {
9076  Int_t ndf = fit->GetNDF();
9077  tt.Form("#chi^{2} / ndf = %6.4g / %d",(Float_t)fit->GetChisquare(),ndf);
9078  stats->AddText(tt.Data());
9079  for (Int_t ipar=0;ipar<fit->GetNpar();ipar++) {
9080  tt.Form("%-8s = %5.4g #pm %5.4g ",fit->GetParName(ipar)
9081  ,(Float_t)fit->GetParameter(ipar)
9082  ,(Float_t)fit->GetParError(ipar));
9083  stats->AddText(tt.Data());
9084  }
9085  }
9086 
9087  if (!done) fFunctions->Add(stats);
9088  stats->Paint();
9089 }
9090 
9091 ////////////////////////////////////////////////////////////////////////////////
9092 /// [Control function to draw a 2D histogram as a surface plot.](#HP18)
9093 
9094 void THistPainter::PaintSurface(Option_t *)
9095 {
9096 
9097  const Double_t ydiff = 1;
9098  const Double_t yligh1 = 10;
9099  const Double_t qa = 0.15;
9100  const Double_t qd = 0.15;
9101  const Double_t qs = 0.8;
9102  Double_t fmin, fmax;
9103  Int_t raster = 0;
9104  Int_t irep = 0;
9105 
9106  if (Hparam.zmin == 0 && Hparam.zmax == 0) {Hparam.zmin = -1; Hparam.zmax = 1;}
9107  Int_t nx = Hparam.xlast - Hparam.xfirst;
9108  Int_t ny = Hparam.ylast - Hparam.yfirst;
9109  Double_t zmin = Hparam.zmin;
9110  Double_t zmax = Hparam.zmax;
9111  Double_t xlab1 = Hparam.xmin;
9112  Double_t xlab2 = Hparam.xmax;
9113  Double_t ylab1 = Hparam.ymin;
9114  Double_t ylab2 = Hparam.ymax;
9115  Double_t dangle = 10*3.141592/180; //Delta angle for Rapidity option
9116  Double_t deltaz = TMath::Abs(zmin);
9117  if (deltaz == 0) deltaz = 1;
9118  if (zmin >= zmax) {
9119  zmin -= 0.5*deltaz;
9120  zmax += 0.5*deltaz;
9121  }
9122  Double_t z1c = zmin;
9123  Double_t z2c = zmin + (zmax-zmin)*(1+gStyle->GetHistTopMargin());
9124  // Compute the lego limits and instantiate a lego object
9125  fXbuf[0] = -1;
9126  fYbuf[0] = 1;
9127  fXbuf[1] = -1;
9128  fYbuf[1] = 1;
9129  if (Hoption.System >= kPOLAR && (Hoption.Surf == 1 || Hoption.Surf == 13)) raster = 1;
9130  if (Hoption.System == kPOLAR) {
9131  fXbuf[2] = z1c;
9132  fYbuf[2] = z2c;
9133  } else if (Hoption.System == kCYLINDRICAL) {
9134  if (Hoption.Logy) {
9135  if (ylab1 > 0) fXbuf[2] = TMath::Log10(ylab1);
9136  else fXbuf[2] = 0;
9137  if (ylab2 > 0) fYbuf[2] = TMath::Log10(ylab2);
9138  else fYbuf[2] = 0;
9139  } else {
9140  fXbuf[2] = ylab1;
9141  fYbuf[2] = ylab2;
9142  }
9143  z1c = 0; z2c = 1;
9144  } else if (Hoption.System == kSPHERICAL) {
9145  fXbuf[2] = -1;
9146  fYbuf[2] = 1;
9147  z1c = 0; z2c = 1;
9148  } else if (Hoption.System == kRAPIDITY) {
9149  fXbuf[2] = -1/TMath::Tan(dangle);
9150  fYbuf[2] = 1/TMath::Tan(dangle);
9151  } else {
9152  fXbuf[0] = xlab1;
9153  fYbuf[0] = xlab2;
9154  fXbuf[1] = ylab1;
9155  fYbuf[1] = ylab2;
9156  fXbuf[2] = z1c;
9157  fYbuf[2] = z2c;
9158  }
9159 
9160  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf, Hoption.System);
9161  fLego->SetEdgeAtt(fH->GetLineColor(),fH->GetLineStyle(),fH->GetLineWidth(),0);
9162  fLego->SetFillColor(fH->GetFillColor());
9163 
9164  // Create axis object
9165 
9166  TGaxis *axis = new TGaxis();
9167 
9168  // Initialize the levels on the Z axis
9169  Int_t ndiv = fH->GetContour();
9170  if (ndiv == 0 ) {
9171  ndiv = gStyle->GetNumberContours();
9172  fH->SetContour(ndiv);
9173  }
9174  Int_t ndivz = TMath::Abs(ndiv);
9175  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ndiv);
9176 
9177  if (Hoption.Surf == 13 || Hoption.Surf == 15) fLego->SetMesh(3);
9178  if (Hoption.Surf == 12 || Hoption.Surf == 14 || Hoption.Surf == 17) fLego->SetMesh(0);
9179 
9180  // Close the surface in case of non cartesian coordinates.
9181 
9182  if (Hoption.System != kCARTESIAN) {nx++; ny++;}
9183 
9184  // Now ready to draw the surface plot
9185 
9186  TView *view = gPad->GetView();
9187  if (!view) {
9188  Error("PaintSurface", "no TView in current pad");
9189  return;
9190  }
9191 
9192  Double_t thedeg = 90 - gPad->GetTheta();
9193  Double_t phideg = -90 - gPad->GetPhi();
9194  Double_t psideg = view->GetPsi();
9195  view->SetView(phideg, thedeg, psideg, irep);
9196 
9197  // Set color/style for back box
9198  if (Hoption.Same) {
9199  fLego->SetFillStyle(0);
9200  fLego->SetFillColor(1);
9201  } else {
9202  fLego->SetFillStyle(gPad->GetFrameFillStyle());
9203  fLego->SetFillColor(gPad->GetFrameFillColor());
9204  }
9205  fLego->TAttFill::Modify();
9206 
9207  Int_t backcolor = gPad->GetFrameFillColor();
9208  if (Hoption.System != kCARTESIAN) backcolor = 0;
9209  view->PadRange(backcolor);
9210 
9211  fLego->SetFillStyle(fH->GetFillStyle());
9212  fLego->SetFillColor(fH->GetFillColor());
9213  fLego->TAttFill::Modify();
9214 
9215  // Draw the filled contour on top
9216  Int_t icol1 = fH->GetFillColor();
9217 
9218  Int_t hoption35 = Hoption.Surf;
9219  if (Hoption.Surf == 13 || Hoption.Surf == 15) {
9220  DefineColorLevels(ndivz);
9221  Hoption.Surf = 23;
9222  fLego->SetSurfaceFunction(&TPainter3dAlgorithms::SurfaceFunction);
9223  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode2);
9224  if (Hoption.System == kPOLAR) fLego->SurfacePolar(1,nx,ny,"BF");
9225  if (Hoption.System == kCYLINDRICAL) fLego->SurfaceCylindrical(1,nx,ny,"BF");
9226  if (Hoption.System == kSPHERICAL) fLego->SurfaceSpherical(0,1,nx,ny,"BF");
9227  if (Hoption.System == kRAPIDITY ) fLego->SurfaceSpherical(1,1,nx,ny,"BF");
9228  if (Hoption.System == kCARTESIAN) fLego->SurfaceCartesian(90,nx,ny,"BF");
9229  Hoption.Surf = hoption35;
9230  fLego->SetMesh(1);
9231  }
9232 
9233  if (raster) fLego->InitRaster(-1.1,-1.1,1.1,1.1,1000,800);
9234  else fLego->InitMoveScreen(-1.1,1.1);
9235 
9236  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 14 || Hoption.Surf == 17) {
9237  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
9238  if (Hoption.System == kCARTESIAN && Hoption.BackBox) {
9239  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
9240  fLego->BackBox(90);
9241  }
9242  }
9243 
9244  // Gouraud Shading surface
9245  if (Hoption.Surf == 14) {
9246  // Set light sources
9247  fLego->LightSource(0, ydiff, 0,0,0,irep);
9248  fLego->LightSource(1, yligh1 ,1,1,1,irep);
9249  fLego->SurfaceProperty(qa, qd, qs, 1, irep);
9250  fmin = ydiff*qa;
9251  fmax = fmin + (yligh1+0.1)*(qd+qs);
9252  Int_t nbcol = 28;
9253  icol1 = 201;
9254  Double_t dcol = 0.5/Double_t(nbcol);
9255  TColor *colref = gROOT->GetColor(fH->GetFillColor());
9256  if (!colref) return;
9257  Float_t r,g,b,hue,light,satur;
9258  colref->GetRGB(r,g,b);
9259  TColor::RGBtoHLS(r,g,b,hue,light,satur);
9260  TColor *acol;
9261  for (Int_t col=0;col<nbcol;col++) {
9262  acol = gROOT->GetColor(col+icol1);
9263  TColor::HLStoRGB(hue,.4+col*dcol,satur,r,g,b);
9264  if (acol) acol->SetRGB(r,g,b);
9265  }
9266  fLego->Spectrum(nbcol, fmin, fmax, icol1, 1, irep);
9267  fLego->SetSurfaceFunction(&TPainter3dAlgorithms::GouraudFunction);
9268  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode2);
9269  if (Hoption.System == kPOLAR) fLego->SurfacePolar(1,nx,ny,"BF");
9270  if (Hoption.System == kCYLINDRICAL) fLego->SurfaceCylindrical(1,nx,ny,"BF");
9271  if (Hoption.System == kSPHERICAL) fLego->SurfaceSpherical(0,1,nx,ny,"BF");
9272  if (Hoption.System == kRAPIDITY ) fLego->SurfaceSpherical(1,1,nx,ny,"BF");
9273  if (Hoption.System == kCARTESIAN) fLego->SurfaceCartesian(90,nx,ny,"BF");
9274  } else if (Hoption.Surf == 15) {
9275  // The surface is not drawn in this case.
9276  } else {
9277  // Draw the surface
9278  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 16 || Hoption.Surf == 17) {
9279  DefineColorLevels(ndivz);
9280  } else {
9281  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
9282  }
9283  fLego->SetSurfaceFunction(&TPainter3dAlgorithms::SurfaceFunction);
9284  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceRaster1);
9285  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode2);
9286  if (Hoption.System == kPOLAR) {
9287  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SurfacePolar(1,nx,ny,"FB");
9288  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SurfacePolar(1,nx,ny,"BF");
9289  } else if (Hoption.System == kCYLINDRICAL) {
9290  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SurfaceCylindrical(1,nx,ny,"FB");
9291  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SurfaceCylindrical(1,nx,ny,"BF");
9292  } else if (Hoption.System == kSPHERICAL) {
9293  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SurfaceSpherical(0,1,nx,ny,"FB");
9294  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SurfaceSpherical(0,1,nx,ny,"BF");
9295  } else if (Hoption.System == kRAPIDITY) {
9296  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SurfaceSpherical(1,1,nx,ny,"FB");
9297  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SurfaceSpherical(1,1,nx,ny,"BF");
9298  } else {
9299  if (Hoption.Surf == 1 || Hoption.Surf == 13) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
9300  if (Hoption.Surf == 16) fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove3);
9301  if (Hoption.Surf == 1 || Hoption.Surf == 13 || Hoption.Surf == 16) fLego->SurfaceCartesian(90,nx,ny,"FB");
9302  if (Hoption.Surf == 11 || Hoption.Surf == 12 || Hoption.Surf == 17) fLego->SurfaceCartesian(90,nx,ny,"BF");
9303  }
9304  }
9305 
9306  // Paint the line contour on top for option SURF7
9307  if (Hoption.Surf == 17) {
9308  fLego->InitMoveScreen(-1.1,1.1);
9309  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
9310  Hoption.Surf = 23;
9311  fLego->SetSurfaceFunction(&TPainter3dAlgorithms::SurfaceFunction);
9312  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawLevelLines);
9313  if (Hoption.System == kPOLAR) fLego->SurfacePolar(1,nx,ny,"FB");
9314  if (Hoption.System == kCYLINDRICAL) fLego->SurfaceCylindrical(1,nx,ny,"FB");
9315  if (Hoption.System == kSPHERICAL) fLego->SurfaceSpherical(0,1,nx,ny,"FB");
9316  if (Hoption.System == kRAPIDITY ) fLego->SurfaceSpherical(1,1,nx,ny,"FB");
9317  if (Hoption.System == kCARTESIAN) fLego->SurfaceCartesian(90,nx,ny,"FB");
9318  }
9319 
9320  if ((!Hoption.Same) &&
9321  (Hoption.Surf == 1 || Hoption.Surf == 13 || Hoption.Surf == 16)) {
9322  if (Hoption.System == kCARTESIAN && Hoption.BackBox) {
9323  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
9324  fLego->BackBox(90);
9325  }
9326  }
9327  if (Hoption.System == kCARTESIAN) {
9328  fLego->InitMoveScreen(-1.1,1.1);
9329  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
9330  if (Hoption.FrontBox) fLego->FrontBox(90);
9331  }
9332  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
9333 
9334  if (Hoption.Zscale) PaintPalette();
9335 
9336  delete axis;
9337  delete fLego; fLego = 0;
9338 }
9339 
9340 ////////////////////////////////////////////////////////////////////////////////
9341 /// Control function to draw a table using Delaunay triangles.
9342 
9343 void THistPainter::PaintTriangles(Option_t *option)
9344 {
9345 
9346  TGraphDelaunay2D *dt = nullptr;
9347  TGraphDelaunay *dtOld = nullptr;
9348 
9349  // Check if fH contains a TGraphDelaunay2D
9350  TList *hl = fH->GetListOfFunctions();
9351  dt = (TGraphDelaunay2D*)hl->FindObject("TGraphDelaunay2D");
9352  if (!dt) dtOld = (TGraphDelaunay*)hl->FindObject("TGraphDelaunay");
9353  if (!dt && !dtOld) return;
9354 
9355  // If needed, create a TGraph2DPainter
9356  if (!fGraph2DPainter) {
9357  if (dt) fGraph2DPainter = new TGraph2DPainter(dt);
9358  else fGraph2DPainter = new TGraph2DPainter(dtOld);
9359  }
9360 
9361  // Define the 3D view
9362  if (Hparam.zmin == 0 && Hparam.zmax == 0) {Hparam.zmin = -1; Hparam.zmax = 1;}
9363  if (Hoption.Same) {
9364  TView *viewsame = gPad->GetView();
9365  if (!viewsame) {
9366  Error("PaintTriangles", "no TView in current pad, do not use option SAME");
9367  return;
9368  }
9369  Double_t *rmin = viewsame->GetRmin();
9370  Double_t *rmax = viewsame->GetRmax();
9371  if (!rmin || !rmax) return;
9372  fXbuf[0] = rmin[0];
9373  fYbuf[0] = rmax[0];
9374  fXbuf[1] = rmin[1];
9375  fYbuf[1] = rmax[1];
9376  fXbuf[2] = rmin[2];
9377  fYbuf[2] = rmax[2];
9378  } else {
9379  fXbuf[0] = Hparam.xmin;
9380  fYbuf[0] = Hparam.xmax;
9381  fXbuf[1] = Hparam.ymin;
9382  fYbuf[1] = Hparam.ymax;
9383  fXbuf[2] = Hparam.zmin;
9384  fYbuf[2] = Hparam.zmax;
9385  }
9386 
9387  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
9388  TView *view = gPad->GetView();
9389  if (!view) {
9390  Error("PaintTriangles", "no TView in current pad");
9391  return;
9392  }
9393  Double_t thedeg = 90 - gPad->GetTheta();
9394  Double_t phideg = -90 - gPad->GetPhi();
9395  Double_t psideg = view->GetPsi();
9396  Int_t irep;
9397  view->SetView(phideg, thedeg, psideg, irep);
9398 
9399  // Set color/style for back box
9400  fLego->SetFillStyle(gPad->GetFrameFillStyle());
9401  fLego->SetFillColor(gPad->GetFrameFillColor());
9402  fLego->TAttFill::Modify();
9403  Int_t backcolor = gPad->GetFrameFillColor();
9404  if (Hoption.System != kCARTESIAN) backcolor = 0;
9405  view->PadRange(backcolor);
9406  fLego->SetFillStyle(fH->GetFillStyle());
9407  fLego->SetFillColor(fH->GetFillColor());
9408  fLego->TAttFill::Modify();
9409 
9410  // Paint the Back Box if needed
9411  if (Hoption.BackBox && !Hoption.Same) {
9412  fLego->InitMoveScreen(-1.1,1.1);
9413  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
9414  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
9415  fLego->BackBox(90);
9416  }
9417 
9418  // Paint the triangles
9419  fGraph2DPainter->Paint(option);
9420 
9421  // Paint the Front Box if needed
9422  if (Hoption.FrontBox) {
9423  fLego->InitMoveScreen(-1.1,1.1);
9424  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
9425  fLego->FrontBox(90);
9426  }
9427 
9428  // Paint the Axis if needed
9429  if (!Hoption.Axis && !Hoption.Same) {
9430  TGaxis *axis = new TGaxis();
9431  PaintLegoAxis(axis, 90);
9432  delete axis;
9433  }
9434 
9435  if (Hoption.Zscale) PaintPalette();
9436 
9437  delete fLego; fLego = 0;
9438 }
9439 
9440 ////////////////////////////////////////////////////////////////////////////////
9441 /// Define the color levels used to paint legos, surfaces etc..
9442 
9443 void THistPainter::DefineColorLevels(Int_t ndivz)
9444 {
9445 
9446  Int_t i, irep;
9447 
9448  // Initialize the color levels
9449  if (ndivz >= 100) {
9450  Warning("PaintSurface", "too many color levels, %d, reset to 8", ndivz);
9451  ndivz = 8;
9452  }
9453  Double_t *funlevel = new Double_t[ndivz+1];
9454  Int_t *colorlevel = new Int_t[ndivz+1];
9455  Int_t theColor;
9456  Int_t ncolors = gStyle->GetNumberOfColors();
9457  for (i = 0; i < ndivz; ++i) {
9458  funlevel[i] = fH->GetContourLevelPad(i);
9459  theColor = Int_t((i+0.99)*Float_t(ncolors)/Float_t(ndivz));
9460  colorlevel[i] = gStyle->GetColorPalette(theColor);
9461  }
9462  colorlevel[ndivz] = gStyle->GetColorPalette(ncolors-1);
9463  fLego->ColorFunction(ndivz, funlevel, colorlevel, irep);
9464  delete [] colorlevel;
9465  delete [] funlevel;
9466 }
9467 
9468 ////////////////////////////////////////////////////////////////////////////////
9469 /// [Control function to draw 2D/3D histograms (tables).](#HP01c)
9470 
9471 void THistPainter::PaintTable(Option_t *option)
9472 {
9473 
9474  // Fill Hparam structure with histo parameters
9475  if (!TableInit()) return;
9476 
9477  // Draw histogram frame
9478  PaintFrame();
9479 
9480  // If palette option not specified, delete a possible existing palette
9481  if (!Hoption.Zscale) {
9482  TObject *palette = fFunctions->FindObject("palette");
9483  if (palette) { fFunctions->Remove(palette); delete palette;}
9484  }
9485 
9486  // Do not draw the histogram. Only the attached functions will be drawn.
9487  if (Hoption.Func == 2) {
9488  if (Hoption.Zscale) {
9489  Int_t ndiv = fH->GetContour();
9490  if (ndiv == 0 ) {
9491  ndiv = gStyle->GetNumberContours();
9492  fH->SetContour(ndiv);
9493  }
9494  PaintPalette();
9495  }
9496 
9497  // Draw the histogram according to the option
9498  } else {
9499  if (fH->InheritsFrom(TH2Poly::Class())) {
9500  if (Hoption.Fill) PaintTH2PolyBins("f");
9501  if (Hoption.Color) PaintTH2PolyColorLevels(option);
9502  if (Hoption.Scat) PaintTH2PolyScatterPlot(option);
9503  if (Hoption.Text) PaintTH2PolyText(option);
9504  if (Hoption.Line) PaintTH2PolyBins("l");
9505  if (Hoption.Mark) PaintTH2PolyBins("P");
9506  } else if (fH->GetEntries() != 0 && Hoption.Axis<=0) {
9507  if (Hoption.Scat) PaintScatterPlot(option);
9508  if (Hoption.Arrow) PaintArrows(option);
9509  if (Hoption.Box) PaintBoxes(option);
9510  if (Hoption.Color) {
9511  if (Hoption.Color == 3) PaintColorLevelsFast(option);
9512  else PaintColorLevels(option);
9513  }
9514  if (Hoption.Contour) PaintContour(option);
9515  if (Hoption.Text) PaintText(option);
9516  if (Hoption.Error >= 100) Paint2DErrors(option);
9517  if (Hoption.Candle) PaintCandlePlot(option);
9518  }
9519  if (Hoption.Lego) PaintLego(option);
9520  if (Hoption.Surf && !Hoption.Contour) PaintSurface(option);
9521  if (Hoption.Tri) PaintTriangles(option);
9522  }
9523 
9524  // Draw histogram title
9525  PaintTitle();
9526 
9527  // Draw the axes
9528  if (!Hoption.Lego && !Hoption.Surf &&
9529  !Hoption.Tri && !(Hoption.Error >= 100)) PaintAxis(kFALSE);
9530 
9531  TF1 *fit = 0;
9532  TIter next(fFunctions);
9533  TObject *obj;
9534  while ((obj = next())) {
9535  if (obj->InheritsFrom(TF1::Class())) {
9536  fit = (TF1*)obj;
9537  break;
9538  }
9539  }
9540  if ((Hoption.Same%10) != 1) {
9541  if (!fH->TestBit(TH1::kNoStats)) { // bit set via TH1::SetStats
9542  if (!gPad->PadInSelectionMode() && !gPad->PadInHighlightMode()) {
9543  //ALWAYS executed on non-iOS platform.
9544  //On iOS, depends on mode.
9545  PaintStat2(gStyle->GetOptStat(),fit);
9546  }
9547  }
9548  }
9549 }
9550 
9551 ////////////////////////////////////////////////////////////////////////////////
9552 /// Control function to draw a TH2Poly bins' contours.
9553 ///
9554 /// - option = "F" draw the bins as filled areas.
9555 /// - option = "L" draw the bins as line.
9556 /// - option = "P" draw the bins as markers.
9557 
9558 void THistPainter::PaintTH2PolyBins(Option_t *option)
9559 {
9560 
9561  //Do not highlight the histogram, if its part was picked.
9562  if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH) return;
9563 
9564  TString opt = option;
9565  opt.ToLower();
9566  Bool_t line = kFALSE;
9567  Bool_t fill = kFALSE;
9568  Bool_t mark = kFALSE;
9569  if (opt.Contains("l")) line = kTRUE;
9570  if (opt.Contains("f")) fill = kTRUE;
9571  if (opt.Contains("p")) mark = kTRUE;
9572 
9573  TH2PolyBin *b;
9574  Double_t z;
9575 
9576  TIter next(((TH2Poly*)fH)->GetBins());
9577  TObject *obj, *poly;
9578 
9579  while ((obj=next())) {
9580  b = (TH2PolyBin*)obj;
9581  z = b->GetContent();
9582  if (z==0 && Hoption.Zero) continue; // Do not draw empty bins in case of option "COL0 L"
9583  poly = b->GetPolygon();
9584 
9585  // Paint the TGraph bins.
9586  if (poly->IsA() == TGraph::Class()) {
9587  TGraph *g = (TGraph*)poly;
9588  g->TAttLine::Modify();
9589  g->TAttMarker::Modify();
9590  g->TAttFill::Modify();
9591  if (line) {
9592  Int_t fs = g->GetFillStyle();
9593  Int_t fc = g->GetFillColor();
9594  g->SetFillStyle(0);
9595  g->SetFillColor(g->GetLineColor());
9596  g->Paint("F");
9597  g->SetFillStyle(fs);
9598  g->SetFillColor(fc);
9599  }
9600  if (fill) g->Paint("F");
9601  if (mark) g->Paint("P");
9602  }
9603 
9604  // Paint the TMultiGraph bins.
9605  if (poly->IsA() == TMultiGraph::Class()) {
9606  TMultiGraph *mg = (TMultiGraph*)poly;
9607  TList *gl = mg->GetListOfGraphs();
9608  if (!gl) return;
9609  TGraph *g;
9610  TIter nextg(gl);
9611  while ((g = (TGraph*) nextg())) {
9612  g->TAttLine::Modify();
9613  g->TAttMarker::Modify();
9614  g->TAttFill::Modify();
9615  if (line) {
9616  Int_t fs = g->GetFillStyle();
9617  Int_t fc = g->GetFillColor();
9618  g->SetFillStyle(0);
9619  g->SetFillColor(g->GetLineColor());
9620  g->Paint("F");
9621  g->SetFillStyle(fs);
9622  g->SetFillColor(fc);
9623  }
9624  if (fill) g->Paint("F");
9625  if (mark) g->Paint("P");
9626  }
9627  }
9628  }
9629 }
9630 
9631 ////////////////////////////////////////////////////////////////////////////////
9632 /// [Control function to draw a TH2Poly as a color plot.](#HP20a)
9633 
9634 void THistPainter::PaintTH2PolyColorLevels(Option_t *)
9635 {
9636 
9637  //Do not highlight the histogram, if its part was picked.
9638  if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH)
9639  return;
9640 
9641  Int_t ncolors, color, theColor;
9642  Double_t z, zc;
9643  Double_t zmin = fH->GetMinimum();
9644  Double_t zmax = fH->GetMaximum();
9645  if (Hoption.Logz) {
9646  if (zmax > 0) {
9647  if (zmin <= 0) zmin = TMath::Min((Double_t)1, (Double_t)0.001*zmax);
9648  zmin = TMath::Log10(zmin);
9649  zmax = TMath::Log10(zmax);
9650  } else {
9651  return;
9652  }
9653  }
9654  Double_t dz = zmax - zmin;
9655 
9656  // Initialize the levels on the Z axis
9657  ncolors = gStyle->GetNumberOfColors();
9658  Int_t ndiv = fH->GetContour();
9659  if (ndiv == 0 ) {
9660  ndiv = gStyle->GetNumberContours();
9661  fH->SetContour(ndiv);
9662  }
9663  Int_t ndivz = TMath::Abs(ndiv);
9664  if (fH->TestBit(TH1::kUserContour) == 0) fH->SetContour(ndiv);
9665  Double_t scale = ndivz/dz;
9666 
9667  TH2PolyBin *b;
9668 
9669  TIter next(((TH2Poly*)fH)->GetBins());
9670  TObject *obj, *poly;
9671 
9672  while ((obj=next())) {
9673  b = (TH2PolyBin*)obj;
9674  poly = b->GetPolygon();
9675 
9676  z = b->GetContent();
9677  if (z==0 && Hoption.Zero) continue;
9678  if (Hoption.Logz) {
9679  if (z > 0) z = TMath::Log10(z);
9680  else z = zmin;
9681  }
9682  if (z < zmin) continue;
9683 
9684  // Define the bin color.
9685  if (fH->TestBit(TH1::kUserContour)) {
9686  zc = fH->GetContourLevelPad(0);
9687  if (z < zc) continue;
9688  color = -1;
9689  for (Int_t k=0; k<ndiv; k++) {
9690  zc = fH->GetContourLevelPad(k);
9691  if (z < zc) {
9692  continue;
9693  } else {
9694  color++;
9695  }
9696  }
9697  } else {
9698  color = Int_t(0.01+(z-zmin)*scale);
9699  }
9700  theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz));
9701  if (theColor > ncolors-1) theColor = ncolors-1;
9702 
9703  // Paint the TGraph bins.
9704  if (poly->IsA() == TGraph::Class()) {
9705  TGraph *g = (TGraph*)poly;
9706  g->SetFillColor(gStyle->GetColorPalette(theColor));
9707  g->TAttFill::Modify();
9708  g->Paint("F");
9709  }
9710 
9711  // Paint the TMultiGraph bins.
9712  if (poly->IsA() == TMultiGraph::Class()) {
9713  TMultiGraph *mg = (TMultiGraph*)poly;
9714  TList *gl = mg->GetListOfGraphs();
9715  if (!gl) return;
9716  TGraph *g;
9717  TIter nextg(gl);
9718  while ((g = (TGraph*) nextg())) {
9719  g->SetFillColor(gStyle->GetColorPalette(theColor));
9720  g->TAttFill::Modify();
9721  g->Paint("F");
9722  }
9723  }
9724  }
9725  if (Hoption.Zscale) PaintPalette();
9726 }
9727 
9728 ////////////////////////////////////////////////////////////////////////////////
9729 /// [Control function to draw a TH2Poly as a scatter plot.](#HP20a)
9730 
9731 void THistPainter::PaintTH2PolyScatterPlot(Option_t *)
9732 {
9733 
9734  //Do not highlight the histogram, if its part was selected.
9735  if (gPad->PadInHighlightMode() && gPad->GetSelected() != fH)
9736  return;
9737 
9738  Int_t k, loop, marker=0;
9739  Double_t z, xk,xstep, yk, ystep, xp, yp;
9740  Double_t scale = 1;
9741  Double_t zmin = fH->GetMinimum();
9742  Double_t zmax = fH->GetMaximum();
9743  if (Hoption.Logz) {
9744  if (zmax > 0) {
9745  if (zmin <= 0) zmin = TMath::Min((Double_t)1, (Double_t)0.001*zmax);
9746  zmin = TMath::Log10(zmin);
9747  zmax = TMath::Log10(zmax);
9748  } else {
9749  return;
9750  }
9751  }
9752  Double_t dz = zmax - zmin;
9753  scale = (kNMAX-1)/dz;
9754 
9755 
9756  // use an independent instance of a random generator
9757  // instead of gRandom to avoid conflicts and
9758  // to get same random numbers when drawing the same histogram
9759  TRandom2 random;
9760 
9761  TH2PolyBin *b;
9762 
9763  TIter next(((TH2Poly*)fH)->GetBins());
9764  TObject *obj, *poly;
9765 
9766  Double_t maxarea = 0, a;
9767  while ((obj=next())) {
9768  b = (TH2PolyBin*)obj;
9769  a = b->GetArea();
9770  if (a>maxarea) maxarea = a;
9771  }
9772 
9773  next.Reset();
9774 
9775  while ((obj=next())) {
9776  b = (TH2PolyBin*)obj;
9777  poly = b->GetPolygon();
9778  z = b->GetContent();
9779  if (z < zmin) z = zmin;
9780  if (z > zmax) z = zmax;
9781  if (Hoption.Logz) {
9782  if (z > 0) z = TMath::Log10(z) - zmin;
9783  } else {
9784  z -= zmin;
9785  }
9786  k = Int_t((z*scale)*(b->GetArea()/maxarea));
9787  xk = b->GetXMin();
9788  yk = b->GetYMin();
9789  xstep = b->GetXMax()-xk;
9790  ystep = b->GetYMax()-yk;
9791 
9792  // Paint the TGraph bins.
9793  if (poly->IsA() == TGraph::Class()) {
9794  TGraph *g = (TGraph*)poly;
9795  if (k <= 0 || z <= 0) continue;
9796  loop = 0;
9797  while (loop<k) {
9798  if (k+marker >= kNMAX) {
9799  gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
9800  marker=0;
9801  }
9802  xp = (random.Rndm()*xstep) + xk;
9803  yp = (random.Rndm()*ystep) + yk;
9804  if (g->IsInside(xp,yp)) {
9805  fXbuf[marker] = xp;
9806  fYbuf[marker] = yp;
9807  marker++;
9808  loop++;
9809  }
9810  }
9811  if (marker > 0) gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
9812  }
9813 
9814  // Paint the TMultiGraph bins.
9815  if (poly->IsA() == TMultiGraph::Class()) {
9816  TMultiGraph *mg = (TMultiGraph*)poly;
9817  TList *gl = mg->GetListOfGraphs();
9818  if (!gl) return;
9819  if (k <= 0 || z <= 0) continue;
9820  loop = 0;
9821  while (loop<k) {
9822  if (k+marker >= kNMAX) {
9823  gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
9824  marker=0;
9825  }
9826  xp = (random.Rndm()*xstep) + xk;
9827  yp = (random.Rndm()*ystep) + yk;
9828  if (mg->IsInside(xp,yp)) {
9829  fXbuf[marker] = xp;
9830  fYbuf[marker] = yp;
9831  marker++;
9832  loop++;
9833  }
9834  }
9835  if (marker > 0) gPad->PaintPolyMarker(marker, fXbuf, fYbuf);
9836  }
9837  }
9838  PaintTH2PolyBins("l");
9839 }
9840 
9841 ////////////////////////////////////////////////////////////////////////////////
9842 /// [Control function to draw a TH2Poly as a text plot.](#HP20a)
9843 
9844 void THistPainter::PaintTH2PolyText(Option_t *)
9845 {
9846 
9847  TLatex text;
9848  text.SetTextFont(gStyle->GetTextFont());
9849  text.SetTextColor(fH->GetMarkerColor());
9850  text.SetTextSize(0.02*fH->GetMarkerSize());
9851 
9852  Double_t x, y, z, e, angle = 0;
9853  TString tt, tf;
9854  tf.Form("%s%s","%",gStyle->GetPaintTextFormat());
9855  if (Hoption.Text >= 1000) angle = Hoption.Text%1000;
9856  Int_t opt = (Int_t)Hoption.Text/1000;
9857 
9858  text.SetTextAlign(22);
9859  if (Hoption.Text == 1) angle = 0;
9860  text.SetTextAngle(angle);
9861  text.TAttText::Modify();
9862 
9863  TH2PolyBin *b;
9864 
9865  TIter next(((TH2Poly*)fH)->GetBins());
9866  TObject *obj, *p;
9867 
9868  while ((obj=next())) {
9869  b = (TH2PolyBin*)obj;
9870  p = b->GetPolygon();
9871  x = (b->GetXMin()+b->GetXMax())/2;
9872  if (Hoption.Logx) {
9873  if (x > 0) x = TMath::Log10(x);
9874  else continue;
9875  }
9876  y = (b->GetYMin()+b->GetYMax())/2;
9877  if (Hoption.Logy) {
9878  if (y > 0) y = TMath::Log10(y);
9879  else continue;
9880  }
9881  z = b->GetContent();
9882  if (z < fH->GetMinimum() || (z == 0 && !Hoption.MinimumZero)) continue;
9883  if (opt==2) {
9884  e = fH->GetBinError(b->GetBinNumber());
9885  tf.Form("#splitline{%s%s}{#pm %s%s}",
9886  "%",gStyle->GetPaintTextFormat(),
9887  "%",gStyle->GetPaintTextFormat());
9888  tt.Form(tf.Data(),z,e);
9889  } else {
9890  tt.Form(tf.Data(),z);
9891  }
9892  if (opt==3) text.PaintLatex(x,y,angle,0.02*fH->GetMarkerSize(),p->GetName());
9893  else text.PaintLatex(x,y,angle,0.02*fH->GetMarkerSize(),tt.Data());
9894  }
9895 
9896  PaintTH2PolyBins("l");
9897 }
9898 
9899 ////////////////////////////////////////////////////////////////////////////////
9900 /// [Control function to draw a 1D/2D histograms with the bin values.](#HP15)
9901 
9902 void THistPainter::PaintText(Option_t *)
9903 {
9904 
9905  TLatex text;
9906  text.SetTextFont(gStyle->GetTextFont());
9907  text.SetTextColor(fH->GetMarkerColor());
9908  text.SetTextSize(0.02*fH->GetMarkerSize());
9909 
9910  Double_t x, y, z, e, angle = 0;
9911  TString tt, tf;
9912  tf.Form("%s%s","%",gStyle->GetPaintTextFormat());
9913  if (Hoption.Text >= 1000) angle = Hoption.Text%1000;
9914 
9915  // 1D histograms
9916  if (fH->GetDimension() == 1) {
9917  Bool_t getentries = kFALSE;
9918  Double_t yt;
9919  TProfile *hp = (TProfile*)fH;
9920  if (Hoption.Text>2000 && fH->InheritsFrom(TProfile::Class())) {
9921  Hoption.Text = Hoption.Text-2000;
9922  getentries = kTRUE;
9923  }
9924  if (Hoption.Text == 1) angle = 90;
9925  text.SetTextAlign(11);
9926  if (angle == 90) text.SetTextAlign(12);
9927  if (angle == 0) text.SetTextAlign(21);
9928  text.TAttText::Modify();
9929  Double_t dt = 0.02*(gPad->GetY2()-gPad->GetY1());
9930  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
9931  if (Hoption.Bar) {
9932  x = fH->GetXaxis()->GetBinLowEdge(i)+
9933  fH->GetXaxis()->GetBinWidth(i)*
9934  (fH->GetBarOffset()+0.5*fH->GetBarWidth());
9935  } else {
9936  x = fH->GetXaxis()->GetBinCenter(i);
9937  }
9938  y = fH->GetBinContent(i);
9939  yt = y;
9940  if (Hoption.MinimumZero && y<0) y = 0;
9941  if (getentries) yt = hp->GetBinEntries(i);
9942  if (yt == 0.) continue;
9943  tt.Form(tf.Data(),yt);
9944  if (Hoption.Logx) {
9945  if (x > 0) x = TMath::Log10(x);
9946  else continue;
9947  }
9948  if (Hoption.Logy) {
9949  if (y > 0) y = TMath::Log10(y);
9950  else continue;
9951  }
9952  if (y >= gPad->GetY2()) continue;
9953  if (y <= gPad->GetY1()) continue;
9954  text.PaintLatex(x,y+0.2*dt,angle,0.02*fH->GetMarkerSize(),tt.Data());
9955  }
9956 
9957  // 2D histograms
9958  } else {
9959  text.SetTextAlign(22);
9960  if (Hoption.Text == 1) angle = 0;
9961  text.SetTextAngle(angle);
9962  text.TAttText::Modify();
9963  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
9964  y = fYaxis->GetBinCenter(j);
9965  if (Hoption.Logy) {
9966  if (y > 0) y = TMath::Log10(y);
9967  else continue;
9968  }
9969  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
9970  Int_t bin = j*(fXaxis->GetNbins()+2) + i;
9971  x = fXaxis->GetBinCenter(i);
9972  if (Hoption.Logx) {
9973  if (x > 0) x = TMath::Log10(x);
9974  else continue;
9975  }
9976  if (!IsInside(x,y)) continue;
9977  z = fH->GetBinContent(bin);
9978  if (z < Hparam.zmin || (z == 0 && !Hoption.MinimumZero)) continue;
9979  if (Hoption.Text>2000) {
9980  e = fH->GetBinError(bin);
9981  tf.Form("#splitline{%s%s}{#pm %s%s}",
9982  "%",gStyle->GetPaintTextFormat(),
9983  "%",gStyle->GetPaintTextFormat());
9984  tt.Form(tf.Data(),z,e);
9985  } else {
9986  tt.Form(tf.Data(),z);
9987  }
9988  text.PaintLatex(x,y+fH->GetBarOffset()*fYaxis->GetBinWidth(j),
9989  angle,0.02*fH->GetMarkerSize(),tt.Data());
9990  }
9991  }
9992  }
9993 }
9994 
9995 ////////////////////////////////////////////////////////////////////////////////
9996 /// [Control function to draw a 3D implicit functions.](#HP27)
9997 
9998 void THistPainter::PaintTF3()
9999 {
10000 
10001  Int_t irep;
10002 
10003  TGaxis *axis = new TGaxis();
10004  TAxis *xaxis = fH->GetXaxis();
10005  TAxis *yaxis = fH->GetYaxis();
10006  TAxis *zaxis = fH->GetZaxis();
10007 
10008  fXbuf[0] = xaxis->GetBinLowEdge(xaxis->GetFirst());
10009  fYbuf[0] = xaxis->GetBinUpEdge(xaxis->GetLast());
10010  fXbuf[1] = yaxis->GetBinLowEdge(yaxis->GetFirst());
10011  fYbuf[1] = yaxis->GetBinUpEdge(yaxis->GetLast());
10012  fXbuf[2] = zaxis->GetBinLowEdge(zaxis->GetFirst());
10013  fYbuf[2] = zaxis->GetBinUpEdge(zaxis->GetLast());
10014 
10015  fLego = new TPainter3dAlgorithms(fXbuf, fYbuf);
10016 
10017  TView *view = gPad->GetView();
10018  if (!view) {
10019  Error("PaintTF3", "no TView in current pad");
10020  return;
10021  }
10022  Double_t thedeg = 90 - gPad->GetTheta();
10023  Double_t phideg = -90 - gPad->GetPhi();
10024  Double_t psideg = view->GetPsi();
10025  view->SetView(phideg, thedeg, psideg, irep);
10026 
10027  fLego->InitMoveScreen(-1.1,1.1);
10028 
10029  if (Hoption.BackBox) {
10030  fLego->DefineGridLevels(fZaxis->GetNdivisions()%100);
10031  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove1);
10032  fLego->BackBox(90);
10033  }
10034 
10035  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMode1);
10036 
10037  fLego->ImplicitFunction(fXbuf, fYbuf, fH->GetNbinsX(),
10038  fH->GetNbinsY(),
10039  fH->GetNbinsZ(), "BF");
10040 
10041  if (Hoption.FrontBox) {
10042  fLego->InitMoveScreen(-1.1,1.1);
10043  fLego->SetDrawFace(&TPainter3dAlgorithms::DrawFaceMove2);
10044  fLego->FrontBox(90);
10045  }
10046  if (!Hoption.Axis && !Hoption.Same) PaintLegoAxis(axis, 90);
10047 
10048  PaintTitle();
10049 
10050  delete axis;
10051  delete fLego; fLego = 0;
10052 }
10053 
10054 ////////////////////////////////////////////////////////////////////////////////
10055 /// Draw the histogram title
10056 ///
10057 /// The title is drawn according to the title alignment returned by
10058 /// `GetTitleAlign()`. It is a 2 digits integer): hv
10059 ///
10060 /// where `h` is the horizontal alignment and `v` is the
10061 /// vertical alignment.
10062 ///
10063 /// - `h` can get the values 1 2 3 for left, center, and right
10064 /// - `v` can get the values 1 2 3 for bottom, middle and top
10065 ///
10066 /// for instance the default alignment is: 13 (left top)
10067 
10068 void THistPainter::PaintTitle()
10069 {
10070  // probably best place for calls PaintHighlightBin
10071  // calls after paint histo (1D or 2D) and before paint title and stats
10072  if (!gPad->GetView()) PaintHighlightBin();
10073 
10074  if (Hoption.Same) return;
10075  if (fH->TestBit(TH1::kNoTitle)) return;
10076  Int_t nt = strlen(fH->GetTitle());
10077  TPaveText *title = 0;
10078  TObject *obj;
10079  TIter next(gPad->GetListOfPrimitives());
10080  while ((obj = next())) {
10081  if (!obj->InheritsFrom(TPaveText::Class())) continue;
10082  title = (TPaveText*)obj;
10083  if (strcmp(title->GetName(),"title")) {title = 0; continue;}
10084  break;
10085  }
10086  if (nt == 0 || gStyle->GetOptTitle() <= 0) {
10087  if (title) delete title;
10088  return;
10089  }
10090  Double_t ht = gStyle->GetTitleH();
10091  Double_t wt = gStyle->GetTitleW();
10092 
10093  if (ht <= 0) {
10094  if (gStyle->GetTitleFont("")%10 == 3) {
10095  Double_t hw = TMath::Max((Double_t)gPad->XtoPixel(gPad->GetX2()),
10096  (Double_t)gPad->YtoPixel(gPad->GetY1()));
10097  ht = 1.1*(gStyle->GetTitleSize("")/hw);
10098  } else {
10099  ht = 1.1*gStyle->GetTitleFontSize();
10100  }
10101  }
10102  if (ht <= 0) ht = 0.05;
10103  if (wt <= 0) {
10104  TLatex l;
10105  l.SetTextSize(ht);
10106  l.SetTitle(fH->GetTitle());
10107  // adjustment in case the title has several lines (#splitline)
10108  ht = TMath::Max(ht, 1.2*l.GetYsize()/(gPad->GetY2() - gPad->GetY1()));
10109  Double_t wndc = l.GetXsize()/(gPad->GetX2() - gPad->GetX1());
10110  wt = TMath::Min(0.7, 0.02+wndc);
10111  }
10112  if (title) {
10113  TText *t0 = (TText*)title->GetLine(0);
10114  if (t0) {
10115  if (!strcmp(t0->GetTitle(),fH->GetTitle())) return;
10116  t0->SetTitle(fH->GetTitle());
10117  if (wt > 0) title->SetX2NDC(title->GetX1NDC()+wt);
10118  }
10119  return;
10120  }
10121 
10122  Int_t talh = gStyle->GetTitleAlign()/10;
10123  if (talh < 1) talh = 1; else if (talh > 3) talh = 3;
10124  Int_t talv = gStyle->GetTitleAlign()%10;
10125  if (talv < 1) talv = 1; else if (talv > 3) talv = 3;
10126  Double_t xpos, ypos;
10127  xpos = gStyle->GetTitleX();
10128  ypos = gStyle->GetTitleY();
10129  if (talh == 2) xpos = xpos-wt/2.;
10130  if (talh == 3) xpos = xpos-wt;
10131  if (talv == 2) ypos = ypos+ht/2.;
10132  if (talv == 1) ypos = ypos+ht;
10133 
10134  TPaveText *ptitle = new TPaveText(xpos, ypos-ht, xpos+wt, ypos,"blNDC");
10135 
10136  // box with the histogram title
10137  ptitle->SetFillColor(gStyle->GetTitleFillColor());
10138  ptitle->SetFillStyle(gStyle->GetTitleStyle());
10139  ptitle->SetName("title");
10140  ptitle->SetBorderSize(gStyle->GetTitleBorderSize());
10141  ptitle->SetTextColor(gStyle->GetTitleTextColor());
10142  ptitle->SetTextFont(gStyle->GetTitleFont(""));
10143  if (gStyle->GetTitleFont("")%10 > 2)
10144  ptitle->SetTextSize(gStyle->GetTitleFontSize());
10145  ptitle->AddText(fH->GetTitle());
10146  ptitle->SetBit(kCanDelete);
10147  ptitle->Draw();
10148  ptitle->Paint();
10149 
10150  if(!gPad->IsEditable()) delete ptitle;
10151 }
10152 
10153 ////////////////////////////////////////////////////////////////////////////////
10154 /// Process message `mess`.
10155 
10156 void THistPainter::ProcessMessage(const char *mess, const TObject *obj)
10157 {
10158 
10159  if (!strcmp(mess,"SetF3")) {
10160  TPainter3dAlgorithms::SetF3((TF3*)obj);
10161  } else if (!strcmp(mess,"SetF3ClippingBoxOff")) {
10162  TPainter3dAlgorithms::SetF3ClippingBoxOff();
10163  } else if (!strcmp(mess,"SetF3ClippingBoxOn")) {
10164  TVectorD &v = (TVectorD&)(*obj);
10165  Double_t xclip = v(0);
10166  Double_t yclip = v(1);
10167  Double_t zclip = v(2);
10168  TPainter3dAlgorithms::SetF3ClippingBoxOn(xclip,yclip,zclip);
10169  }
10170 }
10171 
10172 ////////////////////////////////////////////////////////////////////////////////
10173 /// Static function.
10174 ///
10175 /// Convert Right Ascension, Declination to X,Y using an AITOFF projection.
10176 /// This procedure can be used to create an all-sky map in Galactic
10177 /// coordinates with an equal-area Aitoff projection. Output map
10178 /// coordinates are zero longitude centered.
10179 /// Also called Hammer-Aitoff projection (first presented by Ernst von Hammer in 1892)
10180 ///
10181 /// source: GMT
10182 ///
10183 /// code from Ernst-Jan Buis
10184 
10185 Int_t THistPainter::ProjectAitoff2xy(Double_t l, Double_t b, Double_t &Al, Double_t &Ab)
10186 {
10187 
10188  Double_t x, y;
10189 
10190  Double_t alpha2 = (l/2)*TMath::DegToRad();
10191  Double_t delta = b*TMath::DegToRad();
10192  Double_t r2 = TMath::Sqrt(2.);
10193  Double_t f = 2*r2/TMath::Pi();
10194  Double_t cdec = TMath::Cos(delta);
10195  Double_t denom = TMath::Sqrt(1. + cdec*TMath::Cos(alpha2));
10196  x = cdec*TMath::Sin(alpha2)*2.*r2/denom;
10197  y = TMath::Sin(delta)*r2/denom;
10198  x *= TMath::RadToDeg()/f;
10199  y *= TMath::RadToDeg()/f;
10200  // x *= -1.; // for a skymap swap left<->right
10201  Al = x;
10202  Ab = y;
10203 
10204  return 0;
10205 }
10206 
10207 ////////////////////////////////////////////////////////////////////////////////
10208 /// Static function
10209 ///
10210 /// Probably the most famous of the various map projections, the Mercator projection
10211 /// takes its name from Mercator who presented it in 1569. It is a cylindrical, conformal projection
10212 /// with no distortion along the equator.
10213 /// The Mercator projection has been used extensively for world maps in which the distortion towards
10214 /// the polar regions grows rather large, thus incorrectly giving the impression that, for example,
10215 /// Greenland is larger than South America. In reality, the latter is about eight times the size of
10216 /// Greenland. Also, the Former Soviet Union looks much bigger than Africa or South America. One may wonder
10217 /// whether this illusion has had any influence on U.S. foreign policy.' (Source: GMT)
10218 /// code from Ernst-Jan Buis
10219 
10220 Int_t THistPainter::ProjectMercator2xy(Double_t l, Double_t b, Double_t &Al, Double_t &Ab)
10221 {
10222 
10223  Al = l;
10224  Double_t aid = TMath::Tan((TMath::PiOver2() + b*TMath::DegToRad())/2);
10225  Ab = TMath::Log(aid);
10226  return 0;
10227 }
10228 
10229 ////////////////////////////////////////////////////////////////////////////////
10230 /// Static function code from Ernst-Jan Buis
10231 
10232 Int_t THistPainter::ProjectSinusoidal2xy(Double_t l, Double_t b, Double_t &Al, Double_t &Ab)
10233 {
10234 
10235  Al = l*cos(b*TMath::DegToRad());
10236  Ab = b;
10237  return 0;
10238 }
10239 
10240 ////////////////////////////////////////////////////////////////////////////////
10241 /// Static function code from Ernst-Jan Buis
10242 
10243 Int_t THistPainter::ProjectParabolic2xy(Double_t l, Double_t b, Double_t &Al, Double_t &Ab)
10244 {
10245 
10246  Al = l*(2.*TMath::Cos(2*b*TMath::DegToRad()/3) - 1);
10247  Ab = 180*TMath::Sin(b*TMath::DegToRad()/3);
10248  return 0;
10249 }
10250 
10251 ////////////////////////////////////////////////////////////////////////////////
10252 /// Recompute the histogram range following graphics operations.
10253 
10254 void THistPainter::RecalculateRange()
10255 {
10256 
10257  if (Hoption.Same) return;
10258 
10259  // Compute x,y range
10260  Double_t xmin = Hparam.xmin;
10261  Double_t xmax = Hparam.xmax;
10262  Double_t ymin = Hparam.ymin;
10263  Double_t ymax = Hparam.ymax;
10264 
10265  Double_t xmin_aid, ymin_aid, xmax_aid, ymax_aid;
10266  if (Hoption.Proj ==1) {
10267  // TODO : check x range not lower than -180 and not higher than 180
10268  THistPainter::ProjectAitoff2xy(Hparam.xmin, Hparam.ymin, xmin_aid, ymin_aid);
10269  THistPainter::ProjectAitoff2xy(Hparam.xmin, Hparam.ymax, xmin, ymax_aid);
10270  THistPainter::ProjectAitoff2xy(Hparam.xmax, Hparam.ymax, xmax_aid, ymax);
10271  THistPainter::ProjectAitoff2xy(Hparam.xmax, Hparam.ymin, xmax, ymin);
10272 
10273  if (xmin > xmin_aid) xmin = xmin_aid;
10274  if (ymin > ymin_aid) ymin = ymin_aid;
10275  if (xmax < xmax_aid) xmax = xmax_aid;
10276  if (ymax < ymax_aid) ymax = ymax_aid;
10277  if (Hparam.ymin<0 && Hparam.ymax>0) {
10278  // there is an 'equator', check its range in the plot..
10279  THistPainter::ProjectAitoff2xy(Hparam.xmin*0.9999, 0, xmin_aid, ymin_aid);
10280  THistPainter::ProjectAitoff2xy(Hparam.xmax*0.9999, 0, xmax_aid, ymin_aid);
10281  if (xmin >xmin_aid) xmin = xmin_aid;
10282  if (xmax <xmax_aid) xmax = xmax_aid;
10283  }
10284  if (Hparam.xmin<0 && Hparam.xmax>0) {
10285  THistPainter::ProjectAitoff2xy(0, Hparam.ymin, xmin_aid, ymin_aid);
10286  THistPainter::ProjectAitoff2xy(0, Hparam.ymax, xmax_aid, ymax_aid);
10287  if (ymin >ymin_aid) ymin = ymin_aid;
10288  if (ymax <ymax_aid) ymax = ymax_aid;
10289  }
10290  } else if ( Hoption.Proj ==2) {
10291  if (Hparam.ymin <= -90 || Hparam.ymax >=90) {
10292  Warning("Mercator Projection", "Latitude out of range %f or %f", Hparam.ymin, Hparam.ymax);
10293  Hoption.Proj = 0;
10294  } else {
10295  THistPainter::ProjectMercator2xy(Hparam.xmin, Hparam.ymin, xmin, ymin);
10296  THistPainter::ProjectMercator2xy(Hparam.xmax, Hparam.ymax, xmax, ymax);
10297  }
10298  } else if (Hoption.Proj == 3) {
10299  THistPainter::ProjectSinusoidal2xy(Hparam.xmin, Hparam.ymin, xmin_aid, ymin_aid);
10300  THistPainter::ProjectSinusoidal2xy(Hparam.xmin, Hparam.ymax, xmin, ymax_aid);
10301  THistPainter::ProjectSinusoidal2xy(Hparam.xmax, Hparam.ymax, xmax_aid, ymax);
10302  THistPainter::ProjectSinusoidal2xy(Hparam.xmax, Hparam.ymin, xmax, ymin);
10303 
10304  if (xmin > xmin_aid) xmin = xmin_aid;
10305  if (ymin > ymin_aid) ymin = ymin_aid;
10306  if (xmax < xmax_aid) xmax = xmax_aid;
10307  if (ymax < ymax_aid) ymax = ymax_aid;
10308  if (Hparam.ymin<0 && Hparam.ymax>0) {
10309  THistPainter::ProjectSinusoidal2xy(Hparam.xmin, 0, xmin_aid, ymin_aid);
10310  THistPainter::ProjectSinusoidal2xy(Hparam.xmax, 0, xmax_aid, ymin_aid);
10311  if (xmin >xmin_aid) xmin = xmin_aid;
10312  if (xmax <xmax_aid) xmax = xmax_aid;
10313  }
10314  if (Hparam.xmin<0 && Hparam.xmax>0) {
10315  THistPainter::ProjectSinusoidal2xy(0,Hparam.ymin, xmin_aid, ymin_aid);
10316  THistPainter::ProjectSinusoidal2xy(0, Hparam.ymax, xmax_aid, ymin_aid);
10317  if (ymin >ymin_aid) ymin = ymin_aid;
10318  if (ymax <ymax_aid) ymax = ymax_aid;
10319  }
10320  } else if (Hoption.Proj == 4) {
10321  THistPainter::ProjectParabolic2xy(Hparam.xmin, Hparam.ymin, xmin_aid, ymin_aid);
10322  THistPainter::ProjectParabolic2xy(Hparam.xmin, Hparam.ymax, xmin, ymax_aid);
10323  THistPainter::ProjectParabolic2xy(Hparam.xmax, Hparam.ymax, xmax_aid, ymax);
10324  THistPainter::ProjectParabolic2xy(Hparam.xmax, Hparam.ymin, xmax, ymin);
10325 
10326  if (xmin > xmin_aid) xmin = xmin_aid;
10327  if (ymin > ymin_aid) ymin = ymin_aid;
10328  if (xmax < xmax_aid) xmax = xmax_aid;
10329  if (ymax < ymax_aid) ymax = ymax_aid;
10330  if (Hparam.ymin<0 && Hparam.ymax>0) {
10331  THistPainter::ProjectParabolic2xy(Hparam.xmin, 0, xmin_aid, ymin_aid);
10332  THistPainter::ProjectParabolic2xy(Hparam.xmax, 0, xmax_aid, ymin_aid);
10333  if (xmin >xmin_aid) xmin = xmin_aid;
10334  if (xmax <xmax_aid) xmax = xmax_aid;
10335  }
10336  if (Hparam.xmin<0 && Hparam.xmax>0) {
10337  THistPainter::ProjectParabolic2xy(0, Hparam.ymin, xmin_aid, ymin_aid);
10338  THistPainter::ProjectParabolic2xy(0, Hparam.ymax, xmax_aid, ymin_aid);
10339  if (ymin >ymin_aid) ymin = ymin_aid;
10340  if (ymax <ymax_aid) ymax = ymax_aid;
10341  }
10342  }
10343  Hparam.xmin= xmin;
10344  Hparam.xmax= xmax;
10345  Hparam.ymin= ymin;
10346  Hparam.ymax= ymax;
10347 
10348  Double_t dx = xmax-xmin;
10349  Double_t dy = ymax-ymin;
10350  Double_t dxr = dx/(1 - gPad->GetLeftMargin() - gPad->GetRightMargin());
10351  Double_t dyr = dy/(1 - gPad->GetBottomMargin() - gPad->GetTopMargin());
10352 
10353  // Range() could change the size of the pad pixmap and therefore should
10354  // be called before the other paint routines
10355  gPad->Range(xmin - dxr*gPad->GetLeftMargin(),
10356  ymin - dyr*gPad->GetBottomMargin(),
10357  xmax + dxr*gPad->GetRightMargin(),
10358  ymax + dyr*gPad->GetTopMargin());
10359  gPad->RangeAxis(xmin, ymin, xmax, ymax);
10360 }
10361 
10362 ////////////////////////////////////////////////////////////////////////////////
10363 /// Set current histogram to `h`
10364 
10365 void THistPainter::SetHistogram(TH1 *h)
10366 {
10367 
10368  if (h == 0) return;
10369  fH = h;
10370  fXaxis = h->GetXaxis();
10371  fYaxis = h->GetYaxis();
10372  fZaxis = h->GetZaxis();
10373  fFunctions = fH->GetListOfFunctions();
10374 }
10375 
10376 ////////////////////////////////////////////////////////////////////////////////
10377 /// Initialize various options to draw 2D histograms.
10378 
10379 Int_t THistPainter::TableInit()
10380 {
10381 
10382  static const char *where = "TableInit";
10383 
10384  Int_t first, last;
10385  Double_t yMARGIN= gStyle->GetHistTopMargin();
10386  Double_t zmin, zmax;
10387  Int_t maximum = 0;
10388  Int_t minimum = 0;
10389  if (fH->GetMaximumStored() != -1111) maximum = 1;
10390  if (fH->GetMinimumStored() != -1111) minimum = 1;
10391 
10392  // ----------------- Compute X axis parameters
10393  first = fXaxis->GetFirst();
10394  last = fXaxis->GetLast();
10395  Hparam.xlast = last;
10396  Hparam.xfirst = first;
10397  Hparam.xlowedge = fXaxis->GetBinLowEdge(first);
10398  Hparam.xbinsize = fXaxis->GetBinWidth(first);
10399  Hparam.xmin = Hparam.xlowedge;
10400  Hparam.xmax = fXaxis->GetBinLowEdge(last)+fXaxis->GetBinWidth(last);
10401 
10402  // if log scale in X, replace xmin,max by the log
10403  if (Hoption.Logx) {
10404  // find the first edge of a bin that is > 0
10405  if (Hparam.xlowedge <=0 ) {
10406  Hparam.xlowedge = fXaxis->GetBinUpEdge(fXaxis->FindFixBin(0.01*Hparam.xbinsize));
10407  Hparam.xmin = Hparam.xlowedge;
10408  }
10409  if (Hparam.xmin <=0 || Hparam.xmax <=0) {
10410  Error(where, "cannot set X axis to log scale");
10411  return 0;
10412  }
10413  Hparam.xfirst= fXaxis->FindFixBin(Hparam.xmin);
10414  if (Hparam.xfirst < first) Hparam.xfirst = first;
10415  Hparam.xlast = fXaxis->FindFixBin(Hparam.xmax);
10416  if (Hparam.xlast > last) Hparam.xlast = last;
10417  Hparam.xmin = TMath::Log10(Hparam.xmin);
10418  Hparam.xmax = TMath::Log10(Hparam.xmax);
10419  }
10420 
10421  // ----------------- Compute Y axis parameters
10422  first = fYaxis->GetFirst();
10423  last = fYaxis->GetLast();
10424  Hparam.ylast = last;
10425  Hparam.yfirst = first;
10426  Hparam.ylowedge = fYaxis->GetBinLowEdge(first);
10427  Hparam.ybinsize = fYaxis->GetBinWidth(first);
10428  if (!Hparam.ybinsize) Hparam.ybinsize = 1;
10429  Hparam.ymin = Hparam.ylowedge;
10430  Hparam.ymax = fYaxis->GetBinLowEdge(last)+fYaxis->GetBinWidth(last);
10431 
10432  // if log scale in Y, replace ymin,max by the log
10433  if (Hoption.Logy) {
10434  if (Hparam.ylowedge <=0 ) {
10435  Hparam.ylowedge = fYaxis->GetBinUpEdge(fYaxis->FindFixBin(0.01*Hparam.ybinsize));
10436  Hparam.ymin = Hparam.ylowedge;
10437  }
10438  if (Hparam.ymin <=0 || Hparam.ymax <=0) {
10439  Error(where, "cannot set Y axis to log scale");
10440  return 0;
10441  }
10442  Hparam.yfirst= fYaxis->FindFixBin(Hparam.ymin);
10443  if (Hparam.yfirst < first) Hparam.yfirst = first;
10444  Hparam.ylast = fYaxis->FindFixBin(Hparam.ymax);
10445  if (Hparam.ylast > last) Hparam.ylast = last;
10446  Hparam.ymin = TMath::Log10(Hparam.ymin);
10447  Hparam.ymax = TMath::Log10(Hparam.ymax);
10448  }
10449 
10450 
10451  // ----------------- Compute Z axis parameters
10452  Double_t bigp = TMath::Power(10,32);
10453  zmax = -bigp;
10454  zmin = bigp;
10455  Double_t c1, e1;
10456  Double_t allchan = 0;
10457  for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) {
10458  for (Int_t i=Hparam.xfirst; i<=Hparam.xlast;i++) {
10459  c1 = fH->GetBinContent(i,j);
10460  zmax = TMath::Max(zmax,c1);
10461  if (Hoption.Error) {
10462  e1 = fH->GetBinError(i,j);
10463  zmax = TMath::Max(zmax,c1+e1);
10464  }
10465  zmin = TMath::Min(zmin,c1);
10466  allchan += c1;
10467  }
10468  }
10469 
10470  // Take into account maximum , minimum
10471 
10472  if (maximum) zmax = fH->GetMaximumStored();
10473  if (minimum) zmin = fH->GetMinimumStored();
10474  if (Hoption.Logz && zmax < 0) {
10475  if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", zmax);
10476  return 0;
10477  } else if (Hoption.Logz && zmin>=0 && zmax==0) { // empty histogram in log scale
10478  zmin = 0.01;
10479  zmax = 10.;
10480  }
10481  if (zmin >= zmax) {
10482  if (Hoption.Logz) {
10483  if (zmax > 0) zmin = 0.001*zmax;
10484  else {
10485  if (!Hoption.Same) Error(where, "log scale is requested but maximum is less or equal 0 (%f)", zmax);
10486  return 0;
10487  }
10488  }
10489  }
10490 
10491  // take into account normalization factor
10492  Hparam.allchan = allchan;
10493  Double_t factor = allchan;
10494  if (fH->GetNormFactor() > 0) factor = fH->GetNormFactor();
10495  if (allchan) factor /= allchan;
10496  if (factor == 0) factor = 1;
10497  Hparam.factor = factor;
10498  zmax = factor*zmax;
10499  zmin = factor*zmin;
10500  c1 = zmax;
10501  if (TMath::Abs(zmin) > TMath::Abs(c1)) c1 = zmin;
10502 
10503  // For log scales, histogram coordinates are log10(ymin) and
10504  // log10(ymax). Final adjustment (if not option "Same")
10505  // or "+" for ymax) of ymax and ymin for logarithmic scale, if
10506  // Maximum and Minimum are not defined.
10507  if (Hoption.Logz) {
10508  if (zmin <= 0) {
10509  zmin = TMath::Min((Double_t)1, (Double_t)0.001*zmax);
10510  fH->SetMinimum(zmin);
10511  }
10512  zmin = TMath::Log10(zmin);
10513  if (!minimum) zmin += TMath::Log10(0.5);
10514  zmax = TMath::Log10(zmax);
10515  if (!maximum) zmax += TMath::Log10(2*(0.9/0.95));
10516  goto LZMIN;
10517  }
10518 
10519  // final adjustment of YMAXI for linear scale (if not option "Same"):
10520  // decrease histogram height to MAX% of allowed height if HMAXIM
10521  // has not been called.
10522  // MAX% is the value in percent which has been set in HPLSET
10523  // (default is 90%).
10524  if (!maximum) {
10525  zmax += yMARGIN*(zmax-zmin);
10526  }
10527 
10528  // final adjustment of ymin for linear scale.
10529  // if minimum is not set , then ymin is set to zero if >0
10530  // or to ymin - yMARGIN if <0.
10531  if (!minimum) {
10532  if (Hoption.MinimumZero) {
10533  if (zmin >= 0) zmin = 0;
10534  else zmin -= yMARGIN*(zmax-zmin);
10535  } else {
10536  Double_t dzmin = yMARGIN*(zmax-zmin);
10537  if (zmin >= 0 && (zmin-dzmin <= 0)) zmin = 0;
10538  else zmin -= dzmin;
10539  }
10540  }
10541 
10542 LZMIN:
10543  Hparam.zmin = zmin;
10544  Hparam.zmax = zmax;
10545 
10546  // Set bar offset and width
10547  Hparam.baroffset = fH->GetBarOffset();
10548  Hparam.barwidth = fH->GetBarWidth();
10549 
10550  return 1;
10551 }
10552 
10553 ////////////////////////////////////////////////////////////////////////////////
10554 /// This function returns the best format to print the error value (e)
10555 /// knowing the parameter value (v) and the format (f) used to print it.
10556 
10557 const char * THistPainter::GetBestFormat(Double_t v, Double_t e, const char *f)
10558 {
10559 
10560  static TString ef;
10561  TString tf, tv;
10562 
10563  // print v with the format f in tv.
10564  tf.Form("%s%s","%",f);
10565  tv.Form(tf.Data(),v);
10566 
10567  // Analyse tv.
10568  int ie = tv.Index("e");
10569  int iE = tv.Index("E");
10570  int id = tv.Index(".");
10571 
10572  // v has been printed with the exponent notation.
10573  // There is 2 cases, the exponent is positive or negative
10574  if (ie >= 0 || iE >= 0) {
10575  if (tv.Index("+") >= 0) {
10576  if (e < 1) {
10577  ef.Form("%s.1f","%");
10578  } else {
10579  if (ie >= 0) {
10580  ef.Form("%s.%de","%",ie-id-1);
10581  } else {
10582  ef.Form("%s.%dE","%",iE-id-1);
10583  }
10584  }
10585  } else {
10586  if (ie >= 0) {
10587  ef.Form("%s.%de","%",ie-id-1);
10588  } else {
10589  ef.Form("%s.%dE","%",iE-id-1);
10590  }
10591  }
10592 
10593  // There is not '.' in tv. e will be printed with one decimal digit.
10594  } else if (id < 0) {
10595  ef.Form("%s.1f","%");
10596 
10597  // There is a '.' in tv and no exponent notation. e's decimal part will
10598  // have the same number of digits as v's one.
10599  } else {
10600  ef.Form("%s.%df","%",tv.Length()-id-1);
10601  }
10602 
10603  return ef.Data();
10604 }
10605 
10606 ////////////////////////////////////////////////////////////////////////////////
10607 /// Set projection.
10608 
10609 void THistPainter::SetShowProjection(const char *option,Int_t nbins)
10610 {
10611 
10612  if (fShowProjection) return;
10613  TString opt = option;
10614  opt.ToLower();
10615  Int_t projection = 0;
10616  if (opt.Contains("x")) projection = 1;
10617  if (opt.Contains("y")) projection = 2;
10618  if (opt.Contains("z")) projection = 3;
10619  if (opt.Contains("xy")) projection = 4;
10620  if (opt.Contains("yx")) projection = 5;
10621  if (opt.Contains("xz")) projection = 6;
10622  if (opt.Contains("zx")) projection = 7;
10623  if (opt.Contains("yz")) projection = 8;
10624  if (opt.Contains("zy")) projection = 9;
10625  if (projection < 4) fShowOption = option+1;
10626  else fShowOption = option+2;
10627  fShowProjection = projection+100*nbins;
10628  gROOT->MakeDefCanvas();
10629  gPad->SetName(Form("c_%lx_projection_%d", (ULong_t)fH, fShowProjection));
10630  gPad->SetGrid();
10631 }
10632 
10633 ////////////////////////////////////////////////////////////////////////////////
10634 /// Show projection onto X.
10635 
10636 void THistPainter::ShowProjectionX(Int_t /*px*/, Int_t py)
10637 {
10638 
10639  Int_t nbins = (Int_t)fShowProjection/100;
10640  gPad->SetDoubleBuffer(0); // turn off double buffer mode
10641  gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode
10642 
10643  // Erase old position and draw a line at current position
10644  static int pyold1 = 0;
10645  static int pyold2 = 0;
10646  float uxmin = gPad->GetUxmin();
10647  float uxmax = gPad->GetUxmax();
10648  int pxmin = gPad->XtoAbsPixel(uxmin);
10649  int pxmax = gPad->XtoAbsPixel(uxmax);
10650  Float_t upy = gPad->AbsPixeltoY(py);
10651  Float_t y = gPad->PadtoY(upy);
10652  Int_t biny1 = fH->GetYaxis()->FindBin(y);
10653  Int_t biny2 = TMath::Min(biny1+nbins-1, fH->GetYaxis()->GetNbins());
10654  Int_t py1 = gPad->YtoAbsPixel(fH->GetYaxis()->GetBinLowEdge(biny1));
10655  Int_t py2 = gPad->YtoAbsPixel(fH->GetYaxis()->GetBinUpEdge(biny2));
10656 
10657  if (pyold1 || pyold2) gVirtualX->DrawBox(pxmin,pyold1,pxmax,pyold2,TVirtualX::kFilled);
10658  gVirtualX->DrawBox(pxmin,py1,pxmax,py2,TVirtualX::kFilled);
10659  pyold1 = py1;
10660  pyold2 = py2;
10661 
10662  // Create or set the new canvas proj x
10663  TVirtualPad *padsav = gPad;
10664  TVirtualPad *c = (TVirtualPad*)gROOT->GetListOfCanvases()->FindObject(Form("c_%lx_projection_%d",
10665  (ULong_t)fH, fShowProjection));
10666  if (c) {
10667  c->Clear();
10668  } else {
10669  fShowProjection = 0;
10670  pyold1 = 0;
10671  pyold2 = 0;
10672  return;
10673  }
10674  c->cd();
10675  c->SetLogy(padsav->GetLogz());
10676  c->SetLogx(padsav->GetLogx());
10677 
10678  // Draw slice corresponding to mouse position
10679  TString prjName = TString::Format("slice_px_of_%s",fH->GetName());
10680  TH1D *hp = ((TH2*)fH)->ProjectionX(prjName, biny1, biny2);
10681  if (hp) {
10682  hp->SetFillColor(38);
10683  // apply a patch from Oliver Freyermuth to set the title in the projection
10684  // using the range of the projected Y values
10685  if (biny1 == biny2) {
10686  Double_t valueFrom = fH->GetYaxis()->GetBinLowEdge(biny1);
10687  Double_t valueTo = fH->GetYaxis()->GetBinUpEdge(biny1);
10688  // Limit precision to 1 digit more than the difference between upper and lower bound (to also catch 121.5-120.5).
10689  Int_t valuePrecision = -TMath::Nint(TMath::Log10(valueTo-valueFrom))+1;
10690  if (fH->GetYaxis()->GetLabels() != NULL) {
10691  hp->SetTitle(TString::Format("ProjectionX of biny=%d [y=%.*lf..%.*lf] %s", biny1, valuePrecision, valueFrom, valuePrecision, valueTo, fH->GetYaxis()->GetBinLabel(biny1)));
10692  } else {
10693  hp->SetTitle(TString::Format("ProjectionX of biny=%d [y=%.*lf..%.*lf]", biny1, valuePrecision, valueFrom, valuePrecision, valueTo));
10694  }
10695  } else {
10696  Double_t valueFrom = fH->GetYaxis()->GetBinLowEdge(biny1);
10697  Double_t valueTo = fH->GetYaxis()->GetBinUpEdge(biny2);
10698  // Limit precision to 1 digit more than the difference between upper and lower bound (to also catch 121.5-120.5).
10699  // biny1 is used here to get equal precision no matter how large the binrange is,
10700  // otherwise precision may change when moving the mouse to the histogram boundaries (limiting effective binrange).
10701  Int_t valuePrecision = -TMath::Nint(TMath::Log10(fH->GetYaxis()->GetBinUpEdge(biny1)-valueFrom))+1;
10702  if (fH->GetYaxis()->GetLabels() != NULL) {
10703  hp->SetTitle(TString::Format("ProjectionX of biny=[%d,%d] [y=%.*lf..%.*lf] [%s..%s]", biny1, biny2, valuePrecision, valueFrom, valuePrecision, valueTo, fH->GetYaxis()->GetBinLabel(biny1), fH->GetYaxis()->GetBinLabel(biny2)));
10704  } else {
10705  hp->SetTitle(TString::Format("ProjectionX of biny=[%d,%d] [y=%.*lf..%.*lf]", biny1, biny2, valuePrecision, valueFrom, valuePrecision, valueTo));
10706  }
10707  }
10708  hp->SetXTitle(fH->GetXaxis()->GetTitle());
10709  hp->SetYTitle("Number of Entries");
10710  hp->Draw();
10711  c->Update();
10712  padsav->cd();
10713  }
10714 }
10715 
10716 ////////////////////////////////////////////////////////////////////////////////
10717 /// Show projection onto Y.
10718 
10719 void THistPainter::ShowProjectionY(Int_t px, Int_t /*py*/)
10720 {
10721 
10722  Int_t nbins = (Int_t)fShowProjection/100;
10723  gPad->SetDoubleBuffer(0); // turn off double buffer mode
10724  gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode
10725 
10726  // Erase old position and draw a line at current position
10727  static int pxold1 = 0;
10728  static int pxold2 = 0;
10729  float uymin = gPad->GetUymin();
10730  float uymax = gPad->GetUymax();
10731  int pymin = gPad->YtoAbsPixel(uymin);
10732  int pymax = gPad->YtoAbsPixel(uymax);
10733  Float_t upx = gPad->AbsPixeltoX(px);
10734  Float_t x = gPad->PadtoX(upx);
10735  Int_t binx1 = fH->GetXaxis()->FindBin(x);
10736  Int_t binx2 = TMath::Min(binx1+nbins-1, fH->GetXaxis()->GetNbins());
10737  Int_t px1 = gPad->XtoAbsPixel(fH->GetXaxis()->GetBinLowEdge(binx1));
10738  Int_t px2 = gPad->XtoAbsPixel(fH->GetXaxis()->GetBinUpEdge(binx2));
10739 
10740  if (pxold1 || pxold2) gVirtualX->DrawBox(pxold1,pymin,pxold2,pymax,TVirtualX::kFilled);
10741  gVirtualX->DrawBox(px1,pymin,px2,pymax,TVirtualX::kFilled);
10742  pxold1 = px1;
10743  pxold2 = px2;
10744 
10745  // Create or set the new canvas proj y
10746  TVirtualPad *padsav = gPad;
10747  TVirtualPad *c = (TVirtualPad*)gROOT->GetListOfCanvases()->FindObject(Form("c_%lx_projection_%d",
10748  (ULong_t)fH, fShowProjection));
10749  if (c) {
10750  c->Clear();
10751  } else {
10752  fShowProjection = 0;
10753  pxold1 = 0;
10754  pxold2 = 0;
10755  return;
10756  }
10757  c->cd();
10758  c->SetLogy(padsav->GetLogz());
10759  c->SetLogx(padsav->GetLogy());
10760 
10761  // Draw slice corresponding to mouse position
10762  TString prjName = TString::Format("slice_py_of_%s",fH->GetName());
10763  TH1D *hp = ((TH2*)fH)->ProjectionY(prjName, binx1, binx2);
10764  if (hp) {
10765  hp->SetFillColor(38);
10766  // apply a patch from Oliver Freyermuth to set the title in the projection
10767  // using the range of the projected X values
10768  if (binx1 == binx2) {
10769  Double_t valueFrom = fH->GetXaxis()->GetBinLowEdge(binx1);
10770  Double_t valueTo = fH->GetXaxis()->GetBinUpEdge(binx1);
10771  // Limit precision to 1 digit more than the difference between upper and lower bound (to also catch 121.5-120.5).
10772  Int_t valuePrecision = -TMath::Nint(TMath::Log10(valueTo-valueFrom))+1;
10773  if (fH->GetXaxis()->GetLabels() != NULL) {
10774  hp->SetTitle(TString::Format("ProjectionY of binx=%d [x=%.*lf..%.*lf] [%s]", binx1, valuePrecision, valueFrom, valuePrecision, valueTo, fH->GetXaxis()->GetBinLabel(binx1)));
10775  } else {
10776  hp->SetTitle(TString::Format("ProjectionY of binx=%d [x=%.*lf..%.*lf]", binx1, valuePrecision, valueFrom, valuePrecision, valueTo));
10777  }
10778  } else {
10779  Double_t valueFrom = fH->GetXaxis()->GetBinLowEdge(binx1);
10780  Double_t valueTo = fH->GetXaxis()->GetBinUpEdge(binx2);
10781  // Limit precision to 1 digit more than the difference between upper and lower bound (to also catch 121.5-120.5).
10782  // binx1 is used here to get equal precision no matter how large the binrange is,
10783  // otherwise precision may change when moving the mouse to the histogram boundaries (limiting effective binrange).
10784  Int_t valuePrecision = -TMath::Nint(TMath::Log10(fH->GetXaxis()->GetBinUpEdge(binx1)-valueFrom))+1;
10785  if (fH->GetXaxis()->GetLabels() != NULL) {
10786  hp->SetTitle(TString::Format("ProjectionY of binx=[%d,%d] [x=%.*lf..%.*lf] [%s..%s]", binx1, binx2, valuePrecision, valueFrom, valuePrecision, valueTo, fH->GetXaxis()->GetBinLabel(binx1), fH->GetXaxis()->GetBinLabel(binx2)));
10787  } else {
10788  hp->SetTitle(TString::Format("ProjectionY of binx=[%d,%d] [x=%.*lf..%.*lf]", binx1, binx2, valuePrecision, valueFrom, valuePrecision, valueTo));
10789  }
10790  }
10791  hp->SetXTitle(fH->GetYaxis()->GetTitle());
10792  hp->SetYTitle("Number of Entries");
10793  hp->Draw();
10794  c->Update();
10795  padsav->cd();
10796  }
10797 }
10798 
10799 ////////////////////////////////////////////////////////////////////////////////
10800 /// Show projection (specified by `fShowProjection`) of a `TH3`.
10801 /// The drawing option for the projection is in `fShowOption`.
10802 ///
10803 /// First implementation; R.Brun
10804 ///
10805 /// Full implementation: Tim Tran (timtran@jlab.org) April 2006
10806 
10807 void THistPainter::ShowProjection3(Int_t px, Int_t py)
10808 {
10809 
10810  Int_t nbins=(Int_t)fShowProjection/100; //decode nbins
10811  if (fH->GetDimension() < 3) {
10812  if (fShowProjection%100 == 1) {ShowProjectionX(px,py); return;}
10813  if (fShowProjection%100 == 2) {ShowProjectionY(px,py); return;}
10814  }
10815 
10816  gPad->SetDoubleBuffer(0); // turn off double buffer mode
10817  gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode
10818 
10819  // Erase old position and draw a line at current position
10820  TView *view = gPad->GetView();
10821  if (!view) return;
10822  TH3 *h3 = (TH3*)fH;
10823  TAxis *xaxis = h3->GetXaxis();
10824  TAxis *yaxis = h3->GetYaxis();
10825  TAxis *zaxis = h3->GetZaxis();
10826  Double_t u[3],xx[3];
10827 
10828  static TPoint line1[2];//store end points of a line, initialised 0 by default
10829  static TPoint line2[2];// second line when slice thickness > 1 bin thickness
10830  static TPoint line3[2];
10831  static TPoint line4[2];
10832  static TPoint endface1[5];
10833  static TPoint endface2[5];
10834  static TPoint rect1[5];//store vertices of the polyline (rectangle), initialsed 0 by default
10835  static TPoint rect2[5];// second rectangle when slice thickness > 1 bin thickness
10836 
10837  Double_t uxmin = gPad->GetUxmin();
10838  Double_t uxmax = gPad->GetUxmax();
10839  Double_t uymin = gPad->GetUymin();
10840  Double_t uymax = gPad->GetUymax();
10841 
10842  int pxmin = gPad->XtoAbsPixel(uxmin);
10843  int pxmax = gPad->XtoAbsPixel(uxmax);
10844  if (pxmin==pxmax) return;
10845  int pymin = gPad->YtoAbsPixel(uymin);
10846  int pymax = gPad->YtoAbsPixel(uymax);
10847  if (pymin==pymax) return;
10848  Double_t cx = (pxmax-pxmin)/(uxmax-uxmin);
10849  Double_t cy = (pymax-pymin)/(uymax-uymin);
10850  TVirtualPad *padsav = gPad;
10851  TVirtualPad *c = (TVirtualPad*)gROOT->GetListOfCanvases()->FindObject(Form("c_%lx_projection_%d",
10852  (ULong_t)fH, fShowProjection));
10853  if (!c) {
10854  fShowProjection = 0;
10855  return;
10856  }
10857 
10858  switch ((Int_t)fShowProjection%100) {
10859  case 1:
10860  // "x"
10861  {
10862  Int_t firstY = yaxis->GetFirst();
10863  Int_t lastY = yaxis->GetLast();
10864  Int_t biny = firstY + Int_t((lastY-firstY)*(px-pxmin)/(pxmax-pxmin));
10865  Int_t biny2 = TMath::Min(biny+nbins-1,yaxis->GetNbins() );
10866  yaxis->SetRange(biny,biny2);
10867  Int_t firstZ = zaxis->GetFirst();
10868  Int_t lastZ = zaxis->GetLast();
10869  Int_t binz = firstZ + Int_t((lastZ-firstZ)*(py-pymin)/(pymax-pymin));
10870  Int_t binz2 = TMath::Min(binz+nbins-1,zaxis->GetNbins() );
10871  zaxis->SetRange(binz,binz2);
10872  if (line1[0].GetX()) gVirtualX->DrawPolyLine(2,line1);
10873  if (nbins>1 && line1[0].GetX()) {
10874  gVirtualX->DrawPolyLine(2,line2);
10875  gVirtualX->DrawPolyLine(2,line3);
10876  gVirtualX->DrawPolyLine(2,line4);
10877  gVirtualX->DrawPolyLine(5,endface1);
10878  gVirtualX->DrawPolyLine(5,endface2);
10879  }
10880  xx[0] = xaxis->GetXmin();
10881  xx[2] = zaxis->GetBinCenter(binz);
10882  xx[1] = yaxis->GetBinCenter(biny);
10883  view->WCtoNDC(xx,u);
10884  line1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10885  line1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
10886  xx[0] = xaxis->GetXmax();
10887  view->WCtoNDC(xx,u);
10888  line1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10889  line1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
10890  gVirtualX->DrawPolyLine(2,line1);
10891  if (nbins>1) {
10892  xx[0] = xaxis->GetXmin();
10893  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
10894  xx[1] = yaxis->GetBinCenter(biny);
10895  view->WCtoNDC(xx,u);
10896  line2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10897  line2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
10898  xx[0] = xaxis->GetXmax();
10899  view->WCtoNDC(xx,u);
10900  line2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10901  line2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
10902 
10903  xx[0] = xaxis->GetXmin();
10904  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
10905  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
10906  view->WCtoNDC(xx,u);
10907  line3[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10908  line3[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
10909  xx[0] = xaxis->GetXmax();
10910  view->WCtoNDC(xx,u);
10911  line3[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10912  line3[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
10913 
10914  xx[0] = xaxis->GetXmin();
10915  xx[2] = zaxis->GetBinCenter(binz);
10916  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
10917  view->WCtoNDC(xx,u);
10918  line4[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10919  line4[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
10920  xx[0] = xaxis->GetXmax();
10921  view->WCtoNDC(xx,u);
10922  line4[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
10923  line4[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
10924 
10925  endface1[0].SetX(line1[0].GetX());
10926  endface1[0].SetY(line1[0].GetY());
10927  endface1[1].SetX(line2[0].GetX());
10928  endface1[1].SetY(line2[0].GetY());
10929  endface1[2].SetX(line3[0].GetX());
10930  endface1[2].SetY(line3[0].GetY());
10931  endface1[3].SetX(line4[0].GetX());
10932  endface1[3].SetY(line4[0].GetY());
10933  endface1[4].SetX(line1[0].GetX());
10934  endface1[4].SetY(line1[0].GetY());
10935 
10936  endface2[0].SetX(line1[1].GetX());
10937  endface2[0].SetY(line1[1].GetY());
10938  endface2[1].SetX(line2[1].GetX());
10939  endface2[1].SetY(line2[1].GetY());
10940  endface2[2].SetX(line3[1].GetX());
10941  endface2[2].SetY(line3[1].GetY());
10942  endface2[3].SetX(line4[1].GetX());
10943  endface2[3].SetY(line4[1].GetY());
10944  endface2[4].SetX(line1[1].GetX());
10945  endface2[4].SetY(line1[1].GetY());
10946 
10947  gVirtualX->DrawPolyLine(2,line2);
10948  gVirtualX->DrawPolyLine(2,line3);
10949  gVirtualX->DrawPolyLine(2,line4);
10950  gVirtualX->DrawPolyLine(5,endface1);
10951  gVirtualX->DrawPolyLine(5,endface2);
10952  }
10953  c->Clear();
10954  c->cd();
10955  TH1 *hp = h3->Project3D("x");
10956  yaxis->SetRange(firstY,lastY);
10957  zaxis->SetRange(firstZ,lastZ);
10958  if (hp) {
10959  hp->SetFillColor(38);
10960  if (nbins == 1)
10961  hp->SetTitle(TString::Format("ProjectionX of biny=%d [y=%.1f..%.1f] binz=%d [z=%.1f..%.1f]", biny, yaxis->GetBinLowEdge(biny), yaxis->GetBinUpEdge(biny),
10962  binz, zaxis->GetBinLowEdge(binz), zaxis->GetBinUpEdge(binz)));
10963  else {
10964  hp->SetTitle(TString::Format("ProjectionX, biny=[%d,%d] [y=%.1f..%.1f], binz=[%d,%d] [z=%.1f..%.1f]", biny, biny2, yaxis->GetBinLowEdge(biny), yaxis->GetBinUpEdge(biny2),
10965  binz, binz2, zaxis->GetBinLowEdge(binz), zaxis->GetBinUpEdge(binz2) ) );
10966  }
10967  hp->SetXTitle(fH->GetXaxis()->GetTitle());
10968  hp->SetYTitle("Number of Entries");
10969  hp->Draw(fShowOption.Data());
10970  }
10971  }
10972  break;
10973 
10974  case 2:
10975  // "y"
10976  {
10977  Int_t firstX = xaxis->GetFirst();
10978  Int_t lastX = xaxis->GetLast();
10979  Int_t binx = firstX + Int_t((lastX-firstX)*(px-pxmin)/(pxmax-pxmin));
10980  Int_t binx2 = TMath::Min(binx+nbins-1,xaxis->GetNbins() );
10981  xaxis->SetRange(binx,binx2);
10982  Int_t firstZ = zaxis->GetFirst();
10983  Int_t lastZ = zaxis->GetLast();
10984  Int_t binz = firstZ + Int_t((lastZ-firstZ)*(py-pymin)/(pymax-pymin));
10985  Int_t binz2 = TMath::Min(binz+nbins-1,zaxis->GetNbins() );
10986  zaxis->SetRange(binz,binz2);
10987  if (line1[0].GetX()) gVirtualX->DrawPolyLine(2,line1);
10988  if (nbins>1 && line1[0].GetX()) {
10989  gVirtualX->DrawPolyLine(2,line2);
10990  gVirtualX->DrawPolyLine(2,line3);
10991  gVirtualX->DrawPolyLine(2,line4);
10992  gVirtualX->DrawPolyLine(5,endface1);
10993  gVirtualX->DrawPolyLine(5,endface2);
10994  }
10995  xx[0]=xaxis->GetBinCenter(binx);
10996  xx[2] = zaxis->GetBinCenter(binz);
10997  xx[1] = yaxis->GetXmin();
10998  view->WCtoNDC(xx,u);
10999  line1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11000  line1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11001  xx[1] = yaxis->GetXmax();
11002  view->WCtoNDC(xx,u);
11003  line1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11004  line1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11005  gVirtualX->DrawPolyLine(2,line1);
11006  if (nbins>1) {
11007  xx[1] = yaxis->GetXmin();
11008  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
11009  xx[0] = xaxis->GetBinCenter(binx);
11010  view->WCtoNDC(xx,u);
11011  line2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11012  line2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11013  xx[1] = yaxis->GetXmax();
11014  view->WCtoNDC(xx,u);
11015  line2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11016  line2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11017 
11018  xx[1] = yaxis->GetXmin();
11019  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
11020  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11021  view->WCtoNDC(xx,u);
11022  line3[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11023  line3[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11024  xx[1] = yaxis->GetXmax();
11025  view->WCtoNDC(xx,u);
11026  line3[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11027  line3[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11028 
11029  xx[1] = yaxis->GetXmin();
11030  xx[2] = zaxis->GetBinCenter(binz);
11031  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11032  view->WCtoNDC(xx,u);
11033  line4[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11034  line4[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11035  xx[1] = yaxis->GetXmax();
11036  view->WCtoNDC(xx,u);
11037  line4[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11038  line4[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11039 
11040  endface1[0].SetX(line1[0].GetX());
11041  endface1[0].SetY(line1[0].GetY());
11042  endface1[1].SetX(line2[0].GetX());
11043  endface1[1].SetY(line2[0].GetY());
11044  endface1[2].SetX(line3[0].GetX());
11045  endface1[2].SetY(line3[0].GetY());
11046  endface1[3].SetX(line4[0].GetX());
11047  endface1[3].SetY(line4[0].GetY());
11048  endface1[4].SetX(line1[0].GetX());
11049  endface1[4].SetY(line1[0].GetY());
11050 
11051  endface2[0].SetX(line1[1].GetX());
11052  endface2[0].SetY(line1[1].GetY());
11053  endface2[1].SetX(line2[1].GetX());
11054  endface2[1].SetY(line2[1].GetY());
11055  endface2[2].SetX(line3[1].GetX());
11056  endface2[2].SetY(line3[1].GetY());
11057  endface2[3].SetX(line4[1].GetX());
11058  endface2[3].SetY(line4[1].GetY());
11059  endface2[4].SetX(line1[1].GetX());
11060  endface2[4].SetY(line1[1].GetY());
11061 
11062  gVirtualX->DrawPolyLine(2,line2);
11063  gVirtualX->DrawPolyLine(2,line3);
11064  gVirtualX->DrawPolyLine(2,line4);
11065  gVirtualX->DrawPolyLine(5,endface1);
11066  gVirtualX->DrawPolyLine(5,endface2);
11067  }
11068  c->Clear();
11069  c->cd();
11070  TH1 *hp = h3->Project3D("y");
11071  xaxis->SetRange(firstX,lastX);
11072  zaxis->SetRange(firstZ,lastZ);
11073  if (hp) {
11074  hp->SetFillColor(38);
11075  if (nbins == 1)
11076  hp->SetTitle(TString::Format("ProjectionY of binx=%d [x=%.1f..%.1f] binz=%d [z=%.1f..%.1f]", binx, xaxis->GetBinLowEdge(binx), xaxis->GetBinUpEdge(binx),
11077  binz, zaxis->GetBinLowEdge(binz), zaxis->GetBinUpEdge(binz)));
11078  else
11079  hp->SetTitle(TString::Format("ProjectionY, binx=[%d,%d] [x=%.1f..%.1f], binz=[%d,%d] [z=%.1f..%.1f]", binx, binx2, xaxis->GetBinLowEdge(binx), xaxis->GetBinUpEdge(binx2),
11080  binz, binz2, zaxis->GetBinLowEdge(binz), zaxis->GetBinUpEdge(binz2) ) );
11081  hp->SetXTitle(fH->GetYaxis()->GetTitle());
11082  hp->SetYTitle("Number of Entries");
11083  hp->Draw(fShowOption.Data());
11084  }
11085  }
11086  break;
11087 
11088  case 3:
11089  // "z"
11090  {
11091  Int_t firstX = xaxis->GetFirst();
11092  Int_t lastX = xaxis->GetLast();
11093  Int_t binx = firstX + Int_t((lastX-firstX)*(px-pxmin)/(pxmax-pxmin));
11094  Int_t binx2 = TMath::Min(binx+nbins-1,xaxis->GetNbins() );
11095  xaxis->SetRange(binx,binx2);
11096  Int_t firstY = yaxis->GetFirst();
11097  Int_t lastY = yaxis->GetLast();
11098  Int_t biny = firstY + Int_t((lastY-firstY)*(py-pymin)/(pymax-pymin));
11099  Int_t biny2 = TMath::Min(biny+nbins-1,yaxis->GetNbins() );
11100  yaxis->SetRange(biny,biny2);
11101  if (line1[0].GetX()) gVirtualX->DrawPolyLine(2,line1);
11102  if (nbins>1 && line1[0].GetX()) {
11103  gVirtualX->DrawPolyLine(2,line2);
11104  gVirtualX->DrawPolyLine(2,line3);
11105  gVirtualX->DrawPolyLine(2,line4);
11106  gVirtualX->DrawPolyLine(5,endface1);
11107  gVirtualX->DrawPolyLine(5,endface2);
11108  }
11109  xx[0] = xaxis->GetBinCenter(binx);
11110  xx[1] = yaxis->GetBinCenter(biny);
11111  xx[2] = zaxis->GetXmin();
11112  view->WCtoNDC(xx,u);
11113  line1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11114  line1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11115  xx[2] = zaxis->GetXmax();
11116  view->WCtoNDC(xx,u);
11117  line1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11118  line1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11119  gVirtualX->DrawPolyLine(2,line1);
11120  if (nbins>1) {
11121  xx[2] = zaxis->GetXmin();
11122  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
11123  xx[0] = xaxis->GetBinCenter(binx);
11124  view->WCtoNDC(xx,u);
11125  line2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11126  line2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11127  xx[2] = zaxis->GetXmax();
11128  view->WCtoNDC(xx,u);
11129  line2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11130  line2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11131 
11132  xx[2] = zaxis->GetXmin();
11133  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
11134  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11135  view->WCtoNDC(xx,u);
11136  line3[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11137  line3[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11138  xx[2] = zaxis->GetXmax();
11139  view->WCtoNDC(xx,u);
11140  line3[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11141  line3[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11142 
11143  xx[2] = zaxis->GetXmin();
11144  xx[1] = yaxis->GetBinCenter(biny);
11145  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11146  view->WCtoNDC(xx,u);
11147  line4[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11148  line4[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11149  xx[2] = zaxis->GetXmax();
11150  view->WCtoNDC(xx,u);
11151  line4[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11152  line4[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11153 
11154  endface1[0].SetX(line1[0].GetX());
11155  endface1[0].SetY(line1[0].GetY());
11156  endface1[1].SetX(line2[0].GetX());
11157  endface1[1].SetY(line2[0].GetY());
11158  endface1[2].SetX(line3[0].GetX());
11159  endface1[2].SetY(line3[0].GetY());
11160  endface1[3].SetX(line4[0].GetX());
11161  endface1[3].SetY(line4[0].GetY());
11162  endface1[4].SetX(line1[0].GetX());
11163  endface1[4].SetY(line1[0].GetY());
11164 
11165  endface2[0].SetX(line1[1].GetX());
11166  endface2[0].SetY(line1[1].GetY());
11167  endface2[1].SetX(line2[1].GetX());
11168  endface2[1].SetY(line2[1].GetY());
11169  endface2[2].SetX(line3[1].GetX());
11170  endface2[2].SetY(line3[1].GetY());
11171  endface2[3].SetX(line4[1].GetX());
11172  endface2[3].SetY(line4[1].GetY());
11173  endface2[4].SetX(line1[1].GetX());
11174  endface2[4].SetY(line1[1].GetY());
11175 
11176  gVirtualX->DrawPolyLine(2,line2);
11177  gVirtualX->DrawPolyLine(2,line3);
11178  gVirtualX->DrawPolyLine(2,line4);
11179  gVirtualX->DrawPolyLine(5,endface1);
11180  gVirtualX->DrawPolyLine(5,endface2);
11181  }
11182  c->Clear();
11183  c->cd();
11184  TH1 *hp = h3->Project3D("z");
11185  xaxis->SetRange(firstX,lastX);
11186  yaxis->SetRange(firstY,lastY);
11187  if (hp) {
11188  hp->SetFillColor(38);
11189  if (nbins == 1)
11190  hp->SetTitle(TString::Format("ProjectionZ of binx=%d [x=%.1f..%.1f] biny=%d [y=%.1f..%.1f]", binx, xaxis->GetBinLowEdge(binx), xaxis->GetBinUpEdge(binx),
11191  biny, yaxis->GetBinLowEdge(biny), yaxis->GetBinUpEdge(biny)));
11192  else
11193  hp->SetTitle(TString::Format("ProjectionZ, binx=[%d,%d] [x=%.1f..%.1f], biny=[%d,%d] [y=%.1f..%.1f]", binx, binx2, xaxis->GetBinLowEdge(binx), xaxis->GetBinUpEdge(binx2),
11194  biny, biny2, yaxis->GetBinLowEdge(biny), yaxis->GetBinUpEdge(biny2) ) );
11195  hp->SetXTitle(fH->GetZaxis()->GetTitle());
11196  hp->SetYTitle("Number of Entries");
11197  hp->Draw(fShowOption.Data());
11198  }
11199  }
11200  break;
11201 
11202  case 4:
11203  // "xy"
11204  {
11205  Int_t first = zaxis->GetFirst();
11206  Int_t last = zaxis->GetLast();
11207  Int_t binz = first + Int_t((last-first)*(py-pymin)/(pymax-pymin));
11208  Int_t binz2 = TMath::Min(binz+nbins-1,zaxis->GetNbins() );
11209  zaxis->SetRange(binz,binz2);
11210  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11211  if (nbins>1 && rect2[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11212  xx[0] = xaxis->GetXmin();
11213  xx[1] = yaxis->GetXmax();
11214  xx[2] = zaxis->GetBinCenter(binz);
11215  view->WCtoNDC(xx,u);
11216  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11217  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11218  rect1[4].SetX(rect1[0].GetX());
11219  rect1[4].SetY(rect1[0].GetY());
11220  xx[0] = xaxis->GetXmax();
11221  view->WCtoNDC(xx,u);
11222  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11223  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11224  xx[1] = yaxis->GetXmin();
11225  view->WCtoNDC(xx,u);
11226  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11227  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11228  xx[0] = xaxis->GetXmin();
11229  view->WCtoNDC(xx,u);
11230  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11231  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11232  gVirtualX->DrawPolyLine(5,rect1);
11233  if (nbins>1) {
11234  xx[0] = xaxis->GetXmin();
11235  xx[1] = yaxis->GetXmax();
11236  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
11237  view->WCtoNDC(xx,u);
11238  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11239  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11240  rect2[4].SetX(rect2[0].GetX());
11241  rect2[4].SetY(rect2[0].GetY());
11242  xx[0] = xaxis->GetXmax();
11243  view->WCtoNDC(xx,u);
11244  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11245  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11246  xx[1] = yaxis->GetXmin();
11247  view->WCtoNDC(xx,u);
11248  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11249  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11250  xx[0] = xaxis->GetXmin();
11251  view->WCtoNDC(xx,u);
11252  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11253  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11254  gVirtualX->DrawPolyLine(5,rect2);
11255  }
11256 
11257  c->Clear();
11258  c->cd();
11259  TH2 *hp = (TH2*)h3->Project3D("xy");
11260  zaxis->SetRange(first,last);
11261  if (hp) {
11262  hp->SetFillColor(38);
11263  if (nbins==1)hp->SetTitle(TString::Format("ProjectionXY of binz=%d [z=%.1f..%.f]", binz,zaxis->GetBinLowEdge(binz),zaxis->GetBinUpEdge(binz)));
11264  else hp->SetTitle(TString::Format("ProjectionXY, binz=[%d,%d] [z=%.1f..%.1f]", binz,binz2,zaxis->GetBinLowEdge(binz),zaxis->GetBinUpEdge(binz2)));
11265  hp->SetXTitle(fH->GetYaxis()->GetTitle());
11266  hp->SetYTitle(fH->GetXaxis()->GetTitle());
11267  hp->SetZTitle("Number of Entries");
11268  hp->Draw(fShowOption.Data());
11269  }
11270  }
11271  break;
11272 
11273  case 5:
11274  // "yx"
11275  {
11276  Int_t first = zaxis->GetFirst();
11277  Int_t last = zaxis->GetLast();
11278  Int_t binz = first + Int_t((last-first)*(py-pymin)/(pymax-pymin));
11279  Int_t binz2 = TMath::Min(binz+nbins-1,zaxis->GetNbins() );
11280  zaxis->SetRange(binz,binz2);
11281  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11282  if (nbins>1 && rect2[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11283  xx[0] = xaxis->GetXmin();
11284  xx[1] = yaxis->GetXmax();
11285  xx[2] = zaxis->GetBinCenter(binz);
11286  view->WCtoNDC(xx,u);
11287  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11288  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11289  rect1[4].SetX(rect1[0].GetX());
11290  rect1[4].SetY(rect1[0].GetY());
11291  xx[0] = xaxis->GetXmax();
11292  view->WCtoNDC(xx,u);
11293  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11294  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11295  xx[1] = yaxis->GetXmin();
11296  view->WCtoNDC(xx,u);
11297  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11298  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11299  xx[0] = xaxis->GetXmin();
11300  view->WCtoNDC(xx,u);
11301  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11302  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11303  gVirtualX->DrawPolyLine(5,rect1);
11304  if (nbins>1) {
11305  xx[0] = xaxis->GetXmin();
11306  xx[1] = yaxis->GetXmax();
11307  xx[2] = zaxis->GetBinCenter(binz+nbins-1);
11308  view->WCtoNDC(xx,u);
11309  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11310  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11311  rect2[4].SetX(rect2[0].GetX());
11312  rect2[4].SetY(rect2[0].GetY());
11313  xx[0] = xaxis->GetXmax();
11314  view->WCtoNDC(xx,u);
11315  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11316  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11317  xx[1] = yaxis->GetXmin();
11318  view->WCtoNDC(xx,u);
11319  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11320  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11321  xx[0] = xaxis->GetXmin();
11322  view->WCtoNDC(xx,u);
11323  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11324  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11325  gVirtualX->DrawPolyLine(5,rect2);
11326  }
11327  c->Clear();
11328  c->cd();
11329  TH2 *hp = (TH2*)h3->Project3D("yx");
11330  zaxis->SetRange(first,last);
11331  if (hp) {
11332  hp->SetFillColor(38);
11333  if (nbins==1)hp->SetTitle(TString::Format("ProjectionYX of binz=%d [z=%.1f..%.f]", binz,zaxis->GetBinLowEdge(binz),zaxis->GetBinUpEdge(binz)));
11334  else hp->SetTitle(TString::Format("ProjectionYX, binz=[%d,%d] [z=%.1f..%.1f]", binz,binz2,zaxis->GetBinLowEdge(binz),zaxis->GetBinUpEdge(binz2)));
11335  hp->SetXTitle(fH->GetXaxis()->GetTitle());
11336  hp->SetYTitle(fH->GetYaxis()->GetTitle());
11337  hp->SetZTitle("Number of Entries");
11338  hp->Draw(fShowOption.Data());
11339  }
11340  }
11341  break;
11342 
11343  case 6:
11344  // "xz"
11345  {
11346  Int_t first = yaxis->GetFirst();
11347  Int_t last = yaxis->GetLast();
11348  Int_t biny = first + Int_t((last-first)*(py-pymin)/(pymax-pymin));
11349  Int_t biny2 = TMath::Min(biny+nbins-1,yaxis->GetNbins() );
11350  yaxis->SetRange(biny,biny2);
11351  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11352  if (nbins>1 && rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11353  xx[0] = xaxis->GetXmin();
11354  xx[2] = zaxis->GetXmax();
11355  xx[1] = yaxis->GetBinCenter(biny);
11356  view->WCtoNDC(xx,u);
11357  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11358  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11359  rect1[4].SetX(rect1[0].GetX());
11360  rect1[4].SetY(rect1[0].GetY());
11361  xx[0] = xaxis->GetXmax();
11362  view->WCtoNDC(xx,u);
11363  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11364  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11365  xx[2] = zaxis->GetXmin();
11366  view->WCtoNDC(xx,u);
11367  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11368  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11369  xx[0] = xaxis->GetXmin();
11370  view->WCtoNDC(xx,u);
11371  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11372  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11373  gVirtualX->DrawPolyLine(5,rect1);
11374  if (nbins>1) {
11375  xx[0] = xaxis->GetXmin();
11376  xx[2] = zaxis->GetXmax();
11377  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
11378  view->WCtoNDC(xx,u);
11379  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11380  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11381  rect2[4].SetX(rect2[0].GetX());
11382  rect2[4].SetY(rect2[0].GetY());
11383  xx[0] = xaxis->GetXmax();
11384  view->WCtoNDC(xx,u);
11385  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11386  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11387  xx[2] = zaxis->GetXmin();
11388  view->WCtoNDC(xx,u);
11389  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11390  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11391  xx[0] = xaxis->GetXmin();
11392  view->WCtoNDC(xx,u);
11393  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11394  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11395  gVirtualX->DrawPolyLine(5,rect2);
11396  }
11397  c->Clear();
11398  c->cd();
11399  TH2 *hp = (TH2*)h3->Project3D("xz");
11400  yaxis->SetRange(first,last);
11401  if (hp) {
11402  hp->SetFillColor(38);
11403  if (nbins==1)hp->SetTitle(TString::Format("ProjectionXZ of biny=%d [y=%.1f..%.f]", biny,yaxis->GetBinLowEdge(biny),yaxis->GetBinUpEdge(biny)));
11404  else hp->SetTitle(TString::Format("ProjectionXZ, biny=[%d,%d] [y=%.1f..%.1f]", biny,biny2,yaxis->GetBinLowEdge(biny),yaxis->GetBinUpEdge(biny2)));
11405  hp->SetXTitle(fH->GetZaxis()->GetTitle());
11406  hp->SetYTitle(fH->GetXaxis()->GetTitle());
11407  hp->SetZTitle("Number of Entries");
11408  hp->Draw(fShowOption.Data());
11409  }
11410  }
11411  break;
11412 
11413  case 7:
11414  // "zx"
11415  {
11416  Int_t first = yaxis->GetFirst();
11417  Int_t last = yaxis->GetLast();
11418  Int_t biny = first + Int_t((last-first)*(py-pymin)/(pymax-pymin));
11419  Int_t biny2 = TMath::Min(biny+nbins-1,yaxis->GetNbins() );
11420  yaxis->SetRange(biny,biny2);
11421  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11422  if (nbins>1 && rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11423  xx[0] = xaxis->GetXmin();
11424  xx[2] = zaxis->GetXmax();
11425  xx[1] = yaxis->GetBinCenter(biny);
11426  view->WCtoNDC(xx,u);
11427  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11428  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11429  rect1[4].SetX(rect1[0].GetX());
11430  rect1[4].SetY(rect1[0].GetY());
11431  xx[0] = xaxis->GetXmax();
11432  view->WCtoNDC(xx,u);
11433  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11434  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11435  xx[2] = zaxis->GetXmin();
11436  view->WCtoNDC(xx,u);
11437  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11438  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11439  xx[0] = xaxis->GetXmin();
11440  view->WCtoNDC(xx,u);
11441  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11442  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11443  gVirtualX->DrawPolyLine(5,rect1);
11444  if (nbins>1) {
11445  xx[0] = xaxis->GetXmin();
11446  xx[2] = zaxis->GetXmax();
11447  xx[1] = yaxis->GetBinCenter(biny+nbins-1);
11448  view->WCtoNDC(xx,u);
11449  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11450  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11451  rect2[4].SetX(rect2[0].GetX());
11452  rect2[4].SetY(rect2[0].GetY());
11453  xx[0] = xaxis->GetXmax();
11454  view->WCtoNDC(xx,u);
11455  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11456  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11457  xx[2] = zaxis->GetXmin();
11458  view->WCtoNDC(xx,u);
11459  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11460  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11461  xx[0] = xaxis->GetXmin();
11462  view->WCtoNDC(xx,u);
11463  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11464  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11465  gVirtualX->DrawPolyLine(5,rect2);
11466  }
11467  c->Clear();
11468  c->cd();
11469  TH2 *hp = (TH2*)h3->Project3D("zx");
11470  yaxis->SetRange(first,last);
11471  if (hp) {
11472  hp->SetFillColor(38);
11473  if (nbins==1)hp->SetTitle(TString::Format("ProjectionZX of biny=%d [y=%.1f..%.f]", biny,yaxis->GetBinLowEdge(biny),yaxis->GetBinUpEdge(biny)));
11474  else hp->SetTitle(TString::Format("ProjectionZX, biny=[%d,%d] [y=%.1f..%.1f]", biny,biny2,yaxis->GetBinLowEdge(biny),yaxis->GetBinUpEdge(biny2)));
11475  hp->SetXTitle(fH->GetXaxis()->GetTitle());
11476  hp->SetYTitle(fH->GetZaxis()->GetTitle());
11477  hp->SetZTitle("Number of Entries");
11478  hp->Draw(fShowOption.Data());
11479  }
11480  }
11481  break;
11482 
11483  case 8:
11484  // "yz"
11485  {
11486  Int_t first = xaxis->GetFirst();
11487  Int_t last = xaxis->GetLast();
11488  Int_t binx = first + Int_t((last-first)*(px-pxmin)/(pxmax-pxmin));
11489  Int_t binx2 = TMath::Min(binx+nbins-1,xaxis->GetNbins() );
11490  xaxis->SetRange(binx,binx2);
11491  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11492  if (nbins>1 && rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11493  xx[2] = zaxis->GetXmin();
11494  xx[1] = yaxis->GetXmax();
11495  xx[0] = xaxis->GetBinCenter(binx);
11496  view->WCtoNDC(xx,u);
11497  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11498  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11499  rect1[4].SetX(rect1[0].GetX());
11500  rect1[4].SetY(rect1[0].GetY());
11501  xx[2] = zaxis->GetXmax();
11502  view->WCtoNDC(xx,u);
11503  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11504  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11505  xx[1] = yaxis->GetXmin();
11506  view->WCtoNDC(xx,u);
11507  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11508  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11509  xx[2] = zaxis->GetXmin();
11510  view->WCtoNDC(xx,u);
11511  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11512  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11513  gVirtualX->DrawPolyLine(5,rect1);
11514  if (nbins>1) {
11515  xx[2] = zaxis->GetXmin();
11516  xx[1] = yaxis->GetXmax();
11517  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11518  view->WCtoNDC(xx,u);
11519  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11520  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11521  rect2[4].SetX(rect2[0].GetX());
11522  rect2[4].SetY(rect2[0].GetY());
11523  xx[2] = zaxis->GetXmax();
11524  view->WCtoNDC(xx,u);
11525  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11526  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11527  xx[1] = yaxis->GetXmin();
11528  view->WCtoNDC(xx,u);
11529  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11530  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11531  xx[2] = zaxis->GetXmin();
11532  view->WCtoNDC(xx,u);
11533  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11534  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11535  gVirtualX->DrawPolyLine(5,rect2);
11536  }
11537  c->Clear();
11538  c->cd();
11539  TH2 *hp = (TH2*)h3->Project3D("yz");
11540  xaxis->SetRange(first,last);
11541  if (hp) {
11542  hp->SetFillColor(38);
11543  if (nbins==1)hp->SetTitle(TString::Format("ProjectionYZ of binx=%d [x=%.1f..%.f]", binx,xaxis->GetBinLowEdge(binx),xaxis->GetBinUpEdge(binx)));
11544  else hp->SetTitle(TString::Format("ProjectionYZ, binx=[%d,%d] [x=%.1f..%.1f]", binx,binx2,xaxis->GetBinLowEdge(binx),xaxis->GetBinUpEdge(binx2)));
11545  hp->SetXTitle(fH->GetZaxis()->GetTitle());
11546  hp->SetYTitle(fH->GetYaxis()->GetTitle());
11547  hp->SetZTitle("Number of Entries");
11548  hp->Draw(fShowOption.Data());
11549  }
11550  }
11551  break;
11552 
11553  case 9:
11554  // "zy"
11555  {
11556  Int_t first = xaxis->GetFirst();
11557  Int_t last = xaxis->GetLast();
11558  Int_t binx = first + Int_t((last-first)*(px-pxmin)/(pxmax-pxmin));
11559  Int_t binx2 = TMath::Min(binx+nbins-1,xaxis->GetNbins() );
11560  xaxis->SetRange(binx,binx2);
11561  if (rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect1);
11562  if (nbins>1 && rect1[0].GetX()) gVirtualX->DrawPolyLine(5,rect2);
11563  xx[2] = zaxis->GetXmin();
11564  xx[1] = yaxis->GetXmax();
11565  xx[0] = xaxis->GetBinCenter(binx);
11566  view->WCtoNDC(xx,u);
11567  rect1[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11568  rect1[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11569  rect1[4].SetX(rect1[0].GetX());
11570  rect1[4].SetY(rect1[0].GetY());
11571  xx[2] = zaxis->GetXmax();
11572  view->WCtoNDC(xx,u);
11573  rect1[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11574  rect1[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11575  xx[1] = yaxis->GetXmin();
11576  view->WCtoNDC(xx,u);
11577  rect1[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11578  rect1[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11579  xx[2] = zaxis->GetXmin();
11580  view->WCtoNDC(xx,u);
11581  rect1[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11582  rect1[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11583  gVirtualX->DrawPolyLine(5,rect1);
11584  if (nbins>1) {
11585  xx[2] = zaxis->GetXmin();
11586  xx[1] = yaxis->GetXmax();
11587  xx[0] = xaxis->GetBinCenter(binx+nbins-1);
11588  view->WCtoNDC(xx,u);
11589  rect2[0].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11590  rect2[0].SetY(pymin + Int_t((u[1]-uymin)*cy));
11591  rect2[4].SetX(rect2[0].GetX());
11592  rect2[4].SetY(rect2[0].GetY());
11593  xx[2] = zaxis->GetXmax();
11594  view->WCtoNDC(xx,u);
11595  rect2[1].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11596  rect2[1].SetY(pymin + Int_t((u[1]-uymin)*cy));
11597  xx[1] = yaxis->GetXmin();
11598  view->WCtoNDC(xx,u);
11599  rect2[2].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11600  rect2[2].SetY(pymin + Int_t((u[1]-uymin)*cy));
11601  xx[2] = zaxis->GetXmin();
11602  view->WCtoNDC(xx,u);
11603  rect2[3].SetX(pxmin + Int_t((u[0]-uxmin)*cx));
11604  rect2[3].SetY(pymin + Int_t((u[1]-uymin)*cy));
11605  gVirtualX->DrawPolyLine(5,rect2);
11606  }
11607  c->Clear();
11608  c->cd();
11609  TH2 *hp = (TH2*)h3->Project3D("zy");
11610  xaxis->SetRange(first,last);
11611  if (hp) {
11612  hp->SetFillColor(38);
11613  if (nbins==1)hp->SetTitle(TString::Format("ProjectionZY of binx=%d [x=%.1f..%.f]", binx,xaxis->GetBinLowEdge(binx),xaxis->GetBinUpEdge(binx)));
11614  else hp->SetTitle(TString::Format("ProjectionZY, binx=[%d,%d] [x=%.1f..%.1f]", binx,binx2,xaxis->GetBinLowEdge(binx),xaxis->GetBinUpEdge(binx2)));
11615  hp->SetXTitle(fH->GetYaxis()->GetTitle());
11616  hp->SetYTitle(fH->GetZaxis()->GetTitle());
11617  hp->SetZTitle("Number of Entries");
11618  hp->Draw(fShowOption.Data());
11619  }
11620  }
11621  break;
11622  }
11623  c->Update();
11624  padsav->cd();
11625 }