HIPO4 C++ Library 4.4.1
Columnar I/O library for CLAS12 physics data
Loading...
Searching...
No Matches
ascii.h
Go to the documentation of this file.
1#ifndef INCLUDE_ASCII_ASCII_H_
2#define INCLUDE_ASCII_ASCII_H_
3
4#include <cmath>
5#include <codecvt>
6#include <iomanip>
7#include <map>
8#include <sstream>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13#include "color.h"
14#include "constants.h"
15#include "text.h"
16
17namespace ascii {
19public:
20 enum Type {
21 LINE = 0, // line
22 CIRCLE // circle
23 };
24
25public:
26 explicit Asciichart(const std::vector<double> &series)
27 : type_(LINE), height_(kDoubleNotANumber), min_(kDoubleInfinity),
28 max_(kDoubleNegInfinity), offset_(3), legend_padding_(10),
29 basic_width_of_label_(0), show_legend_(false) {
30 InitSeries(series);
31 InitStyles();
32 InitSymbols();
33 }
34
35 explicit Asciichart(const std::vector<std::vector<double>> &series)
36 : type_(LINE), height_(kDoubleNotANumber), min_(kDoubleInfinity),
37 max_(kDoubleNegInfinity), offset_(3), legend_padding_(10),
38 basic_width_of_label_(0), show_legend_(false) {
39 InitSeries(series);
40 InitStyles();
41 InitSymbols();
42 }
43
44 // For associating a text label with each series
45 explicit Asciichart(
46 const std::unordered_map<std::string, std::vector<double>> &series)
47 : type_(LINE), height_(kDoubleNotANumber), min_(kDoubleInfinity),
48 max_(kDoubleNegInfinity), offset_(3), legend_padding_(10),
49 basic_width_of_label_(0), show_legend_(false) {
50 InitSeries(series);
51 InitStyles();
52 InitSymbols();
53 }
54
57 type_ = type;
58 return *this;
59 }
60
63 height_ = height;
64 return *this;
65 }
66
68 Asciichart &styles(const std::vector<Style> &styles) {
69 styles_ = styles;
70 return *this;
71 }
72
75 Asciichart &min(double min) {
76 min_ = min;
77 return *this;
78 }
79
82 Asciichart &max(double max) {
83 max_ = max;
84 return *this;
85 }
86
89 offset_ = offset;
90 return *this;
91 }
92
94 Asciichart &legend_padding(size_t padding) {
95 legend_padding_ = padding;
96 return *this;
97 }
98
101 show_legend_ = show;
102 return *this;
103 }
104
106 Asciichart &symbols(const std::map<std::string, std::string> &symbols) {
107 symbols_ = symbols;
108 return *this;
109 }
110
112 std::string Plot() {
113 switch (type_) {
114 case LINE:
115 return PlotLineChart();
116 break;
117 case CIRCLE:
118 return PlotCircleChart();
119 break;
120 default:
121 return "";
122 }
123 }
124
125private:
126 std::map<std::string, std::string> symbols_;
127 std::unordered_map<std::string, std::vector<double>> series_;
128 std::vector<Style> styles_;
129
130 Type type_;
131 double height_;
132 double min_;
133 double max_;
134 double offset_;
135 size_t legend_padding_;
136 size_t basic_width_of_label_;
137
138 bool show_legend_;
139
140 void InitSeries(const std::vector<double> &series) {
141 series_["series 0"] = series;
142 }
143
144 void InitSeries(const std::vector<std::vector<double>> &series) {
145 unsigned n = 0;
146 for (const auto &s : series) {
147 series_["series " + std::to_string(n++)] = s;
148 }
149 }
150
151 void InitSeries(
152 const std::unordered_map<std::string, std::vector<double>> &series) {
153 series_ = series;
154 }
155
156 void InitStyles() {
157 styles_ = {
158 Style().fg(Foreground::From(Color::RED)),
159 Style().fg(Foreground::From(Color::CYAN)),
160 Style().fg(Foreground::From(Color::MAGENTA)),
161 Style().fg(Foreground::From(Color::YELLOW)),
162 Style().fg(Foreground::From(Color::WHITE)),
164 };
165 }
166
167 void InitSymbols() {
168 switch (type_) {
169 case LINE:
170 symbols_ = {{"empty", " "}, {"center", "┼"}, {"axis", "┤"},
171 {"c1", "╶"}, {"c2", "╴"}, {"parellel", "─"},
172 {"down", "╰"}, {"up", "╭"}, {"ldown", "╮"},
173 {"lup", "╯"}, {"vertical", "│"}};
174 case CIRCLE:
175 break;
176 default:
177 break;
178 }
179 }
180
183 void PutString(std::vector<std::vector<Text>> &screen, const std::string &str,
184 const Style &style, unsigned row, unsigned col) {
185 for (unsigned i = 0; i < str.length(); i++) {
186 if (str[i] == '\n') {
187 row += 1;
188 } else {
189 screen[row][col + i] = Text(str.substr(i, 1), style);
190 }
191 }
192 }
193
194 std::string FormatLabel(int x) {
195 std::stringstream ss;
196 ss << std::setw(show_legend_ ? legend_padding_ + basic_width_of_label_
197 : basic_width_of_label_)
198 << std::setfill(' ') << std::setprecision(2);
199 ss << x;
200 return ss.str();
201 }
202
203 std::string Print(const std::vector<std::vector<Text>> &screen) {
204 std::stringstream os;
205 for (auto &line : screen) {
206 for (auto &item : line) {
207 os << item;
208 }
209 os << "\n";
210 }
211 return os.str();
212 }
213
214 std::string PlotLineChart() {
215 // 1. calculate min and max
216 for (auto &label_trace_pair : series_) {
217 for (auto &item : label_trace_pair.second) {
218 min_ = std::min(item, min_);
219 max_ = std::max(item, max_);
220 }
221 }
222
223 // 2. calaculate range
224 auto range = max_ - min_;
225 if (range == 0) range = 1;
226
227 // make basic padding as size of str(max)
228 basic_width_of_label_ = std::max(std::to_string((int)max_).length(),
229 std::to_string((int)min_).length());
230
231 // 3. width and height
232 int width = 0;
233 for (auto &label_trace_pair : series_) {
234 width = std::max(width, (int)label_trace_pair.second.size());
235 }
236
237 int legend_cols = 0, legend_rows = 0;
238 if (show_legend_) {
239 // determine width and height of legend, add to offset.
240 for (auto &label_trace_pair : series_) {
241 legend_rows++;
242 legend_cols =
243 std::max(legend_cols, (int)label_trace_pair.first.length());
244 }
245 }
246
247 auto offset = offset_ + legend_cols;
248
249 width += offset;
250
251 if (std::isnan(height_)) {
252 height_ = range;
253 }
254
255 // extend the height of the plot if we need more rows to display the
256 // legend than what the range of the data requires.
257 height_ = std::max((double)legend_rows, height_);
258
259 // calculate ratio using height and range
260 auto ratio = height_ / range;
261
262 int min2 = std::round(min_ * ratio);
263 int max2 = std::round(max_ * ratio);
264
265 // 4. rows and cols of this chart
266 auto rows = max2 - min2;
267 auto cols = width;
268
269 if (rows == 0) rows = 1;
270
271 // 5. initialize chart using empty str
272 std::vector<std::vector<Text>> screen(
273 rows + 1, std::vector<Text>(cols, symbols_["empty"]));
274
275 // 6. axis + labels
276 for (double y = min2; y <= max2; y++) {
277 auto label = FormatLabel(std::round(min_ + (y - min2) * range / rows));
278 // vertical reverse
279 screen[rows - (y - min2)][legend_cols] =
280 // -commented out by Gagik Text(label, Style().fg(Foreground::From(Color::BLUE)));
281 Text(label, Style().fg(Foreground::From(Color::CYAN)));
282 screen[rows - (y - min2)][offset - 1] =
283 Text((y == 0) ? symbols_["center"] : symbols_["axis"],
284 Style().fg(Foreground::From(Color::CYAN)));
285 }
286
287 if (show_legend_) {
288 // 7. Legend
289 {
290 unsigned j = 0;
291 for (auto &label_trace_pair : series_) {
292 auto style = styles_[j % styles_.size()];
293 PutString(screen, label_trace_pair.first, style, j++, 0);
294 }
295 }
296 }
297
298 // 8. Content
299 {
300 unsigned j = 0;
301 for (auto &label_trace_pair : series_) {
302 auto &trace = label_trace_pair.second;
303 auto style = styles_[j++ % styles_.size()];
304 auto y0 = std::round(trace[0] * ratio) - min2;
305 // vertical reverse
306 screen[rows - y0][offset - 1] = Text(symbols_["center"], style);
307
308 for (size_t i = 0; i < trace.size() - 1; i++) {
309 auto y0 = std::round(trace[i] * ratio) - min2;
310 auto y1 = std::round(trace[i + 1] * ratio) - min2;
311
312 if (y0 == y1) {
313 screen[rows - y0][i + offset] = Text(symbols_["parellel"], style);
314 } else {
315 screen[rows - y1][i + offset] =
316 Text(y0 > y1 ? symbols_["down"] : symbols_["up"], style);
317 screen[rows - y0][i + offset] =
318 Text(y0 > y1 ? symbols_["ldown"] : symbols_["lup"], style);
319 auto from = std::min(y0, y1);
320 auto to = std::max(y0, y1);
321 for (size_t y = from + 1; y < to; y++) {
322 screen[rows - y][i + offset] = Text(symbols_["vertical"], style);
323 }
324 }
325 }
326 }
327 }
328
329 return Print(screen);
330 }
331
332 std::string PlotCircleChart() { return ""; }
333};
334} // namespace ascii
335#endif
Definition ascii.h:18
Asciichart & height(double height)
Set height of chart.
Definition ascii.h:62
Type
Definition ascii.h:20
@ CIRCLE
Definition ascii.h:22
@ LINE
Definition ascii.h:21
Asciichart & type(Type type)
Set type of chart.
Definition ascii.h:56
Asciichart & max(double max)
Set max of chart.
Definition ascii.h:82
Asciichart & min(double min)
Set min of chart.
Definition ascii.h:75
Asciichart & legend_padding(size_t padding)
Set padding between legend and label.
Definition ascii.h:94
Asciichart(const std::unordered_map< std::string, std::vector< double > > &series)
Definition ascii.h:45
Asciichart & symbols(const std::map< std::string, std::string > &symbols)
Set symbols used to plot.
Definition ascii.h:106
Asciichart(const std::vector< double > &series)
Definition ascii.h:26
Asciichart & show_legend(bool show)
If show legend.
Definition ascii.h:100
std::string Plot()
Generate this chart.
Definition ascii.h:112
Asciichart & offset(size_t offset)
Set offset of label from axis.
Definition ascii.h:88
Asciichart & styles(const std::vector< Style > &styles)
Set colors of chart.
Definition ascii.h:68
Asciichart(const std::vector< std::vector< double > > &series)
Definition ascii.h:35
static Foreground From(T color)
Definition color.h:96
for detailed info, refered to https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797.
Definition ascii.h:17
constexpr double kDoubleNegInfinity
Definition constants.h:10
constexpr double kDoubleNotANumber
Definition constants.h:8
constexpr double kDoubleInfinity
Definition constants.h:9