openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
asciiPlotter.hpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // openCARP is an open cardiac electrophysiology simulator.
3 //
4 // Copyright (C) 2020 openCARP project
5 //
6 // This program is licensed under the openCARP Academic Public License (APL)
7 // v1.0: You can use and redistribute it and/or modify it in non-commercial
8 // academic environments under the terms of APL as published by the openCARP
9 // project v1.0, or (at your option) any later version. Commercial use requires
10 // a commercial license (info@opencarp.org).
11 //
12 // This program is distributed without any warranty; see the openCARP APL for
13 // more details.
14 //
15 // You should have received a copy of the openCARP APL along with this program
16 // and can find it online: http://www.opencarp.org/license
17 // ----------------------------------------------------------------------------
18 
28 #ifndef _ASCII_PLOTTER
29 #define _ASCII_PLOTTER
30 
31 #include<stdio.h>
32 #include<stdlib.h>
33 #include<math.h>
34 
35 #include<iostream>
36 #include<vector>
37 #include<string>
38 #include<algorithm>
39 
40 #include<assert.h>
41 
42 
43 
44 template<class V>
46 {
47  private:
48  const std::vector<V> & _xval;
49  const std::vector<V> & _yval;
50 
51  public:
52  piecewiseLinear_function(const std::vector<V> & xval, const std::vector<V> & yval): _xval(xval), _yval(yval)
53  {
54  assert(_xval.size() == _yval.size());
55  assert(_xval.size() > 1);
56  }
57 
58  bool operator()(const V x, V & y)
59  {
60  V xs = _xval[0], xe = _xval[1], ys = _yval[0], ye = _yval[1];
61 
62  if( (x < _xval[0]) || (x > _xval[_xval.size()-1]) )
63  return false;
64 
65  size_t size = _xval.size();
66  unsigned int i=1;
67  while(x > xe && i < size-1) {
68  xs = _xval[i], xe = _xval[i+1];
69  ys = _yval[i], ye = _yval[i+1];
70  i++;
71  }
72 
73  V fctr = (x - xs) / (xe - xs);
74  y = ys + (ye - ys)*fctr;
75 
76  return true;
77  }
78 };
79 
80 
85 {
86  private:
87  std::vector< std::vector<char> > _canvas;
88  unsigned int _rows;
89  unsigned int _cols;
90  double _x_min, _x_max, _x_div;
91  double _y_min, _y_max, _y_div;
92 
94  void reset()
95  {
96  for(unsigned int i=0; i<_rows; i++) {
97  _canvas[i].assign(_cols + 1, ' ');
98  _canvas[i][_cols] = '\0';
99  }
100  _x_min = -1;
101  _x_max = -1;
102  _x_div = -1;
103  _y_min = -1;
104  _y_max = -1;
105  _y_div = -1;
106  }
107 
109  template<class V>
110  void compute_xrange(const std::vector<V> & x)
111  {
112  _x_min = x[0], _x_max = x[x.size()-1];
113  _x_div = (_x_max - _x_min) / (_cols - 1);
114  }
116  template<class V>
117  void compute_yrange(const std::vector<V> & func)
118  {
119  _y_min = func[0], _y_max = func[0];
120  for(size_t i=0; i<func.size(); i++) {
121  if(_y_min > func[i]) _y_min = func[i];
122  if(_y_max < func[i]) _y_max = func[i];
123  }
124  _y_div = (_y_max - _y_min) / (_rows - 1);
125  }
126 
128  template<class V>
129  void draw_graph(const std::vector<V> & x, const std::vector<V> & y, char c)
130  {
131  piecewiseLinear_function<V> func(x,y);
132  size_t dpd = 10; // draws per division
133 
134  for(size_t i=0; i<_cols*dpd; i++) {
135  size_t xidx = i/dpd;
136  V xval = _x_min + float(i)/float(dpd)*_x_div;
137  V yval;
138  if(func(xval, yval))
139  {
140  unsigned int yidx = (yval - _y_min) / _y_div;
141  if(yidx < _rows)
142  _canvas[_rows-1 - yidx][xidx] = c;
143  }
144  }
145  }
146 
148  void print_topline()
149  {
150  printf(" ");
151  for(size_t i=0; i<_cols+2; i++) printf("-");
152  printf("\n");
153  }
155  void print_botline()
156  {
157  printf(" ");
158  for(size_t i=0; i<_cols+2; i++) printf("-");
159  printf("\n");
160 
161  unsigned int bsize = 8;
162  unsigned int nblocks = _cols / bsize;
163  printf(" ");
164  for(size_t i=0; i<=nblocks; i++) {
165  if(i%2 == 0) printf("%8.1lf", _x_min + i*bsize*_x_div);
166  else printf(" ");
167  }
168  printf("\n");
169  }
170 
171 
172  public:
175  _rows(0),
176  _cols(0),
177  _x_min(-1),
178  _x_max(-1),
179  _x_div(-1),
180  _y_min(-1),
181  _y_max(-1),
182  _y_div(-1)
183  {}
188  asciiPlotter(const unsigned int rows, const unsigned int cols) :
189  _rows(0),
190  _cols(0)
191  {
192  this->setSize(rows, cols);
193  }
194 
196  void setSize(const unsigned int rows, const unsigned int cols)
197  {
198  _rows = rows;
199  _cols = cols;
200 
201  _canvas.resize(_rows);
202  this->reset();
203  }
204 
212  template<class V>
213  void add_graph(const std::vector<V> & func, char c)
214  {
215  assert(_cols > 0 && _rows > 0);
216 
217  std::vector<V> x(func.size());
218  for(size_t i=0; i<func.size(); i++) x[i] = i;
219 
220  if(_x_div < 0) compute_xrange(x);
221  if(_y_div < 0) compute_yrange(func);
222 
223  draw_graph(x, func, c);
224  }
231  template<class V>
232  void add_graph(const std::vector<V> & x, const std::vector<V> & y, char c)
233  {
234  assert(_cols > 0 && _rows > 0);
235  assert(x.size() == y.size());
236 
237  if(_x_div < 0) compute_xrange(x);
238  if(_y_div < 0) compute_yrange(y);
239 
240  draw_graph(x, y, c);
241  }
242 
244  void print()
245  {
246  print_topline();
247  for(size_t i=0; i<_rows; i++) {
248  if( (i == 0) || (_rows-1-i)%4 == 0 )
249  printf("%+8.2lf |%s|\n", _y_max - i*_y_div, _canvas[i].data());
250  else
251  printf(" |%s|\n", _canvas[i].data());
252  }
253  print_botline();
254  }
255 
257  template<class V>
258  void set_xrange(const std::vector<V> & x)
259  {
260  this->compute_xrange(x);
261  }
263  template<class V>
264  void set_xrange(V min, V max)
265  {
266  _x_min = min;
267  _x_max = max;
268  _x_div = (_x_max - _x_min) / (_cols - 1);
269  }
270 
272  template<class V>
273  void set_yrange(const std::vector<V> & func)
274  {
275  this->compute_yrange(func);
276  }
278  template<class V>
279  void set_yrange(V min, V max)
280  {
281  _y_min = min;
282  _y_max = max;
283  _y_div = (_y_max - _y_min) / (_rows - 1);
284  }
285 };
286 
287 
294 template<class V>
296 {
297  private:
298  asciiPlotter _plotter;
299  std::vector<float> _xval, _yval;
300  size_t _num_int;
301 
302  V _min, _max;
303  double _avrg;
304 
305  void stats(const std::vector<V> & data)
306  {
307  _min = data[0], _max = data[0];
308  _avrg = 0.0;
309 
310  for(size_t i=0; i<data.size(); i++)
311  {
312  V c = data[i];
313  if(_min > c) _min = c;
314  if(_max < c) _max = c;
315  _avrg += c;
316  }
317  _avrg /= double(data.size());
318  }
319 
320  void generate_xy(const std::vector<V> & data)
321  {
322  this->stats(data);
323 
324  float delta = float(_max - _min) / float(_num_int);
325 
326  for(size_t i=0; i<_num_int+1; i++) {
327  _xval[i] = float(_min) + i*delta;
328  _yval[i] = 0.0f;
329  }
330 
331  for(size_t i=0; i < data.size(); i++) {
332  size_t idx = size_t((data[i] - _min) / delta);
333  if(idx < _num_int+1)
334  _yval[idx] += 1.0f;
335  }
336  for(size_t i=0; i<_num_int+1; i++) _yval[i] /= ((float)data.size());
337  }
338 
339  public:
340  histogramm_plotter(size_t num_int, size_t rows, size_t cols) :
341  _plotter(rows, cols), _xval(num_int+1), _yval(num_int+1), _num_int(num_int)
342  {}
343 
344  void plot(const std::vector<V> & data, std::string msg)
345  {
346  this->generate_xy(data);
347 
348  _plotter.set_xrange(_min, _max);
349  _plotter.set_yrange(_yval);
350  _plotter.add_graph(_xval, _yval, '*');
351 
352  std::cout << msg << std::endl << std::endl;
353  std::cout << "Average: " << _avrg << ", (min: " << _min << ", max: " << _max << ")" << std::endl;
354  std::cout << std::endl << " == Histogram == " << std::endl << std::endl;
355  _plotter.print();
356  }
357 };
358 
364 template<class VEC>
366 {
367  private:
368  std::vector< std::vector<char> > _canvas;
369  unsigned int _rows;
370  unsigned int _cols;
371 
372 
380  void draw_matrix(const VEC & cnt,
381  const VEC & col,
382  char s)
383  {
384  long int nrow = cnt.size();
385  long int ncol = *std::max_element(col.begin(), col.end()) + 1;
386  int xdiv = (ncol + _cols - 1) / _cols;
387  int ydiv = (nrow + _rows - 1) / _rows;
388 
389  for(size_t i=0, k=0; i<cnt.size(); i++)
390  for(long int j=0; j < cnt[i]; j++, k++) {
391  int ypos = i / ydiv;
392  int xpos = col[k] / xdiv;
393  _canvas[ypos][xpos] = s;
394  }
395  }
396 
397 
398  public:
400  matrixgraph_plotter() : _rows(0), _cols(0)
401  {}
402 
409  matrixgraph_plotter(const unsigned int rows, const unsigned int cols)
410  {
411  this->setSize(rows, cols);
412  }
413 
417  void reset()
418  {
419  for(unsigned int i=0; i<_rows; i++) {
420  _canvas[i].assign(_cols + 1, ' ');
421  _canvas[i][_cols] = '\0';
422  }
423  }
424 
431  void setSize(const unsigned int rows, const unsigned int cols)
432  {
433  _rows = rows;
434  _cols = cols;
435 
436  _canvas.resize(_rows);
437  this->reset();
438  }
439 
447  void print(const VEC & cnt,
448  const VEC & col,
449  char s)
450  {
451  draw_matrix(cnt, col, s);
452 
453  for(size_t i=0; i<_rows; i++) {
454  printf(" |%s|\n", _canvas[i].data());
455  }
456  }
457 };
458 
459 
460 
461 #endif
462 
constexpr T min(T a, T b)
Definition: ion_type.h:33
piecewiseLinear_function(const std::vector< V > &xval, const std::vector< V > &yval)
constexpr T max(T a, T b)
Definition: ion_type.h:31
histogramm_plotter(size_t num_int, size_t rows, size_t cols)
Class that generates a histogram for a data vector and prints it using asciiPlotter.
asciiPlotter()
empty constructor
void set_yrange(const std::vector< V > &func)
set y range according to min/max of the given function
bool operator()(const V x, V &y)
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 set_xrange(V min, V max)
set x range
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 reset()
Clear the canvas.
void setSize(const unsigned int rows, const unsigned int cols)
set canvas size
void print(const VEC &cnt, const VEC &col, char s)
Print a matrix graph to stdout.
Ascii matrix graph plotter.
void add_graph(const std::vector< V > &func, char c)
void set_yrange(V min, V max)
set y range
matrixgraph_plotter()
empty constructor
asciiPlotter(const unsigned int rows, const unsigned int cols)
void print()
print the plot on stdout
void plot(const std::vector< V > &data, std::string msg)