Skip to content

Commit aff6f64

Browse files
committed
plot can take format and keywords + add more missing _interpreter::get()
1) the basic implementation of plot takes: VectorX, VectorY, string, map. All other possibilities lead back to calling the basic implementation by providing the missing parameters. Advantage: now we can use the python-style linestyle format "ro--" and additional keywords. By-product: named_plot becomes obsolete, this is now used as: plot(x, y, "ro", {{"label", "f(x)"}}) 2) it was still possible to cause a segfault by calling xlim or ylim or title before any other function, this is fixed by adding detail::_interpreter::get() at the beginning of all these
1 parent a3580cb commit aff6f64

File tree

1 file changed

+54
-49
lines changed

1 file changed

+54
-49
lines changed

matplotlibcpp.h

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -436,38 +436,66 @@ template <typename Vector> PyObject *get_array(const Vector &v) {
436436
#endif // WITHOUT_NUMPY
437437

438438
template <typename VectorX, typename VectorY>
439-
bool plot(const VectorX &x, const VectorY &y,
440-
const std::map<std::string, std::string> &keywords) {
439+
bool plot(const VectorX &x, const VectorY &y, const std::string &s = "",
440+
const std::map<std::string, std::string> &keywords = {}) {
441441
assert(x.size() == y.size());
442442

443-
// using numpy arrays
444443
PyObject *xarray = get_array(x);
445444
PyObject *yarray = get_array(y);
446445

447-
// construct positional args
448-
PyObject *args = PyTuple_New(2);
449-
PyTuple_SetItem(args, 0, xarray);
450-
PyTuple_SetItem(args, 1, yarray);
446+
PyObject *pystring = PyString_FromString(s.c_str());
447+
448+
PyObject *plot_args = PyTuple_New(3);
449+
PyTuple_SetItem(plot_args, 0, xarray);
450+
PyTuple_SetItem(plot_args, 1, yarray);
451+
PyTuple_SetItem(plot_args, 2, pystring);
451452

452-
// construct keyword args
453453
PyObject *kwargs = PyDict_New();
454-
for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
455-
it != keywords.end(); ++it) {
456-
PyDict_SetItemString(kwargs, it->first.c_str(),
457-
PyString_FromString(it->second.c_str()));
454+
for (auto const &item : keywords) {
455+
PyDict_SetItemString(kwargs, item.first.c_str(),
456+
PyString_FromString(item.second.c_str()));
458457
}
459458

460459
PyObject *res = PyObject_Call(
461-
detail::_interpreter::get().s_python_function_plot, args, kwargs);
460+
detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
462461

463-
Py_DECREF(args);
462+
Py_DECREF(plot_args);
464463
Py_DECREF(kwargs);
465464
if (res)
466465
Py_DECREF(res);
467466

468467
return res;
469468
}
470469

470+
template <typename VectorX, typename VectorY>
471+
bool plot(const VectorX &x, const VectorY &y,
472+
const std::map<std::string, std::string> &keywords) {
473+
return plot(x, y, "", keywords);
474+
}
475+
476+
template <typename VectorY>
477+
bool plot(const VectorY &y, const std::string &format = "",
478+
const std::map<std::string, std::string> &keywords = {}) {
479+
// TODO can this be <size_t> or do we need <typename Vector::value_type>?
480+
// before the conversion of this function from vector<Numeric> to Vector
481+
// the created vector x was of the same type as y
482+
std::vector<std::size_t> x(y.size());
483+
for (std::size_t i = 0; i < x.size(); ++i)
484+
x.at(i) = i;
485+
486+
return plot(x, y, format);
487+
}
488+
489+
template <typename VectorY>
490+
bool plot(const VectorY &y,
491+
const std::map<std::string, std::string> &keywords) {
492+
std::vector<std::size_t> x(y.size());
493+
for (std::size_t i = 0; i < x.size(); ++i)
494+
x.at(i) = i;
495+
496+
return plot(x, y, "", keywords);
497+
}
498+
471499
template <typename Numeric>
472500
void plot_surface(const std::vector<::std::vector<Numeric>> &x,
473501
const std::vector<::std::vector<Numeric>> &y,
@@ -810,30 +838,6 @@ bool named_hist(std::string label, const std::vector<Numeric> &y,
810838
return res;
811839
}
812840

813-
template <typename VectorX, typename VectorY>
814-
bool plot(const VectorX &x, const VectorY &y, const std::string &s = "") {
815-
assert(x.size() == y.size());
816-
817-
PyObject *xarray = get_array(x);
818-
PyObject *yarray = get_array(y);
819-
820-
PyObject *pystring = PyString_FromString(s.c_str());
821-
822-
PyObject *plot_args = PyTuple_New(3);
823-
PyTuple_SetItem(plot_args, 0, xarray);
824-
PyTuple_SetItem(plot_args, 1, yarray);
825-
PyTuple_SetItem(plot_args, 2, pystring);
826-
827-
PyObject *res = PyObject_CallObject(
828-
detail::_interpreter::get().s_python_function_plot, plot_args);
829-
830-
Py_DECREF(plot_args);
831-
if (res)
832-
Py_DECREF(res);
833-
834-
return res;
835-
}
836-
837841
template <typename NumericX, typename NumericY, typename NumericU,
838842
typename NumericW>
839843
bool quiver(const std::vector<NumericX> &x, const std::vector<NumericY> &y,
@@ -1174,17 +1178,6 @@ bool named_loglog(const std::string &name, const std::vector<Numeric> &x,
11741178
return res;
11751179
}
11761180

1177-
template <typename Vector>
1178-
bool plot(const Vector &y, const std::string &format = "") {
1179-
// TODO can this be <size_t> or do we need <typename Vector::value_type>?
1180-
// before the conversion of this function from vector<Numeric> to Vector
1181-
// the created vector x was of the same type as y
1182-
std::vector<size_t> x(y.size());
1183-
for (size_t i = 0; i < x.size(); ++i)
1184-
x.at(i) = i;
1185-
return plot(x, y, format);
1186-
}
1187-
11881181
template <typename Numeric>
11891182
bool stem(const std::vector<Numeric> &y, const std::string &format = "") {
11901183
std::vector<Numeric> x(y.size());
@@ -1287,6 +1280,8 @@ inline void figure_size(size_t w, size_t h) {
12871280
}
12881281

12891282
inline void legend() {
1283+
detail::_interpreter::get();
1284+
12901285
PyObject *res =
12911286
PyObject_CallObject(detail::_interpreter::get().s_python_function_legend,
12921287
detail::_interpreter::get().s_python_empty_tuple);
@@ -1297,6 +1292,8 @@ inline void legend() {
12971292
}
12981293

12991294
template <typename Numeric> void ylim(Numeric left, Numeric right) {
1295+
detail::_interpreter::get();
1296+
13001297
PyObject *list = PyList_New(2);
13011298
PyList_SetItem(list, 0, PyFloat_FromDouble(left));
13021299
PyList_SetItem(list, 1, PyFloat_FromDouble(right));
@@ -1314,6 +1311,8 @@ template <typename Numeric> void ylim(Numeric left, Numeric right) {
13141311
}
13151312

13161313
template <typename Numeric> void xlim(Numeric left, Numeric right) {
1314+
detail::_interpreter::get();
1315+
13171316
PyObject *list = PyList_New(2);
13181317
PyList_SetItem(list, 0, PyFloat_FromDouble(left));
13191318
PyList_SetItem(list, 1, PyFloat_FromDouble(right));
@@ -1331,6 +1330,8 @@ template <typename Numeric> void xlim(Numeric left, Numeric right) {
13311330
}
13321331

13331332
inline double *xlim() {
1333+
detail::_interpreter::get();
1334+
13341335
PyObject *args = PyTuple_New(0);
13351336
PyObject *res = PyObject_CallObject(
13361337
detail::_interpreter::get().s_python_function_xlim, args);
@@ -1349,6 +1350,8 @@ inline double *xlim() {
13491350
}
13501351

13511352
inline double *ylim() {
1353+
detail::_interpreter::get();
1354+
13521355
PyObject *args = PyTuple_New(0);
13531356
PyObject *res = PyObject_CallObject(
13541357
detail::_interpreter::get().s_python_function_ylim, args);
@@ -1488,6 +1491,8 @@ inline void subplot(long nrows, long ncols, long plot_number) {
14881491

14891492
inline void title(const std::string &titlestr,
14901493
const std::map<std::string, std::string> &keywords = {}) {
1494+
detail::_interpreter::get();
1495+
14911496
PyObject *pytitlestr = PyString_FromString(titlestr.c_str());
14921497
PyObject *args = PyTuple_New(1);
14931498
PyTuple_SetItem(args, 0, pytitlestr);

0 commit comments

Comments
 (0)