TBTK
Need a break? Support the development by playing Polarity Puzzles
matplotlibcpp.h
1 /* Copyright 2019 Kristofer Björnson
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /* The MIT License (MIT)
17  *
18  * Copyright (c) 2014 Benno Evers
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining a copy
21  * of this software and associated documentation files (the "Software"), to deal
22  * in the Software without restriction, including without limitation the rights
23  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24  * copies of the Software, and to permit persons to whom the Software is
25  * furnished to do so, subject to the following conditions:
26  *
27  * The above copyright notice and this permission notice shall be included in all
28  * copies or substantial portions of the Software.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36  * SOFTWARE. */
37 
39 #pragma once
40 
41 #include "TBTK/Visualization/MatPlotLib/Interpreter.h"
42 
43 #include <vector>
44 #include <map>
45 #include <array>
46 #include <numeric>
47 #include <algorithm>
48 #include <stdexcept>
49 #include <iostream>
50 #include <cstdint> // <cstdint> requires c++11 support
51 #include <functional>
52 
53 #include <Python.h>
54 
55 #ifndef WITHOUT_NUMPY
56 # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
57 # include <numpy/arrayobject.h>
58 
59 # ifdef WITH_OPENCV
60 # include <opencv2/opencv.hpp>
61 # endif // WITH_OPENCV
62 
63 /*
64  * A bunch of constants were removed in OpenCV 4 in favour of enum classes, so
65  * define the ones we need here.
66  */
67 # if CV_MAJOR_VERSION > 3
68 # define CV_BGR2RGB cv::COLOR_BGR2RGB
69 # define CV_BGRA2RGBA cv::COLOR_BGRA2RGBA
70 # endif
71 #endif // WITHOUT_NUMPY
72 
73 #if PY_MAJOR_VERSION >= 3
74 # define PyString_FromString PyUnicode_FromString
75 # define PyInt_FromLong PyLong_FromLong
76 # define PyString_FromString PyUnicode_FromString
77 #endif
78 
79 
80 namespace TBTK {
81 namespace Visualization {
82 namespace MatPlotLib {
83 namespace matplotlibcpp {
84 
85 // must be called before the first regular call to matplotlib to have any effect
86 inline void backend(const std::string& name)
87 {
88  detail::s_backend = name;
89 }
90 
91 inline bool annotate(std::string annotation, double x, double y)
92 {
93  PyObject * xy = PyTuple_New(2);
94  PyObject * str = PyString_FromString(annotation.c_str());
95 
96  PyTuple_SetItem(xy,0,PyFloat_FromDouble(x));
97  PyTuple_SetItem(xy,1,PyFloat_FromDouble(y));
98 
99  PyObject* kwargs = PyDict_New();
100  PyDict_SetItemString(kwargs, "xy", xy);
101 
102  PyObject* args = PyTuple_New(1);
103  PyTuple_SetItem(args, 0, str);
104 
105  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_annotate, args, kwargs);
106 
107  Py_DECREF(args);
108  Py_DECREF(kwargs);
109 
110  if(res) Py_DECREF(res);
111 
112  return res;
113 }
114 
115 #ifndef WITHOUT_NUMPY
116 // Type selector for numpy array conversion
117 template <typename T> struct select_npy_type { const static NPY_TYPES type = NPY_NOTYPE; }; //Default
118 template <> struct select_npy_type<double> { const static NPY_TYPES type = NPY_DOUBLE; };
119 template <> struct select_npy_type<float> { const static NPY_TYPES type = NPY_FLOAT; };
120 template <> struct select_npy_type<bool> { const static NPY_TYPES type = NPY_BOOL; };
121 template <> struct select_npy_type<int8_t> { const static NPY_TYPES type = NPY_INT8; };
122 template <> struct select_npy_type<int16_t> { const static NPY_TYPES type = NPY_SHORT; };
123 template <> struct select_npy_type<int32_t> { const static NPY_TYPES type = NPY_INT; };
124 template <> struct select_npy_type<int64_t> { const static NPY_TYPES type = NPY_INT64; };
125 template <> struct select_npy_type<uint8_t> { const static NPY_TYPES type = NPY_UINT8; };
126 template <> struct select_npy_type<uint16_t> { const static NPY_TYPES type = NPY_USHORT; };
127 template <> struct select_npy_type<uint32_t> { const static NPY_TYPES type = NPY_ULONG; };
128 template <> struct select_npy_type<uint64_t> { const static NPY_TYPES type = NPY_UINT64; };
129 
130 template<typename Numeric>
131 PyObject* get_array(const std::vector<Numeric>& v)
132 {
133  detail::Interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
134  NPY_TYPES type = select_npy_type<Numeric>::type;
135  if (type == NPY_NOTYPE)
136  {
137  std::vector<double> vd(v.size());
138  npy_intp vsize = v.size();
139  std::copy(v.begin(),v.end(),vd.begin());
140  PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, (void*)(vd.data()));
141  return varray;
142  }
143 
144  npy_intp vsize = v.size();
145  PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
146  return varray;
147 }
148 
149 template<typename Numeric>
150 PyObject* get_2darray(const std::vector<::std::vector<Numeric>>& v)
151 {
152  detail::Interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
153  if (v.size() < 1) throw std::runtime_error("get_2d_array v too small");
154 
155  npy_intp vsize[2] = {static_cast<npy_intp>(v.size()),
156  static_cast<npy_intp>(v[0].size())};
157 
158  PyArrayObject *varray =
159  (PyArrayObject *)PyArray_SimpleNew(2, vsize, NPY_DOUBLE);
160 
161  double *vd_begin = static_cast<double *>(PyArray_DATA(varray));
162 
163  for (const ::std::vector<Numeric> &v_row : v) {
164  if (v_row.size() != static_cast<size_t>(vsize[1]))
165  throw std::runtime_error("Missmatched array size");
166  std::copy(v_row.begin(), v_row.end(), vd_begin);
167  vd_begin += vsize[1];
168  }
169 
170  return reinterpret_cast<PyObject *>(varray);
171 }
172 
173 template<typename Numeric>
174 PyObject* get_3darray(const std::vector<std::vector<::std::vector<Numeric>>>& v)
175 {
176  detail::Interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
177  if (v.size() < 1) throw std::runtime_error("get_3d_array v too small");
178  if (v[0].size() < 1) throw std::runtime_error("get_3d_array v too small");
179  for(unsigned int n = 0; n < v.size(); n++)
180  if (v[n].size() != v[0].size()) throw std::runtime_error("get_3d_array v too small");
181 
182  npy_intp vsize[3] = {
183  static_cast<npy_intp>(v.size()),
184  static_cast<npy_intp>(v[0].size()),
185  static_cast<npy_intp>(v[0][0].size())
186  };
187 
188  PyArrayObject *varray =
189  (PyArrayObject *)PyArray_SimpleNew(3, vsize, NPY_DOUBLE);
190 
191  double *vd_begin = static_cast<double *>(PyArray_DATA(varray));
192 
193  for (const ::std::vector<::std::vector<Numeric>> &v_x : v) {
194  if (v_x.size() != static_cast<size_t>(vsize[1]))
195  throw std::runtime_error("Missmatched array size");
196  for (const ::std::vector<Numeric> &v_y : v_x) {
197  std::copy(v_y.begin(), v_y.end(), vd_begin);
198  vd_begin += vsize[2];
199  }
200  }
201 
202  return reinterpret_cast<PyObject *>(varray);
203 }
204 
205 #else // fallback if we don't have numpy: copy every element of the given vector
206 
207 template<typename Numeric>
208 PyObject* get_array(const std::vector<Numeric>& v)
209 {
210  PyObject* list = PyList_New(v.size());
211  for(size_t i = 0; i < v.size(); ++i) {
212  PyList_SetItem(list, i, PyFloat_FromDouble(v.at(i)));
213  }
214  return list;
215 }
216 
217 #endif // WITHOUT_NUMPY
218 
219 template<typename Numeric>
220 bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
221 {
222  assert(x.size() == y.size());
223 
224  // using numpy arrays
225  PyObject* xarray = get_array(x);
226  PyObject* yarray = get_array(y);
227 
228  // construct positional args
229  PyObject* args = PyTuple_New(2);
230  PyTuple_SetItem(args, 0, xarray);
231  PyTuple_SetItem(args, 1, yarray);
232 
233  // construct keyword args
234  PyObject* kwargs = PyDict_New();
235  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
236  {
237  if(it->first.compare("linewidth") == 0){
238  char value[it->second.size()+1];
239  for(unsigned int n = 0; n < it->second.size(); n++)
240  value[n] = it->second[n];
241  value[it->second.size()] = '\0';
242  PyDict_SetItemString(kwargs, it->first.c_str(), PyInt_FromString(value, nullptr, 0));
243  }
244  else{
245  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
246  }
247  }
248 
249  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_plot, args, kwargs);
250 
251  Py_DECREF(args);
252  Py_DECREF(kwargs);
253  if(res) Py_DECREF(res);
254 
255  return res;
256 }
257 
258 // TODO - it should be possible to make this work by implementing
259 // a non-numpy alternative for `get_2darray()`.
260 #ifndef WITHOUT_NUMPY
261 template <typename Numeric>
262 void plot_surface(const std::vector<::std::vector<Numeric>> &x,
263  const std::vector<::std::vector<Numeric>> &y,
264  const std::vector<::std::vector<Numeric>> &z,
265  const std::map<std::string, std::string> &keywords =
266  std::map<std::string, std::string>())
267 {
268  // We lazily load the modules here the first time this function is called
269  // because I'm not sure that we can assume "matplotlib installed" implies
270  // "mpl_toolkits installed" on all platforms, and we don't want to require
271  // it for people who don't need 3d plots.
272 /* static PyObject *mpl_toolkitsmod = nullptr, *axis3dmod = nullptr;
273  if (!mpl_toolkitsmod) {
274  detail::Interpreter::get();
275 
276  PyObject* mpl_toolkits = PyString_FromString("mpl_toolkits");
277  PyObject* axis3d = PyString_FromString("mpl_toolkits.mplot3d");
278  if (!mpl_toolkits || !axis3d) { throw std::runtime_error("couldnt create string"); }
279 
280  mpl_toolkitsmod = PyImport_Import(mpl_toolkits);
281  Py_DECREF(mpl_toolkits);
282  if (!mpl_toolkitsmod) { throw std::runtime_error("Error loading module mpl_toolkits!"); }
283 
284  axis3dmod = PyImport_Import(axis3d);
285  Py_DECREF(axis3d);
286  if (!axis3dmod) { throw std::runtime_error("Error loading module mpl_toolkits.mplot3d!"); }
287  }*/
288  detail::Interpreter::get().initializeMPLToolkits();
289 
290  assert(x.size() == y.size());
291  assert(y.size() == z.size());
292 
293  // using numpy arrays
294  PyObject *xarray = get_2darray(x);
295  PyObject *yarray = get_2darray(y);
296  PyObject *zarray = get_2darray(z);
297 
298  // construct positional args
299  PyObject *args = PyTuple_New(3);
300  PyTuple_SetItem(args, 0, xarray);
301  PyTuple_SetItem(args, 1, yarray);
302  PyTuple_SetItem(args, 2, zarray);
303 
304  // Build up the kw args.
305  PyObject *kwargs = PyDict_New();
306  PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1));
307  PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1));
308 
309  PyObject *python_colormap_coolwarm = PyObject_GetAttrString(
310  detail::Interpreter::get().s_python_colormap, "coolwarm");
311 
312  PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
313 
314  for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
315  it != keywords.end(); ++it) {
316  PyDict_SetItemString(kwargs, it->first.c_str(),
317  PyString_FromString(it->second.c_str()));
318  }
319 
320 
321  PyObject *fig =
322  PyObject_CallObject(detail::Interpreter::get().s_python_function_figure,
323  detail::Interpreter::get().s_python_empty_tuple);
324  if (!fig) throw std::runtime_error("Call to figure() failed.");
325 
326  PyObject *gca_kwargs = PyDict_New();
327  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
328 
329  PyObject *gca = PyObject_GetAttrString(fig, "gca");
330  if (!gca) throw std::runtime_error("No gca");
331  Py_INCREF(gca);
332  PyObject *axis = PyObject_Call(
333  gca, detail::Interpreter::get().s_python_empty_tuple, gca_kwargs);
334 
335  if (!axis) throw std::runtime_error("No axis");
336  Py_INCREF(axis);
337 
338  Py_DECREF(gca);
339  Py_DECREF(gca_kwargs);
340 
341  PyObject *plot_surface = PyObject_GetAttrString(axis, "plot_surface");
342  if (!plot_surface) throw std::runtime_error("No surface");
343  Py_INCREF(plot_surface);
344  PyObject *res = PyObject_Call(plot_surface, args, kwargs);
345  if (!res) throw std::runtime_error("failed surface");
346  Py_DECREF(plot_surface);
347 
348  Py_DECREF(axis);
349  Py_DECREF(args);
350  Py_DECREF(kwargs);
351  if (res) Py_DECREF(res);
352 }
353 
354 template <typename Numeric>
355 void quiver(
356  const std::vector<std::vector<::std::vector<Numeric>>> &x,
357  const std::vector<std::vector<::std::vector<Numeric>>> &y,
358  const std::vector<std::vector<::std::vector<Numeric>>> &z,
359  const std::vector<std::vector<::std::vector<Numeric>>> &u,
360  const std::vector<std::vector<::std::vector<Numeric>>> &v,
361  const std::vector<std::vector<::std::vector<Numeric>>> &w,
362  const std::map<std::string, std::string> &keywords =
363  std::map<std::string, std::string>()
364 ){
365  // We lazily load the modules here the first time this function is called
366  // because I'm not sure that we can assume "matplotlib installed" implies
367  // "mpl_toolkits installed" on all platforms, and we don't want to require
368  // it for people who don't need 3d plots.
369  detail::Interpreter::get().initializeMPLToolkits();
370 
371  assert(x.size() == y.size());
372  assert(x.size() == z.size());
373  assert(x.size() == u.size());
374  assert(x.size() == v.size());
375  assert(x.size() == z.size());
376  for(unsigned int n = 0; n < x.size(); n++){
377  assert(x[0].size() == x[n].size());
378  assert(x[0].size() == y[n].size());
379  assert(x[0].size() == z[n].size());
380  assert(x[0].size() == u[n].size());
381  assert(x[0].size() == v[n].size());
382  assert(x[0].size() == w[n].size());
383  for(unsigned int c = 0; c < x[0].size(); c++){
384  assert(x[n][0].size() == x[n][c].size());
385  assert(x[n][0].size() == y[n][c].size());
386  assert(x[n][0].size() == z[n][c].size());
387  assert(x[n][0].size() == u[n][c].size());
388  assert(x[n][0].size() == v[n][c].size());
389  assert(x[n][0].size() == w[n][c].size());
390  }
391  }
392 
393  // using numpy arrays
394  PyObject *xarray = get_3darray(x);
395  PyObject *yarray = get_3darray(y);
396  PyObject *zarray = get_3darray(z);
397  PyObject *uarray = get_3darray(u);
398  PyObject *varray = get_3darray(v);
399  PyObject *warray = get_3darray(w);
400 
401  // construct positional args
402  PyObject *args = PyTuple_New(6);
403  PyTuple_SetItem(args, 0, xarray);
404  PyTuple_SetItem(args, 1, yarray);
405  PyTuple_SetItem(args, 2, zarray);
406  PyTuple_SetItem(args, 3, uarray);
407  PyTuple_SetItem(args, 4, varray);
408  PyTuple_SetItem(args, 5, warray);
409 
410  // Build up the kw args.
411  PyObject *kwargs = PyDict_New();
412 // PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1));
413 // PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1));
414 
415 // PyObject *python_colormap_coolwarm = PyObject_GetAttrString(
416 // detail::Interpreter::get().s_python_colormap, "coolwarm");
417 
418 // PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
419 
420  for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
421  it != keywords.end(); ++it) {
422  if(it->first.compare("length") == 0){
423  char value[it->second.size()+1];
424  for(unsigned int n = 0; n < it->second.size(); n++)
425  value[n] = it->second[n];
426  value[it->second.size()] = '\0';
427  PyDict_SetItemString(
428  kwargs,
429  it->first.c_str(),
430  PyFloat_FromString(PyString_FromString(value))
431  );
432  }
433  else{
434  PyDict_SetItemString(
435  kwargs,
436  it->first.c_str(),
437  PyString_FromString(it->second.c_str())
438  );
439  }
440  }
441 
442 
443  PyObject *fig =
444  PyObject_CallObject(detail::Interpreter::get().s_python_function_figure,
445  detail::Interpreter::get().s_python_empty_tuple);
446  if (!fig) throw std::runtime_error("Call to figure() failed.");
447 
448  PyObject *gca_kwargs = PyDict_New();
449  PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
450 
451  PyObject *gca = PyObject_GetAttrString(fig, "gca");
452  if (!gca) throw std::runtime_error("No gca");
453  Py_INCREF(gca);
454  PyObject *axis = PyObject_Call(
455  gca, detail::Interpreter::get().s_python_empty_tuple, gca_kwargs);
456 
457  if (!axis) throw std::runtime_error("No axis");
458  Py_INCREF(axis);
459 
460  Py_DECREF(gca);
461  Py_DECREF(gca_kwargs);
462 
463  PyObject *quiver = PyObject_GetAttrString(axis, "quiver");
464  if (!quiver) throw std::runtime_error("No quiver");
465  Py_INCREF(quiver);
466  PyObject *res = PyObject_Call(quiver, args, kwargs);
467  if (!res) throw std::runtime_error("failed quiver");
468  Py_DECREF(quiver);
469 
470  Py_DECREF(axis);
471  Py_DECREF(args);
472  Py_DECREF(kwargs);
473  if (res) Py_DECREF(res);
474 }
475 
476 //template <typename Numeric>
477 inline void view_init(
478  const std::map<std::string, std::string> &keywords =
479  std::map<std::string, std::string>())
480 {
481  PyObject *axis = PyObject_CallObject(
482  detail::Interpreter::get().s_python_function_gca,
483  detail::Interpreter::get().s_python_empty_tuple
484  );
485 
486  PyObject *view_init_kwargs = PyDict_New();
487  std::string elev = keywords.at("elev");
488  std::string azim = keywords.at("azim");
489  PyDict_SetItemString(view_init_kwargs, "elev", PyInt_FromString((char*)elev.c_str(), nullptr, 0));
490  PyDict_SetItemString(view_init_kwargs, "azim", PyInt_FromString((char*)azim.c_str(), nullptr, 0));
491 
492  PyObject *view_init = PyObject_GetAttrString(axis, "view_init");
493  if (!view_init) throw std::runtime_error("No view_init");
494  Py_INCREF(view_init);
495  PyObject *res = PyObject_Call(
496  view_init,
497  detail::Interpreter::get().s_python_empty_tuple,
498  view_init_kwargs
499  );
500  if (!res) throw std::runtime_error("failed view_init");
501  Py_DECREF(view_init);
502  if (res) Py_DECREF(res);
503 
504  Py_DECREF(axis);
505 }
506 #endif // WITHOUT_NUMPY
507 
508 template <typename Numeric>
509 void contourf(
510  const std::vector<::std::vector<Numeric>> &x,
511  const std::vector<::std::vector<Numeric>> &y,
512  const std::vector<::std::vector<Numeric>> &z,
513  unsigned int levels = 8,
514  const std::map<std::string, std::string> &keywords =
515  std::map<std::string, std::string>()
516 ){
517  assert(x.size() == y.size());
518  assert(y.size() == z.size());
519 
520  // using numpy arrays
521  PyObject *xarray = get_2darray(x);
522  PyObject *yarray = get_2darray(y);
523  PyObject *zarray = get_2darray(z);
524 
525  // construct positional args
526  PyObject *args = PyTuple_New(4);
527  PyTuple_SetItem(args, 0, xarray);
528  PyTuple_SetItem(args, 1, yarray);
529  PyTuple_SetItem(args, 2, zarray);
530  PyTuple_SetItem(args, 3, PyInt_FromLong(levels));
531 
532  // Build up the kw args.
533  PyObject *kwargs = PyDict_New();
534  PyDict_SetItemString(kwargs, "rstride", PyInt_FromLong(1));
535  PyDict_SetItemString(kwargs, "cstride", PyInt_FromLong(1));
536 
537  PyObject *python_colormap_coolwarm = PyObject_GetAttrString(
538  detail::Interpreter::get().s_python_colormap, "coolwarm");
539 
540  PyDict_SetItemString(kwargs, "cmap", python_colormap_coolwarm);
541 
542  for (std::map<std::string, std::string>::const_iterator it = keywords.begin();
543  it != keywords.end(); ++it) {
544  PyDict_SetItemString(kwargs, it->first.c_str(),
545  PyString_FromString(it->second.c_str()));
546  }
547 
548 
549  PyObject *fig =
550  PyObject_CallObject(detail::Interpreter::get().s_python_function_figure,
551  detail::Interpreter::get().s_python_empty_tuple);
552  if (!fig) throw std::runtime_error("Call to figure() failed.");
553 
554  PyObject *gca_kwargs = PyDict_New();
555 // PyDict_SetItemString(gca_kwargs, "projection", PyString_FromString("3d"));
556 
557  PyObject *gca = PyObject_GetAttrString(fig, "gca");
558  if (!gca) throw std::runtime_error("No gca");
559  Py_INCREF(gca);
560  PyObject *axis = PyObject_Call(
561  gca, detail::Interpreter::get().s_python_empty_tuple, gca_kwargs);
562 
563  if (!axis) throw std::runtime_error("No axis");
564  Py_INCREF(axis);
565 
566  Py_DECREF(gca);
567  Py_DECREF(gca_kwargs);
568 
569  PyObject *contourf = PyObject_GetAttrString(axis, "contourf");
570  if (!contourf) throw std::runtime_error("No surface");
571  Py_INCREF(contourf);
572  PyObject *res = PyObject_Call(contourf, args, kwargs);
573  if (!res) throw std::runtime_error("failed surface");
574 
575  PyObject *colorbar_kwargs = PyDict_New();
576  PyDict_SetItemString(colorbar_kwargs, "mappable", res);
577  PyDict_SetItemString(colorbar_kwargs, "ax", axis);
578  PyObject *colorbar = PyObject_GetAttrString(fig, "colorbar");
579  if(!colorbar) throw std::runtime_error("No colorbar");
580  Py_INCREF(colorbar);
581  PyObject *res2 = PyObject_Call(
582  colorbar,
583  detail::Interpreter::get().s_python_empty_tuple,
584  colorbar_kwargs
585  );
586  if(!res2) throw std::runtime_error("failed colorbar");
587  Py_DECREF(res2);
588 
589  Py_DECREF(contourf);
590 
591 
592  Py_DECREF(axis);
593  Py_DECREF(args);
594  Py_DECREF(kwargs);
595  if (res) Py_DECREF(res);
596 }
597 
598 template<typename Numeric>
599 bool stem(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
600 {
601  assert(x.size() == y.size());
602 
603  // using numpy arrays
604  PyObject* xarray = get_array(x);
605  PyObject* yarray = get_array(y);
606 
607  // construct positional args
608  PyObject* args = PyTuple_New(2);
609  PyTuple_SetItem(args, 0, xarray);
610  PyTuple_SetItem(args, 1, yarray);
611 
612  // construct keyword args
613  PyObject* kwargs = PyDict_New();
614  for (std::map<std::string, std::string>::const_iterator it =
615  keywords.begin(); it != keywords.end(); ++it) {
616  PyDict_SetItemString(kwargs, it->first.c_str(),
617  PyString_FromString(it->second.c_str()));
618  }
619 
620  PyObject* res = PyObject_Call(
621  detail::Interpreter::get().s_python_function_stem, args, kwargs);
622 
623  Py_DECREF(args);
624  Py_DECREF(kwargs);
625  if (res)
626  Py_DECREF(res);
627 
628  return res;
629 }
630 
631 template< typename Numeric >
632 bool fill(const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::map<std::string, std::string>& keywords)
633 {
634  assert(x.size() == y.size());
635 
636  // using numpy arrays
637  PyObject* xarray = get_array(x);
638  PyObject* yarray = get_array(y);
639 
640  // construct positional args
641  PyObject* args = PyTuple_New(2);
642  PyTuple_SetItem(args, 0, xarray);
643  PyTuple_SetItem(args, 1, yarray);
644 
645  // construct keyword args
646  PyObject* kwargs = PyDict_New();
647  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
648  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
649  }
650 
651  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_fill, args, kwargs);
652 
653  Py_DECREF(args);
654  Py_DECREF(kwargs);
655 
656  if (res) Py_DECREF(res);
657 
658  return res;
659 }
660 
661 template< typename Numeric >
662 bool fill_between(const std::vector<Numeric>& x, const std::vector<Numeric>& y1, const std::vector<Numeric>& y2, const std::map<std::string, std::string>& keywords)
663 {
664  assert(x.size() == y1.size());
665  assert(x.size() == y2.size());
666 
667  // using numpy arrays
668  PyObject* xarray = get_array(x);
669  PyObject* y1array = get_array(y1);
670  PyObject* y2array = get_array(y2);
671 
672  // construct positional args
673  PyObject* args = PyTuple_New(3);
674  PyTuple_SetItem(args, 0, xarray);
675  PyTuple_SetItem(args, 1, y1array);
676  PyTuple_SetItem(args, 2, y2array);
677 
678  // construct keyword args
679  PyObject* kwargs = PyDict_New();
680  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it) {
681  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
682  }
683 
684  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_fill_between, args, kwargs);
685 
686  Py_DECREF(args);
687  Py_DECREF(kwargs);
688  if(res) Py_DECREF(res);
689 
690  return res;
691 }
692 
693 template< typename Numeric>
694 bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b",
695  double alpha=1.0, bool cumulative=false)
696 {
697 
698  PyObject* yarray = get_array(y);
699 
700  PyObject* kwargs = PyDict_New();
701  PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
702  PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
703  PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
704  PyDict_SetItemString(kwargs, "cumulative", cumulative ? Py_True : Py_False);
705 
706  PyObject* plot_args = PyTuple_New(1);
707 
708  PyTuple_SetItem(plot_args, 0, yarray);
709 
710 
711  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_hist, plot_args, kwargs);
712 
713 
714  Py_DECREF(plot_args);
715  Py_DECREF(kwargs);
716  if(res) Py_DECREF(res);
717 
718  return res;
719 }
720 
721 #ifndef WITHOUT_NUMPY
722  namespace internal {
723  inline void imshow(void *ptr, const NPY_TYPES type, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords)
724  {
725  assert(type == NPY_UINT8 || type == NPY_FLOAT);
726  assert(colors == 1 || colors == 3 || colors == 4);
727 
728  detail::Interpreter::get(); //interpreter needs to be initialized for the numpy commands to work
729 
730  // construct args
731  npy_intp dims[3] = { rows, columns, colors };
732  PyObject *args = PyTuple_New(1);
733  PyTuple_SetItem(args, 0, PyArray_SimpleNewFromData(colors == 1 ? 2 : 3, dims, type, ptr));
734 
735  // construct keyword args
736  PyObject* kwargs = PyDict_New();
737  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
738  {
739  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
740  }
741 
742  PyObject *res = PyObject_Call(detail::Interpreter::get().s_python_function_imshow, args, kwargs);
743  Py_DECREF(args);
744  Py_DECREF(kwargs);
745  if (!res)
746  throw std::runtime_error("Call to imshow() failed");
747  Py_DECREF(res);
748  }
749  }
750 
751  inline void imshow(const unsigned char *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {})
752  {
753  internal::imshow((void *) ptr, NPY_UINT8, rows, columns, colors, keywords);
754  }
755 
756  inline void imshow(const float *ptr, const int rows, const int columns, const int colors, const std::map<std::string, std::string> &keywords = {})
757  {
758  internal::imshow((void *) ptr, NPY_FLOAT, rows, columns, colors, keywords);
759  }
760 
761 #ifdef WITH_OPENCV
762  void imshow(const cv::Mat &image, const std::map<std::string, std::string> &keywords = {})
763  {
764  // Convert underlying type of matrix, if needed
765  cv::Mat image2;
766  NPY_TYPES npy_type = NPY_UINT8;
767  switch (image.type() & CV_MAT_DEPTH_MASK) {
768  case CV_8U:
769  image2 = image;
770  break;
771  case CV_32F:
772  image2 = image;
773  npy_type = NPY_FLOAT;
774  break;
775  default:
776  image.convertTo(image2, CV_MAKETYPE(CV_8U, image.channels()));
777  }
778 
779  // If color image, convert from BGR to RGB
780  switch (image2.channels()) {
781  case 3:
782  cv::cvtColor(image2, image2, CV_BGR2RGB);
783  break;
784  case 4:
785  cv::cvtColor(image2, image2, CV_BGRA2RGBA);
786  }
787 
788  internal::imshow(image2.data, npy_type, image2.rows, image2.cols, image2.channels(), keywords);
789  }
790 #endif // WITH_OPENCV
791 #endif // WITHOUT_NUMPY
792 
793 template<typename NumericX, typename NumericY>
794 bool scatter(const std::vector<NumericX>& x,
795  const std::vector<NumericY>& y,
796  const double s=1.0) // The marker size in points**2
797 {
798  assert(x.size() == y.size());
799 
800  PyObject* xarray = get_array(x);
801  PyObject* yarray = get_array(y);
802 
803  PyObject* kwargs = PyDict_New();
804  PyDict_SetItemString(kwargs, "s", PyLong_FromLong(s));
805 
806  PyObject* plot_args = PyTuple_New(2);
807  PyTuple_SetItem(plot_args, 0, xarray);
808  PyTuple_SetItem(plot_args, 1, yarray);
809 
810  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_scatter, plot_args, kwargs);
811 
812  Py_DECREF(plot_args);
813  Py_DECREF(kwargs);
814  if(res) Py_DECREF(res);
815 
816  return res;
817 }
818 
819 template <typename Numeric>
820 bool bar(const std::vector<Numeric> & x,
821  const std::vector<Numeric> & y,
822  std::string ec = "black",
823  std::string ls = "-",
824  double lw = 1.0,
825  const std::map<std::string, std::string> & keywords = {}) {
826  PyObject * xarray = get_array(x);
827  PyObject * yarray = get_array(y);
828 
829  PyObject * kwargs = PyDict_New();
830 
831  PyDict_SetItemString(kwargs, "ec", PyString_FromString(ec.c_str()));
832  PyDict_SetItemString(kwargs, "ls", PyString_FromString(ls.c_str()));
833  PyDict_SetItemString(kwargs, "lw", PyFloat_FromDouble(lw));
834 
835  for (std::map<std::string, std::string>::const_iterator it =
836  keywords.begin();
837  it != keywords.end();
838  ++it) {
839  PyDict_SetItemString(
840  kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
841  }
842 
843  PyObject * plot_args = PyTuple_New(2);
844  PyTuple_SetItem(plot_args, 0, xarray);
845  PyTuple_SetItem(plot_args, 1, yarray);
846 
847  PyObject * res = PyObject_Call(
848  detail::Interpreter::get().s_python_function_bar, plot_args, kwargs);
849 
850  Py_DECREF(plot_args);
851  Py_DECREF(kwargs);
852  if (res) Py_DECREF(res);
853 
854  return res;
855 }
856 
857 template <typename Numeric>
858 bool bar(const std::vector<Numeric> & y,
859  std::string ec = "black",
860  std::string ls = "-",
861  double lw = 1.0,
862  const std::map<std::string, std::string> & keywords = {}) {
863  using T = typename std::remove_reference<decltype(y)>::type::value_type;
864 
865  std::vector<T> x;
866  for (std::size_t i = 0; i < y.size(); i++) { x.push_back(i); }
867 
868  return bar(x, y, ec, ls, lw, keywords);
869 }
870 
871 inline bool subplots_adjust(const std::map<std::string, double>& keywords = {})
872 {
873 
874  PyObject* kwargs = PyDict_New();
875  for (std::map<std::string, double>::const_iterator it =
876  keywords.begin(); it != keywords.end(); ++it) {
877  PyDict_SetItemString(kwargs, it->first.c_str(),
878  PyFloat_FromDouble(it->second));
879  }
880 
881 
882  PyObject* plot_args = PyTuple_New(0);
883 
884  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_subplots_adjust, plot_args, kwargs);
885 
886  Py_DECREF(plot_args);
887  Py_DECREF(kwargs);
888  if(res) Py_DECREF(res);
889 
890  return res;
891 }
892 
893 template< typename Numeric>
894 bool named_hist(std::string label,const std::vector<Numeric>& y, long bins=10, std::string color="b", double alpha=1.0)
895 {
896  PyObject* yarray = get_array(y);
897 
898  PyObject* kwargs = PyDict_New();
899  PyDict_SetItemString(kwargs, "label", PyString_FromString(label.c_str()));
900  PyDict_SetItemString(kwargs, "bins", PyLong_FromLong(bins));
901  PyDict_SetItemString(kwargs, "color", PyString_FromString(color.c_str()));
902  PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha));
903 
904 
905  PyObject* plot_args = PyTuple_New(1);
906  PyTuple_SetItem(plot_args, 0, yarray);
907 
908  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_hist, plot_args, kwargs);
909 
910  Py_DECREF(plot_args);
911  Py_DECREF(kwargs);
912  if(res) Py_DECREF(res);
913 
914  return res;
915 }
916 
917 template<typename NumericX, typename NumericY>
918 bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
919 {
920  assert(x.size() == y.size());
921 
922  PyObject* xarray = get_array(x);
923  PyObject* yarray = get_array(y);
924 
925  PyObject* pystring = PyString_FromString(s.c_str());
926 
927  PyObject* plot_args = PyTuple_New(3);
928  PyTuple_SetItem(plot_args, 0, xarray);
929  PyTuple_SetItem(plot_args, 1, yarray);
930  PyTuple_SetItem(plot_args, 2, pystring);
931 
932  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_plot, plot_args);
933 
934  Py_DECREF(plot_args);
935  if(res) Py_DECREF(res);
936 
937  return res;
938 }
939 
940 template<typename NumericX, typename NumericY, typename NumericU, typename NumericW>
941 bool quiver(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::vector<NumericU>& u, const std::vector<NumericW>& w, const std::map<std::string, std::string>& keywords = {})
942 {
943  assert(x.size() == y.size() && x.size() == u.size() && u.size() == w.size());
944 
945  PyObject* xarray = get_array(x);
946  PyObject* yarray = get_array(y);
947  PyObject* uarray = get_array(u);
948  PyObject* warray = get_array(w);
949 
950  PyObject* plot_args = PyTuple_New(4);
951  PyTuple_SetItem(plot_args, 0, xarray);
952  PyTuple_SetItem(plot_args, 1, yarray);
953  PyTuple_SetItem(plot_args, 2, uarray);
954  PyTuple_SetItem(plot_args, 3, warray);
955 
956  // construct keyword args
957  PyObject* kwargs = PyDict_New();
958  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
959  {
960  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
961  }
962 
963  PyObject* res = PyObject_Call(
964  detail::Interpreter::get().s_python_function_quiver, plot_args, kwargs);
965 
966  Py_DECREF(kwargs);
967  Py_DECREF(plot_args);
968  if (res)
969  Py_DECREF(res);
970 
971  return res;
972 }
973 
974 template<typename NumericX, typename NumericY>
975 bool stem(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
976 {
977  assert(x.size() == y.size());
978 
979  PyObject* xarray = get_array(x);
980  PyObject* yarray = get_array(y);
981 
982  PyObject* pystring = PyString_FromString(s.c_str());
983 
984  PyObject* plot_args = PyTuple_New(3);
985  PyTuple_SetItem(plot_args, 0, xarray);
986  PyTuple_SetItem(plot_args, 1, yarray);
987  PyTuple_SetItem(plot_args, 2, pystring);
988 
989  PyObject* res = PyObject_CallObject(
990  detail::Interpreter::get().s_python_function_stem, plot_args);
991 
992  Py_DECREF(plot_args);
993  if (res)
994  Py_DECREF(res);
995 
996  return res;
997 }
998 
999 template<typename NumericX, typename NumericY>
1000 bool semilogx(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
1001 {
1002  assert(x.size() == y.size());
1003 
1004  PyObject* xarray = get_array(x);
1005  PyObject* yarray = get_array(y);
1006 
1007  PyObject* pystring = PyString_FromString(s.c_str());
1008 
1009  PyObject* plot_args = PyTuple_New(3);
1010  PyTuple_SetItem(plot_args, 0, xarray);
1011  PyTuple_SetItem(plot_args, 1, yarray);
1012  PyTuple_SetItem(plot_args, 2, pystring);
1013 
1014  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_semilogx, plot_args);
1015 
1016  Py_DECREF(plot_args);
1017  if(res) Py_DECREF(res);
1018 
1019  return res;
1020 }
1021 
1022 template<typename NumericX, typename NumericY>
1023 bool semilogy(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
1024 {
1025  assert(x.size() == y.size());
1026 
1027  PyObject* xarray = get_array(x);
1028  PyObject* yarray = get_array(y);
1029 
1030  PyObject* pystring = PyString_FromString(s.c_str());
1031 
1032  PyObject* plot_args = PyTuple_New(3);
1033  PyTuple_SetItem(plot_args, 0, xarray);
1034  PyTuple_SetItem(plot_args, 1, yarray);
1035  PyTuple_SetItem(plot_args, 2, pystring);
1036 
1037  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_semilogy, plot_args);
1038 
1039  Py_DECREF(plot_args);
1040  if(res) Py_DECREF(res);
1041 
1042  return res;
1043 }
1044 
1045 template<typename NumericX, typename NumericY>
1046 bool loglog(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
1047 {
1048  assert(x.size() == y.size());
1049 
1050  PyObject* xarray = get_array(x);
1051  PyObject* yarray = get_array(y);
1052 
1053  PyObject* pystring = PyString_FromString(s.c_str());
1054 
1055  PyObject* plot_args = PyTuple_New(3);
1056  PyTuple_SetItem(plot_args, 0, xarray);
1057  PyTuple_SetItem(plot_args, 1, yarray);
1058  PyTuple_SetItem(plot_args, 2, pystring);
1059 
1060  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_loglog, plot_args);
1061 
1062  Py_DECREF(plot_args);
1063  if(res) Py_DECREF(res);
1064 
1065  return res;
1066 }
1067 
1068 template<typename NumericX, typename NumericY>
1069 bool errorbar(const std::vector<NumericX> &x, const std::vector<NumericY> &y, const std::vector<NumericX> &yerr, const std::map<std::string, std::string> &keywords = {})
1070 {
1071  assert(x.size() == y.size());
1072 
1073  PyObject* xarray = get_array(x);
1074  PyObject* yarray = get_array(y);
1075  PyObject* yerrarray = get_array(yerr);
1076 
1077  // construct keyword args
1078  PyObject* kwargs = PyDict_New();
1079  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
1080  {
1081  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1082  }
1083 
1084  PyDict_SetItemString(kwargs, "yerr", yerrarray);
1085 
1086  PyObject *plot_args = PyTuple_New(2);
1087  PyTuple_SetItem(plot_args, 0, xarray);
1088  PyTuple_SetItem(plot_args, 1, yarray);
1089 
1090  PyObject *res = PyObject_Call(detail::Interpreter::get().s_python_function_errorbar, plot_args, kwargs);
1091 
1092  Py_DECREF(kwargs);
1093  Py_DECREF(plot_args);
1094 
1095  if (res)
1096  Py_DECREF(res);
1097  else
1098  throw std::runtime_error("Call to errorbar() failed.");
1099 
1100  return res;
1101 }
1102 
1103 template<typename Numeric>
1104 bool named_plot(const std::string& name, const std::vector<Numeric>& y, const std::string& format = "")
1105 {
1106  PyObject* kwargs = PyDict_New();
1107  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1108 
1109  PyObject* yarray = get_array(y);
1110 
1111  PyObject* pystring = PyString_FromString(format.c_str());
1112 
1113  PyObject* plot_args = PyTuple_New(2);
1114 
1115  PyTuple_SetItem(plot_args, 0, yarray);
1116  PyTuple_SetItem(plot_args, 1, pystring);
1117 
1118  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_plot, plot_args, kwargs);
1119 
1120  Py_DECREF(kwargs);
1121  Py_DECREF(plot_args);
1122  if (res) Py_DECREF(res);
1123 
1124  return res;
1125 }
1126 
1127 template<typename Numeric>
1128 bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
1129 {
1130  PyObject* kwargs = PyDict_New();
1131  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1132 
1133  PyObject* xarray = get_array(x);
1134  PyObject* yarray = get_array(y);
1135 
1136  PyObject* pystring = PyString_FromString(format.c_str());
1137 
1138  PyObject* plot_args = PyTuple_New(3);
1139  PyTuple_SetItem(plot_args, 0, xarray);
1140  PyTuple_SetItem(plot_args, 1, yarray);
1141  PyTuple_SetItem(plot_args, 2, pystring);
1142 
1143  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_plot, plot_args, kwargs);
1144 
1145  Py_DECREF(kwargs);
1146  Py_DECREF(plot_args);
1147  if (res) Py_DECREF(res);
1148 
1149  return res;
1150 }
1151 
1152 template<typename Numeric>
1153 bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
1154 {
1155  PyObject* kwargs = PyDict_New();
1156  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1157 
1158  PyObject* xarray = get_array(x);
1159  PyObject* yarray = get_array(y);
1160 
1161  PyObject* pystring = PyString_FromString(format.c_str());
1162 
1163  PyObject* plot_args = PyTuple_New(3);
1164  PyTuple_SetItem(plot_args, 0, xarray);
1165  PyTuple_SetItem(plot_args, 1, yarray);
1166  PyTuple_SetItem(plot_args, 2, pystring);
1167 
1168  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_semilogx, plot_args, kwargs);
1169 
1170  Py_DECREF(kwargs);
1171  Py_DECREF(plot_args);
1172  if (res) Py_DECREF(res);
1173 
1174  return res;
1175 }
1176 
1177 template<typename Numeric>
1178 bool named_semilogy(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
1179 {
1180  PyObject* kwargs = PyDict_New();
1181  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1182 
1183  PyObject* xarray = get_array(x);
1184  PyObject* yarray = get_array(y);
1185 
1186  PyObject* pystring = PyString_FromString(format.c_str());
1187 
1188  PyObject* plot_args = PyTuple_New(3);
1189  PyTuple_SetItem(plot_args, 0, xarray);
1190  PyTuple_SetItem(plot_args, 1, yarray);
1191  PyTuple_SetItem(plot_args, 2, pystring);
1192 
1193  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_semilogy, plot_args, kwargs);
1194 
1195  Py_DECREF(kwargs);
1196  Py_DECREF(plot_args);
1197  if (res) Py_DECREF(res);
1198 
1199  return res;
1200 }
1201 
1202 template<typename Numeric>
1203 bool named_loglog(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
1204 {
1205  PyObject* kwargs = PyDict_New();
1206  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1207 
1208  PyObject* xarray = get_array(x);
1209  PyObject* yarray = get_array(y);
1210 
1211  PyObject* pystring = PyString_FromString(format.c_str());
1212 
1213  PyObject* plot_args = PyTuple_New(3);
1214  PyTuple_SetItem(plot_args, 0, xarray);
1215  PyTuple_SetItem(plot_args, 1, yarray);
1216  PyTuple_SetItem(plot_args, 2, pystring);
1217  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_loglog, plot_args, kwargs);
1218 
1219  Py_DECREF(kwargs);
1220  Py_DECREF(plot_args);
1221  if (res) Py_DECREF(res);
1222 
1223  return res;
1224 }
1225 
1226 template<typename Numeric>
1227 bool plot(const std::vector<Numeric>& y, const std::string& format = "")
1228 {
1229  std::vector<Numeric> x(y.size());
1230  for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
1231  return plot(x,y,format);
1232 }
1233 
1234 template<typename Numeric>
1235 bool plot(const std::vector<Numeric>& y, const std::map<std::string, std::string>& keywords)
1236 {
1237  std::vector<Numeric> x(y.size());
1238  for(size_t i=0; i<x.size(); ++i) x.at(i) = i;
1239  return plot(x,y,keywords);
1240 }
1241 
1242 template<typename Numeric>
1243 bool stem(const std::vector<Numeric>& y, const std::string& format = "")
1244 {
1245  std::vector<Numeric> x(y.size());
1246  for (size_t i = 0; i < x.size(); ++i) x.at(i) = i;
1247  return stem(x, y, format);
1248 }
1249 
1250 template<typename Numeric>
1251 void text(Numeric x, Numeric y, const std::string& s = "")
1252 {
1253  PyObject* args = PyTuple_New(3);
1254  PyTuple_SetItem(args, 0, PyFloat_FromDouble(x));
1255  PyTuple_SetItem(args, 1, PyFloat_FromDouble(y));
1256  PyTuple_SetItem(args, 2, PyString_FromString(s.c_str()));
1257 
1258  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_text, args);
1259  if(!res) throw std::runtime_error("Call to text() failed.");
1260 
1261  Py_DECREF(args);
1262  Py_DECREF(res);
1263 }
1264 
1265 
1266 inline long figure(long number = -1)
1267 {
1268  PyObject *res;
1269  if (number == -1)
1270  res = PyObject_CallObject(detail::Interpreter::get().s_python_function_figure, detail::Interpreter::get().s_python_empty_tuple);
1271  else {
1272  assert(number > 0);
1273 
1274  // Make sure interpreter is initialised
1275  detail::Interpreter::get();
1276 
1277  PyObject *args = PyTuple_New(1);
1278  PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1279  res = PyObject_CallObject(detail::Interpreter::get().s_python_function_figure, args);
1280  Py_DECREF(args);
1281  }
1282 
1283  if(!res) throw std::runtime_error("Call to figure() failed.");
1284 
1285  PyObject* num = PyObject_GetAttrString(res, "number");
1286  if (!num) throw std::runtime_error("Could not get number attribute of figure object");
1287  const long figureNumber = PyLong_AsLong(num);
1288 
1289  Py_DECREF(num);
1290  Py_DECREF(res);
1291 
1292  return figureNumber;
1293 }
1294 
1295 inline bool fignum_exists(long number)
1296 {
1297  // Make sure interpreter is initialised
1298  detail::Interpreter::get();
1299 
1300  PyObject *args = PyTuple_New(1);
1301  PyTuple_SetItem(args, 0, PyLong_FromLong(number));
1302  PyObject *res = PyObject_CallObject(detail::Interpreter::get().s_python_function_fignum_exists, args);
1303  if(!res) throw std::runtime_error("Call to fignum_exists() failed.");
1304 
1305  bool ret = PyObject_IsTrue(res);
1306  Py_DECREF(res);
1307  Py_DECREF(args);
1308 
1309  return ret;
1310 }
1311 
1312 inline void figure_size(size_t w, size_t h)
1313 {
1314  // Make sure interpreter is initialised
1315  detail::Interpreter::get();
1316 
1317  const size_t dpi = 100;
1318  PyObject* size = PyTuple_New(2);
1319  PyTuple_SetItem(size, 0, PyFloat_FromDouble((double)w / dpi));
1320  PyTuple_SetItem(size, 1, PyFloat_FromDouble((double)h / dpi));
1321 
1322  PyObject* kwargs = PyDict_New();
1323  PyDict_SetItemString(kwargs, "figsize", size);
1324  PyDict_SetItemString(kwargs, "dpi", PyLong_FromSize_t(dpi));
1325 
1326  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_figure,
1327  detail::Interpreter::get().s_python_empty_tuple, kwargs);
1328 
1329  Py_DECREF(kwargs);
1330 
1331  if(!res) throw std::runtime_error("Call to figure_size() failed.");
1332  Py_DECREF(res);
1333 }
1334 
1335 inline void legend()
1336 {
1337  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_legend, detail::Interpreter::get().s_python_empty_tuple);
1338  if(!res) throw std::runtime_error("Call to legend() failed.");
1339 
1340  Py_DECREF(res);
1341 }
1342 
1343 template<typename Numeric>
1344 void ylim(Numeric left, Numeric right)
1345 {
1346  PyObject* list = PyList_New(2);
1347  PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1348  PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1349 
1350  PyObject* args = PyTuple_New(1);
1351  PyTuple_SetItem(args, 0, list);
1352 
1353  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_ylim, args);
1354  if(!res) throw std::runtime_error("Call to ylim() failed.");
1355 
1356  Py_DECREF(args);
1357  Py_DECREF(res);
1358 }
1359 
1360 template<typename Numeric>
1361 void xlim(Numeric left, Numeric right)
1362 {
1363  PyObject* list = PyList_New(2);
1364  PyList_SetItem(list, 0, PyFloat_FromDouble(left));
1365  PyList_SetItem(list, 1, PyFloat_FromDouble(right));
1366 
1367  PyObject* args = PyTuple_New(1);
1368  PyTuple_SetItem(args, 0, list);
1369 
1370  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_xlim, args);
1371  if(!res) throw std::runtime_error("Call to xlim() failed.");
1372 
1373  Py_DECREF(args);
1374  Py_DECREF(res);
1375 }
1376 
1377 
1378 inline double* xlim()
1379 {
1380  PyObject* args = PyTuple_New(0);
1381  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_xlim, args);
1382  PyObject* left = PyTuple_GetItem(res,0);
1383  PyObject* right = PyTuple_GetItem(res,1);
1384 
1385  double* arr = new double[2];
1386  arr[0] = PyFloat_AsDouble(left);
1387  arr[1] = PyFloat_AsDouble(right);
1388 
1389  if(!res) throw std::runtime_error("Call to xlim() failed.");
1390 
1391  Py_DECREF(res);
1392  return arr;
1393 }
1394 
1395 
1396 inline double* ylim()
1397 {
1398  PyObject* args = PyTuple_New(0);
1399  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_ylim, args);
1400  PyObject* left = PyTuple_GetItem(res,0);
1401  PyObject* right = PyTuple_GetItem(res,1);
1402 
1403  double* arr = new double[2];
1404  arr[0] = PyFloat_AsDouble(left);
1405  arr[1] = PyFloat_AsDouble(right);
1406 
1407  if(!res) throw std::runtime_error("Call to ylim() failed.");
1408 
1409  Py_DECREF(res);
1410  return arr;
1411 }
1412 
1413 template<typename Numeric>
1414 inline void xticks(const std::vector<Numeric> &ticks, const std::vector<std::string> &labels = {}, const std::map<std::string, std::string>& keywords = {})
1415 {
1416  assert(labels.size() == 0 || ticks.size() == labels.size());
1417 
1418  // using numpy array
1419  PyObject* ticksarray = get_array(ticks);
1420 
1421  PyObject* args;
1422  if(labels.size() == 0) {
1423  // construct positional args
1424  args = PyTuple_New(1);
1425  PyTuple_SetItem(args, 0, ticksarray);
1426  } else {
1427  // make tuple of tick labels
1428  PyObject* labelstuple = PyTuple_New(labels.size());
1429  for (size_t i = 0; i < labels.size(); i++)
1430  PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
1431 
1432  // construct positional args
1433  args = PyTuple_New(2);
1434  PyTuple_SetItem(args, 0, ticksarray);
1435  PyTuple_SetItem(args, 1, labelstuple);
1436  }
1437 
1438  // construct keyword args
1439  PyObject* kwargs = PyDict_New();
1440  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
1441  {
1442  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1443  }
1444 
1445  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_xticks, args, kwargs);
1446 
1447  Py_DECREF(args);
1448  Py_DECREF(kwargs);
1449  if(!res) throw std::runtime_error("Call to xticks() failed");
1450 
1451  Py_DECREF(res);
1452 }
1453 
1454 template<typename Numeric>
1455 inline void xticks(const std::vector<Numeric> &ticks, const std::map<std::string, std::string>& keywords)
1456 {
1457  xticks(ticks, {}, keywords);
1458 }
1459 
1460 template<typename Numeric>
1461 inline void yticks(const std::vector<Numeric> &ticks, const std::vector<std::string> &labels = {}, const std::map<std::string, std::string>& keywords = {})
1462 {
1463  assert(labels.size() == 0 || ticks.size() == labels.size());
1464 
1465  // using numpy array
1466  PyObject* ticksarray = get_array(ticks);
1467 
1468  PyObject* args;
1469  if(labels.size() == 0) {
1470  // construct positional args
1471  args = PyTuple_New(1);
1472  PyTuple_SetItem(args, 0, ticksarray);
1473  } else {
1474  // make tuple of tick labels
1475  PyObject* labelstuple = PyTuple_New(labels.size());
1476  for (size_t i = 0; i < labels.size(); i++)
1477  PyTuple_SetItem(labelstuple, i, PyUnicode_FromString(labels[i].c_str()));
1478 
1479  // construct positional args
1480  args = PyTuple_New(2);
1481  PyTuple_SetItem(args, 0, ticksarray);
1482  PyTuple_SetItem(args, 1, labelstuple);
1483  }
1484 
1485  // construct keyword args
1486  PyObject* kwargs = PyDict_New();
1487  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
1488  {
1489  PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str()));
1490  }
1491 
1492  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_yticks, args, kwargs);
1493 
1494  Py_DECREF(args);
1495  Py_DECREF(kwargs);
1496  if(!res) throw std::runtime_error("Call to yticks() failed");
1497 
1498  Py_DECREF(res);
1499 }
1500 
1501 template<typename Numeric>
1502 inline void yticks(const std::vector<Numeric> &ticks, const std::map<std::string, std::string>& keywords)
1503 {
1504  yticks(ticks, {}, keywords);
1505 }
1506 
1507 inline void subplot(long nrows, long ncols, long plot_number)
1508 {
1509  // construct positional args
1510  PyObject* args = PyTuple_New(3);
1511  PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
1512  PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
1513  PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));
1514 
1515  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_subplot, args);
1516  if(!res) throw std::runtime_error("Call to subplot() failed.");
1517 
1518  Py_DECREF(args);
1519  Py_DECREF(res);
1520 }
1521 
1522 inline void subplot2grid(long nrows, long ncols, long rowid=0, long colid=0, long rowspan=1, long colspan=1)
1523 {
1524  PyObject* shape = PyTuple_New(2);
1525  PyTuple_SetItem(shape, 0, PyLong_FromLong(nrows));
1526  PyTuple_SetItem(shape, 1, PyLong_FromLong(ncols));
1527 
1528  PyObject* loc = PyTuple_New(2);
1529  PyTuple_SetItem(loc, 0, PyLong_FromLong(rowid));
1530  PyTuple_SetItem(loc, 1, PyLong_FromLong(colid));
1531 
1532  PyObject* args = PyTuple_New(4);
1533  PyTuple_SetItem(args, 0, shape);
1534  PyTuple_SetItem(args, 1, loc);
1535  PyTuple_SetItem(args, 2, PyLong_FromLong(rowspan));
1536  PyTuple_SetItem(args, 3, PyLong_FromLong(colspan));
1537 
1538  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_subplot2grid, args);
1539  if(!res) throw std::runtime_error("Call to subplot2grid() failed.");
1540 
1541  Py_DECREF(shape);
1542  Py_DECREF(loc);
1543  Py_DECREF(args);
1544  Py_DECREF(res);
1545 }
1546 
1547 inline void title(const std::string &titlestr, const std::map<std::string, std::string> &keywords = {})
1548 {
1549  PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
1550  PyObject* args = PyTuple_New(1);
1551  PyTuple_SetItem(args, 0, pytitlestr);
1552 
1553  PyObject* kwargs = PyDict_New();
1554  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1555  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1556  }
1557 
1558  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_title, args, kwargs);
1559  if(!res) throw std::runtime_error("Call to title() failed.");
1560 
1561  Py_DECREF(args);
1562  Py_DECREF(kwargs);
1563  Py_DECREF(res);
1564 }
1565 
1566 inline void suptitle(const std::string &suptitlestr, const std::map<std::string, std::string> &keywords = {})
1567 {
1568  PyObject* pysuptitlestr = PyString_FromString(suptitlestr.c_str());
1569  PyObject* args = PyTuple_New(1);
1570  PyTuple_SetItem(args, 0, pysuptitlestr);
1571 
1572  PyObject* kwargs = PyDict_New();
1573  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1574  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1575  }
1576 
1577  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_suptitle, args, kwargs);
1578  if(!res) throw std::runtime_error("Call to suptitle() failed.");
1579 
1580  Py_DECREF(args);
1581  Py_DECREF(kwargs);
1582  Py_DECREF(res);
1583 }
1584 
1585 inline void axis(const std::string &axisstr)
1586 {
1587  PyObject* str = PyString_FromString(axisstr.c_str());
1588  PyObject* args = PyTuple_New(1);
1589  PyTuple_SetItem(args, 0, str);
1590 
1591  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_axis, args);
1592  if(!res) throw std::runtime_error("Call to title() failed.");
1593 
1594  Py_DECREF(args);
1595  Py_DECREF(res);
1596 }
1597 
1598 inline void xlabel(const std::string &str, const std::map<std::string, std::string> &keywords = {})
1599 {
1600  PyObject* pystr = PyString_FromString(str.c_str());
1601  PyObject* args = PyTuple_New(1);
1602  PyTuple_SetItem(args, 0, pystr);
1603 
1604  PyObject* kwargs = PyDict_New();
1605  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1606  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1607  }
1608 
1609  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_xlabel, args, kwargs);
1610  if(!res) throw std::runtime_error("Call to xlabel() failed.");
1611 
1612  Py_DECREF(args);
1613  Py_DECREF(kwargs);
1614  Py_DECREF(res);
1615 }
1616 
1617 inline void ylabel(const std::string &str, const std::map<std::string, std::string>& keywords = {})
1618 {
1619  PyObject* pystr = PyString_FromString(str.c_str());
1620  PyObject* args = PyTuple_New(1);
1621  PyTuple_SetItem(args, 0, pystr);
1622 
1623  PyObject* kwargs = PyDict_New();
1624  for (auto it = keywords.begin(); it != keywords.end(); ++it) {
1625  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1626  }
1627 
1628  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_ylabel, args, kwargs);
1629  if(!res) throw std::runtime_error("Call to ylabel() failed.");
1630 
1631  Py_DECREF(args);
1632  Py_DECREF(kwargs);
1633  Py_DECREF(res);
1634 }
1635 
1636 inline void grid(bool flag)
1637 {
1638  PyObject* pyflag = flag ? Py_True : Py_False;
1639  Py_INCREF(pyflag);
1640 
1641  PyObject* args = PyTuple_New(1);
1642  PyTuple_SetItem(args, 0, pyflag);
1643 
1644  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_grid, args);
1645  if(!res) throw std::runtime_error("Call to grid() failed.");
1646 
1647  Py_DECREF(args);
1648  Py_DECREF(res);
1649 }
1650 
1651 inline void show(const bool block = true)
1652 {
1653  PyObject* res;
1654  if(block)
1655  {
1656  res = PyObject_CallObject(
1657  detail::Interpreter::get().s_python_function_show,
1658  detail::Interpreter::get().s_python_empty_tuple);
1659  }
1660  else
1661  {
1662  PyObject *kwargs = PyDict_New();
1663  PyDict_SetItemString(kwargs, "block", Py_False);
1664  res = PyObject_Call( detail::Interpreter::get().s_python_function_show, detail::Interpreter::get().s_python_empty_tuple, kwargs);
1665  Py_DECREF(kwargs);
1666  }
1667 
1668 
1669  if (!res) throw std::runtime_error("Call to show() failed.");
1670 
1671  Py_DECREF(res);
1672 }
1673 
1674 inline void close()
1675 {
1676  PyObject* res = PyObject_CallObject(
1677  detail::Interpreter::get().s_python_function_close,
1678  detail::Interpreter::get().s_python_empty_tuple);
1679 
1680  if (!res) throw std::runtime_error("Call to close() failed.");
1681 
1682  Py_DECREF(res);
1683 }
1684 
1685 inline void xkcd() {
1686  PyObject* res;
1687  PyObject *kwargs = PyDict_New();
1688 
1689  res = PyObject_Call(detail::Interpreter::get().s_python_function_xkcd,
1690  detail::Interpreter::get().s_python_empty_tuple, kwargs);
1691 
1692  Py_DECREF(kwargs);
1693 
1694  if (!res)
1695  throw std::runtime_error("Call to show() failed.");
1696 
1697  Py_DECREF(res);
1698 }
1699 
1700 inline void draw()
1701 {
1702  PyObject* res = PyObject_CallObject(
1703  detail::Interpreter::get().s_python_function_draw,
1704  detail::Interpreter::get().s_python_empty_tuple);
1705 
1706  if (!res) throw std::runtime_error("Call to draw() failed.");
1707 
1708  Py_DECREF(res);
1709 }
1710 
1711 template<typename Numeric>
1712 inline void pause(Numeric interval)
1713 {
1714  PyObject* args = PyTuple_New(1);
1715  PyTuple_SetItem(args, 0, PyFloat_FromDouble(interval));
1716 
1717  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_pause, args);
1718  if(!res) throw std::runtime_error("Call to pause() failed.");
1719 
1720  Py_DECREF(args);
1721  Py_DECREF(res);
1722 }
1723 
1724 inline void save(const std::string& filename)
1725 {
1726  PyObject* pyfilename = PyString_FromString(filename.c_str());
1727 
1728  PyObject* args = PyTuple_New(1);
1729  PyTuple_SetItem(args, 0, pyfilename);
1730 
1731  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_save, args);
1732  if (!res) throw std::runtime_error("Call to save() failed.");
1733 
1734  Py_DECREF(args);
1735  Py_DECREF(res);
1736 }
1737 
1738 inline void clf() {
1739  PyObject *res = PyObject_CallObject(
1740  detail::Interpreter::get().s_python_function_clf,
1741  detail::Interpreter::get().s_python_empty_tuple);
1742 
1743  if (!res) throw std::runtime_error("Call to clf() failed.");
1744 
1745  Py_DECREF(res);
1746 }
1747 
1748  inline void ion() {
1749  PyObject *res = PyObject_CallObject(
1750  detail::Interpreter::get().s_python_function_ion,
1751  detail::Interpreter::get().s_python_empty_tuple);
1752 
1753  if (!res) throw std::runtime_error("Call to ion() failed.");
1754 
1755  Py_DECREF(res);
1756 }
1757 
1758 inline std::vector<std::array<double, 2>> ginput(const int numClicks = 1, const std::map<std::string, std::string>& keywords = {})
1759 {
1760  PyObject *args = PyTuple_New(1);
1761  PyTuple_SetItem(args, 0, PyLong_FromLong(numClicks));
1762 
1763  // construct keyword args
1764  PyObject* kwargs = PyDict_New();
1765  for(std::map<std::string, std::string>::const_iterator it = keywords.begin(); it != keywords.end(); ++it)
1766  {
1767  PyDict_SetItemString(kwargs, it->first.c_str(), PyUnicode_FromString(it->second.c_str()));
1768  }
1769 
1770  PyObject* res = PyObject_Call(
1771  detail::Interpreter::get().s_python_function_ginput, args, kwargs);
1772 
1773  Py_DECREF(kwargs);
1774  Py_DECREF(args);
1775  if (!res) throw std::runtime_error("Call to ginput() failed.");
1776 
1777  const size_t len = PyList_Size(res);
1778  std::vector<std::array<double, 2>> out;
1779  out.reserve(len);
1780  for (size_t i = 0; i < len; i++) {
1781  PyObject *current = PyList_GetItem(res, i);
1782  std::array<double, 2> position;
1783  position[0] = PyFloat_AsDouble(PyTuple_GetItem(current, 0));
1784  position[1] = PyFloat_AsDouble(PyTuple_GetItem(current, 1));
1785  out.push_back(position);
1786  }
1787  Py_DECREF(res);
1788 
1789  return out;
1790 }
1791 
1792 // Actually, is there any reason not to call this automatically for every plot?
1793 inline void tight_layout() {
1794  PyObject *res = PyObject_CallObject(
1795  detail::Interpreter::get().s_python_function_tight_layout,
1796  detail::Interpreter::get().s_python_empty_tuple);
1797 
1798  if (!res) throw std::runtime_error("Call to tight_layout() failed.");
1799 
1800  Py_DECREF(res);
1801 }
1802 
1803 // Support for variadic plot() and initializer lists:
1804 
1805 namespace detail {
1806 
1807 template<typename T>
1808 using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
1809 
1810 template<bool obj, typename T>
1811 struct is_callable_impl;
1812 
1813 template<typename T>
1814 struct is_callable_impl<false, T>
1815 {
1816  typedef is_function<T> type;
1817 }; // a non-object is callable iff it is a function
1818 
1819 template<typename T>
1820 struct is_callable_impl<true, T>
1821 {
1822  struct Fallback { void operator()(); };
1823  struct Derived : T, Fallback { };
1824 
1825  template<typename U, U> struct Check;
1826 
1827  template<typename U>
1828  static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
1829 
1830  template<typename U>
1831  static std::false_type test( Check<void(Fallback::*)(), &U::operator()>* );
1832 
1833 public:
1834  typedef decltype(test<Derived>(nullptr)) type;
1835  typedef decltype(&Fallback::operator()) dtype;
1836  static constexpr bool value = type::value;
1837 }; // an object is callable iff it defines operator()
1838 
1839 template<typename T>
1840 struct is_callable
1841 {
1842  // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
1843  typedef typename is_callable_impl<std::is_class<T>::value, T>::type type;
1844 };
1845 
1846 template<typename IsYDataCallable>
1847 struct plot_impl { };
1848 
1849 template<>
1850 struct plot_impl<std::false_type>
1851 {
1852  template<typename IterableX, typename IterableY>
1853  bool operator()(const IterableX& x, const IterableY& y, const std::string& format)
1854  {
1855  // 2-phase lookup for distance, begin, end
1856  using std::distance;
1857  using std::begin;
1858  using std::end;
1859 
1860  auto xs = distance(begin(x), end(x));
1861  auto ys = distance(begin(y), end(y));
1862  assert(xs == ys && "x and y data must have the same number of elements!");
1863 
1864  PyObject* xlist = PyList_New(xs);
1865  PyObject* ylist = PyList_New(ys);
1866  PyObject* pystring = PyString_FromString(format.c_str());
1867 
1868  auto itx = begin(x), ity = begin(y);
1869  for(size_t i = 0; i < xs; ++i) {
1870  PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++));
1871  PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++));
1872  }
1873 
1874  PyObject* plot_args = PyTuple_New(3);
1875  PyTuple_SetItem(plot_args, 0, xlist);
1876  PyTuple_SetItem(plot_args, 1, ylist);
1877  PyTuple_SetItem(plot_args, 2, pystring);
1878 
1879  PyObject* res = PyObject_CallObject(detail::Interpreter::get().s_python_function_plot, plot_args);
1880 
1881  Py_DECREF(plot_args);
1882  if(res) Py_DECREF(res);
1883 
1884  return res;
1885  }
1886 };
1887 
1888 template<>
1889 struct plot_impl<std::true_type>
1890 {
1891  template<typename Iterable, typename Callable>
1892  bool operator()(const Iterable& ticks, const Callable& f, const std::string& format)
1893  {
1894  if(begin(ticks) == end(ticks)) return true;
1895 
1896  // We could use additional meta-programming to deduce the correct element type of y,
1897  // but all values have to be convertible to double anyways
1898  std::vector<double> y;
1899  for(auto x : ticks) y.push_back(f(x));
1900  return plot_impl<std::false_type>()(ticks,y,format);
1901  }
1902 };
1903 
1904 } // end namespace detail
1905 
1906 // recursion stop for the above
1907 template<typename... Args>
1908 bool plot() { return true; }
1909 
1910 template<typename A, typename B, typename... Args>
1911 bool plot(const A& a, const B& b, const std::string& format, Args... args)
1912 {
1913  return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot(args...);
1914 }
1915 
1916 /*
1917  * This group of plot() functions is needed to support initializer lists, i.e. calling
1918  * plot( {1,2,3,4} )
1919  */
1920 inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::string& format = "") {
1921  return plot<double,double>(x,y,format);
1922 }
1923 
1924 inline bool plot(const std::vector<double>& y, const std::string& format = "") {
1925  return plot<double>(y,format);
1926 }
1927 
1928 inline bool plot(const std::vector<double>& x, const std::vector<double>& y, const std::map<std::string, std::string>& keywords) {
1929  return plot<double>(x,y,keywords);
1930 }
1931 
1932 /*
1933  * This class allows dynamic plots, ie changing the plotted data without clearing and re-plotting
1934  */
1935 
1936 class Plot
1937 {
1938 public:
1939  // default initialization with plot label, some data and format
1940  template<typename Numeric>
1941  Plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
1942 
1943  assert(x.size() == y.size());
1944 
1945  PyObject* kwargs = PyDict_New();
1946  if(name != "")
1947  PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
1948 
1949  PyObject* xarray = get_array(x);
1950  PyObject* yarray = get_array(y);
1951 
1952  PyObject* pystring = PyString_FromString(format.c_str());
1953 
1954  PyObject* plot_args = PyTuple_New(3);
1955  PyTuple_SetItem(plot_args, 0, xarray);
1956  PyTuple_SetItem(plot_args, 1, yarray);
1957  PyTuple_SetItem(plot_args, 2, pystring);
1958 
1959  PyObject* res = PyObject_Call(detail::Interpreter::get().s_python_function_plot, plot_args, kwargs);
1960 
1961  Py_DECREF(kwargs);
1962  Py_DECREF(plot_args);
1963 
1964  if(res)
1965  {
1966  line= PyList_GetItem(res, 0);
1967 
1968  if(line)
1969  set_data_fct = PyObject_GetAttrString(line,"set_data");
1970  else
1971  Py_DECREF(line);
1972  Py_DECREF(res);
1973  }
1974  }
1975 
1976  // shorter initialization with name or format only
1977  // basically calls line, = plot([], [])
1978  Plot(const std::string& name = "", const std::string& format = "")
1979  : Plot(name, std::vector<double>(), std::vector<double>(), format) {}
1980 
1981  template<typename Numeric>
1982  bool update(const std::vector<Numeric>& x, const std::vector<Numeric>& y) {
1983  assert(x.size() == y.size());
1984  if(set_data_fct)
1985  {
1986  PyObject* xarray = get_array(x);
1987  PyObject* yarray = get_array(y);
1988 
1989  PyObject* plot_args = PyTuple_New(2);
1990  PyTuple_SetItem(plot_args, 0, xarray);
1991  PyTuple_SetItem(plot_args, 1, yarray);
1992 
1993  PyObject* res = PyObject_CallObject(set_data_fct, plot_args);
1994  if (res) Py_DECREF(res);
1995  return res;
1996  }
1997  return false;
1998  }
1999 
2000  // clears the plot but keep it available
2001  bool clear() {
2002  return update(std::vector<double>(), std::vector<double>());
2003  }
2004 
2005  // definitely remove this line
2006  void remove() {
2007  if(line)
2008  {
2009  auto remove_fct = PyObject_GetAttrString(line,"remove");
2010  PyObject* args = PyTuple_New(0);
2011  PyObject* res = PyObject_CallObject(remove_fct, args);
2012  if (res) Py_DECREF(res);
2013  }
2014  decref();
2015  }
2016 
2017  ~Plot() {
2018  decref();
2019  }
2020 private:
2021 
2022  void decref() {
2023  if(line)
2024  Py_DECREF(line);
2025  if(set_data_fct)
2026  Py_DECREF(set_data_fct);
2027  }
2028 
2029 
2030  PyObject* line = nullptr;
2031  PyObject* set_data_fct = nullptr;
2032 };
2033 
2034 } // end namespace matplotlibcpp
2035 } // end namespace MatPlotLib
2036 } // end namespace Visualization
2037 } // end namespace TBTK
Definition: Boolean.h:32