ROOT  6.06/09
Reference Guide
TAxis.h
Go to the documentation of this file.
1 /// \file ROOT/TAxis.h
2 /// \ingroup Hist
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-03-23
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
6 
7 /*************************************************************************
8  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
9  * All rights reserved. *
10  * *
11  * For the licensing terms see $ROOTSYS/LICENSE. *
12  * For the list of contributors see $ROOTSYS/README/CREDITS. *
13  *************************************************************************/
14 
15 #ifndef ROOT7_TAxis
16 #define ROOT7_TAxis
17 
18 #include <algorithm>
19 #include <string>
20 #include <unordered_map>
21 #include <vector>
22 
23 #include "ROOT/TLogger.h"
24 
25 namespace ROOT {
26 
27 /**
28  \class TAxisBase ROOT7
29  Histogram axis base class. Keeps track of the number of bins and overflow
30  handling. Offers bin iteration.
31 
32  Bin indices are starting from 0 for the underflow bin (representing values that
33  are lower than the axis range). Starting at index 1 are the actual bins of the
34  axis, up to N + 1 for an axis with N bins. Index N + 2 is the overflow bin for
35  values larger than the axis range.
36  */
37 class TAxisBase {
38 public:
39  /// Status of FindBin(x)
40  enum class EFindStatus {
41  kCanGrow, ///< Coordinate could fit after growing the axis
42  kValid ///< The returned bin index is valid
43  };
44 
45 protected:
46  ///\name Inaccessible copy, assignment
47  /// The copy and move constructors and assignment operators are protected to
48  /// prevent slicing.
49  ///\{
50  TAxisBase(const TAxisBase&) = default;
51  TAxisBase(TAxisBase&&) = default;
52  TAxisBase& operator=(const TAxisBase&) = default;
53  TAxisBase& operator=(TAxisBase&&) = default;
54  ///\}
55 
56  /// Given rawbin (<0 for underflow, >= GetNBinsNoOver() for overflow), determine the
57  /// actual bin number taking into account how over/underflow should be
58  /// handled.
59  ///
60  /// \param[out] status result status of the bin determination.
61  /// \return Returns the bin number adjusted for potential over- and underflow
62  /// bins. Returns kIgnoreBin if the axis cannot handle the over- / underflow,
63  /// in which case `status` will tell how to deal with this overflow.
64  constexpr int AdjustOverflowBinNumber(int rawbin) const {
65  if (rawbin < 0) return 0;
66  // Take underflow into account.
67  ++rawbin;
68 
69  if (rawbin >= GetNBins())
70  return GetNBins() - 1;
71 
72  return rawbin;
73  }
74 
75 public:
76  /**
77  \class const_iterator
78  Random const_iterator through bins. Represents the bin index, not a bin
79  content: the axis has no notion of any content.
80  */
82  public std::iterator<std::random_access_iterator_tag,
83  int /*value*/, int /*distance*/,
84  const int* /*pointer*/, const int& /*ref*/> {
85  int fCursor = 0; ///< Current iteration position
86 
87  public:
88  const_iterator() = default;
89  /// Initialize a const_iterator with its position
90  explicit const_iterator(int cursor) noexcept: fCursor(cursor) {}
91 
92  /// ++i
93  const_iterator &operator++() noexcept {
94  // Could check whether fCursor < fEnd - but what for?
95  ++fCursor;
96  return *this;
97  }
98 
99  /// --i
101  // Could check whether fCursor > fBegin - but what for?
102  --fCursor;
103  return *this;
104  }
106  /// i++
107  const_iterator operator++(int) noexcept {
108  const_iterator old(*this);
109  ++(*this);
110  return old;
111  }
112 
113  // i--
114  const_iterator operator--(int) noexcept {
115  const_iterator old(*this);
116  --(*this);
117  return old;
118  }
120  // i += 2
121  const_iterator &operator+=(int d) noexcept {
122  fCursor += d;
123  return *this;
124  }
126  // i -= 2
127  const_iterator &operator-=(int d) noexcept {
128  fCursor -= d;
129  return *this;
130  }
132  // i + 2
133  const_iterator operator+(int d) noexcept {
134  const_iterator ret(*this);
135  ret += d;
136  return ret;
137  }
139  // i - 2
140  const_iterator operator-(int d) noexcept {
141  const_iterator ret(*this);
142  ret -= d;
143  return ret;
144  }
145 
146  // *i
147  const int* operator*() const noexcept { return &fCursor; }
148  // i->
149  int operator->() const noexcept { return fCursor; }
150 
151  friend bool operator<(const_iterator lhs, const_iterator rhs) noexcept;
152  friend bool operator>(const_iterator lhs, const_iterator rhs) noexcept;
153  friend bool operator<=(const_iterator lhs, const_iterator rhs) noexcept;
154  friend bool operator>=(const_iterator lhs, const_iterator rhs) noexcept;
155  friend bool operator==(const_iterator lhs, const_iterator rhs) noexcept;
156  friend bool operator!=(const_iterator lhs, const_iterator rhs) noexcept;
157  };
158 
159 
160  /// FindBin() returns this bin to signal that the bin number is invalid.
161  constexpr static const int kIgnoreBin = -1;
162 
163  /// Extra bins for each EAxisOverflow value.
164  constexpr static const int kNOverflowBins[4] = {0, 1, 1, 2};
165 
166  /// Construct a TAxisBase.
167  ///
168  ///\param[in] nbins - number of bins in this axis, excluding under- and
169  /// overflow bins.
170  constexpr TAxisBase(int nbins) noexcept:
171  fNBinsNoOver(nbins) { }
172 
173  /// Get the number of bins, excluding under- and overflow.
174  constexpr int GetNBinsNoOver() const noexcept {
175  return fNBinsNoOver;
176  }
177 
178  /// Get the number of bins, including under- and overflow.
179  constexpr int GetNBins() const noexcept {
180  return fNBinsNoOver + 2;
181  }
182 
183  /// Get the bin index for the underflow bin.
184  constexpr int GetUnderflowBin() const noexcept { return 0; }
185 
186  /// Get the bin index for the underflow bin.
187  constexpr int GetOverflowBin() const noexcept { return GetNBinsNoOver() + 1; }
188 
189  /// Whether the bin index is referencing a bin lower than the axis range.
190  constexpr bool IsUnderflowBin(int bin) const noexcept {
191  return bin <= GetUnderflowBin();
192  }
194  /// Whether the bin index is referencing a bin higher than the axis range.
195  constexpr bool IsOverflowBin(int bin) const noexcept {
196  return bin >= GetOverflowBin();
197  }
198 
199  ///\name Iterator interfaces
200  ///\{
201 
202  /// Get a const_iterator pointing to the first non-underflow bin.
203  const_iterator begin() const noexcept { return const_iterator{1}; }
204 
205  /// Get a const_iterator pointing the underflow bin.
206  const_iterator begin_with_underflow() const noexcept { return const_iterator{0}; }
207 
208  /// Get a const_iterator pointing right beyond the last non-overflow bin
209  /// (i.e. pointing to the overflow bin).
210  const_iterator end() const noexcept {
211  return const_iterator{GetOverflowBin()};
212  }
214  /// Get a const_iterator pointing right beyond the overflow bin.
216  return const_iterator{GetOverflowBin() + 1};
217  }
218  ///\}
219 
220 private:
221  unsigned int fNBinsNoOver; ///< Number of bins excluding under- and overflow.
222 };
224 ///\name TAxisBase::const_iterator comparison operators
225 ///\{
226 
227 /// i < j
229  TAxisBase::const_iterator rhs) noexcept {
230  return lhs.fCursor < rhs.fCursor;
231 }
232 
233 /// i > j
235  TAxisBase::const_iterator rhs) noexcept {
236  return lhs.fCursor > rhs.fCursor;
237 }
238 
239 /// i <= j
241  TAxisBase::const_iterator rhs) noexcept {
242  return lhs.fCursor <= rhs.fCursor;
243 }
244 
245 /// i >= j
247  TAxisBase::const_iterator rhs) noexcept {
248  return lhs.fCursor >= rhs.fCursor;
249 }
250 
251 /// i == j
253  TAxisBase::const_iterator rhs) noexcept {
254  return lhs.fCursor == rhs.fCursor;
255 }
256 
257 /// i != j
259  TAxisBase::const_iterator rhs) noexcept {
260  return lhs.fCursor != rhs.fCursor;
261 }
262 ///\}
263 
264 
265 /**
266  Axis with equidistant bin borders. Defined by lower l and upper u limit and
267  the number of bins n. All bins have the same width (u-l)/n.
268 
269  This axis cannot grow; use `TAxisGrow` for that.
270  */
272 protected:
273  double fLow = 0.; ///< The lower limit of the axis
274  double fInvBinWidth = 0.; ///< The inverse of the bin width
275 
276 public:
277  TAxisEquidistant() = default;
278 
279  /// Initialize a TAxisEquidistant.
280  /// \param nbins - number of bins in the axis, excluding under- and overflow
281  /// bins.
282  /// \param low - the low axis range. Any coordinate below that is considered
283  /// as underflow. The first bin's lower edge is at this value.
284  /// \param high - the high axis range. Any coordinate above that is considered
285  /// as overflow. The last bin's higher edge is at this value.
286  constexpr TAxisEquidistant(int nbins, double low, double high) noexcept:
287  TAxisBase(nbins), fLow(low),
288  fInvBinWidth(nbins / (high - low)) { }
289 
290  /// Find the bin index for the given coordinate.
291  /// \note Passing a bin border coordinates can either return the bin above or
292  /// below the bin border. I.e. don't do that for reliable results!
293  constexpr int FindBin(double x) const noexcept {
294  int rawbin = (x - fLow) * fInvBinWidth;
295  return AdjustOverflowBinNumber(rawbin);
296  }
297 
298  /// This axis cannot grow.
299  constexpr static bool CanGrow() noexcept { return false; }
300 
301  /// Get the low end of the axis range.
302  double GetMinimum() const noexcept { return fLow; }
303 
304  /// Get the high end of the axis range.
305  double GetMaximum() const noexcept { return fLow + fInvBinWidth * GetNBinsNoOver(); }
306 
307  /// Get the width of the bins
308  double GetBinWidth() const noexcept { return 1./fInvBinWidth; }
309 
310  /// Get the inverse of the width of the bins
311  double GetInverseBinWidth() const noexcept { return fInvBinWidth; }
312 
313  /// Get the bin center for the given bin index.
314  double GetBinCenter(int bin) const noexcept {
315  return fLow + (bin + 0.5) / fInvBinWidth;
316  }
317 
318  /// Get the low bin border for the given bin index.
319  double GetBinFrom(int bin) const noexcept {
320  return fLow + bin / fInvBinWidth;
321  }
322 
323  /// Get the high bin border for the given bin index.
324  double GetBinTo(int bin) const noexcept {
325  return GetBinFrom(bin + 1);
326  }
327 
328  int GetBinIndexForLowEdge(double x) const noexcept;
329 };
330 
331 /// Equality-compare two TAxisEquidistant.
332 inline
333 bool operator==(const TAxisEquidistant& lhs, const TAxisEquidistant& rhs) noexcept {
334  return lhs.GetNBins() == rhs.GetNBins()
335  && lhs.GetMinimum() == rhs.GetMinimum()
336  && lhs.GetInverseBinWidth() == rhs.GetInverseBinWidth();
337 }
338 
339 
340 /** An axis that can extend its range, keeping the number of its bins unchanged.
341  The axis is constructed with an initial range. Apart from its ability to
342  grow, this axis behaves like a TAxisEquidistant.
343  */
345 public:
346  /// Initialize a TAxisGrow.
347  /// \param nbins - number of bins in the axis, excluding under- and overflow
348  /// bins. This value is fixed over the lifetime of the object.
349  /// \param low - the initial value for the low axis range. Any coordinate
350  /// below that is considered as underflow. To trigger the growing of the
351  /// axis call Grow().
352  /// \param high - the initial value for the high axis range. Any coordinate
353  /// above that is considered as overflow. To trigger the growing of the
354  /// axis call Grow()
355  constexpr TAxisGrow(int nbins, double low, double high) noexcept:
356  TAxisEquidistant(nbins, low, high) { }
357 
358  /// Grow this axis to make the "virtual bin" toBin in-range. This keeps the
359  /// non-affected axis limit unchanged, and extends the other axis limit such
360  /// that a number of consecutive bins are merged.
361  ///
362  /// Example, assuming an initial TAxisGrow with 10 bins from 0. to 1.:
363  /// - `Grow(0)`: that (virtual) bin spans from -0.1 to 0. To include it
364  /// in the axis range, the lower limit must be shifted. The minimal number
365  /// of bins that can be merged is 2, thus the new axis will span from
366  /// -1. to 1.
367  /// - `Grow(-1)`: that (virtual) bin spans from -0.2 to 0.1. To include it
368  /// in the axis range, the lower limit must be shifted. The minimal number
369  /// of bins that can be merged is 2, thus the new axis will span from
370  /// -1. to 1.
371  /// - `Grow(50)`: that (virtual) bin spans from 4.9 to 5.0. To include it
372  /// in the axis range, the higher limit must be shifted. Five bins need to
373  /// be merged, making the new axis range 0. to 5.0.
374  ///
375  /// \param toBin - the "virtual" bin number, as if the axis had an infinite
376  /// number of bins with the current bin width. For instance, for an axis
377  /// with ten bins in the range 0. to 1., the coordinate 2.05 has the virtual
378  /// bin index 20.
379  /// \return Returns the number of bins that were merged to reach the value.
380  /// A value of 1 means that no bins were merged (toBin was in the original
381  /// axis range).
382  int Grow(int toBin);
383 
384  /// This axis kind can increase its range.
385  constexpr bool CanGrow() const { return false; }
386 };
387 
388 
389 /**
390  An axis with non-equidistant bins (also known as "variable binning"). It is
391  defined by an array of bin borders - one more than the number of
392  (non-overflow-) bins it has! As an example, an axis with two bin needs three
393  bin borders:
394  - lower edge of the first bin;
395  - higher edge of the first bin, identical to the lower edge of the second
396  bin;
397  - higher edge of the second bin
398 
399  This axis cannot grow; the size of new bins would not be well defined.
400  */
401 class TAxisIrregular: public TAxisBase {
402 private:
403  /// Bin borders, one more than the number of non-overflow bins.
404  std::vector<double> fBinBorders;
405 
406 public:
407  /// Construct a TAxisIrregular from a vector of bin borders.
408  /// \note The bin borders must be sorted in increasing order!
409  TAxisIrregular(const std::vector<double> &binborders):
410  TAxisBase(binborders.size()), fBinBorders(binborders) {
411 #ifdef R__DO_RANGE_CHECKS
412  if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
413  R__ERROR_HERE("HIST") << "Bin borders must be sorted!";
414 #endif // R__DO_RANGE_CHECKS
415  }
416 
417  /// Construct a TAxisIrregular from a vector of bin borders.
418  /// \note The bin borders must be sorted in increasing order!
419  /// Faster, noexcept version taking an rvalue of binborders. The compiler will
420  /// know when it can take this one.
421  TAxisIrregular(std::vector<double> &&binborders) noexcept:
422  TAxisBase(binborders.size()), fBinBorders(std::move(binborders)) {
423 #ifdef R__DO_RANGE_CHECKS
424  if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
425  R__ERROR_HERE("HIST") << "Bin borders must be sorted!";
426 #endif // R__DO_RANGE_CHECKS
427  }
428 
429  /// Find the bin index corresponding to coordinate x. If the coordinate is
430  /// below the axis range, return 0. If it is above, return N + 1 for an axis
431  /// with N non-overflow bins.
432  int FindBin(double x) const noexcept {
433  const auto bBegin = fBinBorders.begin();
434  const auto bEnd = fBinBorders.end();
435  auto iNotLess = std::lower_bound(bBegin, bEnd, x);
436  int rawbin = iNotLess - bBegin;
437  // if x is < bBegin then iNotLess == bBegin thus rawbin == 0:
438  // we don't want not-less but just-below, thus:
439  rawbin -= 1;
440  return AdjustOverflowBinNumber(rawbin);
441  }
442 
443  /// Get the bin center of the bin with the given index.
444  ///
445  /// For the bin at index 0 (i.e. the underflow bin), a bin center of
446  /// `std::numeric_limits<double>::min()` is returned, i.e. the minimum value
447  /// that can be held in a double.
448  /// Similarly, for the bin at index N + 1 (i.e. the overflow bin), a bin
449  /// center of `std::numeric_limits<double>::max()` is returned, i.e. the
450  /// maximum value that can be held in a double.
451  double GetBinCenter(int bin) const noexcept {
452  if (IsUnderflowBin(bin))
454  if (IsOverflowBin(bin))
456  return 0.5 * (fBinBorders[bin - 1] + fBinBorders[bin]);
457  }
458 
459  /// Get the lower bin border for a given bin index.
460  ///
461  /// For the bin at index 0 (i.e. the underflow bin), a lower bin border of
462  /// `std::numeric_limits<double>::min()` is returned, i.e. the minimum value
463  /// that can be held in a double.
464  double GetBinFrom(int bin) const noexcept {
465  if (IsUnderflowBin(bin))
467  // bin 0 is underflow;
468  // bin 1 starts at fBinBorders[0]
469  return fBinBorders[bin - 1];
470  }
471 
472  /// Get the higher bin border for a given bin index.
473  ///
474  /// For the bin at index N + 1 (i.e. the overflow bin), a bin border of
475  /// `std::numeric_limits<double>::max()` is returned, i.e. the maximum value
476  /// that can be held in a double.
477  double GetBinTo(int bin) const noexcept {
478  if (IsOverflowBin(bin))
480  return GetBinFrom(bin + 1);
481  }
482 
483  /// This axis cannot be extended.
484  constexpr static bool CanGrow() noexcept { return false; }
485 
486  /// Access to the bin borders used by this axis.
487  const std::vector<double>& GetBinBorders() const noexcept { return fBinBorders; }
488 };
489 
490 
491 /**
492  \class TAxisLabels
493  A TAxisGrow that has a label assigned to each bin and a bin width of 1.
494 
495  While filling still works through coordinates (i.e. arrays of doubles),
496  TAxisLabels allows to convert a string to a bin number or the bin's coordinate
497  center. The number of labels and the number of bins reported by TAxisGrow might
498  differ: the TAxisGrow will only grow when seeing a Fill(), while the TAxisLabels
499  will add a new label whenever `GetBinCenter()` is called.
500 
501  Implementation details:
502  Filling happens often; GetBinCenter() needs to be fast. Thus the unordered_map.
503  The painter needs the reverse: it wants the label for bin 0, bin 1 etc. The axis
504  should only store the bin labels once; referencing them is (due to re-allocation,
505  hashing etc) non-trivial. So instead, build a vector<string_view> for the few
506  times the axis needs to be painted.
507  */
508 class TAxisLabels: public TAxisGrow {
509 private:
510  /// Map of label (view on `fLabels`'s elements) to bin index
511  std::unordered_map<std::string, int /*bin number*/> fLabelsIndex;
512 
513 public:
514  /// Construct a TAxisLables from a `vector` of `string_view`s
515  TAxisLabels(const std::vector<std::string_view>& labels):
516  TAxisGrow(labels.size(), 0., static_cast<double>(labels.size())) {
517  for (size_t i = 0, n = labels.size(); i < n; ++i)
518  fLabelsIndex[std::string(labels[i])] = i;
519  }
520 
521  /// Construct a TAxisLables from a `vector` of `string`s
522  TAxisLabels(const std::vector<std::string>& labels):
523  TAxisGrow(labels.size(), 0., static_cast<double>(labels.size())) {
524  for (size_t i = 0, n = labels.size(); i < n; ++i)
525  fLabelsIndex[labels[i]] = i;
526  }
527 
528  /// Get the bin index with label.
529  int GetBinIndex(const std::string& label) {
530  auto insertResult = fLabelsIndex.insert({label, -1});
531  if (insertResult.second) {
532  // we have created a new label
533  int idx = fLabelsIndex.size() - 1;
534  insertResult.first->second = idx;
535  return idx;
536  }
537  return insertResult.first->second;
538  }
539 
540  /// Get the center of the bin with label.
541  double GetBinCenter(const std::string& label) {
542  return GetBinIndex(label) - 0.5; // bin *center*
543  }
544 
545  /// Build a vector of labels. The position in the vector defines the label's bin.
546  std::vector<std::string_view> GetBinLabels() const {
547  std::vector<std::string_view> vec(fLabelsIndex.size());
548  for (const auto& kv: fLabelsIndex)
549  vec.at(kv.second) = kv.first;
550  return vec;
551  }
552 };
553 
554 
555 /**
556  \class TAxisConfig
557  Objects used to configure the different axis types. It can store the
558  properties of all possible axis types, together with the type of the axis.
559 
560  TODO: that's what a variant will be invented for!
561  */
562 class TAxisConfig: public TAxisBase {
563 public:
564  enum EKind {
565  kEquidistant, ///< represents a TAxisEquidistant
566  kGrow, ///< represents a TAxisGrow
567  kIrregular, ///< represents a TAxisIrregular
568  kLabels, ///< represents a TAxisLabels
570  };
571 
572 private:
573  EKind fKind; ///< The kind of axis represented by this configuration
574  std::vector<double> fBinBorders; ///< Bin borders of the TAxisIrregular
575  std::vector<std::string> fLabels; ///< Bin labels for a TAxisLabels
576 
577 public:
578  /// Tag type signalling that an axis should be able to grow; used for calling
579  /// the appropriate constructor.
580  struct Grow_t {
581  };
582  /// Tag signalling that an axis should be able to grow; used for calling the
583  /// appropriate constructor like so:
584  /// TAxisConfig ac(TAxisConfig::Grow, 10, 0., 1.);
585  constexpr static const Grow_t Grow{};
586 
587  /// Represents a `TAxisEquidistant` with `nbins` from `from` to `to`.
588  TAxisConfig(int nbins, double from, double to):
589  TAxisBase(nbins), fKind(kEquidistant),
590  fBinBorders({from, to}) { }
591 
592  /// Represents a `TAxisGrow` with `nbins` from `from` to `to`.
593  TAxisConfig(Grow_t, int nbins, double from, double to):
594  TAxisBase(nbins), fKind(kGrow),
595  fBinBorders({from, to}) { }
596 
597  /// Represents a `TAxisIrregular` with `binborders`.
598  TAxisConfig(const std::vector<double> &binborders):
599  TAxisBase(binborders.size()), fKind(kIrregular),
600  fBinBorders(binborders) { }
601 
602  /// Represents a `TAxisIrregular` with `binborders`.
603  TAxisConfig(std::vector<double> &&binborders) noexcept:
604  TAxisBase(binborders.size()), fKind(kIrregular),
605  fBinBorders(std::move(binborders)) { }
606 
607  /// Represents a `TAxisLabels` with `labels`.
608  TAxisConfig(const std::vector<std::string_view>& labels):
609  TAxisBase(labels.size()),
610  fKind(kLabels),
611  fLabels(labels.begin(), labels.end()) {}
612 
613  /// Represents a `TAxisLabels` with `labels`.
614  TAxisConfig(std::vector<std::string>&& labels):
615  TAxisBase(labels.size()),
616  fKind(kLabels),
617  fLabels(labels.begin(), labels.end()) {}
618 
619  /// \name Axis normalization
620  ///\{
621 
622  /// Build a TAxisConfig from a TAxisEquidistant.
624  TAxisBase(ax), fKind(kEquidistant),
625  fBinBorders{{ax.GetMinimum(), ax.GetMaximum()}} {}
626 
627  /// Build a TAxisConfig from a TAxisGrow.
628  TAxisConfig(const TAxisGrow& ax):
629  TAxisBase(ax), fKind(kGrow), fBinBorders{{ax.GetMinimum(), ax.GetMaximum()}} {}
630 
631  /// Build a TAxisConfig from a TAxisIrregular.
632  TAxisConfig(const TAxisIrregular& ax):
633  TAxisBase(ax), fKind(kIrregular), fBinBorders(ax.GetBinBorders()) {}
634 
635  /// Build a TAxisConfig from a TAxisLabels.
637  TAxisBase(ax), fKind(kLabels) {
638  auto labels = ax.GetBinLabels();
639  for (auto&& lab: labels)
640  fLabels.emplace_back(std::string(lab));
641  }
642  ///\}
643 
644  /// Get the axis kind represented by this `TAxisConfig`.
645  EKind GetKind() const noexcept { return fKind; }
646 
647  /// Get the bin borders; non-empty if the GetKind() == kIrregular.
648  const std::vector<double> &GetBinBorders() const noexcept { return fBinBorders; }
649  /// Get the bin labels; non-empty if the GetKind() == kLabels.
650  const std::vector<std::string> &GetBinLabels() const noexcept { return fLabels; }
651 };
652 
653 
654 namespace Internal {
655 
656 /// Converts a TAxisConfig of whatever kind to the corresponding TAxisBase-derived
657 /// object.
658 template<TAxisConfig::EKind>
659 struct AxisConfigToType; // Only specializations are defined.
660 
661 template<>
662 struct AxisConfigToType<TAxisConfig::kEquidistant> {
664 
665  Axis_t operator()(TAxisConfig cfg) noexcept {
666  return TAxisEquidistant(cfg.GetNBinsNoOver(),
667  cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
668  }
669 };
670 
671 template<>
673  using Axis_t = TAxisGrow;
674  Axis_t operator()(TAxisConfig cfg) noexcept {
675  return TAxisGrow(cfg.GetNBinsNoOver(),
676  cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
677  }
678 };
679 template<>
680 struct AxisConfigToType<TAxisConfig::kIrregular> {
683  return TAxisIrregular(cfg.GetBinBorders());
684  }
685 };
686 
687 template<>
688 struct AxisConfigToType<TAxisConfig::kLabels> {
691  return TAxisLabels(cfg.GetBinLabels());
692  }
693 };
694 
695 } // namespace Internal
696 
697 
698 /// Common view on a TAxis, no matter what its kind.
699 class TAxisView {
700  /// View on a `TAxisEquidistant`, `TAxisGrow` or `TAxisLabel`.
701  const TAxisEquidistant* fEqui = nullptr;
702  /// View on a `TAxisIrregular`.
703  const TAxisIrregular* fIrr = nullptr;
704 
705 public:
706  /// Construct a view on a `TAxisEquidistant`, `TAxisGrow` or `TAxisLabel`.
707  TAxisView(const TAxisEquidistant& equi): fEqui(&equi)
708  {}
709  /// Construct a view on a `TAxisIrregular`.
710  TAxisView(const TAxisIrregular& irr): fIrr(&irr)
711  {}
712 
713  /// Find the bin containing coordinate `x`. Forwards to the underlying axis.
714  int FindBin(double x) const noexcept {
715  if (fEqui)
716  return fEqui->FindBin(x);
717  return fIrr->FindBin(x);
718  }
719 
720  /// Get the number of bins. Forwards to the underlying axis.
721  int GetNBins() const noexcept {
722  if (fEqui)
723  return fEqui->GetNBins();
724  return fIrr->GetNBins();
725  }
726 
727  /// Get the bin center of bin index `i`. Forwards to the underlying axis.
728  double GetBinCenter(int i) const noexcept {
729  if (fEqui)
730  return fEqui->GetBinCenter(i);
731  return fIrr->GetBinCenter(i);
732  }
733 
734  /// Get the minimal coordinate of bin index `i`. Forwards to the underlying axis.
735  double GetBinFrom(int i) const noexcept {
736  if (fEqui)
737  return fEqui->GetBinFrom(i);
738  return fIrr->GetBinFrom(i);
739  }
740 
741  /// Get the maximal coordinate of bin index `i`. Forwards to the underlying axis.
742  double GetBinTo(int i) const noexcept {
743  if (fEqui)
744  return fEqui->GetBinTo(i);
745  return fIrr->GetBinTo(i);
746  }
747 };
748 
749 ///\name Axis Compatibility
750 ///\{
751 enum class EAxisCompatibility {
752  kIdentical, ///< Source and target axes are identical
753 
754  kContains, ///< The source is a subset of bins of the target axis
755 
756  /// The bins of the source axis have finer granularity, but the bin borders
757  /// are compatible. Example:
758  /// source: 0., 1., 2., 3., 4., 5., 6.; target: 0., 2., 5., 6.
759  /// Note that this is *not* a symmetrical property: only one of
760  /// CanMerge(source, target), CanMap(target, source) can return kContains.
761  kSampling,
762 
763  /// The source axis and target axis have different binning. Example:
764  /// source: 0., 1., 2., 3., 4., target: 0., 0.1, 0.2, 0.3, 0.4
766 };
767 
768 EAxisCompatibility CanMap(TAxisEquidistant& target, TAxisEquidistant& source) noexcept;
769 ///\}
770 
771 
772 
773 
774 } // namespace ROOT
775 
776 #endif
bool operator==(const TKey &lhs, const TKey &rhs)
Definition: TKey.h:43
Histogram axis base class.
Definition: TAxis.h:37
const_iterator operator--(int) noexcept
Definition: TAxis.h:114
const std::vector< double > & GetBinBorders() const noexcept
Access to the bin borders used by this axis.
Definition: TAxis.h:487
TAxisConfig(std::vector< double > &&binborders) noexcept
Represents a TAxisIrregular with binborders.
Definition: TAxis.h:603
TAxisView(const TAxisIrregular &irr)
Construct a view on a TAxisIrregular.
Definition: TAxis.h:710
bool operator<(const TKey &lhs, const TKey &rhs)
Definition: TKey.h:37
constexpr int GetNBinsNoOver() const noexcept
Get the number of bins, excluding under- and overflow.
Definition: TAxis.h:174
int GetBinIndex(const std::string &label)
Get the bin index with label.
Definition: TAxis.h:529
static Vc_ALWAYS_INLINE int_v min(const int_v &x, const int_v &y)
Definition: vector.h:433
bool operator<=(const TKey &lhs, const TKey &rhs)
Definition: TKey.h:46
Coordinate could fit after growing the axis.
constexpr bool IsOverflowBin(int bin) const noexcept
Whether the bin index is referencing a bin higher than the axis range.
Definition: TAxis.h:195
Objects used to configure the different axis types.
Definition: TAxis.h:562
constexpr TAxisBase(int nbins) noexcept
Construct a TAxisBase.
Definition: TAxis.h:170
Namespace for new ROOT classes and functions.
Definition: ROOT.py:1
constexpr int GetNBins() const noexcept
Get the number of bins, including under- and overflow.
Definition: TAxis.h:179
std::unordered_map< std::string, int > fLabelsIndex
Map of label (view on fLabels's elements) to bin index.
Definition: TAxis.h:511
Common view on a TAxis, no matter what its kind.
Definition: TAxis.h:699
The source is a subset of bins of the target axis.
const TAxisEquidistant * fEqui
View on a TAxisEquidistant, TAxisGrow or TAxisLabel.
Definition: TAxis.h:701
bool operator>(const TKey &lhs, const TKey &rhs)
Definition: TKey.h:40
TAxisConfig(const TAxisLabels &ax)
Build a TAxisConfig from a TAxisLabels.
Definition: TAxis.h:636
int FindBin(double x) const noexcept
Find the bin containing coordinate x. Forwards to the underlying axis.
Definition: TAxis.h:714
int GetNBins() const noexcept
Get the number of bins. Forwards to the underlying axis.
Definition: TAxis.h:721
unsigned int fNBinsNoOver
Number of bins excluding under- and overflow.
Definition: TAxis.h:221
std::vector< std::string_view > GetBinLabels() const
Build a vector of labels. The position in the vector defines the label's bin.
Definition: TAxis.h:546
double GetBinCenter(const std::string &label)
Get the center of the bin with label.
Definition: TAxis.h:541
static constexpr const int kIgnoreBin
FindBin() returns this bin to signal that the bin number is invalid.
Definition: TAxis.h:161
double GetInverseBinWidth() const noexcept
Get the inverse of the width of the bins.
Definition: TAxis.h:311
Converts a TAxisConfig of whatever kind to the corresponding TAxisBase-derived object.
Definition: TAxis.h:659
An axis that can extend its range, keeping the number of its bins unchanged.
Definition: TAxis.h:344
int nbins[3]
STL namespace.
double fLow
The lower limit of the axis.
Definition: TAxis.h:273
std::vector< double > fBinBorders
Bin borders, one more than the number of non-overflow bins.
Definition: TAxis.h:404
double GetBinTo(int bin) const noexcept
Get the high bin border for the given bin index.
Definition: TAxis.h:324
friend bool operator!=(const_iterator lhs, const_iterator rhs) noexcept
i != j
Definition: TAxis.h:258
The source axis and target axis have different binning.
static constexpr bool CanGrow() noexcept
This axis cannot grow.
Definition: TAxis.h:299
int Grow(int toBin)
Grow this axis to make the "virtual bin" toBin in-range.
double GetBinCenter(int i) const noexcept
Get the bin center of bin index i. Forwards to the underlying axis.
Definition: TAxis.h:728
double GetBinCenter(int bin) const noexcept
Get the bin center of the bin with the given index.
Definition: TAxis.h:451
friend bool operator<(const_iterator lhs, const_iterator rhs) noexcept
i < j
Definition: TAxis.h:228
double GetBinWidth() const noexcept
Get the width of the bins.
Definition: TAxis.h:308
TAxisConfig(const std::vector< double > &binborders)
Represents a TAxisIrregular with binborders.
Definition: TAxis.h:598
A TAxisGrow that has a label assigned to each bin and a bin width of 1.
Definition: TAxis.h:508
constexpr TAxisEquidistant(int nbins, double low, double high) noexcept
Initialize a TAxisEquidistant.
Definition: TAxis.h:286
TAxisBase & operator=(const TAxisBase &)=default
Tag type signalling that an axis should be able to grow; used for calling the appropriate constructor...
Definition: TAxis.h:580
int GetBinIndexForLowEdge(double x) const noexcept
If the coordinate x is a bin low edge (within 1E-6 of the coordinate), return the bin for which this ...
Definition: TAxis.cxx:24
Double_t x[n]
Definition: legend1.C:17
friend bool operator==(const_iterator lhs, const_iterator rhs) noexcept
i == j
Definition: TAxis.h:252
represents a TAxisLabels
Definition: TAxis.h:568
EKind fKind
The kind of axis represented by this configuration.
Definition: TAxis.h:573
double GetBinFrom(int bin) const noexcept
Get the low bin border for the given bin index.
Definition: TAxis.h:319
TAxisConfig(std::vector< std::string > &&labels)
Represents a TAxisLabels with labels.
Definition: TAxis.h:614
const int * operator*() const noexcept
Definition: TAxis.h:147
represents a TAxisEquidistant
Definition: TAxis.h:565
static constexpr const int kNOverflowBins[4]
Extra bins for each EAxisOverflow value.
Definition: TAxis.h:164
Axis with equidistant bin borders.
Definition: TAxis.h:271
const_iterator begin() const noexcept
Get a const_iterator pointing to the first non-underflow bin.
Definition: TAxis.h:203
const_iterator operator-(int d) noexcept
Definition: TAxis.h:140
double GetMaximum() const noexcept
Get the high end of the axis range.
Definition: TAxis.h:305
TAxisIrregular(std::vector< double > &&binborders) noexcept
Construct a TAxisIrregular from a vector of bin borders.
Definition: TAxis.h:421
double GetMinimum() const noexcept
Get the low end of the axis range.
Definition: TAxis.h:302
constexpr bool CanGrow() const
This axis kind can increase its range.
Definition: TAxis.h:385
constexpr int FindBin(double x) const noexcept
Find the bin index for the given coordinate.
Definition: TAxis.h:293
const_iterator end_with_overflow() const noexcept
Get a const_iterator pointing right beyond the overflow bin.
Definition: TAxis.h:215
represents a TAxisGrow
Definition: TAxis.h:566
TAxisIrregular(const std::vector< double > &binborders)
Construct a TAxisIrregular from a vector of bin borders.
Definition: TAxis.h:409
const_iterator & operator-=(int d) noexcept
Definition: TAxis.h:127
const_iterator & operator--() noexcept
–i
Definition: TAxis.h:100
TAxisConfig(const std::vector< std::string_view > &labels)
Represents a TAxisLabels with labels.
Definition: TAxis.h:608
int operator->() const noexcept
Definition: TAxis.h:149
const std::vector< double > & GetBinBorders() const noexcept
Get the bin borders; non-empty if the GetKind() == kIrregular.
Definition: TAxis.h:648
Source and target axes are identical.
int FindBin(double x) const noexcept
Find the bin index corresponding to coordinate x.
Definition: TAxis.h:432
EAxisCompatibility CanMap(TAxisEquidistant &target, TAxisEquidistant &source) noexcept
Whether (and how) the source axis can be merged into the target axis.
Definition: TAxis.cxx:49
double fInvBinWidth
The inverse of the bin width.
Definition: TAxis.h:274
const_iterator begin_with_underflow() const noexcept
Get a const_iterator pointing the underflow bin.
Definition: TAxis.h:206
std::vector< double > fBinBorders
Bin borders of the TAxisIrregular.
Definition: TAxis.h:574
TAxisLabels(const std::vector< std::string_view > &labels)
Construct a TAxisLables from a vector of string_views.
Definition: TAxis.h:515
friend bool operator>=(const_iterator lhs, const_iterator rhs) noexcept
i >= j
Definition: TAxis.h:246
double GetBinTo(int i) const noexcept
Get the maximal coordinate of bin index i. Forwards to the underlying axis.
Definition: TAxis.h:742
const_iterator & operator++() noexcept
++i
Definition: TAxis.h:93
Axis_t operator()(TAxisConfig cfg) noexcept
Definition: TAxis.h:674
The bins of the source axis have finer granularity, but the bin borders are compatible.
double GetBinTo(int bin) const noexcept
Get the higher bin border for a given bin index.
Definition: TAxis.h:477
const_iterator end() const noexcept
Get a const_iterator pointing right beyond the last non-overflow bin (i.e.
Definition: TAxis.h:210
const_iterator operator++(int) noexcept
i++
Definition: TAxis.h:107
The returned bin index is valid.
const_iterator operator+(int d) noexcept
Definition: TAxis.h:133
An axis with non-equidistant bins (also known as "variable binning").
Definition: TAxis.h:401
static Vc_ALWAYS_INLINE int_v max(const int_v &x, const int_v &y)
Definition: vector.h:440
constexpr int GetOverflowBin() const noexcept
Get the bin index for the underflow bin.
Definition: TAxis.h:187
const TAxisIrregular * fIrr
View on a TAxisIrregular.
Definition: TAxis.h:703
TAxisConfig(const TAxisEquidistant &ax)
Build a TAxisConfig from a TAxisEquidistant.
Definition: TAxis.h:623
double GetBinFrom(int i) const noexcept
Get the minimal coordinate of bin index i. Forwards to the underlying axis.
Definition: TAxis.h:735
std::vector< std::string > fLabels
Bin labels for a TAxisLabels.
Definition: TAxis.h:575
TAxisView(const TAxisEquidistant &equi)
Construct a view on a TAxisEquidistant, TAxisGrow or TAxisLabel.
Definition: TAxis.h:707
TAxisLabels(const std::vector< std::string > &labels)
Construct a TAxisLables from a vector of strings.
Definition: TAxis.h:522
Random const_iterator through bins.
Definition: TAxis.h:81
#define R__ERROR_HERE(GROUP)
Definition: TLogger.h:125
EKind GetKind() const noexcept
Get the axis kind represented by this TAxisConfig.
Definition: TAxis.h:645
double GetBinCenter(int bin) const noexcept
Get the bin center for the given bin index.
Definition: TAxis.h:314
const_iterator & operator+=(int d) noexcept
Definition: TAxis.h:121
double GetBinFrom(int bin) const noexcept
Get the lower bin border for a given bin index.
Definition: TAxis.h:464
friend bool operator>(const_iterator lhs, const_iterator rhs) noexcept
i > j
Definition: TAxis.h:234
constexpr TAxisGrow(int nbins, double low, double high) noexcept
Initialize a TAxisGrow.
Definition: TAxis.h:355
constexpr int GetUnderflowBin() const noexcept
Get the bin index for the underflow bin.
Definition: TAxis.h:184
EFindStatus
Status of FindBin(x)
Definition: TAxis.h:40
represents a TAxisIrregular
Definition: TAxis.h:567
constexpr int AdjustOverflowBinNumber(int rawbin) const
Given rawbin (<0 for underflow, >= GetNBinsNoOver() for overflow), determine the actual bin number ta...
Definition: TAxis.h:64
static constexpr bool CanGrow() noexcept
This axis cannot be extended.
Definition: TAxis.h:484
int fCursor
Current iteration position.
Definition: TAxis.h:85
const std::vector< std::string > & GetBinLabels() const noexcept
Get the bin labels; non-empty if the GetKind() == kLabels.
Definition: TAxis.h:650
friend bool operator<=(const_iterator lhs, const_iterator rhs) noexcept
i <= j
Definition: TAxis.h:240
bool operator!=(TAxisBase::const_iterator lhs, TAxisBase::const_iterator rhs) noexcept
i != j
Definition: TAxis.h:258
TAxisConfig(Grow_t, int nbins, double from, double to)
Represents a TAxisGrow with nbins from from to to.
Definition: TAxis.h:593
TAxisConfig(int nbins, double from, double to)
Represents a TAxisEquidistant with nbins from from to to.
Definition: TAxis.h:588
TAxisBase(const TAxisBase &)=default
const_iterator(int cursor) noexcept
Initialize a const_iterator with its position.
Definition: TAxis.h:90
static constexpr const Grow_t Grow
Tag signalling that an axis should be able to grow; used for calling the appropriate constructor like...
Definition: TAxis.h:585
const Int_t n
Definition: legend1.C:16
EAxisCompatibility
Definition: TAxis.h:751
constexpr bool IsUnderflowBin(int bin) const noexcept
Whether the bin index is referencing a bin lower than the axis range.
Definition: TAxis.h:190
bool operator>=(const TKey &lhs, const TKey &rhs)
Definition: TKey.h:49