24
24
#include < numeric>
25
25
#include < stdexcept>
26
26
#include < vector>
27
+ #include < sstream>
27
28
28
29
#include < Python.h>
29
30
@@ -231,24 +232,23 @@ struct _interpreter {
231
232
!s_python_function_draw || !s_python_function_pause ||
232
233
!s_python_function_figure || !s_python_function_fignum_exists ||
233
234
!s_python_function_plot || !s_python_function_quiver ||
234
- !s_python_function_contour ||
235
- !s_python_function_semilogx || !s_python_function_semilogy ||
236
- !s_python_function_loglog || !s_python_function_fill ||
237
- !s_python_function_fill_between || !s_python_function_subplot ||
238
- !s_python_function_legend || !s_python_function_ylim ||
239
- !s_python_function_title || !s_python_function_axis ||
240
- !s_python_function_xlabel || !s_python_function_ylabel ||
241
- !s_python_function_xticks || !s_python_function_yticks ||
242
- !s_python_function_xscale || !s_python_function_yscale ||
243
- !s_python_function_grid || !s_python_function_xlim ||
244
- !s_python_function_ion || !s_python_function_ginput ||
245
- !s_python_function_save || !s_python_function_clf ||
246
- !s_python_function_annotate || !s_python_function_errorbar ||
247
- !s_python_function_errorbar || !s_python_function_tight_layout ||
248
- !s_python_function_stem || !s_python_function_xkcd ||
249
- !s_python_function_text || !s_python_function_suptitle ||
250
- !s_python_function_bar || !s_python_function_subplots_adjust ||
251
- !s_python_function_spy) {
235
+ !s_python_function_contour || !s_python_function_semilogx ||
236
+ !s_python_function_semilogy || !s_python_function_loglog ||
237
+ !s_python_function_fill || !s_python_function_fill_between ||
238
+ !s_python_function_subplot || !s_python_function_legend ||
239
+ !s_python_function_ylim || !s_python_function_title ||
240
+ !s_python_function_axis || !s_python_function_xlabel ||
241
+ !s_python_function_ylabel || !s_python_function_xticks ||
242
+ !s_python_function_yticks || !s_python_function_xscale ||
243
+ !s_python_function_yscale || !s_python_function_grid ||
244
+ !s_python_function_xlim || !s_python_function_ion ||
245
+ !s_python_function_ginput || !s_python_function_save ||
246
+ !s_python_function_clf || !s_python_function_annotate ||
247
+ !s_python_function_errorbar || !s_python_function_errorbar ||
248
+ !s_python_function_tight_layout || !s_python_function_stem ||
249
+ !s_python_function_xkcd || !s_python_function_text ||
250
+ !s_python_function_suptitle || !s_python_function_bar ||
251
+ !s_python_function_subplots_adjust || !s_python_function_spy) {
252
252
throw std::runtime_error (" Couldn't find required function!" );
253
253
}
254
254
@@ -303,6 +303,24 @@ struct _interpreter {
303
303
~_interpreter () { Py_Finalize (); }
304
304
};
305
305
306
+ void process_keywords (PyObject *kwargs,
307
+ const std::map<std::string, std::string> &keywords) {
308
+ for (auto const &item : keywords) {
309
+ // check if the keyword is a number
310
+ try {
311
+ std::stringstream ss (item.second );
312
+ double d;
313
+ ss >> d;
314
+ PyDict_SetItemString (kwargs, item.first .c_str (), PyFloat_FromDouble (d));
315
+ }
316
+ // if its not, then leave it as string
317
+ catch (std::exception& e) {
318
+ PyDict_SetItemString (kwargs, item.first .c_str (),
319
+ PyString_FromString (item.second .c_str ()));
320
+ }
321
+ }
322
+ }
323
+
306
324
} // end namespace detail
307
325
308
326
// must be called before the first regular call to matplotlib to have any effect
@@ -429,8 +447,7 @@ PyObject *get_2darray(const std::vector<::std::vector<Numeric>> &v) {
429
447
}
430
448
431
449
// suitable for more general matrices (especially Eigen matrices)
432
- template <typename Matrix>
433
- PyObject *get_2darray (const Matrix &A) {
450
+ template <typename Matrix> PyObject *get_2darray (const Matrix &A) {
434
451
detail::_interpreter::get (); // interpreter needs to be initialized for the
435
452
// numpy commands to work
436
453
if (A.size () < 1 )
@@ -455,8 +472,7 @@ PyObject *get_2darray(const Matrix &A) {
455
472
456
473
#else // fallback if we don't have numpy: copy every element of the given vector
457
474
458
- template <typename Vector>
459
- PyObject *get_array (const Vector &v) {
475
+ template <typename Vector> PyObject *get_array (const Vector &v) {
460
476
detail::_interpreter::get ();
461
477
PyObject *list = PyList_New (v.size ());
462
478
for (size_t i = 0 ; i < v.size (); ++i) {
@@ -666,7 +682,7 @@ bool semilogy(const VectorY &y,
666
682
// @param z The function value of the datapoints in a matrix
667
683
// @param keywords Additional keywords
668
684
template <typename Matrix>
669
- void plot_surface (const Matrix &x, const Matrix& y, const Matrix& z,
685
+ void plot_surface (const Matrix &x, const Matrix & y, const Matrix & z,
670
686
const std::map<std::string, std::string> &keywords =
671
687
std::map<std::string, std::string>()) {
672
688
// We lazily load the modules here the first time this function is called
@@ -765,14 +781,13 @@ void plot_surface(const Matrix &x, const Matrix& y, const Matrix& z,
765
781
Py_DECREF (res);
766
782
}
767
783
768
-
769
784
// @brief plot_surface for datapoints (x_ij, y_ij, z_ij) with i,j = 0..n
770
785
// @param x The x values of the datapoints in a matrix
771
786
// @param y The y values of the datapoints in a matrix
772
787
// @param z The function value of the datapoints in a matrix
773
788
// @param keywords Additional keywords
774
789
template <typename Matrix>
775
- void contour (const Matrix &x, const Matrix& y, const Matrix& z,
790
+ void contour (const Matrix &x, const Matrix & y, const Matrix & z,
776
791
const std::map<std::string, std::string> &keywords = {}) {
777
792
detail::_interpreter::get ();
778
793
@@ -801,8 +816,8 @@ void contour(const Matrix &x, const Matrix& y, const Matrix& z,
801
816
PyString_FromString (it->second .c_str ()));
802
817
}
803
818
804
- PyObject *res = PyObject_Call (detail::_interpreter::get (). s_python_function_contour ,
805
- args, kwargs);
819
+ PyObject *res = PyObject_Call (
820
+ detail::_interpreter::get (). s_python_function_contour , args, kwargs);
806
821
if (!res)
807
822
throw std::runtime_error (" failed surface" );
808
823
@@ -980,18 +995,17 @@ bool scatter(const VectorX &x, const VectorY &y, const double s = 1.0,
980
995
981
996
template <typename VectorX, typename VectorY>
982
997
bool scatter (const VectorX &x, const VectorY &y,
983
- const std::map<std::string, std::string>& keywords) {
998
+ const std::map<std::string, std::string> & keywords) {
984
999
return scatter (x, y, 1.0 , keywords);
985
1000
}
986
1001
987
-
988
1002
// @brief Spy plot
989
1003
// @param A the matrix
990
1004
// @param precision Plot all elements above `|precision|`
991
1005
// @param keywords Additional keywords
992
1006
template <typename Matrix>
993
1007
bool spy (const Matrix &A,
994
- const std::map<std::string, std::string>& keywords = {}) {
1008
+ const std::map<std::string, std::string> & keywords = {}) {
995
1009
PyObject *Aarray = get_2darray (A);
996
1010
997
1011
PyObject *kwargs = PyDict_New ();
@@ -1048,7 +1062,8 @@ bool bar(const std::vector<Numeric> &y, std::string ec = "black",
1048
1062
return res;
1049
1063
}
1050
1064
1051
- inline bool subplots_adjust (const std::map<std::string, double > &keywords = {}) {
1065
+ inline bool
1066
+ subplots_adjust (const std::map<std::string, double > &keywords = {}) {
1052
1067
1053
1068
PyObject *kwargs = PyDict_New ();
1054
1069
for (std::map<std::string, double >::const_iterator it = keywords.begin ();
@@ -1217,8 +1232,7 @@ bool stem(const std::vector<NumericX> &x, const std::vector<NumericY> &y,
1217
1232
}
1218
1233
1219
1234
template <typename VectorX, typename VectorY>
1220
- bool errorbar (const VectorX &x, const VectorY &y,
1221
- const VectorY &yerr,
1235
+ bool errorbar (const VectorX &x, const VectorY &y, const VectorY &yerr,
1222
1236
const std::map<std::string, std::string> &keywords = {}) {
1223
1237
assert (x.size () == y.size ());
1224
1238
@@ -1359,7 +1373,7 @@ inline void figure_size(size_t w, size_t h) {
1359
1373
template <typename Vector = std::vector<double >>
1360
1374
inline void legend (const std::string &loc = " best" ,
1361
1375
const Vector &bbox_to_anchor = Vector(),
1362
- const std::map<std::string, std::string>& keywords = {}) {
1376
+ const std::map<std::string, std::string> & keywords = {}) {
1363
1377
detail::_interpreter::get ();
1364
1378
1365
1379
PyObject *kwargs = PyDict_New ();
@@ -1375,11 +1389,7 @@ inline void legend(const std::string &loc = "best",
1375
1389
}
1376
1390
1377
1391
// add other keywords
1378
- for (std::map<std::string, std::string>::const_iterator it = keywords.begin ();
1379
- it != keywords.end (); ++it) {
1380
- PyDict_SetItemString (kwargs, it->first .c_str (),
1381
- PyUnicode_FromString (it->second .c_str ()));
1382
- }
1392
+ detail::process_keywords (kwargs, keywords);
1383
1393
1384
1394
PyObject *res =
1385
1395
PyObject_Call (detail::_interpreter::get ().s_python_function_legend ,
@@ -1394,11 +1404,23 @@ inline void legend(const std::string &loc = "best",
1394
1404
}
1395
1405
1396
1406
template <typename Vector>
1397
- inline void legend (const Vector& bbox_to_anchor,
1398
- const std::map<std::string, std::string>& keywords = {}) {
1407
+ inline void legend (const Vector & bbox_to_anchor,
1408
+ const std::map<std::string, std::string> & keywords = {}) {
1399
1409
legend (" " , bbox_to_anchor, keywords);
1400
1410
}
1401
1411
1412
+ inline void legend (const std::string &loc,
1413
+ const std::map<std::string, std::string> &keywords = {}) {
1414
+ legend (loc, std::vector<double >(), keywords);
1415
+ }
1416
+
1417
+ // to support C-style strings we also need const char[], std::string only
1418
+ // does not capture calls of style legend("lower left")
1419
+ inline void legend (const char loc[],
1420
+ const std::map<std::string, std::string> &keywords = {}) {
1421
+ legend (loc, std::vector<double >(), keywords);
1422
+ }
1423
+
1402
1424
/*
1403
1425
inline void legend(const std::string& loc,
1404
1426
const std::map<std::string, std::string>& keywords = {}) {
@@ -1410,8 +1432,7 @@ inline void legend(const std::map<std::string, std::string>& keywords) {
1410
1432
}
1411
1433
*/
1412
1434
1413
- template <typename Numeric>
1414
- void ylim (const Numeric bottom, const Numeric top) {
1435
+ template <typename Numeric> void ylim (const Numeric bottom, const Numeric top) {
1415
1436
detail::_interpreter::get ();
1416
1437
1417
1438
PyObject *list = PyList_New (2 );
@@ -1430,8 +1451,7 @@ void ylim(const Numeric bottom, const Numeric top) {
1430
1451
Py_DECREF (res);
1431
1452
}
1432
1453
1433
- template <typename Numeric>
1434
- void xlim (const Numeric left, const Numeric right) {
1454
+ template <typename Numeric> void xlim (const Numeric left, const Numeric right) {
1435
1455
detail::_interpreter::get ();
1436
1456
1437
1457
PyObject *list = PyList_New (2 );
0 commit comments