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#include "RSliceSpec.hxx"
12
13#include <cassert>
14#include <cstddef>
15#include <cstdint>
16#include <stdexcept>
17#include <string>
18#include <string_view>
19#include <unordered_set>
20#include <utility>
21#include <vector>
22
23class TBuffer;
24
25namespace ROOT {
26namespace Experimental {
27
28/**
29An axis with categorical bins.
30
31For example, the following creates an axis with 3 categories:
32\code
33std::vector<std::string> categories = {"a", "b", "c"};
34ROOT::Experimental::RCategoricalAxis axis(categories);
35\endcode
36
37It is possible to disable the overflow bin by passing `enableOverflowBin = false`. In that case, arguments outside the
38axis will be silently discarded.
39
40\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
41Feedback is welcome!
42*/
44public:
45 using ArgumentType = std::string_view;
46
47private:
48 /// The categories as defined by the user
49 std::vector<std::string> fCategories;
50 /// Whether the overflow bin is enabled
52
53public:
54 /// Construct an axis object with categories.
55 ///
56 /// \param[in] categories the categories without duplicates, must define at least one bin (i.e. size >= 1)
57 /// \param[in] enableOverflowBin whether to enable the overflow bin
58 explicit RCategoricalAxis(std::vector<std::string> categories, bool enableOverflowBin = true)
60 {
61 if (fCategories.size() < 1) {
62 throw std::invalid_argument("must have at least one category");
63 }
64 // Check for duplicates, use std::string_view to avoid copying the category strings.
65 std::unordered_set<std::string_view> set;
66 for (std::size_t i = 0; i < fCategories.size(); i++) {
67 if (!set.insert(fCategories[i]).second) {
68 std::string msg = "duplicate category '" + fCategories[i] + "' for bin " + std::to_string(i);
69 throw std::invalid_argument(msg);
70 }
71 }
72 }
73
74 std::uint64_t GetNNormalBins() const { return fCategories.size(); }
75 std::uint64_t GetTotalNBins() const { return fEnableOverflowBin ? fCategories.size() + 1 : fCategories.size(); }
76 const std::vector<std::string> &GetCategories() const { return fCategories; }
77 bool HasOverflowBin() const { return fEnableOverflowBin; }
78
80 {
81 return lhs.fCategories == rhs.fCategories && lhs.fEnableOverflowBin == rhs.fEnableOverflowBin;
82 }
83
84 /// Compute the linarized index for a single argument.
85 ///
86 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
87 /// \f$fCategories.size()\f$. If the argument is not a recognized category and the overflow bin is disabled, the
88 /// return value is invalid.
89 ///
90 /// \param[in] x the argument
91 /// \return the linearized index that may be invalid
93 {
94 // FIXME: Optimize with hashing... (?)
95 for (std::size_t bin = 0; bin < fCategories.size(); bin++) {
96 if (fCategories[bin] == x) {
97 return {bin, true};
98 }
99 }
100
101 // Category not found
102 return {fCategories.size(), fEnableOverflowBin};
103 }
104
105 /// Get the linearized index for an RBinIndex.
106 ///
107 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
108 /// \f$fCategories.size()\f$.
109 ///
110 /// \param[in] index the RBinIndex
111 /// \return the linearized index that may be invalid
113 {
114 if (index.IsUnderflow()) {
115 // No underflow bin for RCategoricalAxis...
116 return {0, false};
117 } else if (index.IsOverflow()) {
118 return {fCategories.size(), fEnableOverflowBin};
119 } else if (index.IsInvalid()) {
120 return {0, false};
121 }
122 assert(index.IsNormal());
123 std::uint64_t bin = index.GetIndex();
124 return {bin, bin < fCategories.size()};
125 }
126
127 /// Get the range of all normal bins.
128 ///
129 /// \return the bin index range from the first to the last normal bin, inclusive
134
135 /// Get a range of normal bins.
136 ///
137 /// \param[in] begin the begin of the bin index range (inclusive), must be normal
138 /// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
139 /// \return a bin index range \f$[begin, end)\f$
141 {
142 if (!begin.IsNormal()) {
143 throw std::invalid_argument("begin must be a normal bin");
144 }
145 if (begin.GetIndex() >= fCategories.size()) {
146 throw std::invalid_argument("begin must be inside the axis");
147 }
148 if (!end.IsNormal()) {
149 throw std::invalid_argument("end must be a normal bin");
150 }
151 if (end.GetIndex() > fCategories.size()) {
152 throw std::invalid_argument("end must be inside or past the axis");
153 }
154 if (!(end >= begin)) {
155 throw std::invalid_argument("end must be >= begin");
156 }
157 return Internal::CreateBinIndexRange(begin, end, 0);
158 }
159
160 /// Get the full range of all bins.
161 ///
162 /// This includes the overflow bin, if enabled.
163 ///
164 /// \return the bin index range of all bins
170
171 /// Slice this axis according to the specification.
172 ///
173 /// A categorical axis cannot be sliced. The method will throw if a specification other than the default slice
174 /// operation is passed.
175 ///
176 /// \param[in] sliceSpec the slice specification
177 /// \return the sliced / copied axis
179 {
180 if (sliceSpec.GetOperationSum() != nullptr) {
181 throw std::runtime_error("sum operation makes dimension disappear");
182 }
183
184 if (!sliceSpec.GetRange().IsInvalid()) {
185 throw std::runtime_error("slicing of RCategoricalAxis not implemented");
186 }
187 if (sliceSpec.GetOperationRebin() != nullptr) {
188 throw std::runtime_error("cannot rebin RCategoricalAxis");
189 }
190
191 // The sliced axis always has flow bins enabled, for symmetry with other axis types.
192 bool enableOverflowBin = true;
194 }
195
196 /// %ROOT Streamer function to throw when trying to store an object of this class.
197 void Streamer(TBuffer &) { throw std::runtime_error("unable to store RCategoricalAxis"); }
198};
199
200} // namespace Experimental
201} // namespace ROOT
202
203#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:80
std::uint64_t GetIndex() const
Return the index for a normal bin.
Definition RBinIndex.hxx:71
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.
RCategoricalAxis Slice(const RSliceSpec &sliceSpec) const
Slice this axis according to the specification.
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.
Specification of a slice operation along one dimension.
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.