diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d95d46ad..dc6100fe 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -435,6 +435,47 @@ PyObject* get_listlist(const std::vector>& ll) } // namespace detail +// helper function to parse keywords dictionary +static inline std::string trim_copy(const std::string& s) { + size_t a = 0, b = s.size(); + while (a < b && std::isspace(static_cast(s[a]))) ++a; + while (b > a && std::isspace(static_cast(s[b - 1]))) --b; + return s.substr(a, b - a); +} + +static inline PyObject* kw_to_pyobject(const std::string& value_in) { + std::string s = trim_copy(value_in); + if (s.empty()) return PyUnicode_FromString(""); + + // bool / None + if (s == "True" || s == "true") return PyBool_FromLong(1); + if (s == "False"|| s == "false") return PyBool_FromLong(0); + if (s == "None" || s == "none" || s == "null") { Py_RETURN_NONE; } + + // int + { + char* end = nullptr; + errno = 0; + long long iv = std::strtoll(s.c_str(), &end, 10); + if (end && *end == '\0' && errno == 0) { + return PyLong_FromLong(iv); + } + } + + // float + { + char* end = nullptr; + errno = 0; + double dv = std::strtod(s.c_str(), &end); + if (end && *end == '\0' && errno == 0) { + return PyFloat_FromDouble(dv); + } + } + + // fallback: string + return PyUnicode_FromString(s.c_str()); +} + /// Plot a line through the given x and y data points.. /// /// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html @@ -458,7 +499,7 @@ bool plot(const std::vector &x, const std::vector &y, const st PyObject* kwargs = PyDict_New(); for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); @@ -840,7 +881,7 @@ bool fill_between(const std::vector& x, const std::vector& y1, // construct keyword args PyObject* kwargs = PyDict_New(); for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_fill_between, args, kwargs); @@ -1959,7 +2000,7 @@ inline void legend(const std::map& keywords) PyObject* kwargs = PyDict_New(); for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); @@ -2255,9 +2296,9 @@ inline void subplot(long nrows, long ncols, long plot_number) // construct positional args PyObject* args = PyTuple_New(3); - PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows)); - PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols)); - PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number)); + PyTuple_SetItem(args, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(args, 1, PyLong_FromLong(ncols)); + PyTuple_SetItem(args, 2, PyLong_FromLong(plot_number)); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); if(!res) throw std::runtime_error("Call to subplot() failed."); @@ -2303,7 +2344,7 @@ inline void title(const std::string &titlestr, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_title, args, kwargs); @@ -2438,7 +2479,7 @@ inline void xlabel(const std::string &str, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_xlabel, args, kwargs); @@ -2459,7 +2500,7 @@ inline void ylabel(const std::string &str, const std::mapfirst.c_str(), PyUnicode_FromString(it->second.c_str())); + PyDict_SetItemString(kwargs, it->first.c_str(), kw_to_pyobject(it->second.c_str())); } PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_ylabel, args, kwargs);