2424#include < numeric>
2525#include < stdexcept>
2626#include < vector>
27+ #include < sstream>
2728
2829#include < Python.h>
2930
@@ -231,24 +232,23 @@ struct _interpreter {
231232 !s_python_function_draw || !s_python_function_pause ||
232233 !s_python_function_figure || !s_python_function_fignum_exists ||
233234 !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) {
252252 throw std::runtime_error (" Couldn't find required function!" );
253253 }
254254
@@ -303,6 +303,24 @@ struct _interpreter {
303303 ~_interpreter () { Py_Finalize (); }
304304};
305305
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+
306324} // end namespace detail
307325
308326// 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) {
429447}
430448
431449// 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) {
434451 detail::_interpreter::get (); // interpreter needs to be initialized for the
435452 // numpy commands to work
436453 if (A.size () < 1 )
@@ -455,8 +472,7 @@ PyObject *get_2darray(const Matrix &A) {
455472
456473#else // fallback if we don't have numpy: copy every element of the given vector
457474
458- template <typename Vector>
459- PyObject *get_array (const Vector &v) {
475+ template <typename Vector> PyObject *get_array (const Vector &v) {
460476 detail::_interpreter::get ();
461477 PyObject *list = PyList_New (v.size ());
462478 for (size_t i = 0 ; i < v.size (); ++i) {
@@ -666,7 +682,7 @@ bool semilogy(const VectorY &y,
666682// @param z The function value of the datapoints in a matrix
667683// @param keywords Additional keywords
668684template <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,
670686 const std::map<std::string, std::string> &keywords =
671687 std::map<std::string, std::string>()) {
672688 // 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,
765781 Py_DECREF (res);
766782}
767783
768-
769784// @brief plot_surface for datapoints (x_ij, y_ij, z_ij) with i,j = 0..n
770785// @param x The x values of the datapoints in a matrix
771786// @param y The y values of the datapoints in a matrix
772787// @param z The function value of the datapoints in a matrix
773788// @param keywords Additional keywords
774789template <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,
776791 const std::map<std::string, std::string> &keywords = {}) {
777792 detail::_interpreter::get ();
778793
@@ -801,8 +816,8 @@ void contour(const Matrix &x, const Matrix& y, const Matrix& z,
801816 PyString_FromString (it->second .c_str ()));
802817 }
803818
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);
806821 if (!res)
807822 throw std::runtime_error (" failed surface" );
808823
@@ -980,18 +995,17 @@ bool scatter(const VectorX &x, const VectorY &y, const double s = 1.0,
980995
981996template <typename VectorX, typename VectorY>
982997bool 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) {
984999 return scatter (x, y, 1.0 , keywords);
9851000}
9861001
987-
9881002// @brief Spy plot
9891003// @param A the matrix
9901004// @param precision Plot all elements above `|precision|`
9911005// @param keywords Additional keywords
9921006template <typename Matrix>
9931007bool spy (const Matrix &A,
994- const std::map<std::string, std::string>& keywords = {}) {
1008+ const std::map<std::string, std::string> & keywords = {}) {
9951009 PyObject *Aarray = get_2darray (A);
9961010
9971011 PyObject *kwargs = PyDict_New ();
@@ -1048,7 +1062,8 @@ bool bar(const std::vector<Numeric> &y, std::string ec = "black",
10481062 return res;
10491063}
10501064
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 = {}) {
10521067
10531068 PyObject *kwargs = PyDict_New ();
10541069 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,
12171232}
12181233
12191234template <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,
12221236 const std::map<std::string, std::string> &keywords = {}) {
12231237 assert (x.size () == y.size ());
12241238
@@ -1359,7 +1373,7 @@ inline void figure_size(size_t w, size_t h) {
13591373template <typename Vector = std::vector<double >>
13601374inline void legend (const std::string &loc = " best" ,
13611375 const Vector &bbox_to_anchor = Vector(),
1362- const std::map<std::string, std::string>& keywords = {}) {
1376+ const std::map<std::string, std::string> & keywords = {}) {
13631377 detail::_interpreter::get ();
13641378
13651379 PyObject *kwargs = PyDict_New ();
@@ -1375,11 +1389,7 @@ inline void legend(const std::string &loc = "best",
13751389 }
13761390
13771391 // 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);
13831393
13841394 PyObject *res =
13851395 PyObject_Call (detail::_interpreter::get ().s_python_function_legend ,
@@ -1394,11 +1404,23 @@ inline void legend(const std::string &loc = "best",
13941404}
13951405
13961406template <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 = {}) {
13991409 legend (" " , bbox_to_anchor, keywords);
14001410}
14011411
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+
14021424/*
14031425inline void legend(const std::string& loc,
14041426 const std::map<std::string, std::string>& keywords = {}) {
@@ -1410,8 +1432,7 @@ inline void legend(const std::map<std::string, std::string>& keywords) {
14101432}
14111433*/
14121434
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) {
14151436 detail::_interpreter::get ();
14161437
14171438 PyObject *list = PyList_New (2 );
@@ -1430,8 +1451,7 @@ void ylim(const Numeric bottom, const Numeric top) {
14301451 Py_DECREF (res);
14311452}
14321453
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) {
14351455 detail::_interpreter::get ();
14361456
14371457 PyObject *list = PyList_New (2 );
0 commit comments