@@ -53,6 +53,8 @@ struct _interpreter {
5353 PyObject *s_python_function_fignum_exists;
5454 PyObject *s_python_function_plot;
5555 PyObject *s_python_function_quiver;
56+ PyObject *s_python_function_axhline;
57+ PyObject *s_python_function_axvline;
5658 PyObject *s_python_function_semilogx;
5759 PyObject *s_python_function_semilogy;
5860 PyObject *s_python_function_loglog;
@@ -182,6 +184,8 @@ struct _interpreter {
182184 PyObject_GetAttrString (pymod, " fignum_exists" );
183185 s_python_function_plot = PyObject_GetAttrString (pymod, " plot" );
184186 s_python_function_quiver = PyObject_GetAttrString (pymod, " quiver" );
187+ s_python_function_axhline = PyObject_GetAttrString (pymod, " axhline" );
188+ s_python_function_axvline = PyObject_GetAttrString (pymod, " axvline" );
185189 s_python_function_semilogx = PyObject_GetAttrString (pymod, " semilogx" );
186190 s_python_function_semilogy = PyObject_GetAttrString (pymod, " semilogy" );
187191 s_python_function_loglog = PyObject_GetAttrString (pymod, " loglog" );
@@ -1063,6 +1067,64 @@ bool quiver(const std::vector<NumericX> &x, const std::vector<NumericY> &y,
10631067 return res;
10641068}
10651069
1070+ template <typename NumericY>
1071+ void axhline (const NumericY y,
1072+ const std::map<std::string, std::string> keywords = {}) {
1073+ detail::_interpreter::get ();
1074+
1075+ PyObject *kwargs = PyDict_New ();
1076+
1077+ // add location
1078+ PyDict_SetItemString (kwargs, " y" , PyFloat_FromDouble (y));
1079+
1080+ // add other keywords
1081+ for (std::map<std::string, std::string>::const_iterator it = keywords.begin ();
1082+ it != keywords.end (); ++it) {
1083+ PyDict_SetItemString (kwargs, it->first .c_str (),
1084+ PyUnicode_FromString (it->second .c_str ()));
1085+ }
1086+
1087+ PyObject *res =
1088+ PyObject_Call (detail::_interpreter::get ().s_python_function_axhline ,
1089+ detail::_interpreter::get ().s_python_empty_tuple , kwargs);
1090+
1091+ Py_DECREF (kwargs);
1092+
1093+ if (!res)
1094+ throw std::runtime_error (" Call to axhline() failed." );
1095+
1096+ Py_DECREF (res);
1097+ }
1098+
1099+ template <typename NumericX>
1100+ void axvline (const NumericX x,
1101+ const std::map<std::string, std::string> keywords = {}) {
1102+ detail::_interpreter::get ();
1103+
1104+ PyObject *kwargs = PyDict_New ();
1105+
1106+ // add location
1107+ PyDict_SetItemString (kwargs, " x" , PyFloat_FromDouble (x));
1108+
1109+ // add other keywords
1110+ for (std::map<std::string, std::string>::const_iterator it = keywords.begin ();
1111+ it != keywords.end (); ++it) {
1112+ PyDict_SetItemString (kwargs, it->first .c_str (),
1113+ PyUnicode_FromString (it->second .c_str ()));
1114+ }
1115+
1116+ PyObject *res =
1117+ PyObject_Call (detail::_interpreter::get ().s_python_function_axvline ,
1118+ detail::_interpreter::get ().s_python_empty_tuple , kwargs);
1119+
1120+ Py_DECREF (kwargs);
1121+
1122+ if (!res)
1123+ throw std::runtime_error (" Call to axvline() failed." );
1124+
1125+ Py_DECREF (res);
1126+ }
1127+
10661128template <typename NumericX, typename NumericY>
10671129bool stem (const std::vector<NumericX> &x, const std::vector<NumericY> &y,
10681130 const std::string &s = " " ) {
@@ -1230,17 +1292,29 @@ inline void figure_size(size_t w, size_t h) {
12301292
12311293template <typename Vector = std::vector<double >>
12321294inline void legend (const std::string &loc = " best" ,
1233- const Vector &bbox_to_anchor = Vector()) {
1295+ const Vector &bbox_to_anchor = Vector(),
1296+ const std::map<std::string, std::string>& keywords = {}) {
12341297 detail::_interpreter::get ();
12351298
12361299 PyObject *kwargs = PyDict_New ();
1237- PyDict_SetItemString (kwargs, " loc" , PyString_FromString (loc.c_str ()));
12381300
1301+ // add location
1302+ if (loc != " " )
1303+ PyDict_SetItemString (kwargs, " loc" , PyString_FromString (loc.c_str ()));
1304+
1305+ // add bbox to anchor
12391306 if (bbox_to_anchor.size () == 2 || bbox_to_anchor.size () == 4 ) {
12401307 PyObject *bbox = get_array (bbox_to_anchor);
12411308 PyDict_SetItemString (kwargs, " bbox_to_anchor" , bbox);
12421309 }
12431310
1311+ // add other keywords
1312+ for (std::map<std::string, std::string>::const_iterator it = keywords.begin ();
1313+ it != keywords.end (); ++it) {
1314+ PyDict_SetItemString (kwargs, it->first .c_str (),
1315+ PyUnicode_FromString (it->second .c_str ()));
1316+ }
1317+
12441318 PyObject *res =
12451319 PyObject_Call (detail::_interpreter::get ().s_python_function_legend ,
12461320 detail::_interpreter::get ().s_python_empty_tuple , kwargs);
@@ -1253,7 +1327,25 @@ inline void legend(const std::string &loc = "best",
12531327 Py_DECREF (res);
12541328}
12551329
1256- template <typename Numeric> void ylim (Numeric bottom, Numeric top) {
1330+ template <typename Vector>
1331+ inline void legend (const Vector& bbox_to_anchor,
1332+ const std::map<std::string, std::string>& keywords = {}) {
1333+ legend (" " , bbox_to_anchor, keywords);
1334+ }
1335+
1336+ /*
1337+ inline void legend(const std::string& loc,
1338+ const std::map<std::string, std::string>& keywords = {}) {
1339+ legend(loc, std::vector<double>(), keywords);
1340+ }
1341+
1342+ inline void legend(const std::map<std::string, std::string>& keywords) {
1343+ legend("", std::vector<double>(), keywords);
1344+ }
1345+ */
1346+
1347+ template <typename Numeric>
1348+ void ylim (const Numeric bottom, const Numeric top) {
12571349 detail::_interpreter::get ();
12581350
12591351 PyObject *list = PyList_New (2 );
@@ -1272,7 +1364,8 @@ template <typename Numeric> void ylim(Numeric bottom, Numeric top) {
12721364 Py_DECREF (res);
12731365}
12741366
1275- template <typename Numeric> void xlim (Numeric left, Numeric right) {
1367+ template <typename Numeric>
1368+ void xlim (const Numeric left, const Numeric right) {
12761369 detail::_interpreter::get ();
12771370
12781371 PyObject *list = PyList_New (2 );
@@ -1751,11 +1844,8 @@ bool plot(const A &a, const B &b, const std::string &format, Args... args) {
17511844 return plot (a, b, format) && plot (args...);
17521845}
17531846
1754- /*
1755- * This class allows dynamic plots, ie changing the plotted data without
1756- * clearing and re-plotting
1757- */
1758-
1847+ // This class allows dynamic plots, ie changing the plotted data without
1848+ // clearing and re-plotting
17591849class Plot {
17601850public:
17611851 // default initialization with plot label, some data and format
0 commit comments