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 <stdexcept>
15#include <string>
16#include <string_view>
17#include <unordered_set>
18#include <utility>
19#include <vector>
20
21class TBuffer;
22
23namespace ROOT {
24namespace Experimental {
25
26/**
27An axis with categorical bins.
28
29For example, the following creates an axis with 3 categories:
30\code
31std::vector<std::string> categories = {"a", "b", "c"};
32ROOT::Experimental::RCategoricalAxis axis(categories);
33\endcode
34
35It is possible to disable the overflow bin by passing `enableOverflowBin = false`. In that case, arguments outside the
36axis will be silently discarded.
37
38\warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
39Feedback is welcome!
40*/
42public:
43 using ArgumentType = std::string_view;
44
45private:
46 /// The categories as defined by the user
47 std::vector<std::string> fCategories;
48 /// Whether the overflow bin is enabled
50
51public:
52 /// Construct an axis object with categories.
53 ///
54 /// \param[in] categories the categories without duplicates, must define at least one bin (i.e. size >= 1)
55 /// \param[in] enableOverflowBin whether to enable the overflow bin
56 explicit RCategoricalAxis(std::vector<std::string> categories, bool enableOverflowBin = true)
58 {
59 if (fCategories.size() < 1) {
60 throw std::invalid_argument("must have at least one category");
61 }
62 // Check for duplicates, use std::string_view to avoid copying the category strings.
63 std::unordered_set<std::string_view> set;
64 for (std::size_t i = 0; i < fCategories.size(); i++) {
65 if (!set.insert(fCategories[i]).second) {
66 std::string msg = "duplicate category '" + fCategories[i] + "' for bin " + std::to_string(i);
67 throw std::invalid_argument(msg);
68 }
69 }
70 }
71
72 std::size_t GetNNormalBins() const { return fCategories.size(); }
73 std::size_t GetTotalNBins() const { return fEnableOverflowBin ? fCategories.size() + 1 : fCategories.size(); }
74 const std::vector<std::string> &GetCategories() const { return fCategories; }
75 bool HasOverflowBin() const { return fEnableOverflowBin; }
76
78 {
79 return lhs.fCategories == rhs.fCategories && lhs.fEnableOverflowBin == rhs.fEnableOverflowBin;
80 }
81
82 /// Compute the linarized index for a single argument.
83 ///
84 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
85 /// \f$fCategories.size()\f$. If the argument is not a recognized category and the overflow bin is disabled, the
86 /// return value is invalid.
87 ///
88 /// \param[in] x the argument
89 /// \return the linearized index that may be invalid
91 {
92 // FIXME: Optimize with hashing... (?)
93 for (std::size_t bin = 0; bin < fCategories.size(); bin++) {
94 if (fCategories[bin] == x) {
95 return {bin, true};
96 }
97 }
98
99 // Category not found
100 return {fCategories.size(), fEnableOverflowBin};
101 }
102
103 /// Get the linearized index for an RBinIndex.
104 ///
105 /// The normal bins have indices \f$0\f$ to \f$fCategories.size() - 1\f$ and the overflow bin has index
106 /// \f$fCategories.size()\f$.
107 ///
108 /// \param[in] index the RBinIndex
109 /// \return the linearized index that may be invalid
111 {
112 if (index.IsUnderflow()) {
113 // No underflow bin for RCategoricalAxis...
114 return {0, false};
115 } else if (index.IsOverflow()) {
116 return {fCategories.size(), fEnableOverflowBin};
117 } else if (index.IsInvalid()) {
118 return {0, false};
119 }
120 assert(index.IsNormal());
121 std::size_t bin = index.GetIndex();
122 return {bin, bin < fCategories.size()};
123 }
124
125 /// Get the range of all normal bins.
126 ///
127 /// \return the bin index range from the first to the last normal bin, inclusive
132
133 /// Get a range of normal bins.
134 ///
135 /// \param[in] begin the begin of the bin index range (inclusive), must be normal
136 /// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
137 /// \return a bin index range \f$[begin, end)\f$
139 {
140 if (!begin.IsNormal()) {
141 throw std::invalid_argument("begin must be a normal bin");
142 }
143 if (begin.GetIndex() >= fCategories.size()) {
144 throw std::invalid_argument("begin must be inside the axis");
145 }
146 if (!end.IsNormal()) {
147 throw std::invalid_argument("end must be a normal bin");
148 }
149 if (end.GetIndex() > fCategories.size()) {
150 throw std::invalid_argument("end must be inside or past the axis");
151 }
152 if (!(end >= begin)) {
153 throw std::invalid_argument("end must be >= begin");
154 }
155 return Internal::CreateBinIndexRange(begin, end, 0);
156 }
157
158 /// Get the full range of all bins.
159 ///
160 /// This includes the overflow bin, if enabled.
161 ///
162 /// \return the bin index range of all bins
168
169 /// %ROOT Streamer function to throw when trying to store an object of this class.
170 void Streamer(TBuffer &) { throw std::runtime_error("unable to store RCategoricalAxis"); }
171};
172
173} // namespace Experimental
174} // namespace ROOT
175
176#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:22
std::size_t GetIndex() const
Return the index for a normal bin.
Definition RBinIndex.hxx:37
bool IsNormal() const
A bin index is normal iff it is not one of the special values.
Definition RBinIndex.hxx:46
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
RBinIndexRange CreateBinIndexRange(RBinIndex begin, RBinIndex end, std::size_t nNormalBins)
Internal function to create RBinIndexRange.
A linearized index that can be invalid.