Logo ROOT   6.14/05
Reference Guide
TCandle.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Georg Troska 19/05/16
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 <iostream>
14 #include "TROOT.h"
15 #include "TCandle.h"
16 #include "TClass.h"
17 #include "TPad.h"
18 #include "TRandom2.h"
19 
24 
26 
27 /** \class TCandle
28 \ingroup BasicGraphics
29 
30 The candle plot painter class.
31 
32 Instances of this class are generated by the histograms painting
33 classes (THistPainter and THStack) when an candle plot (box plot) is drawn.
34 TCandle is the "painter class" of the box plots. Therefore it is never used
35 directly to draw a candle.
36 */
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 /// TCandle default constructor.
40 
42 {
43  fIsCalculated = 0;
44  fIsRaw = 0;
45  fPosCandleAxis = 0.;
46  fCandleWidth = 1.0;
47  fHistoWidth = 1.0;
48  fMean = 0.;
49  fMedian = 0.;
50  fMedianErr = 0;
51  fBoxUp = 0.;
52  fBoxDown = 0.;
53  fWhiskerUp = 0.;
54  fWhiskerDown = 0.;
55  fNDatapoints = 0;
56  fDismiss = 0;
57  fLogX = 0;
58  fLogY = 0;
59  fLogZ = 0;
60  fNDrawPoints = 0;
61  fNHistoPoints = 0;
62  fAxisMin = 0.;
63  fAxisMax = 0.;
65  fProj = NULL;
66  fDatapoints = 0;
67 
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// TCandle constructor passing a draw-option.
72 
73 TCandle::TCandle(const char *opt)
74 {
75  fIsCalculated = 0;
76  fIsRaw = 0;
77  fPosCandleAxis = 0.;
78  fCandleWidth = 1.0;
79  fHistoWidth = 1.0;
80  fMean = 0.;
81  fMedian = 0.;
82  fMedianErr = 0;
83  fBoxUp = 0.;
84  fBoxDown = 0.;
85  fWhiskerUp = 0.;
86  fWhiskerDown = 0.;
87  fNDatapoints = 0;
88  fDismiss = 0;
89  fLogX = 0;
90  fLogY = 0;
91  fLogZ = 0;
92  fNDrawPoints = 0;
93  fNHistoPoints = 0;
94  fAxisMin = 0.;
95  fAxisMax = 0.;
97  fProj = NULL;
98  fDatapoints = 0;
99 
100 
101  // Conversion necessary in order to cast from const char* to char*
102  char myopt[128];
103  strlcpy(myopt,opt,128);
104 
105 
106  ParseOption(myopt);
107 }
108 
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// TCandle constructor for raw-data candles.
112 
113 TCandle::TCandle(const Double_t candlePos, const Double_t candleWidth, Long64_t n, Double_t * points)
114  : TAttLine(), TAttFill(), TAttMarker()
115 {
116  //Preliminary values only, need to be calculated before paint
117  fMean = 0;
118  fMedian = 0;
119  fMedianErr = 0;
120  fBoxUp = 0;
121  fBoxDown = 0;
122  fWhiskerUp = 0;
123  fWhiskerDown = 0;
124  fNDatapoints = n;
125  fIsCalculated = 0;
126  fIsRaw = true;
127  fPosCandleAxis = candlePos;
128  fCandleWidth = candleWidth;
129  fHistoWidth = candleWidth;
131  fProj = NULL;
132  fDismiss = 0;
133  fOption = kNoOption;
134  fLogX = 0;
135  fLogY = 0;
136  fLogZ = 0;
137  fNDrawPoints = 0;
138  fNHistoPoints = 0;
139  fAxisMin = 0.;
140  fAxisMax = 0.;
141  sprintf(fOptionStr," ");
142 }
143 
144 ////////////////////////////////////////////////////////////////////////////////
145 /// TCandle TH1 data constructor.
146 
147 TCandle::TCandle(const Double_t candlePos, const Double_t candleWidth, TH1D *proj)
148  : TAttLine(), TAttFill(), TAttMarker()
149 {
150  //Preliminary values only, need to be calculated before paint
151  fMean = 0;
152  fMedian = 0;
153  fMedianErr = 0;
154  fBoxUp = 0;
155  fBoxDown = 0;
156  fWhiskerUp = 0;
157  fWhiskerDown = 0;
158  fNDatapoints = 0;
159  fIsCalculated = 0;
160  fIsRaw = 0;
161  fPosCandleAxis = candlePos;
162  fCandleWidth = candleWidth;
163  fHistoWidth = candleWidth;
164  fDatapoints = 0;
165  fProj = proj;
166  fDismiss = 0;
167  fOption = kNoOption;
168  fLogX = 0;
169  fLogY = 0;
170  fLogZ = 0;
171  fNDrawPoints = 0;
172  fNHistoPoints = 0;
173  fAxisMin = 0.;
174  fAxisMax = 0.;
175  sprintf(fOptionStr," ");
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 /// TCandle default destructor.
180 
182  if (fIsRaw && fProj) delete fProj;
183 }
184 
186 {
187  return fScaledCandle;
188 }
189 
191 {
192  return fScaledViolin;
193 }
194 
195 ////////////////////////////////////////////////////////////////////////////////
196 /// Static function to set fWhiskerRange, by setting whisker-range, one can force
197 /// the whiskers to cover the fraction of the distribution.
198 /// Set wRange between 0 and 1. Default is 1
199 /// TCandle::SetWhiskerRange(0.95) will set all candle-charts to cover 95% of
200 /// the distribution with the whiskers.
201 /// Can only be used with the standard-whisker definition
202 
203 void TCandle::SetWhiskerRange(const Double_t wRange) {
204  if (wRange < 0) fWhiskerRange = 0;
205  else if (wRange > 1) fWhiskerRange = 1;
206  else fWhiskerRange = wRange;
207 
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 /// Static function to set fBoxRange, by setting whisker-range, one can force the
212 /// box of the candle-chart to cover that given fraction of the distribution.
213 /// Set bRange between 0 and 1. Default is 0.5
214 /// TCandle::SetBoxRange(0.68) will set all candle-charts to cover 68% of the
215 /// distribution by the box
216 
217 void TCandle::SetBoxRange(const Double_t bRange) {
218  if (bRange < 0) fBoxRange = 0;
219  else if (bRange > 1) fBoxRange = 1;
220  else fBoxRange = bRange;
221 }
222 
223 ////////////////////////////////////////////////////////////////////////////////
224 /// Static function to set scaling between candles-withs. A candle containing
225 /// 100 entries with be two times wider than a candle containing 50 entries
226 
227 void TCandle::SetScaledCandle(const Bool_t cScale) {
228  fScaledCandle = cScale;
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// Static function to set scaling between violin-withs. A violin or histo chart
233 /// with a maximum bin content to 100 will be two times as high as a violin with
234 /// a maximum bin content of 50
235 
236 void TCandle::SetScaledViolin(const Bool_t vScale) {
237  fScaledViolin = vScale;
238 }
239 
240 ////////////////////////////////////////////////////////////////////////////////
241 /// Parsing of the option-string.
242 /// The option-string will be empty at the end (by-reference).
243 
244 int TCandle::ParseOption(char * opt) {
245  fOption = kNoOption;
246  char *l;
247 
248  l = strstr(opt,"CANDLE");
249  if (l) {
250  const CandleOption fallbackCandle = (CandleOption)(kBox + kMedianLine + kMeanCircle + kWhiskerAll + kAnchor);
251 
252  char direction = ' ';
253  char preset = ' ';
254 
255 
256 
257  if (l[6] >= 'A' && l[6] <= 'Z') direction = l[6];
258  if (l[6] >= '1' && l[6] <= '9') preset = l[6];
259  if (l[7] >= 'A' && l[7] <= 'Z' && preset != ' ') direction = l[7];
260  if (l[7] >= '1' && l[7] <= '9' && direction != ' ') preset = l[7];
261 
262  if (direction == 'X' || direction == 'V') { /* nothing */ }
263  if (direction == 'Y' || direction == 'H') { fOption = (CandleOption)(fOption + kHorizontal); }
264  if (preset == '1') //Standard candle using old candle-definition
265  fOption = (CandleOption)(fOption + fallbackCandle);
266  else if (preset == '2') //New standard candle with better whisker definition + outlier
268  else if (preset == '3') //Like candle2 but with a fMean as a circle
270  else if (preset == '4') //Like candle3 but showing the uncertainty of the fMedian as well
272  else if (preset == '5') //Like candle2 but showing all datapoints
274  else if (preset == '6') //Like candle2 but showing all datapoints scattered
276  else if (preset != ' ') //For all other presets not implemented yet used fallback candle
277  fOption = (CandleOption)(fOption + fallbackCandle);
278 
279  if (preset != ' ' && direction != ' ')
280  strncpy(l," ",8);
281  else if (preset != ' ' || direction != ' ')
282  strncpy(l," ",7);
283  else
284  strncpy(l," ",6);
285 
286  Bool_t useIndivOption = false;
287 
288  if (direction == ' ') direction = 'X';
289  if (preset == ' ') { // Check if the user wants to set the properties individually
290  char *brOpen = strstr(opt,"(");
291  char *brClose = strstr(opt,")");
292  char indivOption[32];
293  if (brOpen && brClose) {
294  useIndivOption = true;
295  bool isHorizontal = IsHorizontal();
296  strlcpy(indivOption, brOpen, brClose-brOpen+2); //Now the string "(....)" including brackets is in this array
297  sscanf(indivOption,"(%d)", (int*) &fOption);
298  if (isHorizontal) {fOption = (CandleOption)(fOption + kHorizontal);}
299  strncpy(brOpen," ",brClose-brOpen+1); //Cleanup
300 
301  sprintf(fOptionStr,"CANDLE%c(%ld)",direction,(long)fOption);
302  } else {
303  preset = 1;
304  fOption = (CandleOption)(fOption + fallbackCandle);
305  }
306  } else {
307  sprintf(fOptionStr,"CANDLE%c%c",direction,preset);
308  }
309  //Handle option "CANDLE" ,"CANDLEX" or "CANDLEY" to behave like "CANDLEX1" or "CANDLEY1"
310  if (!useIndivOption && !fOption ) {
311  fOption = fallbackCandle;
312  sprintf(fOptionStr,"CANDLE%c2",direction);
313  }
314  }
315 
316  l = strstr(opt,"VIOLIN");
317  if (l) {
319 
320  char direction = ' ';
321  char preset = ' ';
322 
323  if (l[6] >= 'A' && l[6] <= 'Z') direction = l[6];
324  if (l[6] >= '1' && l[6] <= '9') preset = l[6];
325  if (l[7] >= 'A' && l[7] <= 'Z' && preset != ' ') direction = l[7];
326  if (l[7] >= '1' && l[7] <= '9' && direction != ' ') preset = l[7];
327 
328  if (direction == 'X' || direction == 'V') { /* nothing */ }
329  if (direction == 'Y' || direction == 'H') { fOption = (CandleOption)(fOption + kHorizontal); }
330  if (preset == '1') //Standard candle using old candle-definition
331  fOption = (CandleOption)(fOption + fallbackCandle);
332  else if (preset == '2') //New standard candle with better whisker definition + outlier
334  else if (preset != ' ') //For all other presets not implemented yet used fallback candle
335  fOption = (CandleOption)(fOption + fallbackCandle);
336 
337  if (preset != ' ' && direction != ' ')
338  strncpy(l," ",8);
339  else if (preset != ' ' || direction != ' ')
340  strncpy(l," ",7);
341  else
342  strncpy(l," ",6);
343 
344  Bool_t useIndivOption = false;
345 
346  if (direction == ' ') direction = 'X';
347  if (preset == ' ') { // Check if the user wants to set the properties individually
348  char *brOpen = strstr(opt,"(");
349  char *brClose = strstr(opt,")");
350  char indivOption[32];
351  if (brOpen && brClose) {
352  useIndivOption = true;
353  bool isHorizontal = IsHorizontal();
354  strlcpy(indivOption, brOpen, brClose-brOpen +2); //Now the string "(....)" including brackets is in this array
355  sscanf(indivOption,"(%d)", (int*) &fOption);
356  if (isHorizontal) {fOption = (CandleOption)(fOption + kHorizontal);}
357  strncpy(brOpen," ",brClose-brOpen+1); //Cleanup
358 
359  sprintf(fOptionStr,"VIOLIN%c(%ld)",direction,(long)fOption);
360 
361  } else {
362  preset = 1;
363  fOption = (CandleOption)(fOption + fallbackCandle);
364  }
365  } else {
366  sprintf(fOptionStr,"VIOLIN%c%c",direction,preset);
367  }
368  //Handle option "VIOLIN" ,"VIOLINX" or "VIOLINY" to behave like "VIOLINX1" or "VIOLINY1"
369  if (!useIndivOption && !fOption ) {
370  fOption = fallbackCandle;
371  sprintf(fOptionStr,"VIOLIN%c1",direction);
372  }
373  }
374 
375  fIsCalculated = false;
376 
377  return fOption;
378 
379 }
380 
381 ////////////////////////////////////////////////////////////////////////////////
382 /// Calculates all values needed by the candle definition depending on the
383 /// candle options.
384 
386  //Reset everything
387  fNDrawPoints = 0;
388  fNHistoPoints = 0;
389 
390  Bool_t swapXY = IsOption(kHorizontal);
391  Bool_t doLogY = (!(swapXY) && fLogY) || (swapXY && fLogX);
392  Bool_t doLogX = (!(swapXY) && fLogX) || (swapXY && fLogY);
393  Bool_t doLogZ = fLogZ;
394 
395  //Will be min and max values of raw-data
396  Double_t min = 1e15;
397  Double_t max = -1e15;
398 
399  // Determining the quantiles
400  Double_t *prob = new Double_t[5];
401 
402  if (fWhiskerRange >= 1) {
403  prob[0] = 1e-15;
404  prob[4] = 1-1e-15;
405  } else {
406  prob[0] = 0.5 - fWhiskerRange/2.;
407  prob[4] = 0.5 + fWhiskerRange/2.;
408  }
409 
410 
411  if (fBoxRange >= 1) {
412  prob[1] = 1E-14;
413  prob[3] = 1-1E-14;
414  } else {
415  prob[1] = 0.5 - fBoxRange/2.;
416  prob[3] = 0.5 + fBoxRange/2.;
417  }
418 
419  prob[2]=0.5;
420  Double_t *quantiles = new Double_t[5];
421  quantiles[0]=0.; quantiles[1]=0.; quantiles[2] = 0.; quantiles[3] = 0.; quantiles[4] = 0.;
422  if (!fIsRaw && fProj) { //Need a calculation for a projected histo
423  if (((IsOption(kHistoLeft)) || (IsOption(kHistoRight)) || (IsOption(kHistoViolin))) && fProj->GetNbinsX() > 500) {
424  // When using the histooption the number of bins of the projection is
425  // limited because of the array space defined by kNMAXPOINTS.
426  // So the histo is rebinned, that it can be displayed at any time.
427  // Finer granularity is not useful anyhow
428  int divideBy = ((fProj->GetNbinsX() - 1)/((kNMAXPOINTS-10)/4))+1;
429  fProj->RebinX(divideBy);
430  }
431  fProj->GetQuantiles(5, quantiles, prob);
432  } else { //Need a calculation for a raw-data candle
434  }
435 
436  // Check if the quantiles are valid, seems the under- and overflow is taken
437  // into account as well, we need to ignore this!
438  if (quantiles[0] >= quantiles[4] ||
439  quantiles[1] >= quantiles[3]) {
440  delete [] prob;
441  delete [] quantiles;
442  return;
443  }
444 
445  // Definition of the candle in the standard case
446  fBoxUp = quantiles[3];
447  fBoxDown = quantiles[1];
448  fWhiskerUp = quantiles[4]; //Standard case
449  fWhiskerDown = quantiles[0]; //Standard case
450  fMedian = quantiles[2];
451  Double_t iqr = fBoxUp-fBoxDown;
452  Int_t nOutliers = 0;
453 
454  if (IsOption(kWhisker15)) { // Improved whisker definition, with 1.5*iqr
455  if (!fIsRaw && fProj) { //Need a calculation for a projected histo
456  int bin = fProj->FindBin(fBoxDown-1.5*iqr);
457  // extending only to the lowest data value within this range
458  while (fProj->GetBinContent(bin) == 0 && bin <= fProj->GetNbinsX()) bin++;
460 
461  bin = fProj->FindBin(fBoxUp+1.5*iqr);
462  while (fProj->GetBinContent(bin) == 0 && bin >= 1) bin--;
463  fWhiskerUp = fProj->GetBinCenter(bin);
464  } else { //Need a calculation for a raw-data candle
467 
468  //Need to find highest value up to 1.5*iqr from the BoxUp-pos, and the lowest value up to -1.5*iqr from the boxLow-pos
469  for (Long64_t i = 0; i < fNDatapoints; ++i) {
470  Double_t myData = fDatapoints[i];
471  if (myData > fWhiskerUp && myData <= fBoxUp + 1.5*iqr) fWhiskerUp = myData;
472  if (myData < fWhiskerDown && myData >= fBoxDown - 1.5*iqr) fWhiskerDown = myData;
473  }
474  }
475  }
476 
477  if (!fIsRaw && fProj) { //Need a calculation for a projected histo
478  fMean = fProj->GetMean();
479  fMedianErr = 1.57*iqr/sqrt(fProj->GetEntries());
480  fAxisMin = fProj->GetXaxis()->GetXmin();
481  fAxisMax = fProj->GetXaxis()->GetXmax();
482  } else { //Need a calculation for a raw-data candle
483  //Calculate the Mean
484  fMean = 0;
485  for (Long64_t i = 0; i < fNDatapoints; ++i) {
486  fMean += fDatapoints[i];
487  if (fDatapoints[i] < min) min = fDatapoints[i];
488  if (fDatapoints[i] > max) max = fDatapoints[i];
489  if (fDatapoints[i] < fWhiskerDown || fDatapoints[i] > fWhiskerUp) nOutliers++;
490  }
491  fMean /= fNDatapoints;
492  fMedianErr = 1.57*iqr/sqrt(fNDatapoints);
493  }
494 
495  delete [] prob;
496  delete [] quantiles;
497 
498  //Doing the outliers and other single points to show
499  if (GetCandleOption(5) > 0) { //Draw outliers
500  TRandom2 random;
501  const int maxOutliers = kNMAXPOINTS;
502  Double_t myScale = 1.;
503  if (!fIsRaw && fProj) { //Need a calculation for a projected histo
504  if (fProj->GetEntries() > maxOutliers/2) myScale = fProj->GetEntries()/(maxOutliers/2.);
505  fNDrawPoints = 0;
506  for (int bin = 0; bin < fProj->GetNbinsX(); bin++) {
507  // Either show them only outside the whiskers, or all of them
508  if (fProj->GetBinContent(bin) > 0 && (fProj->GetBinCenter(bin) < fWhiskerDown || fProj->GetBinCenter(bin) > fWhiskerUp || (GetCandleOption(5) > 1)) ) {
509  Double_t scaledBinContent = fProj->GetBinContent(bin)/myScale;
510  if (scaledBinContent >0 && scaledBinContent < 1) scaledBinContent = 1; //Outliers have a typical bin content between 0 and 1, when scaling they would disappear
511  for (int j=0; j < (int)scaledBinContent; j++) {
512  if (fNDrawPoints > maxOutliers) break;
513  if (IsOption(kPointsAllScat)) { //Draw outliers and "all" values scattered
516  } else { //Draw them in the "candle line"
518  if ((int)scaledBinContent == 1) //If there is only one datapoint available put it in the middle of the bin
520  else //If there is more than one datapoint scatter it along the bin, otherwise all marker would be (invisibly) stacked on top of each other
522  }
523  if (swapXY) {
524  //Swap X and Y
525  Double_t keepCurrently;
526  keepCurrently = fDrawPointsX[fNDrawPoints];
528  fDrawPointsY[fNDrawPoints] = keepCurrently;
529  }
530  // Continue fMeans, that fNDrawPoints is not increased, so that value will not be shown
531  if (doLogX) {
533  }
534  if (doLogY) {
536  }
537  fNDrawPoints++;
538  }
539  }
540  if (fNDrawPoints > maxOutliers) { //Should never happen, due to myScale!!!
541  Error ("PaintCandlePlot","Not possible to draw all outliers.");
542  break;
543  }
544  }
545  } else { //Raw data candle
546  //If only outliers are shown, calculate myScale only based on nOutliers, use fNDatapoints (all) instead
547  if (IsOption(kPointsOutliers) && nOutliers > maxOutliers/2) {
548  myScale = nOutliers/(maxOutliers/2.);
549  } else {
550  if (fNDatapoints > maxOutliers/2) myScale = fNDatapoints/(maxOutliers/2.);
551  }
552  fNDrawPoints = 0;
553  for (int i = 0; i < fNDatapoints; i++ ) {
554  Double_t myData = fDatapoints[i];
555  Double_t maxScatter = (fWhiskerUp-fWhiskerDown)/100;
556  if (!(i % (int) myScale == 0 )) continue; //If the amount of data is too large take only every 2nd or 3rd to reduce the amount
557  // Either show them only outside the whiskers, or all of them
558  if (myData < fWhiskerDown || myData > fWhiskerUp || (GetCandleOption(5) > 1)) {
559  if (IsOption(kPointsAllScat)) { //Draw outliers and "all" values scattered
561  fDrawPointsY[fNDrawPoints] = myData + (random.Rndm() - 0.5)*maxScatter; //random +- 0.5 of candle-height
562  } else { //Draw them in the "candle line"
564  fDrawPointsY[fNDrawPoints] = myData + (random.Rndm() - 0.5)*maxScatter; //random +- 0.5 of candle-height
565  }
566  if (swapXY) {
567  //Swap X and Y
568  Double_t keepCurrently;
569  keepCurrently = fDrawPointsX[fNDrawPoints];
571  fDrawPointsY[fNDrawPoints] = keepCurrently;
572  }
573  // Continue fMeans, that fNDrawPoints is not increased, so that value will not be shown
574  if (doLogX) {
576  else continue;
577  }
578  if (doLogY) {
580  else continue;
581  }
582  fNDrawPoints++;
583  if (fNDrawPoints > maxOutliers) { //Should never happen, due to myScale!!!
584  Error ("PaintCandlePlotRaw","Not possible to draw all outliers.");
585  break;
586  }
587  }
588  }
589  }
590  }
592  //We are starting with kHistoRight, left will be modified from right later
593  if (fIsRaw) { //This is a raw-data candle
594  if (!fProj) {
595  fProj = new TH1D("hpa","hpa",100,min,max+0.0001*(max-min));
596  for (Long64_t i = 0; i < fNDatapoints; ++i) {
597  fProj->Fill(fDatapoints[i]);
598  }
599  }
600  }
601 
602  fNHistoPoints = 0;
603  Double_t maxContent = fProj->GetMaximum();
604  Double_t maxHistoHeight = fHistoWidth;
605  if (IsOption(kHistoViolin)) maxHistoHeight *= 0.5;
606 
607  bool isFirst = true;
608  int lastNonZero = 0;
609  for (int bin = 1; bin <= fProj->GetNbinsX(); bin++) {
610  if (isFirst) {
611  if (fProj->GetBinContent(bin) > 0) {
614  if (doLogX) {
616  }
617  if (doLogY) {
619  }
620  fNHistoPoints++;
621  isFirst = false;
622  } else {
623  continue;
624  }
625  }
626 
627  Double_t myBinValue = fProj->GetBinContent(bin);
628  if (doLogZ) {
629  if (myBinValue > 0) myBinValue = TMath::Log10(myBinValue); else myBinValue = 0;
630  }
631  fHistoPointsX[fNHistoPoints] = fPosCandleAxis + myBinValue/maxContent*maxHistoHeight;
633  fNHistoPoints++;
634  fHistoPointsX[fNHistoPoints] = fPosCandleAxis + myBinValue/maxContent*maxHistoHeight;
636  if (doLogX) {
639  }
640  if (doLogY) {
643  }
644 
645  fNHistoPoints++;
646  if (fProj->GetBinContent(bin) > 0) lastNonZero = fNHistoPoints;
647  }
648 
651  fNHistoPoints = lastNonZero+1; //+1 so that the line down to 0 is added as well
652 
653  if (IsOption(kHistoLeft)) {
654  for (int i = 0; i < fNHistoPoints; i++) {
656  }
657  }
658  if (IsOption(kHistoViolin)) {
659  for (int i = 0; i < fNHistoPoints; i++) {
660  fHistoPointsX[fNHistoPoints + i] = 2*fPosCandleAxis - fHistoPointsX[fNHistoPoints -i-1];
661  fHistoPointsY[fNHistoPoints + i] = fHistoPointsY[fNHistoPoints -i-1];
662  }
663  fNHistoPoints *= 2;
664  }
665  }
666 
667 
668  fIsCalculated = true;
669 }
670 
671 ////////////////////////////////////////////////////////////////////////////////
672 /// Paint one candle with its current attributes.
673 
675 {
676  //If something was changed before, we need to recalculate some values
677  if (!fIsCalculated) Calculate();
678 
679  // Save the attributes as they were set originally
680  Style_t saveLine = GetLineStyle();
681  Style_t saveMarker = GetMarkerStyle();
682  Style_t saveFillStyle = GetFillStyle();
683  Style_t saveFillColor = GetFillColor();
684  Style_t saveLineColor = GetLineColor();
685 
686  Double_t dimLeft = fPosCandleAxis-0.5*fCandleWidth;
687  Double_t dimRight = fPosCandleAxis+0.5*fCandleWidth;
688 
692 
693  Bool_t swapXY = IsOption(kHorizontal);
694  Bool_t doLogY = (!(swapXY) && fLogY) || (swapXY && fLogX);
695  Bool_t doLogX = (!(swapXY) && fLogX) || (swapXY && fLogY);
696 
697  // From now on this is real painting only, no calculations anymore
698 
700  SetLineColor(saveFillColor);
703  SetLineColor(saveLineColor);
705  }
706 
707 
709  if (IsOption(kHistoZeroIndicator) && (saveFillStyle != 0)) {
710  SetLineColor(saveFillColor);
712  }
713  if (!swapXY) {
714  gPad->PaintFillArea(fNHistoPoints, fHistoPointsX, fHistoPointsY);
715  gPad->PaintPolyLine(fNHistoPoints, fHistoPointsX, fHistoPointsY);
716  } else {
717  gPad->PaintFillArea(fNHistoPoints, fHistoPointsY, fHistoPointsX);
718  gPad->PaintPolyLine(fNHistoPoints, fHistoPointsY, fHistoPointsX);
719  }
720  if (IsOption(kHistoZeroIndicator) && (saveFillStyle != 0)) {
721  SetLineColor(saveLineColor);
723  }
724  }
725 
726  if (IsOption(kBox)) { // Draw a simple box
727  if (IsOption(kMedianNotched)) { // Check if we have to draw a box with notches
728  Double_t x[] = {dimLeft, dimLeft, dimLeft+fCandleWidth/3., dimLeft, dimLeft, dimRight,
729  dimRight, dimRight-fCandleWidth/3., dimRight, dimRight, dimLeft};
731  fMedian+fMedianErr, fMedian, fMedian-fMedianErr, fBoxDown, fBoxDown};
732  PaintBox(11, x, y, swapXY);
733  } else { // draw a simple box
734  Double_t x[] = {dimLeft, dimLeft, dimRight, dimRight, dimLeft};
735  Double_t y[] = {fBoxDown, fBoxUp, fBoxUp, fBoxDown, fBoxDown};
736  PaintBox(5, x, y, swapXY);
737  }
738  }
739 
740  if (IsOption(kAnchor)) { // Draw the anchor line
741  PaintLine(dimLeft, fWhiskerUp, dimRight, fWhiskerUp, swapXY);
742  PaintLine(dimLeft, fWhiskerDown, dimRight, fWhiskerDown, swapXY);
743  }
744 
745  if (IsOption(kWhiskerAll) && !IsOption(kHistoZeroIndicator)) { // Whiskers are dashed
746  SetLineStyle(2);
750  SetLineStyle(saveLine);
752  } else if ((IsOption(kWhiskerAll) && IsOption(kHistoZeroIndicator)) || IsOption(kWhisker15) ) { // Whiskers without dashing, better whisker definition, or forced when using zero line
755  }
756 
757  if (IsOption(kMedianLine)) { // Paint fMedian as a line
758  PaintLine(dimLeft, fMedian, dimRight, fMedian, swapXY);
759  } else if (IsOption(kMedianNotched)) { // Paint fMedian as a line (using notches, fMedian line is shorter)
760  PaintLine(dimLeft+fCandleWidth/3, fMedian, dimRight-fCandleWidth/3., fMedian, swapXY);
761  } else if (IsOption(kMedianCircle)) { // Paint fMedian circle
762  Double_t myMedianX[1], myMedianY[1];
763  if (!swapXY) {
764  myMedianX[0] = fPosCandleAxis;
765  myMedianY[0] = fMedian;
766  } else {
767  myMedianX[0] = fMedian;
768  myMedianY[0] = fPosCandleAxis;
769  }
770 
771  Bool_t isValid = true;
772  if (doLogX) {
773  if (myMedianX[0] > 0) myMedianX[0] = TMath::Log10(myMedianX[0]); else isValid = false;
774  }
775  if (doLogY) {
776  if (myMedianY[0] > 0) myMedianY[0] = TMath::Log10(myMedianY[0]); else isValid = false;
777  }
778 
779  SetMarkerStyle(24);
781 
782  if (isValid) gPad->PaintPolyMarker(1,myMedianX,myMedianY); // A circle for the fMedian
783 
784  SetMarkerStyle(saveMarker);
786 
787  }
788 
789  if (IsOption(kMeanCircle)) { // Paint fMean as a circle
790  Double_t myMeanX[1], myMeanY[1];
791  if (!swapXY) {
792  myMeanX[0] = fPosCandleAxis;
793  myMeanY[0] = fMean;
794  } else {
795  myMeanX[0] = fMean;
796  myMeanY[0] = fPosCandleAxis;
797  }
798 
799  Bool_t isValid = true;
800  if (doLogX) {
801  if (myMeanX[0] > 0) myMeanX[0] = TMath::Log10(myMeanX[0]); else isValid = false;
802  }
803  if (doLogY) {
804  if (myMeanY[0] > 0) myMeanY[0] = TMath::Log10(myMeanY[0]); else isValid = false;
805  }
806 
807  SetMarkerStyle(24);
809 
810  if (isValid) gPad->PaintPolyMarker(1,myMeanX,myMeanY); // A circle for the fMean
811 
812  SetMarkerStyle(saveMarker);
814 
815  } else if (IsOption(kMeanLine)) { // Paint fMean as a dashed line
816  SetLineStyle(2);
818 
819  PaintLine(dimLeft, fMean, dimRight, fMean, swapXY);
820  SetLineStyle(saveLine);
822 
823  }
824 
825  if (IsOption(kAnchor)) { //Draw standard anchor
826  PaintLine(dimLeft, fWhiskerDown, dimRight, fWhiskerDown, swapXY); // the lower anchor line
827  PaintLine(dimLeft, fWhiskerUp, dimRight, fWhiskerUp, swapXY); // the upper anchor line
828  }
829 
830  // This is a bit complex. All values here are handled as outliers. Usually
831  // only the datapoints outside the whiskers are shown.
832  // One can show them in one row as crosses, or scattered randomly. If activated
833  // all datapoint are shown in the same way
834 
835  if (GetCandleOption(5) > 0) { //Draw outliers
836  if (IsOption(kPointsAllScat)) { //Draw outliers and "all" values scattered
837  SetMarkerStyle(0);
838  } else {
839  SetMarkerStyle(5);
840  }
842  gPad->PaintPolyMarker(fNDrawPoints,fDrawPointsX, fDrawPointsY);
843  }
844 }
845 
846 ////////////////////////////////////////////////////////////////////////////////
847 /// Return true is this option is activated in fOption
848 
850  long myOpt = 9;
851  int pos = 0;
852  for (pos = 0; pos < 16; pos++) {
853  if (myOpt > opt) break;
854  else myOpt *=10;
855  }
856  myOpt /= 9;
857  int thisOpt = GetCandleOption(pos);
858 
859  return ((thisOpt * myOpt) == opt);
860 }
861 
862 ////////////////////////////////////////////////////////////////////////////////
863 /// Paint a box for candle.
864 
865 void TCandle::PaintBox(Int_t nPoints, Double_t *x, Double_t *y, Bool_t swapXY)
866 {
867  Bool_t doLogY = (!(swapXY) && fLogY) || (swapXY && fLogX);
868  Bool_t doLogX = (!(swapXY) && fLogX) || (swapXY && fLogY);
869  if (doLogY) {
870  for (int i=0; i<nPoints; i++) {
871  if (y[i] > 0) y[i] = TMath::Log10(y[i]);
872  else return;
873  }
874  }
875  if (doLogX) {
876  for (int i=0; i<nPoints; i++) {
877  if (x[i] > 0) x[i] = TMath::Log10(x[i]);
878  else return;
879  }
880  }
881  if (!swapXY) {
882  gPad->PaintFillArea(nPoints, x, y);
883  gPad->PaintPolyLine(nPoints, x, y);
884  } else {
885  gPad->PaintFillArea(nPoints, y, x);
886  gPad->PaintPolyLine(nPoints, y, x);
887  }
888 }
889 
890 ////////////////////////////////////////////////////////////////////////////////
891 /// Paint a line for candle.
892 
894 {
895  Bool_t doLogY = (!(swapXY) && fLogY) || (swapXY && fLogX);
896  Bool_t doLogX = (!(swapXY) && fLogX) || (swapXY && fLogY);
897  if (doLogY) {
898  if (y1 > 0) y1 = TMath::Log10(y1); else return;
899  if (y2 > 0) y2 = TMath::Log10(y2); else return;
900  }
901  if (doLogX) {
902  if (x1 > 0) x1 = TMath::Log10(x1); else return;
903  if (x2 > 0) x2 = TMath::Log10(x2); else return;
904  }
905  if (!swapXY) {
906  gPad->PaintLine(x1, y1, x2, y2);
907  } else {
908  gPad->PaintLine(y1, x1, y2, x2);
909  }
910 }
911 
912 ////////////////////////////////////////////////////////////////////////////////
913 /// Stream an object of class TCandle.
914 
915 void TCandle::Streamer(TBuffer &R__b)
916 {
917  if (R__b.IsReading()) {
918  UInt_t R__s, R__c;
919  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
920  if (R__v > 3) {
921  R__b.ReadClassBuffer(TCandle::Class(), this, R__v, R__s, R__c);
922  return;
923  }
924  } else {
925  R__b.WriteClassBuffer(TCandle::Class(),this);
926  }
927 }
928 
929 ////////////////////////////////////////////////////////////////////////////////
930 /// The coordinates in the TParallelCoordVar-class are in Pad-Coordinates, so we need to convert them
931 
932 void TCandle::ConvertToPadCoords(Double_t minAxis, Double_t maxAxis, Double_t axisMinCoord, Double_t axisMaxCoord)
933 {
934  if (!fIsCalculated) Calculate();
935  Double_t a,b;
936  if (fLogY) {
937  a = TMath::Log10(minAxis);
938  b = TMath::Log10(maxAxis/minAxis);
939  } else {
940  a = minAxis;
941  b = maxAxis-minAxis;
942  }
943 
944  fMean = axisMinCoord + ((fMean-a)/b)*(axisMaxCoord-axisMinCoord);
945  fMedian = axisMinCoord + ((fMedian-a)/b)*(axisMaxCoord-axisMinCoord);
946  fMedianErr = axisMinCoord + ((fMedianErr-a)/b)*(axisMaxCoord-axisMinCoord);
947  fBoxUp = axisMinCoord + ((fBoxUp-a)/b)*(axisMaxCoord-axisMinCoord);
948  fBoxDown = axisMinCoord + ((fBoxDown-a)/b)*(axisMaxCoord-axisMinCoord);
949  fWhiskerUp = axisMinCoord + ((fWhiskerUp-a)/b)*(axisMaxCoord-axisMinCoord);
950  fWhiskerDown = axisMinCoord + ((fWhiskerDown-a)/b)*(axisMaxCoord-axisMinCoord);
951 
952  for (int i = 0; i < fNDrawPoints; i++) {
953  fDrawPointsY[i] = axisMinCoord + ((fDrawPointsY[i]-a)/b)*(axisMaxCoord-axisMinCoord);
954  }
955  for (int i = 0; i < fNHistoPoints; i++) {
956  fHistoPointsY[i] = axisMinCoord + ((fHistoPointsY[i]-a)/b)*(axisMaxCoord-axisMinCoord);
957  }
958 }
Bool_t IsReading() const
Definition: TBuffer.h:83
virtual Int_t FindBin(Double_t x, Double_t y=0, Double_t z=0)
Return Global bin number corresponding to x,y,z.
Definition: TH1.cxx:3572
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3251
TCandle()
TCandle default constructor.
Definition: TCandle.cxx:41
virtual Double_t GetMaximum(Double_t maxval=FLT_MAX) const
Return maximum value smaller than maxval of bins in the range, unless the value has been overridden b...
Definition: TH1.cxx:7844
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
virtual Double_t GetBinCenter(Int_t bin) const
Return bin center for 1D histogram.
Definition: TH1.cxx:8434
Double_t fMedian
Position of the median.
Definition: TCandle.h:62
long long Long64_t
Definition: RtypesCore.h:69
short Style_t
Definition: RtypesCore.h:76
Bool_t IsHorizontal()
Definition: TCandle.h:116
static Double_t fBoxRange
The fraction which is covered by the box (0 < x < 1), default 0.5.
Definition: TCandle.h:90
short Version_t
Definition: RtypesCore.h:61
If this bit is not set it is vertical.
Definition: TCandle.h:46
Double_t fWhiskerUp
Position of the upper whisker end.
Definition: TCandle.h:66
bool IsOption(CandleOption opt)
Return true is this option is activated in fOption.
Definition: TCandle.cxx:849
const char Option_t
Definition: RtypesCore.h:62
Random number generator class based on the maximally quidistributed combined Tausworthe generator by ...
Definition: TRandom2.h:27
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition: TH1.cxx:4770
virtual Int_t GetQuantiles(Int_t nprobSum, Double_t *q, const Double_t *probSum=0)
Compute Quantiles for this histogram Quantile x_q of a probability distribution Function F is defined...
Definition: TH1.cxx:4322
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
virtual Double_t GetMean(Int_t axis=1) const
For axis = 1,2 or 3 returns the mean value of the histogram along X,Y or Z axis.
Definition: TH1.cxx:6930
int ParseOption(char *optin)
Parsing of the option-string.
Definition: TCandle.cxx:244
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
static Bool_t fScaledCandle
shall the box-width be scaled to each other by the integral of a box?
Definition: TCandle.h:92
Double_t fAxisMin
The Minimum which is visible by the axis (used by zero indicator)
Definition: TCandle.h:86
Double_t * fDatapoints
position of all Datapoints within this candle
Definition: TCandle.h:69
Double_t fDrawPointsX[kNMAXPOINTS]
x-coord for every outlier, ..
Definition: TCandle.h:72
virtual Double_t GetBinLowEdge(Int_t bin) const
Return bin lower edge for 1D histogram.
Definition: TH1.cxx:8445
virtual void Modify()
Change current line attributes if necessary.
Definition: TAttLine.cxx:234
void PaintLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Bool_t swapXY)
Paint a line for candle.
Definition: TCandle.cxx:893
Double_t fMean
Position of the mean.
Definition: TCandle.h:61
virtual Style_t GetMarkerStyle() const
Return the marker style.
Definition: TAttMarker.h:32
Marker Attributes class.
Definition: TAttMarker.h:19
virtual Style_t GetLineStyle() const
Return the line style.
Definition: TAttLine.h:34
double sqrt(double)
CandleOption
Definition: TCandle.h:28
Double_t GetXmin() const
Definition: TAxis.h:133
static const double x2[5]
Fill Area Attributes class.
Definition: TAttFill.h:19
bool fIsCalculated
Definition: TCandle.h:53
Double_t x[n]
Definition: legend1.C:17
Double_t fHistoWidth
The histo width (the height of the max bin)
Definition: TCandle.h:59
void Class()
Definition: Class.C:29
Double_t fCandleWidth
The candle width.
Definition: TCandle.h:58
int fLogX
make the candle appear logx-like
Definition: TCandle.h:82
void Quantiles(Int_t n, Int_t nprob, Double_t *x, Double_t *quantiles, Double_t *prob, Bool_t isSorted=kTRUE, Int_t *index=0, Int_t type=7)
virtual void Modify()
Change current fill area attributes if necessary.
Definition: TAttFill.cxx:210
void PaintBox(Int_t nPoints, Double_t *x, Double_t *y, Bool_t swapXY)
Paint a box for candle.
Definition: TCandle.cxx:865
Double_t Log10(Double_t x)
Definition: TMath.h:763
Bool_t IsCandleScaled()
Definition: TCandle.cxx:185
static Bool_t fScaledViolin
shall the violin or histos be scaled to each other by the maximum height?
Definition: TCandle.h:93
Double_t fDrawPointsY[kNMAXPOINTS]
y-coord for every outlier, ..
Definition: TCandle.h:73
void Error(const char *location, const char *msgfmt,...)
Double_t fHistoPointsX[kNMAXPOINTS]
x-coord for the polyline of the histo
Definition: TCandle.h:76
Double_t fBoxDown
Position of the lower box end.
Definition: TCandle.h:65
void ConvertToPadCoords(Double_t minAxis, Double_t maxAxis, Double_t axisMinCoord, Double_t axisMaxCoord)
The coordinates in the TParallelCoordVar-class are in Pad-Coordinates, so we need to convert them...
Definition: TCandle.cxx:932
point * points
Definition: X3DBuffer.c:20
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition: TAttLine.h:40
virtual void Modify()
Change current marker attributes if necessary.
Definition: TAttMarker.cxx:220
Double_t fBoxUp
Position of the upper box end.
Definition: TCandle.h:64
auto * a
Definition: textangle.C:12
int fLogY
make the candle appear logy-like
Definition: TCandle.h:83
The candle plot painter class.
Definition: TCandle.h:25
unsigned int UInt_t
Definition: RtypesCore.h:42
void Calculate()
Calculates all values needed by the candle definition depending on the candle options.
Definition: TCandle.cxx:385
Double_t fAxisMax
The Maximum which is visible by the axis (used by zero indicator)
Definition: TCandle.h:87
virtual void SetMarkerStyle(Style_t mstyle=1)
Set the marker style.
Definition: TAttMarker.h:40
1-D histogram with a double per channel (see TH1 documentation)}
Definition: TH1.h:610
constexpr Double_t E()
Base of natural log: .
Definition: TMath.h:97
virtual void Paint(Option_t *option="")
Paint one candle with its current attributes.
Definition: TCandle.cxx:674
const Bool_t kFALSE
Definition: RtypesCore.h:88
static void SetBoxRange(const Double_t bRange)
Static function to set fBoxRange, by setting whisker-range, one can force the box of the candle-chart...
Definition: TCandle.cxx:217
virtual Color_t GetLineColor() const
Return the line color.
Definition: TAttLine.h:33
bool fDismiss
True if the candle cannot be painted.
Definition: TCandle.h:55
static void SetScaledCandle(const Bool_t cScale=true)
Static function to set scaling between candles-withs.
Definition: TCandle.cxx:227
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
static Double_t fWhiskerRange
The fraction which is covered by the whiskers (0 < x < 1), default 1.
Definition: TCandle.h:89
virtual Double_t GetBinWidth(Int_t bin) const
Return bin width for 1D histogram.
Definition: TH1.cxx:8456
virtual Double_t Rndm()
TausWorth generator from L&#39;Ecuyer, uses as seed 3x32bits integers Use a mask of 0xffffffffUL to make ...
Definition: TRandom2.cxx:56
static const double x1[5]
#define ClassImp(name)
Definition: Rtypes.h:359
virtual TH1 * RebinX(Int_t ngroup=2, const char *newname="")
Definition: TH1.h:343
TH1D * fProj
Definition: TCandle.h:54
double Double_t
Definition: RtypesCore.h:55
char fOptionStr[128]
String to draw the candle.
Definition: TCandle.h:81
CandleOption fOption
Setting the style of the candle.
Definition: TCandle.h:80
Double_t fMedianErr
The size of the notch.
Definition: TCandle.h:63
Double_t y[n]
Definition: legend1.C:17
Double_t fHistoPointsY[kNMAXPOINTS]
y-coord for the polyline of the histo
Definition: TCandle.h:77
virtual Color_t GetFillColor() const
Return the fill area color.
Definition: TAttFill.h:30
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
virtual Double_t GetEntries() const
Return the current number of entries.
Definition: TH1.cxx:4185
int GetCandleOption(const int pos)
Definition: TCandle.h:97
Long64_t fNDrawPoints
max number of outliers or other point to be shown
Definition: TCandle.h:74
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition: TAttLine.h:42
static void SetWhiskerRange(const Double_t wRange)
Static function to set fWhiskerRange, by setting whisker-range, one can force the whiskers to cover t...
Definition: TCandle.cxx:203
static void SetScaledViolin(const Bool_t vScale=true)
Static function to set scaling between violin-withs.
Definition: TCandle.cxx:236
Double_t fWhiskerDown
Position of the lower whisker end.
Definition: TCandle.h:67
auto * l
Definition: textangle.C:4
Double_t fPosCandleAxis
x-pos for a vertical candle
Definition: TCandle.h:57
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
const Int_t kNMAXPOINTS
Definition: TCandle.h:23
THist< 1, double, THistStatContent, THistStatUncertainty > TH1D
Definition: THist.hxx:284
#define gPad
Definition: TVirtualPad.h:285
Bool_t IsViolinScaled()
Definition: TCandle.cxx:190
virtual ~TCandle()
TCandle default destructor.
Definition: TCandle.cxx:181
bool fIsRaw
0: for TH1 projection, 1: using raw data
Definition: TCandle.h:52
virtual Int_t GetNbinsX() const
Definition: TH1.h:291
virtual Style_t GetFillStyle() const
Return the fill area style.
Definition: TAttFill.h:31
int fLogZ
make the candle appear logz-like
Definition: TCandle.h:84
int fNHistoPoints
Definition: TCandle.h:78
Double_t GetXmax() const
Definition: TAxis.h:134
const Int_t n
Definition: legend1.C:16
Line Attributes class.
Definition: TAttLine.h:18
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition: TH1.h:315
virtual Version_t ReadVersion(UInt_t *start=0, UInt_t *bcnt=0, const TClass *cl=0)=0
Long64_t fNDatapoints
Number of Datapoints within this candle.
Definition: TCandle.h:70