@@ -47,6 +47,7 @@ struct _interpreter {
47
47
PyObject *s_python_function_legend;
48
48
PyObject *s_python_function_xlim;
49
49
PyObject *s_python_function_ion;
50
+ PyObject *s_python_function_ginput;
50
51
PyObject *s_python_function_ylim;
51
52
PyObject *s_python_function_title;
52
53
PyObject *s_python_function_axis;
@@ -62,6 +63,8 @@ struct _interpreter {
62
63
PyObject *s_python_empty_tuple;
63
64
PyObject *s_python_function_stem;
64
65
PyObject *s_python_function_xkcd;
66
+ PyObject *s_python_function_text;
67
+ PyObject *s_python_function_suptitle;
65
68
66
69
/* For now, _interpreter is implemented as a singleton since its currently not possible to have
67
70
multiple independent embedded python interpreters without patching the python source code
@@ -158,13 +161,16 @@ struct _interpreter {
158
161
s_python_function_grid = PyObject_GetAttrString (pymod, " grid" );
159
162
s_python_function_xlim = PyObject_GetAttrString (pymod, " xlim" );
160
163
s_python_function_ion = PyObject_GetAttrString (pymod, " ion" );
164
+ s_python_function_ginput = PyObject_GetAttrString (pymod, " ginput" );
161
165
s_python_function_save = PyObject_GetAttrString (pylabmod, " savefig" );
162
166
s_python_function_annotate = PyObject_GetAttrString (pymod," annotate" );
163
167
s_python_function_clf = PyObject_GetAttrString (pymod, " clf" );
164
168
s_python_function_errorbar = PyObject_GetAttrString (pymod, " errorbar" );
165
169
s_python_function_tight_layout = PyObject_GetAttrString (pymod, " tight_layout" );
166
170
s_python_function_stem = PyObject_GetAttrString (pymod, " stem" );
167
171
s_python_function_xkcd = PyObject_GetAttrString (pymod, " xkcd" );
172
+ s_python_function_text = PyObject_GetAttrString (pymod, " text" );
173
+ s_python_function_suptitle = PyObject_GetAttrString (pymod, " suptitle" );
168
174
169
175
if ( !s_python_function_show
170
176
|| !s_python_function_close
@@ -187,6 +193,7 @@ struct _interpreter {
187
193
|| !s_python_function_grid
188
194
|| !s_python_function_xlim
189
195
|| !s_python_function_ion
196
+ || !s_python_function_ginput
190
197
|| !s_python_function_save
191
198
|| !s_python_function_clf
192
199
|| !s_python_function_annotate
@@ -195,6 +202,8 @@ struct _interpreter {
195
202
|| !s_python_function_tight_layout
196
203
|| !s_python_function_stem
197
204
|| !s_python_function_xkcd
205
+ || !s_python_function_text
206
+ || !s_python_function_suptitle
198
207
) { throw std::runtime_error (" Couldn't find required function!" ); }
199
208
200
209
if ( !PyFunction_Check (s_python_function_show)
@@ -219,12 +228,15 @@ struct _interpreter {
219
228
|| !PyFunction_Check (s_python_function_grid)
220
229
|| !PyFunction_Check (s_python_function_xlim)
221
230
|| !PyFunction_Check (s_python_function_ion)
231
+ || !PyFunction_Check (s_python_function_ginput)
222
232
|| !PyFunction_Check (s_python_function_save)
223
233
|| !PyFunction_Check (s_python_function_clf)
224
234
|| !PyFunction_Check (s_python_function_tight_layout)
225
235
|| !PyFunction_Check (s_python_function_errorbar)
226
236
|| !PyFunction_Check (s_python_function_stem)
227
237
|| !PyFunction_Check (s_python_function_xkcd)
238
+ || !PyFunction_Check (s_python_function_text)
239
+ || !PyFunction_Check (s_python_function_suptitle)
228
240
) { throw std::runtime_error (" Python object is unexpectedly not a PyFunction." ); }
229
241
230
242
s_python_empty_tuple = PyTuple_New (0 );
@@ -511,6 +523,7 @@ bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y, cons
511
523
PyObject* res = PyObject_Call (
512
524
detail::_interpreter::get ().s_python_function_quiver , plot_args, kwargs);
513
525
526
+ Py_DECREF (kwargs);
514
527
Py_DECREF (plot_args);
515
528
if (res)
516
529
Py_DECREF (res);
@@ -787,6 +800,22 @@ bool stem(const std::vector<Numeric>& y, const std::string& format = "")
787
800
return stem (x, y, format);
788
801
}
789
802
803
+ template <typename Numeric>
804
+ void text (Numeric x, Numeric y, const std::string& s = " " )
805
+ {
806
+ PyObject* args = PyTuple_New (3 );
807
+ PyTuple_SetItem (args, 0 , PyFloat_FromDouble (x));
808
+ PyTuple_SetItem (args, 1 , PyFloat_FromDouble (y));
809
+ PyTuple_SetItem (args, 2 , PyString_FromString (s.c_str ()));
810
+
811
+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_text , args);
812
+ if (!res) throw std::runtime_error (" Call to text() failed." );
813
+
814
+ Py_DECREF (args);
815
+ Py_DECREF (res);
816
+ }
817
+
818
+
790
819
inline void figure ()
791
820
{
792
821
PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_figure , detail::_interpreter::get ().s_python_empty_tuple );
@@ -1015,6 +1044,19 @@ inline void title(const std::string &titlestr)
1015
1044
Py_DECREF (res);
1016
1045
}
1017
1046
1047
+ inline void suptitle (const std::string &suptitlestr)
1048
+ {
1049
+ PyObject* pysuptitlestr = PyString_FromString (suptitlestr.c_str ());
1050
+ PyObject* args = PyTuple_New (1 );
1051
+ PyTuple_SetItem (args, 0 , pysuptitlestr);
1052
+
1053
+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_suptitle , args);
1054
+ if (!res) throw std::runtime_error (" Call to suptitle() failed." );
1055
+
1056
+ Py_DECREF (args);
1057
+ Py_DECREF (res);
1058
+ }
1059
+
1018
1060
inline void axis (const std::string &axisstr)
1019
1061
{
1020
1062
PyObject* str = PyString_FromString (axisstr.c_str ());
@@ -1176,6 +1218,40 @@ inline void clf() {
1176
1218
Py_DECREF (res);
1177
1219
}
1178
1220
1221
+ inline std::vector<std::array<double , 2 >> ginput (const int numClicks = 1 , const std::map<std::string, std::string>& keywords = {})
1222
+ {
1223
+ PyObject *args = PyTuple_New (1 );
1224
+ PyTuple_SetItem (args, 0 , PyLong_FromLong (numClicks));
1225
+
1226
+ // construct keyword args
1227
+ PyObject* kwargs = PyDict_New ();
1228
+ for (std::map<std::string, std::string>::const_iterator it = keywords.begin (); it != keywords.end (); ++it)
1229
+ {
1230
+ PyDict_SetItemString (kwargs, it->first .c_str (), PyUnicode_FromString (it->second .c_str ()));
1231
+ }
1232
+
1233
+ PyObject* res = PyObject_Call (
1234
+ detail::_interpreter::get ().s_python_function_ginput , args, kwargs);
1235
+
1236
+ Py_DECREF (kwargs);
1237
+ Py_DECREF (args);
1238
+ if (!res) throw std::runtime_error (" Call to ginput() failed." );
1239
+
1240
+ const size_t len = PyList_Size (res);
1241
+ std::vector<std::array<double , 2 >> out;
1242
+ out.reserve (len);
1243
+ for (size_t i = 0 ; i < len; i++) {
1244
+ PyObject *current = PyList_GetItem (res, i);
1245
+ std::array<double , 2 > position;
1246
+ position[0 ] = PyFloat_AsDouble (PyTuple_GetItem (current, 0 ));
1247
+ position[1 ] = PyFloat_AsDouble (PyTuple_GetItem (current, 1 ));
1248
+ out.push_back (position);
1249
+ }
1250
+ Py_DECREF (res);
1251
+
1252
+ return out;
1253
+ }
1254
+
1179
1255
// Actually, is there any reason not to call this automatically for every plot?
1180
1256
inline void tight_layout () {
1181
1257
PyObject *res = PyObject_CallObject (
0 commit comments