forked from alandefreitas/matplotplusplus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilled_area.cpp
More file actions
182 lines (158 loc) 路 6.4 KB
/
Copy pathfilled_area.cpp
File metadata and controls
182 lines (158 loc) 路 6.4 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
//
// Created by Alan Freitas on 09/07/20.
//
#include <cmath>
#include <matplot/axes_objects/filled_area.h>
#include <matplot/core/axes_type.h>
#include <sstream>
namespace matplot {
filled_area::filled_area(class axes_type *parent) : line(parent) {}
filled_area::filled_area(class axes_type *parent,
const std::vector<double> &x,
const std::vector<double> &y,
const std::vector<double> &base_values,
bool stacked, std::string_view line_spec)
: line(parent, x, y, line_spec), stacked_(stacked),
base_data_(base_values) {}
void filled_area::maybe_update_face_color() {
// if user has not defined the color yet, get it from the xlim
if (!fill_user_color_) {
// get it from the xlim
// the line spec is not altered from black
auto c = parent_->get_color_and_bump();
face_color_ = c;
// if not stacked
if (!stacked_) {
// visualization is better with some alpha
face_color_[0] *= 0.5;
}
fill_user_color_ = true;
}
}
std::string filled_area::plot_string() {
// we get the fill color and not the line spec from the xlim
maybe_update_face_color();
// plot fill curve
std::string res = "'-' with filledcurve linecolor rgb \"" +
to_string(face_color_) + "\"";
// plot base line
if (plot_base_line_ && line_spec_.has_line()) {
// base line has no markers
auto previous_marker = line_spec_.marker();
line_spec_.marker(line_spec::marker_style::none);
res += ", " + line::plot_string();
line_spec_.marker(previous_marker);
}
// plot line as usual
res += ", " + line::plot_string();
return res;
}
std::string filled_area::data_string() {
std::stringstream ss;
ss.precision(10);
ss << std::fixed;
std::vector<double> stacked_data;
if (!stacked_) {
// send data for filled curve
for (size_t i = 0; i < y_data_.size(); ++i) {
if (std::isfinite(y_data_[i])) {
double base_value = base_data_.empty() ? 0.0
: base_data_.size() == 1
? base_data_[0]
: base_data_[i];
ss << " " << x_data_[i] << " " << base_value << " "
<< y_data_[i] << "\n";
} else {
ss << " \n";
}
}
ss << " e\n";
} else {
// If the area is stacked, the data for filled curve needs
// to consider previous area plots in the xlim. Also,
// the sooner it comes in the xlim, the more in the background.
// So we stack the y_values with all y_values that come *after*
// the area in the xlim
stacked_data = y_data_;
for (auto children_it = parent_->children().rbegin();
children_it != parent_->children().rend(); ++children_it) {
const auto &child = *children_it;
auto ptr = dynamic_cast<filled_area *>(child.get());
if (ptr != nullptr) {
if (ptr != this) {
size_t n =
std::min(stacked_data.size(), ptr->y_data_.size());
for (size_t i = 0; i < n; ++i) {
stacked_data[i] += ptr->y_data_[i];
}
} else {
break;
}
}
}
// send data
for (size_t i = 0; i < stacked_data.size(); ++i) {
double base_value = base_data_.empty() ? 0.0
: base_data_.size() == 1 ? base_data_[0]
: base_data_[i];
ss << " " << x_data_[i] << " " << base_value << " "
<< stacked_data[i] << "\n";
}
ss << " e\n";
}
// send data for base line
for (size_t i = 0; i < y_data_.size(); ++i) {
double base_value = base_data_.empty() ? 0.0
: base_data_.size() == 1 ? base_data_[0]
: base_data_[i];
if (std::isfinite(base_value) && std::isfinite(x_data_[i])) {
ss << " " << x_data_[i] << " " << base_value << "\n";
} else {
ss << " \n";
}
}
ss << " e\n";
// send data for foreground line as usual
if (!stacked_) {
ss << line::data_string();
} else {
std::swap(y_data_, stacked_data);
ss << line::data_string();
std::swap(y_data_, stacked_data);
}
return ss.str();
}
enum axes_object::axes_category filled_area::axes_category() {
// filled area is always 2d
return axes_object::axes_category::two_dimensional;
}
bool filled_area::stacked() const { return stacked_; }
class filled_area &filled_area::stacked(bool stacked) {
stacked_ = stacked;
return *this;
}
const std::vector<double> &filled_area::base_data() const {
return base_data_;
}
class filled_area &
filled_area::base_data(const std::vector<double> &base_data) {
base_data_ = base_data;
return *this;
}
bool filled_area::plot_base_line() const { return plot_base_line_; }
class filled_area &filled_area::plot_base_line(bool plot_base_line) {
plot_base_line_ = plot_base_line;
return *this;
}
const color_array &filled_area::face_color() const { return face_color_; }
class filled_area &filled_area::face_color(const color_array &face_color) {
face_color_ = face_color;
fill_user_color_ = true;
return *this;
}
bool filled_area::fill_user_color() const { return fill_user_color_; }
class filled_area &filled_area::fill_user_color(bool fill_user_color) {
fill_user_color_ = fill_user_color;
return *this;
}
} // namespace matplot