8000 replace python lists with numpy arrays and avoid copy of input data · konanrobot/matplotlib-cpp@ac61b3f · GitHub
[go: up one dir, main page]

Skip to content

Commit ac61b3f

Browse files
ChristosTBenno Evers
authored and
Benno Evers
committed
replace python lists with numpy arrays and avoid copy of input data
1 parent 0bfb012 commit ac61b3f

File tree

1 file changed

+78
-74
lines changed

1 file changed

+78
-74
lines changed

matplotlibcpp.h

Lines changed: 78 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <vector>
44
#include <map>
55
#include <numeric>
6+
#include <algorithm>
67
#include <stdexcept>
78
#include <iostream>
89

@@ -23,6 +24,8 @@
2324
#define PyString_FromString PyUnicode_FromString
2425
#endif
2526

27+
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
28+
#include <numpy/arrayobject.h>
2629

2730
namespace matplotlibcpp {
2831

@@ -72,6 +75,8 @@ namespace matplotlibcpp {
7275
Py_SetProgramName(name);
7376
Py_Initialize();
7477

78+
import_array(); // initialize numpy C-API
79+
7580
PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
7681
PyObject* pylabname = PyString_FromString("pylab");
7782
if(!pyplotname || !pylabname) { throw std::runtime_error("couldnt create string"); }
@@ -177,25 +182,52 @@ namespace matplotlibcpp {
177182

178183
return res;
179184
}
185+
// Type selector for numpy array conversion
186+
template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
187+
template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
188+
template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
189+
template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
190+
template <> struct select_npy_type<std::int8_t> { const static NPY_TYPES type = NPY_INT8; };
191 10000 +
template <> struct select_npy_type<std::int16_t> { const static NPY_TYPES type = NPY_SHORT; };
192+
template <> struct select_npy_type<std::int32_t> { const static NPY_TYPES type = NPY_INT; };
193+
template <> struct select_npy_type<std::int64_t> { const static NPY_TYPES type = NPY_INT64; };
194+
template <> struct select_npy_type<std::uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
195+
template <> struct select_npy_type<std::uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
196+
template <> struct select_npy_type<std::uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
197+
template <> struct select_npy_type<std::uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
198+
199+
template<typename Numeric>
200+
PyObject* get_array(const std::vector<Numeric>& v)
201+
{
202+
detail::_interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
203+
NPY_TYPES type = select_npy_type<Numeric>::type;
204+
if (type == NPY_NOTYPE)
205+
{
206+
std::vector<double> vd(v.size());
207+
npy_intp vsize = v.size();
208+
std::copy(v.begin(),v.end(),vd.begin());
209+
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
210+
return varray;
211+
}
212+
213+
npy_intp vsize = v.size();
214+
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
215+
return varray;
216+
}
180217

181218
template<typename Numeric>
182219
bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
183220
{
184221
assert(x.size() == y.size());
185222

186-
// using python lists
187-
PyObject* xlist = PyList_New(x.size());
188-
PyObject* ylist = PyList_New(y.size());
189-
190-
for(size_t i = 0; i < x.size(); ++i) {
191-
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
192-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
193-
}
223+
// using numpy arrays
224+
PyObject* xarray = get_array(x);
225+
PyObject* yarray = get_array(y);
194226

195227
// construct positional args
196228
PyObject* args = PyTuple_New(2);
197-
PyTuple_SetItem(args, 0, xlist);
198-
PyTuple_SetItem(args, 1, ylist);
229+
PyTuple_SetItem(args, 0, xarray);
230+
PyTuple_SetItem(args, 1, yarray);
199231

200232
// construct keyword args
201233
PyObject* kwargs = PyDict_New();
@@ -219,22 +251,16 @@ namespace matplotlibcpp {
219251
assert(x.size() == y1.size());
220252
assert(x.size() == y2.size());
221253

222-
// using python lists
223-
PyObject* xlist = PyList_New(x.size());
224-
PyObject* y1list = PyList_New(y1.size());
225-
PyObject* y2list = PyList_New(y2.size());
226-
227-
for(size_t i = 0; i < x.size(); ++i) {
228-
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
229-
PyList_SetItem(y1list, i, PyFloat_FromDouble(y1.at(i)));
230-
PyList_SetItem(y2list, i, PyFloat_FromDouble(y2.at(i)));
231-
}
254+
// using numpy arrays
255+
PyObject* xarray = get_array(x);
256+
PyObject* y1array = get_array(y1);
257+
PyObject* y2array = get_array(y2);
232258

233259
// construct positional args
234260
PyObject* args = PyTuple_New(3);
235-
PyTuple_SetItem(args, 0, xlist);
236-
PyTuple_SetItem(args, 1, y1list);
237-
PyTuple_SetItem(args, 2, y2list);
261+
PyTuple_SetItem(args, 0, xarray);
262+
PyTuple_SetItem(args, 1, y1array);
263+
PyTuple_SetItem(args, 2, y2array);
238264

239265
// construct keyword args
240266
PyObject* kwargs = PyDict_New();
@@ -255,20 +281,18 @@ namespace matplotlibcpp {
255281
template< typename Numeric>
256282
bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b", double alpha=1.0)
257283
{
258-
PyObject* ylist = PyList_New(y.size());
259-
284+
285+
PyObject* yarray = get_array(y);
286+
260287
PyObject* kwargs = PyDict_New();
261288
PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
262289
PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
263290
PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
264291

265-
for(size_t i = 0; i < y.size(); ++i) {
266-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
267-
}
268292

269293
PyObject* plot_args = PyTuple_New(1);
270294

271-
PyTuple_SetItem(plot_args, 0, ylist);
295+
PyTuple_SetItem(plot_args, 0, yarray);
272296

273297

274298
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
@@ -284,19 +308,17 @@ namespace matplotlibcpp {
284308
template< typename Numeric>
285309
bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10, std::string color="b", double alpha=1.0)
286310
{
287-
PyObject* ylist = PyList_New(y.size());
311+
PyObject* yarray = get_array(y);
312+
288313
PyObject* kwargs = PyDict_New();
289314
PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
290315
PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
291-
PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
316+
PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
292317
PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
293-
294-
for(size_t i = 0; i < y.size(); ++i) {
295-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
296-
}
318+
297319

298320
PyObject* plot_args = PyTuple_New(1);
299-
PyTuple_SetItem(plot_args, 0, ylist);
321+
PyTuple_SetItem(plot_args, 0, yarray);
300322

301323
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_hist, plot_args, kwargs);
302324

@@ -312,18 +334,14 @@ namespace matplotlibcpp {
312334
{
313335
assert(x.size() == y.size());
314336

315-
PyObject* xlist = PyList_New(x.size());
316-
PyObject* ylist = PyList_New(y.size());
317-
PyObject* pystring = PyString_FromString(s.c_str());
337+
PyObject* xarray = get_array(x);
338+
PyObject* yarray = get_array(y);
318339

319-
for(size_t i = 0; i < x.size(); ++i) {
320-
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
321-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
322-
}
340+
PyObject* pystring = PyString_FromString(s.c_str());
323341

324342
PyObject* plot_args = PyTuple_New(3);
325-
PyTuple_SetItem(plot_args, 0, xlist);
326-
PyTuple_SetItem(plot_args, 1, ylist);
343+
PyTuple_SetItem(plot_args, 0, xarray);
344+
PyTuple_SetItem(plot_args, 1, yarray);
327345
PyTuple_SetItem(plot_args, 2, pystring);
328346

329347
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args);
@@ -339,26 +357,19 @@ namespace matplotlibcpp {
339357
{
340358
assert(x.size() == y.size());
341359

342-
PyObject *kwargs = PyDict_New();
343-
PyObject *xlist = PyList_New(x.size());
344-
PyObject *ylist = PyList_New(y.size());
345-
PyObject *yerrlist = PyList_New(yerr.size());
360+
PyObject* xarray = get_array(x);
361+
PyObject* yarray = get_array(y);
362+
PyObject* yerrarray = get_array(yerr);
346363

347-
for (size_t i = 0; i < yerr.size(); ++i)
348-
PyList_SetItem(yerrlist, i, PyFloat_FromDouble(yerr.at(i)));
364+
PyObject *kwargs = PyDict_New();
349365

350-
PyDict_SetItemString(kwargs, "yerr", yerrlist);
366+
PyDict_SetItemString(kwargs, "yerr", yerrarray);
351367

352368
PyObject *pystring = PyString_FromString(s.c_str());
353369

354-
for (size_t i = 0; i < x.size(); ++i) {
355-
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
356-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
357-
}
358-
359370
PyObject *plot_args = PyTuple_New(2);
360-
PyTuple_SetItem(plot_args, 0, xlist);
361-
PyTuple_SetItem(plot_args, 1, ylist);
371+
PyTuple_SetItem(plot_args, 0, xarray);
372+
PyTuple_SetItem(plot_args, 1, yarray);
362373

363374
PyObject *res = PyObject_Call(detail::_interpreter::get().s_python_function_errorbar, plot_args, kwargs);
364375

@@ -379,16 +390,13 @@ namespace matplotlibcpp {
379390
PyObject* kwargs = PyDict_New();
380391
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
381392

382-
PyObject* ylist = PyList_New(y.size());
383-
PyObject* pystring = PyString_FromString(format.c_str());
393+
PyObject* yarray = get_array(y);
384394

385-
for(size_t i = 0; i < y.size(); ++i) {
386-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
387-
}
395+
PyObject* pystring = PyString_FromString(format.c_str());
388396

389397
PyObject* plot_args = PyTuple_New(2);
390398

391-
PyTuple_SetItem(plot_args, 0, ylist);
399+
PyTuple_SetItem(plot_args, 0, yarray);
392400
PyTuple_SetItem(plot_args, 1, pystring);
393401

394402
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
@@ -406,18 +414,14 @@ namespace matplotlibcpp {
406414
PyObject* kwargs = PyDict_New();
407415
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
408416

409-
PyObject* xlist = PyList_New(x.size());
410-
PyObject* ylist = PyList_New(y.size());
411-
PyObject* pystring = PyString_FromString(format.c_str());
417+
PyObject* xarray = get_array(x);
418+
PyObject* yarray = get_array(y);
412419

413-
for(size_t i = 0; i < x.size(); ++i) {
414-
PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i)));
415-
PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i)));
416-
}
420+
PyObject* pystring = PyString_FromString(format.c_str());
417421

418422
PyObject* plot_args = PyTuple_New(3);
419-
PyTuple_SetItem(plot_args, 0, xlist);
420-
PyTuple_SetItem(plot_args, 1, ylist);
423+
PyTuple_SetItem(plot_args, 0, xarray);
424+
PyTuple_SetItem(plot_args, 1, yarray);
421425
PyTuple_SetItem(plot_args, 2, pystring);
422426

423427
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);

0 commit comments

Comments
 (0)
0