openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
asciiPlotter.hpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
13 #ifndef _ASCII_PLOTTER
14 #define _ASCII_PLOTTER
15 
16 #include<stdio.h>
17 #include<stdlib.h>
18 #include<math.h>
19 
20 #include<iostream>
21 #include<vector>
22 #include<string>
23 #include<algorithm>
24 
25 #include<assert.h>
26 
27 
28 
29 template<class V>
31 {
32  private:
33  const std::vector<V> & _xval;
34  const std::vector<V> & _yval;
35 
36  public:
37  piecewiseLinear_function(const std::vector<V> & xval, const std::vector<V> & yval): _xval(xval), _yval(yval)
38  {
39  assert(_xval.size() == _yval.size());
40  assert(_xval.size() > 1);
41  }
42 
43  bool operator()(const V x, V & y)
44  {
45  V xs = _xval[0], xe = _xval[1], ys = _yval[0], ye = _yval[1];
46 
47  if( (x < _xval[0]) || (x > _xval[_xval.size()-1]) )
48  return false;
49 
50  size_t size = _xval.size();
51  unsigned int i=1;
52  while(x > xe && i < size-1) {
53  xs = _xval[i], xe = _xval[i+1];
54  ys = _yval[i], ye = _yval[i+1];
55  i++;
56  }
57 
58  V fctr = (x - xs) / (xe - xs);
59  y = ys + (ye - ys)*fctr;
60 
61  return true;
62  }
63 };
64 
65 
70 {
71  private:
72  std::vector< std::vector<char> > _canvas;
73  unsigned int _rows;
74  unsigned int _cols;
75  double _x_min, _x_max, _x_div;
76  double _y_min, _y_max, _y_div;
77 
79  void reset()
80  {
81  for(unsigned int i=0; i<_rows; i++) {
82  _canvas[i].assign(_cols + 1, ' ');
83  _canvas[i][_cols] = '\0';
84  }
85  _x_min = -1;
86  _x_max = -1;
87  _x_div = -1;
88  _y_min = -1;
89  _y_max = -1;
90  _y_div = -1;
91  }
92 
94  template<class V>
95  void compute_xrange(const std::vector<V> & x)
96  {
97  _x_min = x[0], _x_max = x[x.size()-1];
98  _x_div = (_x_max - _x_min) / (_cols - 1);
99  }
101  template<class V>
102  void compute_yrange(const std::vector<V> & func)
103  {
104  _y_min = func[0], _y_max = func[0];
105  for(size_t i=0; i<func.size(); i++) {
106  if(_y_min > func[i]) _y_min = func[i];
107  if(_y_max < func[i]) _y_max = func[i];
108  }
109  _y_div = (_y_max - _y_min) / (_rows - 1);
110  }
111 
113  template<class V>
114  void draw_graph(const std::vector<V> & x, const std::vector<V> & y, char c)
115  {
116  piecewiseLinear_function<V> func(x,y);
117  size_t dpd = 10; // draws per division
118 
119  for(size_t i=0; i<_cols*dpd; i++) {
120  size_t xidx = i/dpd;
121  V xval = _x_min + float(i)/float(dpd)*_x_div;
122  V yval;
123  if(func(xval, yval))
124  {
125  unsigned int yidx = (yval - _y_min) / _y_div;
126  if(yidx < _rows)
127  _canvas[_rows-1 - yidx][xidx] = c;
128  }
129  }
130  }
131 
133  void print_topline()
134  {
135  printf(" ");
136  for(size_t i=0; i<_cols+2; i++) printf("-");
137  printf("\n");
138  }
140  void print_botline()
141  {
142  printf(" ");
143  for(size_t i=0; i<_cols+2; i++) printf("-");
144  printf("\n");
145 
146  unsigned int bsize = 8;
147  unsigned int nblocks = _cols / bsize;
148  printf(" ");
149  for(size_t i=0; i<=nblocks; i++) {
150  if(i%2 == 0) printf("%8.1lf", _x_min + i*bsize*_x_div);
151  else printf(" ");
152  }
153  printf("\n");
154  }
155 
156 
157  public:
160  _rows(0),
161  _cols(0),
162  _x_min(-1),
163  _x_max(-1),
164  _x_div(-1),
165  _y_min(-1),
166  _y_max(-1),
167  _y_div(-1)
168  {}
173  asciiPlotter(const unsigned int rows, const unsigned int cols) :
174  _rows(0),
175  _cols(0)
176  {
177  this->setSize(rows, cols);
178  }
179 
181  void setSize(const unsigned int rows, const unsigned int cols)
182  {
183  _rows = rows;
184  _cols = cols;
185 
186  _canvas.resize(_rows);
187  this->reset();
188  }
189 
197  template<class V>
198  void add_graph(const std::vector<V> & func, char c)
199  {
200  assert(_cols > 0 && _rows > 0);
201 
202  std::vector<V> x(func.size());
203  for(size_t i=0; i<func.size(); i++) x[i] = i;
204 
205  if(_x_div < 0) compute_xrange(x);
206  if(_y_div < 0) compute_yrange(func);
207 
208  draw_graph(x, func, c);
209  }
216  template<class V>
217  void add_graph(const std::vector<V> & x, const std::vector<V> & y, char c)
218  {
219  assert(_cols > 0 && _rows > 0);
220  assert(x.size() == y.size());
221 
222  if(_x_div < 0) compute_xrange(x);
223  if(_y_div < 0) compute_yrange(y);
224 
225  draw_graph(x, y, c);
226  }
227 
229  void print()
230  {
231  print_topline();
232  for(size_t i=0; i<_rows; i++) {
233  if( (i == 0) || (_rows-1-i)%4 == 0 )
234  printf("%+8.2lf |%s|\n", _y_max - i*_y_div, _canvas[i].data());
235  else
236  printf(" |%s|\n", _canvas[i].data());
237  }
238  print_botline();
239  }
240 
242  template<class V>
243  void set_xrange(const std::vector<V> & x)
244  {
245  this->compute_xrange(x);
246  }
248  template<class V>
249  void set_xrange(V min, V max)
250  {
251  _x_min = min;
252  _x_max = max;
253  _x_div = (_x_max - _x_min) / (_cols - 1);
254  }
255 
257  template<class V>
258  void set_yrange(const std::vector<V> & func)
259  {
260  this->compute_yrange(func);
261  }
263  template<class V>
264  void set_yrange(V min, V max)
265  {
266  _y_min = min;
267  _y_max = max;
268  _y_div = (_y_max - _y_min) / (_rows - 1);
269  }
270 };
271 
272 
279 template<class V>
281 {
282  private:
283  asciiPlotter _plotter;
284  std::vector<float> _xval, _yval;
285  size_t _num_int;
286 
287  V _min, _max;
288  double _avrg;
289 
290  void stats(const std::vector<V> & data)
291  {
292  _min = data[0], _max = data[0];
293  _avrg = 0.0;
294 
295  for(size_t i=0; i<data.size(); i++)
296  {
297  V c = data[i];
298  if(_min > c) _min = c;
299  if(_max < c) _max = c;
300  _avrg += c;
301  }
302  _avrg /= double(data.size());
303  }
304 
305  void generate_xy(const std::vector<V> & data)
306  {
307  this->stats(data);
308 
309  float delta = float(_max - _min) / float(_num_int);
310 
311  for(size_t i=0; i<_num_int+1; i++) {
312  _xval[i] = float(_min) + i*delta;
313  _yval[i] = 0.0f;
314  }
315 
316  for(size_t i=0; i < data.size(); i++) {
317  size_t idx = size_t((data[i] - _min) / delta);
318  if(idx < _num_int+1)
319  _yval[idx] += 1.0f;
320  }
321  for(size_t i=0; i<_num_int+1; i++) _yval[i] /= ((float)data.size());
322  }
323 
324  public:
325  histogramm_plotter(size_t num_int, size_t rows, size_t cols) :
326  _plotter(rows, cols), _xval(num_int+1), _yval(num_int+1), _num_int(num_int)
327  {}
328 
329  void plot(const std::vector<V> & data, std::string msg)
330  {
331  this->generate_xy(data);
332 
333  _plotter.set_xrange(_min, _max);
334  _plotter.set_yrange(_yval);
335  _plotter.add_graph(_xval, _yval, '*');
336 
337  std::cout << msg << std::endl << std::endl;
338  std::cout << "Average: " << _avrg << ", (min: " << _min << ", max: " << _max << ")" << std::endl;
339  std::cout << std::endl << " == Histogram == " << std::endl << std::endl;
340  _plotter.print();
341  }
342 };
343 
349 template<class VEC>
351 {
352  private:
353  std::vector< std::vector<char> > _canvas;
354  unsigned int _rows;
355  unsigned int _cols;
356 
357 
365  void draw_matrix(const VEC & cnt,
366  const VEC & col,
367  char s)
368  {
369  long int nrow = cnt.size();
370  long int ncol = *std::max_element(col.begin(), col.end()) + 1;
371  int xdiv = (ncol + _cols - 1) / _cols;
372  int ydiv = (nrow + _rows - 1) / _rows;
373 
374  for(size_t i=0, k=0; i<cnt.size(); i++)
375  for(long int j=0; j < cnt[i]; j++, k++) {
376  int ypos = i / ydiv;
377  int xpos = col[k] / xdiv;
378  _canvas[ypos][xpos] = s;
379  }
380  }
381 
382 
383  public:
385  matrixgraph_plotter() : _rows(0), _cols(0)
386  {}
387 
394  matrixgraph_plotter(const unsigned int rows, const unsigned int cols)
395  {
396  this->setSize(rows, cols);
397  }
398 
402  void reset()
403  {
404  for(unsigned int i=0; i<_rows; i++) {
405  _canvas[i].assign(_cols + 1, ' ');
406  _canvas[i][_cols] = '\0';
407  }
408  }
409 
416  void setSize(const unsigned int rows, const unsigned int cols)
417  {
418  _rows = rows;
419  _cols = cols;
420 
421  _canvas.resize(_rows);
422  this->reset();
423  }
424 
432  void print(const VEC & cnt,
433  const VEC & col,
434  char s)
435  {
436  draw_matrix(cnt, col, s);
437 
438  for(size_t i=0; i<_rows; i++) {
439  printf(" |%s|\n", _canvas[i].data());
440  }
441  }
442 };
443 
444 
445 
446 #endif
447 
void add_graph(const std::vector< V > &func, char c)
asciiPlotter(const unsigned int rows, const unsigned int cols)
void set_xrange(V min, V max)
set x range
void set_yrange(const std::vector< V > &func)
set y range according to min/max of the given function
void set_yrange(V min, V max)
set y range
void setSize(const unsigned int rows, const unsigned int cols)
set canvas size
void set_xrange(const std::vector< V > &x)
set x range according to min/max of the given vector
void add_graph(const std::vector< V > &x, const std::vector< V > &y, char c)
void print()
print the plot on stdout
asciiPlotter()
empty constructor
Class that generates a histogram for a data vector and prints it using asciiPlotter.
void plot(const std::vector< V > &data, std::string msg)
histogramm_plotter(size_t num_int, size_t rows, size_t cols)
Ascii matrix graph plotter.
void reset()
Clear the canvas.
matrixgraph_plotter()
empty constructor
void setSize(const unsigned int rows, const unsigned int cols)
Set new size and clear the canvas.
matrixgraph_plotter(const unsigned int rows, const unsigned int cols)
Constructor specifying the canvas size.
void print(const VEC &cnt, const VEC &col, char s)
Print a matrix graph to stdout.
piecewiseLinear_function(const std::vector< V > &xval, const std::vector< V > &yval)
bool operator()(const V x, V &y)
constexpr T min(T a, T b)
Definition: ion_type.h:18
constexpr T max(T a, T b)
Definition: ion_type.h:16