Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RCategoricalAxis.hxx
Go to the documentation of this file.
1/// \file
2/// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
3/// Feedback is welcome!
4
5#ifndef ROOT_RCategoricalAxis
6#define ROOT_RCategoricalAxis
7
8#include "RBinIndex.hxx"
9#include "RBinIndexRange.hxx"
10#include "RLinearizedIndex.hxx"
11
12#include <cassert>
13#include <cstddef>
14#include <cstdint>
15#include <stdexcept>
16#include <string>
17#include <string_view>
18#include <unordered_set>
19#include <utility>
20#include <vector>
21
22class TBuffer;
23
24namespace ROOT {
25namespace Experimental {
26
27/**
28An axis with categorical bins.
29
30For example, the following creates an axis with 3 categories:
31\code
32std::vector<std::string> categories = {"a", "b", "c"};
33ROOT::Experimental::RCategoricalAxis axis(categories);
34\endcode
35
36It is possible to disable the overflow bin by passing `enableOverflowBin = false`. In that case, arguments outside the
37axis will be silently discarded.
38
39\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
40Feedback is welcome!
41*/
43public:
44 using ArgumentType = std::string_view;
45
46private:
47 /// The categories as defined by the user
48 std::vector<std::string> fCategories;
49 /// Whether the overflow bin is enabled
51
52public:
53 /// Construct an axis object with categories.
54 ///
55 /// \param[in] categories the categories without duplicates, must define at least one bin (i.e. size >= 1)
56 /// \param[in] enableOverflowBin whether to enable the overflow bin
57 explicit RCategoricalAxis(std::vector<std::string> categories, bool enableOverflowBin = true)
59 {
60 if (fCategories.size() < 1) {
61 throw std::invalid_argument("must have at least one category");
62 }
63 // Check for duplicates, use std::string_view to avoid copying the category strings.
64 std::unordered_set<std::string_view> set;
65 for (std::size_t i = 0; i < fCategories.size(); i++) {
66 if (!set.insert(fCategories[i]).second) {
67 std::string msg = "duplicate category '" + fCategories[i] + "' for bin " + std::to_string(i);
68 throw std::invalid_argument(msg);
69 }
70 }
71 }
72
73 std::uint64_t GetNNormalBins() const { return fCategories.size(); }
74 std::uint64_t GetTotalNBins() const { return fEnableOverflowBin ? fCategories.size() + 1 : fCategories.size(); }
75 const std::vector<std::string> &GetCategories() const { return fCategories; }
76 bool HasOverflowBin() const { return fEnableOverflowBin; }
77
79 {
80 return lhs.fCategories == rhs.fCategories && lhs.fEnableOverflowBin == rhs.fEnableOverflowBin;
81 }
82
83 /// Compute the linarized index for a single argument.
84 ///
85 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
86 /// \f$fCategories.size()\f$. If the argument is not a recognized category and the overflow bin is disabled, the
87 /// return value is invalid.
88 ///
89 /// \param[in] x the argument
90 /// \return the linearized index that may be invalid
92 {
93 // FIXME: Optimize with hashing... (?)
94 for (std::size_t bin = 0; bin < fCategories.size(); bin++) {
95 if (fCategories[bin] == x) {
96 return {bin, true};
97 }
98 }
99
100 // Category not found
101 return {fCategories.size(), fEnableOverflowBin};
102 }
103
104 /// Get the linearized index for an RBinIndex.
105 ///
106 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
107 /// \f$fCategories.size()\f$.
108 ///
109 /// \param[in] index the RBinIndex
110 /// \return the linearized index that may be invalid
112 {
113 if (index.IsUnderflow()) {
114 // No underflow bin for RCategoricalAxis...
115 return {0, false};
116 } else if (index.IsOverflow()) {
117 return {fCategories.size(), fEnableOverflowBin};
118 } else if (index.IsInvalid()) {
119 return {0, false};
120 }
121 assert(index.IsNormal());
122 std::uint64_t bin = index.GetIndex();
123 return {bin, bin < fCategories.size()};
124 }
125
126 /// Get the range of all normal bins.
127 ///
128 /// \return the bin index range from the first to the last normal bin, inclusive
133
134 /// Get a range of normal bins.
135 ///
136 /// \param[in] begin the begin of the bin index range (inclusive), must be normal
137 /// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
138 /// \return a bin index range \f$[begin, end)\f$
140 {
141 if (!begin.IsNormal()) {
142 throw std::invalid_argument("begin must be a normal bin");
143 }
144 if (begin.GetIndex() >= fCategories.size()) {
145 throw std::invalid_argument("begin must be inside the axis");
146 }
147 if (!end.IsNormal()) {
148 throw std::invalid_argument("end must be a normal bin");
149 }
150 if (end.GetIndex() > fCategories.size()) {
151 throw std::invalid_argument("end must be inside or past the axis");
152 }
153 if (!(end >= begin)) {
154 throw std::invalid_argument("end must be >= begin");
155 }
156 return Internal::CreateBinIndexRange(begin, end, 0);
157 }
158
159 /// Get the full range of all bins.
160 ///
161 /// This includes the overflow bin, if enabled.
162 ///
163 /// \return the bin index range of all bins
169
170 /// %ROOT Streamer function to throw when trying to store an object of this class.
171 void Streamer(TBuffer &) { throw std::runtime_error("unable to store RCategoricalAxis"); }
172};
173
174} // namespace Experimental
175} // namespace ROOT
176
177#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
A bin index with special values for underflow and overflow bins.
Definition RBinIndex.hxx:23
bool IsNormal() const
A bin index is normal iff it is not one of the special values.
Definition RBinIndex.hxx:51
std::uint64_t GetIndex() const
Return the index for a normal bin.
Definition RBinIndex.hxx:42
An axis with categorical bins.
RCategoricalAxis(std::vector< std::string > categories, bool enableOverflowBin=true)
Construct an axis object with categories.
std::vector< std::string > fCategories
The categories as defined by the user.
RBinIndexRange GetFullRange() const
Get the full range of all bins.
RBinIndexRange GetNormalRange(RBinIndex begin, RBinIndex end) const
Get a range of normal bins.
RLinearizedIndex ComputeLinearizedIndex(std::string_view x) const
Compute the linarized index for a single argument.
bool fEnableOverflowBin
Whether the overflow bin is enabled.
const std::vector< std::string > & GetCategories() const
friend bool operator==(const RCategoricalAxis &lhs, const RCategoricalAxis &rhs)
RBinIndexRange GetNormalRange() const
Get the range of all normal bins.
void Streamer(TBuffer &)
ROOT Streamer function to throw when trying to store an object of this class.
RLinearizedIndex GetLinearizedIndex(RBinIndex index) const
Get the linearized index for an RBinIndex.
Buffer base class used for serializing objects.
Definition TBuffer.h:43
Double_t x[n]
Definition legend1.C:17
static RBinIndexRange CreateBinIndexRange(RBinIndex begin, RBinIndex end, std::uint64_t nNormalBins)
Internal function to create RBinIndexRange.
A linearized index that can be invalid.