forked from alandefreitas/matplotplusplus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhistogram.h
More file actions
268 lines (217 loc) 路 10.8 KB
/
Copy pathhistogram.h
File metadata and controls
268 lines (217 loc) 路 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//
// Created by Alan Freitas on 2020-07-04.
//
#ifndef MATPLOTPLUSPLUS_HISTOGRAM_H
#define MATPLOTPLUSPLUS_HISTOGRAM_H
#include <array>
#include <cmath>
#include <map>
#include <matplot/core/axes_object.h>
#include <matplot/core/figure_type.h>
#include <matplot/core/line_spec.h>
#include <matplot/util/common.h>
#include <matplot/util/concepts.h>
#include <matplot/util/handle_types.h>
namespace matplot {
class axes_type;
class histogram : public axes_object {
public:
// source code in 'edit histcount'
enum class binning_algorithm {
automatic, // Scott's rule for doubles or integers rule for data
// distributed around integers
scott, // Scott鈥檚 rule - bin_width = 3.5*std(x)*|X|^(-1/3)
fd, // Freedman-Diaconis rule - bin width =
// 2*IQR(X(:))*numel(X)^(-1/3) (for heavy tailed distributions,
// less sensitive to outliers) - IQR = interquartile range of X
integers, // Integer rule - bin width = 1
sturges, // Sturges' rule - number of bins = ceil(1+log2(numel(X)))
sqrt // Square root rule - number of bins = ceil(sqrt(numel(X)))
};
enum class normalization {
count, // value_i = count_i
count_density, // value_i = count_i / bin_width_i
cummulative_count, // value_i = sum_j=1^i count_j
probability, // value_i = count_i / size -> (sum(heights) <= 1)
pdf, // value_i = count_i / (size * width_i) -> (sum(areas) <= 1)
cdf // value_i = sum_j=1^i count_j / size
};
public:
explicit histogram(class axes_type *parent);
histogram(class axes_type *parent, const std::vector<double> &data,
size_t n_bins,
enum histogram::normalization normalization_alg =
histogram::normalization::count);
histogram(class axes_type *parent, const std::vector<double> &data,
const std::vector<double> &edges,
enum histogram::normalization normalization_alg =
histogram::normalization::count);
histogram(class axes_type *parent, const std::vector<double> &data,
binning_algorithm algorithm = binning_algorithm::automatic,
histogram::normalization normalization_alg =
histogram::normalization::count);
/// If we receive an axes_handle, we can convert it to a raw
/// pointer because there is no ownership involved here
template <class... Args>
histogram(const axes_handle &parent, Args&&... args)
: histogram(parent.get(), std::forward<Args>(args)...) {}
virtual ~histogram() = default;
public /* xlim object virtual functions */:
// std::string set_variables_string() override;
std::string plot_string() override;
std::string legend_string(std::string_view title) override;
std::string data_string() override;
// std::string unset_variables_string() override;
double xmax() override;
double xmin() override;
double ymax() override;
double ymin() override;
enum axes_object::axes_category axes_category() override;
public /* useful functions for histograms */:
/// Increase number of bins
size_t morebins(double bin_increase = 0.1);
/// Decrease number of bins
size_t fewerbins(double bin_decrease = 0.1);
/// Find appropriate edges given a fixed number of bins and target bin
/// width If nbins == 0, round the bin width and create
/// (xmax-xmin)/bin_width bins If nbins != 0, bin width is set to
/// (xmax-xmin)/nbins and create nbins bins
static std::vector<double> bin_picker(double xmin, double xmax,
size_t nbins, double bin_width);
/// Find appropriate edges with a given algorithm
static std::vector<double> histogram_edges(
const std::vector<double> &data, double minx, double maxx,
binning_algorithm algorithm = binning_algorithm::automatic,
bool hard_limits = false);
/// Count points within each pair of edges
static std::vector<size_t>
histogram_count(const std::vector<double> &values,
const std::vector<double> &edges);
/// Normalize the instagram count
static std::vector<double>
histogram_normalize(const std::vector<size_t> &bin_count,
const std::vector<double> &bin_edges,
size_t data_size,
enum normalization normalization_algorithm);
public /* getters and setters */:
const std::vector<double> &data() const;
class histogram &data(const std::vector<double> &data);
const std::vector<double> &values() const;
class histogram &values(const std::vector<double> &values);
const std::vector<size_t> &bin_counts() const;
class histogram &bin_counts(const std::vector<size_t> &bin_counts);
size_t num_bins();
class histogram &num_bins(size_t num_bins);
binning_algorithm algorithm() const;
class histogram &algorithm(binning_algorithm algorithm);
std::vector<double> &bin_edges();
class histogram &bin_edges(const std::vector<double> &bin_edges);
double bin_width() const;
class histogram &bin_width(double bin_width);
double bin_limits_min() const;
class histogram &bin_limits_min(double bin_limits_min);
double bin_limits_max() const;
class histogram &bin_limits_max(double bin_limits_max);
normalization normalization() const;
class histogram &normalization(enum normalization normalization);
const color_array &face_color() const;
class histogram &face_color(const color_array &face_color);
class histogram &face_color(std::initializer_list<float> face_color);
class histogram &face_color(std::string_view color);
class histogram &face_alpha(float alpha);
class histogram &edge_alpha(float alpha);
bool manual_face_color() const;
class histogram &manual_face_color(bool manual_face_color);
const color_array &edge_color() const;
class histogram &edge_color(const color_array &edge_color);
class histogram &edge_color(std::initializer_list<float> face_color);
class histogram &edge_color(std::string_view edge_color);
const line_spec &edge_style() const;
class histogram &edge_style(const line_spec &edge_style);
float line_width() const;
class histogram &line_width(float line_width);
bool vertical_orientation() const;
class histogram &vertical_orientation(bool vertical_orientation);
bool visible() const;
class histogram &visible(bool visible);
float bar_width() const;
class histogram &bar_width(float bar_width);
bool polar() const;
class histogram &polar(bool polar);
bool stairs_only() const;
class histogram &stairs_only(bool stairs_only);
/// Algorithms to determine histogram edges
static std::vector<double> scotts_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
static std::vector<double> fd_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
static std::vector<double> integers_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
static std::vector<double> sqrt_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
static std::vector<double> sturges_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
static std::vector<double> automatic_rule(const std::vector<double> &x,
double minx, double maxx,
bool hard_limits);
public /* getters and setters bypassing the histogram_spec */:
private:
/// If the user has not set the face color,
/// we get a color from the xlim
void maybe_update_face_color();
/// Make sure we have already calculated the normalized values
/// for the current parameters. We reset the normalized values
/// every time the user changes the algorithm.
void make_sure_data_is_preprocessed();
protected:
// original data
std::vector<double> data_;
// normalized values (in the simplest case, values_ = bin_counts_)
std::vector<double> values_;
// number of elements in each bin
std::vector<size_t> bin_counts_;
// target num of bins (0 indicates no target: the algorithm should
// decide)
size_t num_bins_{0};
// algorithm we use to create the bins
binning_algorithm algorithm_;
// where edges start
std::vector<double> bin_edges_;
// binning mode
enum binning_mode_type {
use_algorithm, // use algorithm to decide everything
use_bin_limits, // use algorithm with bin limits
use_fixed_num_bins, // use fixed num of bins
use_fixed_bin_width, // use fixed num of bins
use_fixed_edges, // use fixed edges, including edges of variable
// size
};
binning_mode_type binning_mode_{binning_mode_type::use_algorithm};
// bin width (if zero, the algorithm determines the bin width)
double bin_width_{0.0};
// bin limits
double bin_limits_min_;
double bin_limits_max_;
// normalization algorithm
enum normalization normalization_ { normalization::count };
// color and style
color_array face_color_{0.4f, 0, 0, 0};
bool manual_face_color_{false};
color_array edge_color_{0, 0, 0, 0};
bool manual_edge_color_{false};
line_spec edge_style_{"-"};
float line_width_{0.5};
bool vertical_orientation_{true};
float bar_width_{1.0};
bool polar_{false};
bool stairs_only_{false};
// True if visible
bool visible_{true};
};
} // namespace matplot
#endif // MATPLOTPLUSPLUS_HISTOGRAM_H