4
4
#include < map>
5
5
#include < numeric>
6
6
#include < stdexcept>
7
+ #include < iostream>
8
+
9
+ #if __cplusplus > 199711L
10
+ #include < functional>
11
+ #endif
7
12
8
13
#include < python2.7/Python.h>
9
14
@@ -26,7 +31,8 @@ namespace matplotlibcpp {
26
31
27
32
private:
28
33
_pyplot_global () {
29
- Py_SetProgramName (" plotting" ); /* optional but recommended */
34
+ char name[] = " plotting" ; // silence compiler warning abount const strings
35
+ Py_SetProgramName (name); // optional but recommended
30
36
Py_Initialize ();
31
37
32
38
PyObject* pyname = PyString_FromString (" matplotlib.pyplot" );
@@ -109,13 +115,16 @@ namespace matplotlibcpp {
109
115
}
110
116
111
117
112
- template <typename Numeric>
113
- bool plot (const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = " " ) {
118
+ template <typename NumericX, typename NumericY>
119
+ bool plot (const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = " " )
120
+ {
114
121
assert (x.size () == y.size ());
115
122
123
+ // std::string format(s);
124
+
116
125
PyObject* xlist = PyList_New (x.size ());
117
126
PyObject* ylist = PyList_New (y.size ());
118
- PyObject* pystring = PyString_FromString (format .c_str ());
127
+ PyObject* pystring = PyString_FromString (s .c_str ());
119
128
120
129
for (size_t i = 0 ; i < x.size (); ++i) {
121
130
PyList_SetItem (xlist, i, PyFloat_FromDouble (x.at (i)));
@@ -181,7 +190,7 @@ namespace matplotlibcpp {
181
190
* plot( {1,2,3,4} )
182
191
*/
183
192
bool plot (const std::vector<double >& x, const std::vector<double >& y, const std::string& format = " " ) {
184
- return plot<double >(x,y,format);
193
+ return plot<double , double >(x,y,format);
185
194
}
186
195
187
196
bool plot (const std::vector<double >& y, const std::string& format = " " ) {
@@ -196,6 +205,117 @@ namespace matplotlibcpp {
196
205
return named_plot<double >(name,x,y,format);
197
206
}
198
207
208
+ #if __cplusplus > 199711L
209
+
210
+ template <typename T>
211
+ using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
212
+
213
+ template <bool obj, typename T>
214
+ struct is_callable_impl ;
215
+
216
+ template <typename T>
217
+ struct is_callable_impl <false , T>
218
+ {
219
+ typedef is_function<T> type;
220
+ }; // a non-object is callable iff it is a function
221
+
222
+ template <typename T>
223
+ struct is_callable_impl <true , T>
224
+ {
225
+ struct Fallback { void operator ()(); };
226
+ struct Derived : T, Fallback { };
227
+
228
+ template <typename U, U> struct Check ;
229
+
230
+ template <typename U>
231
+ static std::true_type test ( ... ); // use a variadic function to make use (1) it accepts everything and (2) its always the worst match
232
+
233
+ template <typename U>
234
+ static std::false_type test ( Check<void (Fallback::*)(), &U::operator()>* );
235
+
236
+ public:
237
+ typedef decltype (test<Derived>(nullptr )) type;
238
+ typedef decltype (&Fallback::operator ()) dtype;
239
+ static constexpr bool value = type::value;
240
+ }; // an object is callable iff it defines operator()
241
+
242
+ template <typename T>
243
+ struct is_callable
244
+ {
245
+ // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
246
+ typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
247
+ };
248
+
249
+ template <typename IsYDataCallable>
250
+ struct plot_impl { };
251
+
252
+ template <>
253
+ struct plot_impl <std::false_type>
254
+ {
255
+ template <typename IterableX, typename IterableY>
256
+ bool operator ()(const IterableX& x, const IterableY& y, const std::string& format)
257
+ {
258
+ // It's annoying that we have to repeat the code of plot() above
259
+ auto xs = std::distance (std::begin (x), std::end (x));
260
+ auto ys = std::distance (std::begin (y), std::end (y));
261
+ assert (xs == ys && " x and y data must have the same number of elements!" );
262
+
263
+ PyObject* xlist = PyList_New (xs);
264
+ PyObject* ylist = PyList_New (ys);
265
+ PyObject* pystring = PyString_FromString (format.c_str ());
266
+
267
+ auto itx = std::begin (x), ity = std::begin (y);
268
+ for (size_t i = 0 ; i < xs; ++i) {
269
+ PyList_SetItem (xlist, i, PyFloat_FromDouble (*itx++));
270
+ PyList_SetItem (ylist, i, PyFloat_FromDouble (*ity++));
271
+ }
272
+
273
+ PyObject* plot_args = PyTuple_New (3 );
274
+ PyTuple_SetItem (plot_args, 0 , xlist);
275
+ PyTuple_SetItem (plot_args, 1 , ylist);
276
+ PyTuple_SetItem (plot_args, 2 , pystring);
277
+
278
+ PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_plot , plot_args);
279
+
280
+ Py_DECREF (xlist);
281
+ Py_DECREF (ylist);
282
+ Py_DECREF (plot_args);
283
+ if (res) Py_DECREF (res);
284
+
285
+ return res;
286
+ }
287
+ };
288
+
289
+ template <>
290
+ struct plot_impl <std::true_type>
291
+ {
292
+ template <typename Iterable, typename Callable>
293
+ bool operator ()(const Iterable& ticks, const Callable& f, const std::string& format)
294
+ {
295
+ // std::cout << "Callable impl called" << std::endl;
296
+
297
+ if (begin (ticks) == end (ticks)) return true ;
298
+
299
+ // We could use additional meta-programming to deduce the correct element type of y,
300
+ // but all values have to be convertible to double anyways
301
+ std::vector<double > y;
302
+ for (auto x : ticks) y.push_back (f (x));
303
+ return plot_impl<std::false_type>()(ticks,y,format);
304
+ }
305
+ };
306
+
307
+ // recursion stop for the above
308
+ template <typename ... Args>
309
+ bool plot () { return true ; }
310
+
311
+ template <typename A, typename B, typename ... Args>
312
+ bool plot (const A& a, const B& b, const std::string& format, Args... args)
313
+ {
314
+ return plot_impl<typename is_callable<B>::type>()(a,b,format) && plot (args...);
315
+ }
316
+
317
+ #endif
318
+
199
319
inline void legend () {
200
320
PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_legend , detail::_pyplot_global::get ().s_python_empty_tuple );
201
321
if (!res) throw std::runtime_error (" Call to legend() failed." );
0 commit comments