Skip to content

Commit ccbcfc1

Browse files
author
Benno Evers
committed
Cleanup and documentation changes
1 parent 029a613 commit ccbcfc1

File tree

1 file changed

+136
-124
lines changed

1 file changed

+136
-124
lines changed

matplotlibcpp.h

Lines changed: 136 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
namespace matplotlibcpp {
1616

1717
namespace detail {
18-
struct _pyplot_global {
18+
struct _interpreter {
1919
PyObject *s_python_function_show;
2020
PyObject *s_python_function_figure;
2121
PyObject *s_python_function_plot;
@@ -24,13 +24,20 @@ namespace matplotlibcpp {
2424
PyObject *s_python_function_ylim;
2525
PyObject *s_python_empty_tuple;
2626

27-
static _pyplot_global& get() {
28-
static _pyplot_global ctx;
27+
/* For now, _interpreter is implemented as a singleton since its currently not possible to have
28+
multiple independent embedded python interpreters without patching the python source code
29+
or starting a seperate process for each.
30+
31+
http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
32+
*/
33+
34+
static _interpreter& get() {
35+
static _interpreter ctx;
2936
return ctx;
3037
}
3138

3239
private:
33-
_pyplot_global() {
40+
_interpreter() {
3441
char name[] = "plotting"; // silence compiler warning abount const strings
3542
Py_SetProgramName(name); // optional but recommended
3643
Py_Initialize();
@@ -68,7 +75,7 @@ namespace matplotlibcpp {
6875
s_python_empty_tuple = PyTuple_New(0);
6976
}
7077

71-
~_pyplot_global() {
78+
~_interpreter() {
7279
Py_Finalize();
7380
}
7481
};
@@ -105,7 +112,7 @@ namespace matplotlibcpp {
105112
PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
106113
}
107114

108-
PyObject* res = PyObject_Call(detail::_pyplot_global::get().s_python_function_plot, args, kwargs);
115+
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs);
109116

110117
Py_DECREF(args);
111118
Py_DECREF(kwargs);
@@ -136,7 +143,7 @@ namespace matplotlibcpp {
136143
PyTuple_SetItem(plot_args, 1, ylist);
137144
PyTuple_SetItem(plot_args, 2, pystring);
138145

139-
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_plot, plot_args);
146+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
140147

141148
Py_DECREF(xlist);
142149
Py_DECREF(ylist);
@@ -166,7 +173,7 @@ namespace matplotlibcpp {
166173
PyTuple_SetItem(plot_args, 1, ylist);
167174
PyTuple_SetItem(plot_args, 2, pystring);
168175

169-
PyObject* res = PyObject_Call(detail::_pyplot_global::get().s_python_function_plot, plot_args, kwargs);
176+
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
170177

171178
Py_DECREF(kwargs);
172179
Py_DECREF(xlist);
@@ -205,119 +212,8 @@ namespace matplotlibcpp {
205212
return named_plot<double>(name,x,y,format);
206213
}
207214

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-
319-
inline void legend() {
320-
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_legend, detail::_pyplot_global::get().s_python_empty_tuple);
215+
inline void legend() {
216+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
321217
if(!res) throw std::runtime_error("Call to legend() failed.");
322218

323219
Py_DECREF(res);
@@ -333,7 +229,7 @@ namespace matplotlibcpp {
333229
PyObject* args = PyTuple_New(1);
334230
PyTuple_SetItem(args, 0, list);
335231

336-
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_ylim, args);
232+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args);
337233
if(!res) throw std::runtime_error("Call to ylim() failed.");
338234

339235
Py_DECREF(list);
@@ -351,7 +247,7 @@ namespace matplotlibcpp {
351247
PyObject* args = PyTuple_New(1);
352248
PyTuple_SetItem(args, 0, list);
353249

354-
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_xlim, args);
250+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args);
355251
if(!res) throw std::runtime_error("Call to xlim() failed.");
356252

357253
Py_DECREF(list);
@@ -360,11 +256,127 @@ namespace matplotlibcpp {
360256
}
361257

362258
inline void show() {
363-
PyObject* res = PyObject_CallObject(detail::_pyplot_global::get().s_python_function_show, detail::_pyplot_global::get().s_python_empty_tuple);
259+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple);
364260
if(!res) throw std::runtime_error("Call to show() failed.");
365261

366262
Py_DECREF(res);
367263
}
368264

265+
#if __cplusplus > 199711L
266+
// C++11-exclusive content starts here, in particular the variadic plot()
267+
268+
namespace detail {
269+
template<typename T>
270+
using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
271+
272+
template<bool obj, typename T>
273+
struct is_callable_impl;
274+
275+
template<typename T>
276+
struct is_callable_impl<false, T>
277+
{
278+
typedef is_function<T> type;
279+
}; // a non-object is callable iff it is a function
280+
281+
template<typename T>
282+
struct is_callable_impl<true, T>
283+
{
284+
struct Fallback { void operator()(); };
285+
struct Derived : T, Fallback { };
286+
287+
template<typename U, U> struct Check;
288+
289+
template<typename U>
290+
static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
291+
292+
template<typename U>
293+
static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
294+
295+
public:
296+
typedef decltype(test<Derived>(nullptr)) type;
297+
typedef decltype(&Fallback::operator()) dtype;
298+
static constexpr bool value = type::value;
299+
}; // an object is callable iff it defines operator()
300+
301+
template<typename T>
302+
struct is_callable
303+
{
304+
// dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
305+
typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
306+
};
307+
308+
template<typename IsYDataCallable>
309+
struct plot_impl { };
310+
311+
template<>
312+
struct plot_impl<std::false_type>
313+
{
314+
template<typename IterableX, typename IterableY>
315+
bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
316+
{
317+
// It's annoying that we have to repeat the code of plot() above
318+
auto xs = std::distance(std::begin(x), std::end(x));
319+
auto ys = std::distance(std::begin(y), std::end(y));
320+
assert(xs == ys && "x and y data must have the same number of elements!");
321+
322+
PyObject* xlist = PyList_New(xs);
323+
PyObject* ylist = PyList_New(ys);
324+
PyObject* pystring = PyString_FromString(format.c_str());
325+
326+
auto itx = std::begin(x), ity = std::begin(y);
327+
for(size_t i = 0; i < xs; ++i) {
328+
PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
329+
PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
330+
}
331+
332+
PyObject* plot_args = PyTuple_New(3);
333+
PyTuple_SetItem(plot_args, 0, xlist);
334+
PyTuple_SetItem(plot_args, 1, ylist);
335+
PyTuple_SetItem(plot_args, 2, pystring);
336+
337+
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
338+
339+
Py_DECREF(xlist);
340+
Py_DECREF(ylist);
341+
Py_DECREF(plot_args);
342+
if(res) Py_DECREF(res);
343+
344+
return res;
345+
}
346+
};
347+
348+
template<>
349+
struct plot_impl<std::true_type>
350+
{
351+
template<typename Iterable, typename Callable>
352+
bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
353+
{
354+
//std::cout << "Callable impl called" << std::endl;
355+
356+
if(begin(ticks) == end(ticks)) return true;
357+
358+
// We could use additional meta-programming to deduce the correct element type of y,
359+
// but all values have to be convertible to double anyways
360+
std::vector<double> y;
361+
for(auto x : ticks) y.push_back(f(x));
362+
return plot_impl<std::false_type>()(ticks,y,format);
363+
}
364+
};
365+
}
366+
367+
// recursion stop for the above
368+
template<typename... Args>
369+
bool plot() { return true; }
370+
371+
template<typename A, typename B, typename... Args>
372+
bool plot(const A& a, const B& b, const std::string& format, Args... args)
373+
{
374+
return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
375+
}
376+
377+
#endif
378+
379+
380+
369381

370382
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy