1
+ //
2
+ // Changes:
3
+ // * Make work for Eigen Vectors and Matrices
4
+ // * Implement a better way for named_plot, maybe just as additional
5
+ // method with extra keyword
6
+ // * add location keyword for legend
7
+ // * add submodule for our own functions such as spy
8
+ //
9
+
1
10
#pragma once
2
11
3
12
#include < algorithm>
@@ -57,6 +66,8 @@ struct _interpreter {
57
66
PyObject *s_python_function_ylabel;
58
67
PyObject *s_python_function_xticks;
59
68
PyObject *s_python_function_yticks;
69
+ PyObject *s_python_function_xscale;
70
+ PyObject *s_python_function_yscale;
60
71
PyObject *s_python_function_grid;
61
72
PyObject *s_python_function_clf;
62
73
PyObject *s_python_function_errorbar;
@@ -181,6 +192,8 @@ struct _interpreter {
181
192
s_python_function_ylabel = PyObject_GetAttrString (pymod, " ylabel" );
182
193
s_python_function_xticks = PyObject_GetAttrString (pymod, " xticks" );
183
194
s_python_function_yticks = PyObject_GetAttrString (pymod, " yticks" );
195
+ s_python_function_xscale = PyObject_GetAttrString (pymod, " xscale" );
196
+ s_python_function_yscale = PyObject_GetAttrString (pymod, " yscale" );
184
197
s_python_function_grid = PyObject_GetAttrString (pymod, " grid" );
185
198
s_python_function_xlim = PyObject_GetAttrString (pymod, " xlim" );
186
199
s_python_function_ion = PyObject_GetAttrString (pymod, " ion" );
@@ -209,6 +222,8 @@ struct _interpreter {
209
222
!s_python_function_legend || !s_python_function_ylim ||
210
223
!s_python_function_title || !s_python_function_axis ||
211
224
!s_python_function_xlabel || !s_python_function_ylabel ||
225
+ !s_python_function_xticks || !s_python_function_yticks ||
226
+ !s_python_function_xscale || !s_python_function_yscale ||
212
227
!s_python_function_grid || !s_python_function_xlim ||
213
228
!s_python_function_ion || !s_python_function_ginput ||
214
229
!s_python_function_save || !s_python_function_clf ||
@@ -241,6 +256,10 @@ struct _interpreter {
241
256
!PyFunction_Check (s_python_function_axis) ||
242
257
!PyFunction_Check (s_python_function_xlabel) ||
243
258
!PyFunction_Check (s_python_function_ylabel) ||
259
+ !PyFunction_Check (s_python_function_xticks) ||
260
+ !PyFunction_Check (s_python_function_yticks) ||
261
+ !PyFunction_Check (s_python_function_xscale) ||
262
+ !PyFunction_Check (s_python_function_yscale) ||
244
263
!PyFunction_Check (s_python_function_grid) ||
245
264
!PyFunction_Check (s_python_function_xlim) ||
246
265
!PyFunction_Check (s_python_function_ion) ||
@@ -334,6 +353,8 @@ template <> struct select_npy_type<uint64_t> {
334
353
const static NPY_TYPES type = NPY_UINT64;
335
354
};
336
355
356
+ // TODO change to Vector template so useable for Eigen vectors,
357
+ // should be enough since it also provides the end and begin methods
337
358
template <typename Numeric> PyObject *get_array (const std::vector<Numeric> &v) {
338
359
detail::_interpreter::get (); // interpreter needs to be initialized for the
339
360
// numpy commands to work
@@ -353,6 +374,29 @@ template <typename Numeric> PyObject *get_array(const std::vector<Numeric> &v) {
353
374
return varray;
354
375
}
355
376
377
+ template <typename Vector> PyObject *get_array (const Vector &v) {
378
+ detail::_interpreter::get (); // interpreter needs to be initialized for the
379
+ // numpy commands to work
380
+ // both Eigen::Matrix<..> and std::vector<..> have the member value_type
381
+ NPY_TYPES type = select_npy_type<typename Vector::value_type>::type;
382
+ if (type == NPY_NOTYPE) {
383
+ std::vector<double > vd (v.size ());
384
+ npy_intp vsize = v.size ();
385
+ std::copy (v.begin (), v.end (), vd.begin ());
386
+ PyObject *varray =
387
+ PyArray_SimpleNewFromData (1 , &vsize, NPY_DOUBLE, (void *)(vd.data ()));
388
+ return varray;
389
+ }
390
+
391
+ npy_intp vsize = v.size ();
392
+ PyObject *varray =
393
+ PyArray_SimpleNewFromData (1 , &vsize, type, (void *)(v.data ()));
394
+ return varray;
395
+ }
396
+
397
+ // TODO maybe we have to add a function for Eigen matrices, not sure
398
+ // if the v[0] is valid for matrices and also the ::std::vector &v_row
399
+ // probably doesn't work
356
400
template <typename Numeric>
357
401
PyObject *get_2darray (const std::vector<::std::vector<Numeric>> &v) {
358
402
detail::_interpreter::get (); // interpreter needs to be initialized for the
@@ -380,9 +424,16 @@ PyObject *get_2darray(const std::vector<::std::vector<Numeric>> &v) {
380
424
381
425
#else // fallback if we don't have numpy: copy every element of the given vector
382
426
427
+ // TODO to Vector templat
383
428
template <typename Numeric> PyObject *get_array (const std::vector<Numeric> &v) {
384
- detail::_interpreter::get ();
429
+ PyObject *list = PyList_New (v.size ());
430
+ for (size_t i = 0 ; i < v.size (); ++i) {
431
+ PyList_SetItem (list, i, PyFloat_FromDouble (v.at (i)));
432
+ }
433
+ return list;
434
+ }
385
435
436
+ template <typename Vector> PyObject *get_array (const Vector &v) {
386
437
PyObject *list = PyList_New (v.size ());
387
438
for (size_t i = 0 ; i < v.size (); ++i) {
388
439
PyList_SetItem (list, i, PyFloat_FromDouble (v.at (i)));
@@ -392,8 +443,8 @@ template <typename Numeric> PyObject *get_array(const std::vector<Numeric> &v) {
392
443
393
444
#endif // WITHOUT_NUMPY
394
445
395
- template <typename Numeric >
396
- bool plot (const std::vector<Numeric> &x, const std::vector<Numeric> &y,
446
+ template <typename VectorX, typename VectorY >
447
+ bool plot (const VectorX &x, const VectorY &y,
397
448
const std::map<std::string, std::string> &keywords) {
398
449
assert (x.size () == y.size ());
399
450
@@ -767,9 +818,8 @@ bool named_hist(std::string label, const std::vector<Numeric> &y,
767
818
return res;
768
819
}
769
820
770
- template <typename NumericX, typename NumericY>
771
- bool plot (const std::vector<NumericX> &x, const std::vector<NumericY> &y,
772
- const std::string &s = " " ) {
821
+ template <typename VectorX, typename VectorY>
822
+ bool plot (const VectorX &x, const VectorY &y, const std::string &s = " " ) {
773
823
assert (x.size () == y.size ());
774
824
775
825
PyObject *xarray = get_array (x);
@@ -904,29 +954,54 @@ bool semilogy(const std::vector<NumericX> &x, const std::vector<NumericY> &y,
904
954
return res;
905
955
}
906
956
907
- template <typename NumericX, typename NumericY>
908
- bool loglog (const std::vector<NumericX> &x, const std::vector<NumericY> &y,
909
- const std::string &s = " " ) {
910
- assert (x.size () == y.size ());
957
+ template <typename ... Args> bool loglog_call (Args... args) {
958
+ // argument for xscale/yscale is only the string "log"
959
+ PyObject *log_arg = PyTuple_New (1 );
960
+ PyObject *pystring = PyString_FromString (" log" );
961
+ PyTuple_SetItem (log_arg, 0 , pystring);
911
962
912
- PyObject *xarray = get_array (x);
913
- PyObject *yarray = get_array (y);
963
+ // call xscale("log") and yscale("log"), no kwargs needed hence pass NULL,
964
+ // as explained in https://docs.python.org/3/c-api/object.html
965
+ PyObject *res_x = PyObject_Call (
966
+ detail::_interpreter::get ().s_python_function_xscale , log_arg, NULL );
967
+ PyObject *res_y = PyObject_Call (
968
+ detail::_interpreter::get ().s_python_function_yscale , log_arg, NULL );
914
969
915
- PyObject *pystring = PyString_FromString (s.c_str ());
970
+ // clean up
971
+ Py_DECREF (log_arg);
916
972
917
- PyObject *plot_args = PyTuple_New (3 );
918
- PyTuple_SetItem (plot_args, 0 , xarray);
919
- PyTuple_SetItem (plot_args, 1 , yarray);
920
- PyTuple_SetItem (plot_args, 2 , pystring);
973
+ if (!res_x)
974
+ throw std::runtime_error (" Call to xscale() failed" );
975
+ Py_DECREF (res_x);
921
976
922
- PyObject *res = PyObject_CallObject (
923
- detail::_interpreter::get ().s_python_function_loglog , plot_args);
977
+ if (!res_y)
978
+ throw std::runtime_error (" Call to yscale() failed" );
979
+ Py_DECREF (res_y);
924
980
925
- Py_DECREF (plot_args);
926
- if (res)
927
- Py_DECREF (res);
981
+ // call plot, which gets now plotted in doubly logarithmic scale
982
+ return plot (args...);
983
+ }
928
984
929
- return res;
985
+ template <typename VectorY>
986
+ bool loglog (const VectorY &y, const std::string &s = " " ) {
987
+ return loglog_call (y, s);
988
+ }
989
+
990
+ template <typename VectorX, typename VectorY>
991
+ bool loglog (const VectorX &x, const VectorY &y, const std::string &s = " " ) {
992
+ return loglog_call (x, y, s);
993
+ }
994
+
995
+ template <typename VectorY>
996
+ bool loglog (const VectorY &y,
997
+ const std::map<std::string, std::string> &kwargs) {
998
+ return loglog_call (y, kwargs);
999
+ }
1000
+
1001
+ template <typename VectorX, typename VectorY>
1002
+ bool loglog (const VectorX &x, const VectorY &y,
1003
+ const std::map<std::string, std::string> &kwargs) {
1004
+ return loglog_call (x, y, kwargs);
930
1005
}
931
1006
932
1007
template <typename NumericX, typename NumericY>
@@ -1107,9 +1182,12 @@ bool named_loglog(const std::string &name, const std::vector<Numeric> &x,
1107
1182
return res;
1108
1183
}
1109
1184
1110
- template <typename Numeric>
1111
- bool plot (const std::vector<Numeric> &y, const std::string &format = " " ) {
1112
- std::vector<Numeric> x (y.size ());
1185
+ template <typename Vector>
1186
+ bool plot (const Vector &y, const std::string &format = " " ) {
1187
+ // TODO can this be <size_t> or do we need <typename Vector::value_type>?
F987
1188
+ // before the conversion of this function from vector<Numeric> to Vector
1189
+ // the created vector x was of the same type as y
1190
+ std::vector<size_t > x (y.size ());
1113
1191
for (size_t i = 0 ; i < x.size (); ++i)
1114
1192
x.at (i) = i;
1115
1193
return plot (x, y, format);
@@ -1125,8 +1203,6 @@ bool stem(const std::vector<Numeric> &y, const std::string &format = "") {
1125
1203
1126
1204
template <typename Numeric>
1127
1205
void text (Numeric x, Numeric y, const std::string &s = " " ) {
1128
- detail::_interpreter::get ();
1129
-
1130
1206
PyObject *args = PyTuple_New (3 );
1131
1207
PyTuple_SetItem (args, 0 , PyFloat_FromDouble (x));
1132
1208
PyTuple_SetItem (args, 1 , PyFloat_FromDouble (y));
@@ -1399,9 +1475,6 @@ inline void yticks(const std::vector<Numeric> &ticks,
1399
1475
}
1400
1476
1401
1477
inline void subplot (long nrows, long ncols, long plot_number) {
1402
-
1403
- detail::_interpreter::get ();
1404
-
1405
1478
// construct positional args
1406
1479
PyObject *args = PyTuple_New (3 );
1407
1480
PyTuple_SetItem (args, 0 , PyFloat_FromDouble (nrows));
@@ -1441,7 +1514,6 @@ inline void title(const std::string &titlestr,
1441
1514
1442
1515
inline void suptitle (const std::string &suptitlestr,
1443
1516
const std::map<std::string, std::string> &keywords = {}) {
1444
- detail::_interpreter::get ();
1445
1517
PyObject *pysuptitlestr = PyString_FromString (suptitlestr.c_str ());
1446
1518
PyObject *args = PyTuple_New (1 );
1447
1519
PyTuple_SetItem (args, 0 , pysuptitlestr);
@@ -1741,8 +1813,6 @@ template <> struct plot_impl<std::false_type> {
1741
1813
template <typename IterableX, typename IterableY>
1742
1814
bool operator ()(const IterableX &x, const IterableY &y,
1743
1815
const std::string &format) {
1744
- detail::_interpreter::get ();
1745
-
1746
1816
// 2-phase lookup for distance, begin, end
1747
1817
using std::begin;
1748
1818
using std::distance;
@@ -1812,16 +1882,16 @@ bool plot(const A &a, const B &b, const std::string &format, Args... args) {
1812
1882
*/
1813
1883
inline bool plot (const std::vector<double > &x, const std::vector<double > &y,
1814
1884
const std::string &format = " " ) {
1815
- return plot<double , double >(x, y, format);
1885
+ return plot<std::vector< double >, std::vector< double > >(x, y, format);
1816
1886
}
1817
1887
1818
1888
inline bool plot (const std::vector<double > &y, const std::string &format = " " ) {
1819
- return plot<double >(y, format);
1889
+ return plot<std::vector< double > >(y, format);
1820
1890
}
1821
1891
1822
1892
inline bool plot (const std::vector<double > &x, const std::vector<double > &y,
1823
1893
const std::map<std::string, std::string> &keywords) {
1824
- return plot<double >(x, y, keywords);
1894
+ return plot<std::vector< double >, std::vector< double > >(x, y, keywords);
1825
1895
}
1826
1896
1827
1897
/*
0 commit comments