├── .gitignore ├── LICENSE ├── README.md ├── build_and_run.sh ├── main.cpp ├── makefile └── matplotlibcpp.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Atsushi Sakai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # matplotlib-cpp-starter 2 | 3 | This is a starter kit with matplotlib-cpp 4 | 5 | - [lava/matplotlib-cpp: Extremely simple yet powerful header-only C++ plotting library built on the popular matplotlib](https://github.com/lava/matplotlib-cpp "lava/matplotlib-cpp: Extremely simple yet powerful header-only C++ plotting library built on the popular matplotlib") 6 | 7 | # Denpendency 8 | 9 | - python2.7.x 10 | 11 | - matplotlib 12 | 13 | # Usage 14 | 15 | clone this repository. 16 | 17 | > $ git clone https://github.com/AtsushiSakai/matplotlib-cpp-starter.git 18 | 19 | Then, run the script. 20 | 21 | > $ ./build_and_run.sh 22 | 23 | You can see the matplotlib graph from C++ code. 24 | 25 | ![20160116081515.png](http://cdn-ak.f.st-hatena.com/images/fotolife/m/meison_amsl/20160116/20160116081515.png) 26 | 27 | # LICENSE 28 | 29 | MIT 30 | -------------------------------------------------------------------------------- /build_and_run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # get file path 3 | cwd=`dirname "${0}"` 4 | expr "${0}" : "/.*" > /dev/null || cwd=`(cd "${cwd}" && pwd)` 5 | 6 | g++ ${cwd}/main.cpp -lstdc++ -lpython2.7 -std=c++11 && ${cwd}/a.out 7 | 8 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include"matplotlibcpp.h" 3 | using namespace std; 4 | 5 | namespace plt = matplotlibcpp; 6 | 7 | int main(){ 8 | cout<<"matplotlib-cpp sample start"< x(n), y(n); 12 | // vector x(1), y(1); 13 | for(int i=0; i 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #if __cplusplus > 199711L 10 | #include 11 | #endif 12 | 13 | #include 14 | 15 | namespace matplotlibcpp { 16 | 17 | namespace detail { 18 | struct _interpreter { 19 | PyObject *s_python_function_show; 20 | PyObject *s_python_function_save; 21 | PyObject *s_python_function_figure; 22 | PyObject *s_python_function_plot; 23 | PyObject *s_python_function_legend; 24 | PyObject *s_python_function_xlim; 25 | PyObject *s_python_function_ylim; 26 | PyObject *s_python_function_title; 27 | PyObject *s_python_function_axis; 28 | PyObject *s_python_function_xlabel; 29 | PyObject *s_python_function_ylabel; 30 | PyObject *s_python_function_grid; 31 | PyObject *s_python_function_pause; 32 | PyObject *s_python_empty_tuple; 33 | 34 | /* For now, _interpreter is implemented as a singleton since its currently not possible to have 35 | multiple independent embedded python interpreters without patching the python source code 36 | or starting a seperate process for each. 37 | 38 | http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program 39 | */ 40 | 41 | static _interpreter& get() { 42 | static _interpreter ctx; 43 | return ctx; 44 | } 45 | 46 | private: 47 | _interpreter() { 48 | char name[] = "plotting"; // silence compiler warning abount const strings 49 | Py_SetProgramName(name); // optional but recommended 50 | Py_Initialize(); 51 | 52 | PyObject* pyplotname = PyString_FromString("matplotlib.pyplot"); 53 | PyObject* pylabname = PyString_FromString("pylab"); 54 | if(!pyplotname || !pylabname) { throw std::runtime_error("couldnt create string"); } 55 | 56 | PyObject* pymod = PyImport_Import(pyplotname); 57 | Py_DECREF(pyplotname); 58 | if(!pymod) { throw std::runtime_error("Error loading module matplotlib.pyplot!"); } 59 | 60 | PyObject* pylabmod = PyImport_Import(pylabname); 61 | Py_DECREF(pylabname); 62 | if(!pymod) { throw std::runtime_error("Error loading module pylab!"); } 63 | 64 | s_python_function_show = PyObject_GetAttrString(pymod, "show"); 65 | s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); 66 | s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); 67 | s_python_function_legend = PyObject_GetAttrString(pymod, "legend"); 68 | s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim"); 69 | s_python_function_title = PyObject_GetAttrString(pymod, "title"); 70 | s_python_function_axis = PyObject_GetAttrString(pymod, "axis"); 71 | s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel"); 72 | s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel"); 73 | s_python_function_grid = PyObject_GetAttrString(pymod, "grid"); 74 | s_python_function_pause = PyObject_GetAttrString(pymod, "pause"); 75 | s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim"); 76 | 77 | s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig"); 78 | 79 | if(!s_python_function_show 80 | || !s_python_function_save 81 | || !s_python_function_figure 82 | || !s_python_function_plot 83 | || !s_python_function_legend 84 | || !s_python_function_xlim 85 | || !s_python_function_ylim 86 | || !s_python_function_title 87 | || !s_python_function_axis 88 | || !s_python_function_xlabel 89 | || !s_python_function_ylabel 90 | || !s_python_function_grid 91 | || !s_python_function_pause 92 | ) 93 | { throw std::runtime_error("Couldnt find required function!"); } 94 | 95 | if(!PyFunction_Check(s_python_function_show) 96 | || !PyFunction_Check(s_python_function_save) 97 | || !PyFunction_Check(s_python_function_figure) 98 | || !PyFunction_Check(s_python_function_plot) 99 | || !PyFunction_Check(s_python_function_legend) 100 | || !PyFunction_Check(s_python_function_xlim) 101 | || !PyFunction_Check(s_python_function_ylim) 102 | || !PyFunction_Check(s_python_function_title) 103 | || !PyFunction_Check(s_python_function_axis) 104 | || !PyFunction_Check(s_python_function_xlabel) 105 | || !PyFunction_Check(s_python_function_ylabel) 106 | || !PyFunction_Check(s_python_function_grid) 107 | || !PyFunction_Check(s_python_function_pause) 108 | ) 109 | { throw std::runtime_error("Python object is unexpectedly not a PyFunction."); } 110 | 111 | s_python_empty_tuple = PyTuple_New(0); 112 | } 113 | 114 | ~_interpreter() { 115 | Py_Finalize(); 116 | } 117 | }; 118 | } 119 | 120 | 121 | 122 | template 123 | bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) 124 | { 125 | assert(x.size() == y.size()); 126 | 127 | // using python lists 128 | PyObject* xlist = PyList_New(x.size()); 129 | PyObject* ylist = PyList_New(y.size()); 130 | 131 | for(size_t i = 0; i < x.size(); ++i) { 132 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 133 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 134 | } 135 | 136 | // construct positional args 137 | PyObject* args = PyTuple_New(2); 138 | PyTuple_SetItem(args, 0, xlist); 139 | PyTuple_SetItem(args, 1, ylist); 140 | 141 | Py_DECREF(xlist); 142 | Py_DECREF(ylist); 143 | 144 | // construct keyword args 145 | PyObject* kwargs = PyDict_New(); 146 | for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) 147 | { 148 | PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); 149 | } 150 | 151 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); 152 | 153 | Py_DECREF(args); 154 | Py_DECREF(kwargs); 155 | if(res) Py_DECREF(res); 156 | 157 | return res; 158 | } 159 | 160 | 161 | template 162 | bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") 163 | { 164 | assert(x.size() == y.size()); 165 | 166 | PyObject* xlist = PyList_New(x.size()); 167 | PyObject* ylist = PyList_New(y.size()); 168 | PyObject* pystring = PyString_FromString(s.c_str()); 169 | 170 | for(size_t i = 0; i < x.size(); ++i) { 171 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 172 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 173 | } 174 | 175 | PyObject* plot_args = PyTuple_New(3); 176 | PyTuple_SetItem(plot_args, 0, xlist); 177 | PyTuple_SetItem(plot_args, 1, ylist); 178 | PyTuple_SetItem(plot_args, 2, pystring); 179 | 180 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); 181 | 182 | Py_DECREF(xlist); 183 | Py_DECREF(ylist); 184 | Py_DECREF(plot_args); 185 | if(res) Py_DECREF(res); 186 | 187 | return res; 188 | } 189 | 190 | 191 | template 192 | bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { 193 | PyObject* kwargs = PyDict_New(); 194 | PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); 195 | 196 | PyObject* xlist = PyList_New(x.size()); 197 | PyObject* ylist = PyList_New(y.size()); 198 | PyObject* pystring = PyString_FromString(format.c_str()); 199 | 200 | for(size_t i = 0; i < x.size(); ++i) { 201 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x.at(i))); 202 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y.at(i))); 203 | } 204 | 205 | PyObject* plot_args = PyTuple_New(3); 206 | PyTuple_SetItem(plot_args, 0, xlist); 207 | PyTuple_SetItem(plot_args, 1, ylist); 208 | PyTuple_SetItem(plot_args, 2, pystring); 209 | 210 | PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs); 211 | 212 | Py_DECREF(kwargs); 213 | Py_DECREF(xlist); 214 | Py_DECREF(ylist); 215 | Py_DECREF(plot_args); 216 | if(res) Py_DECREF(res); 217 | 218 | return res; 219 | } 220 | 221 | template 222 | bool plot(const std::vector& y, const std::string& format = "") 223 | { 224 | std::vector x(y.size()); 225 | for(size_t i=0; i 238 | void ylim(Numeric left, Numeric right) 239 | { 240 | PyObject* list = PyList_New(2); 241 | PyList_SetItem(list, 0, PyFloat_FromDouble(left)); 242 | PyList_SetItem(list, 1, PyFloat_FromDouble(right)); 243 | 244 | PyObject* args = PyTuple_New(1); 245 | PyTuple_SetItem(args, 0, list); 246 | 247 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylim, args); 248 | if(!res) throw std::runtime_error("Call to ylim() failed."); 249 | 250 | Py_DECREF(list); 251 | Py_DECREF(args); 252 | Py_DECREF(res); 253 | } 254 | 255 | template 256 | void xlim(Numeric left, Numeric right) 257 | { 258 | PyObject* list = PyList_New(2); 259 | PyList_SetItem(list, 0, PyFloat_FromDouble(left)); 260 | PyList_SetItem(list, 1, PyFloat_FromDouble(right)); 261 | 262 | PyObject* args = PyTuple_New(1); 263 | PyTuple_SetItem(args, 0, list); 264 | 265 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlim, args); 266 | if(!res) throw std::runtime_error("Call to xlim() failed."); 267 | 268 | Py_DECREF(list); 269 | Py_DECREF(args); 270 | Py_DECREF(res); 271 | } 272 | 273 | 274 | inline void title(const std::string &titlestr) 275 | { 276 | PyObject* pytitlestr = PyString_FromString(titlestr.c_str()); 277 | PyObject* args = PyTuple_New(1); 278 | PyTuple_SetItem(args, 0, pytitlestr); 279 | 280 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_title, args); 281 | if(!res) throw std::runtime_error("Call to title() failed."); 282 | 283 | //if PyDeCRFF, the show function doesn't wook on Mac OS 284 | } 285 | 286 | inline void axis(const std::string &axisstr) 287 | { 288 | PyObject* str = PyString_FromString(axisstr.c_str()); 289 | PyObject* args = PyTuple_New(1); 290 | PyTuple_SetItem(args, 0, str); 291 | 292 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_axis, args); 293 | if(!res) throw std::runtime_error("Call to title() failed."); 294 | 295 | //if PyDeCRFF, the show function doesn't wook on Mac OS 296 | } 297 | 298 | 299 | 300 | inline void xlabel(const std::string &str) 301 | { 302 | PyObject* pystr = PyString_FromString(str.c_str()); 303 | PyObject* args = PyTuple_New(1); 304 | PyTuple_SetItem(args, 0, pystr); 305 | 306 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_xlabel, args); 307 | if(!res) throw std::runtime_error("Call to xlabel() failed."); 308 | 309 | //if PyDeCRFF, the show function doesn't wook on Mac OS 310 | } 311 | 312 | inline void ylabel(const std::string &str) 313 | { 314 | PyObject* pystr = PyString_FromString(str.c_str()); 315 | PyObject* args = PyTuple_New(1); 316 | PyTuple_SetItem(args, 0, pystr); 317 | 318 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_ylabel, args); 319 | if(!res) throw std::runtime_error("Call to ylabel() failed."); 320 | 321 | //if PyDeCRFF, the show function doesn't wook on Mac OS 322 | } 323 | 324 | inline void grid(const bool &flag) 325 | { 326 | PyObject* pyflag; 327 | if(flag){ 328 | pyflag=Py_True; 329 | } 330 | else{ 331 | pyflag=Py_False; 332 | } 333 | PyObject* args = PyTuple_New(1); 334 | PyTuple_SetItem(args, 0, pyflag); 335 | 336 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_grid, args); 337 | if(!res) throw std::runtime_error("Call to grid() failed."); 338 | 339 | //if PyDeCRFF, the show function doesn't wook on Mac OS 340 | } 341 | 342 | void pause(double sec) 343 | { 344 | PyObject* pysec = PyFloat_FromDouble(sec); 345 | 346 | PyObject* args = PyTuple_New(1); 347 | PyTuple_SetItem(args, 0, pysec); 348 | 349 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_pause, args); 350 | if(!res) throw std::runtime_error("Call to pause() failed."); 351 | 352 | } 353 | 354 | 355 | 356 | 357 | inline void show() 358 | { 359 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple); 360 | if(!res) throw std::runtime_error("Call to show() failed."); 361 | 362 | Py_DECREF(res); 363 | } 364 | 365 | inline void save(const std::string& filename) 366 | { 367 | PyObject* pyfilename = PyString_FromString(filename.c_str()); 368 | 369 | PyObject* args = PyTuple_New(1); 370 | PyTuple_SetItem(args, 0, pyfilename); 371 | 372 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_save, args); 373 | if(!res) throw std::runtime_error("Call to save() failed."); 374 | 375 | Py_DECREF(pyfilename); 376 | Py_DECREF(args); 377 | Py_DECREF(res); 378 | } 379 | 380 | #if __cplusplus > 199711L 381 | // C++11-exclusive content starts here (variadic plot() and initializer list support) 382 | 383 | namespace detail { 384 | template 385 | using is_function = typename std::is_function>>::type; 386 | 387 | template 388 | struct is_callable_impl; 389 | 390 | template 391 | struct is_callable_impl 392 | { 393 | typedef is_function type; 394 | }; // a non-object is callable iff it is a function 395 | 396 | template 397 | struct is_callable_impl 398 | { 399 | struct Fallback { void operator()(); }; 400 | struct Derived : T, Fallback { }; 401 | 402 | template struct Check; 403 | 404 | template 405 | static std::true_type test( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match 406 | 407 | template 408 | static std::false_type test( Check* ); 409 | 410 | public: 411 | typedef decltype(test(nullptr)) type; 412 | typedef decltype(&Fallback::operator()) dtype; 413 | static constexpr bool value = type::value; 414 | }; // an object is callable iff it defines operator() 415 | 416 | template 417 | struct is_callable 418 | { 419 | // dispatch to is_callable_impl or is_callable_impl depending on whether T is of class type or not 420 | typedef typename is_callable_impl::value, T>::type type; 421 | }; 422 | 423 | template 424 | struct plot_impl { }; 425 | 426 | template<> 427 | struct plot_impl 428 | { 429 | template 430 | bool operator()(const IterableX& x, const IterableY& y, const std::string& format) 431 | { 432 | // 2-phase lookup for distance, begin, end 433 | using std::distance; 434 | using std::begin; 435 | using std::end; 436 | 437 | auto xs = distance(begin(x), end(x)); 438 | auto ys = distance(begin(y), end(y)); 439 | assert(xs == ys && "x and y data must have the same number of elements!"); 440 | 441 | PyObject* xlist = PyList_New(xs); 442 | PyObject* ylist = PyList_New(ys); 443 | PyObject* pystring = PyString_FromString(format.c_str()); 444 | 445 | auto itx = begin(x), ity = begin(y); 446 | for(size_t i = 0; i < xs; ++i) { 447 | PyList_SetItem(xlist, i, PyFloat_FromDouble(*itx++)); 448 | PyList_SetItem(ylist, i, PyFloat_FromDouble(*ity++)); 449 | } 450 | 451 | PyObject* plot_args = PyTuple_New(3); 452 | PyTuple_SetItem(plot_args, 0, xlist); 453 | PyTuple_SetItem(plot_args, 1, ylist); 454 | PyTuple_SetItem(plot_args, 2, pystring); 455 | 456 | PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); 457 | 458 | Py_DECREF(xlist); 459 | Py_DECREF(ylist); 460 | Py_DECREF(plot_args); 461 | if(res) Py_DECREF(res); 462 | 463 | return res; 464 | } 465 | }; 466 | 467 | template<> 468 | struct plot_impl 469 | { 470 | template 471 | bool operator()(const Iterable& ticks, const Callable& f, const std::string& format) 472 | { 473 | //std::cout << "Callable impl called" << std::endl; 474 | 475 | if(begin(ticks) == end(ticks)) return true; 476 | 477 | // We could use additional meta-programming to deduce the correct element type of y, 478 | // but all values have to be convertible to double anyways 479 | std::vector y; 480 | for(auto x : ticks) y.push_back(f(x)); 481 | return plot_impl()(ticks,y,format); 482 | } 483 | }; 484 | } 485 | 486 | // recursion stop for the above 487 | template 488 | bool plot() { return true; } 489 | 490 | template 491 | bool plot(const A& a, const B& b, const std::string& format, Args... args) 492 | { 493 | return detail::plot_impl::type>()(a,b,format) && plot(args...); 494 | } 495 | 496 | /* 497 | * This group of plot() functions is needed to support initializer lists, i.e. calling 498 | * plot( {1,2,3,4} ) 499 | */ 500 | bool plot(const std::vector& x, const std::vector& y, const std::string& format = "") { 501 | return plot(x,y,format); 502 | } 503 | 504 | bool plot(const std::vector& y, const std::string& format = "") { 505 | return plot(y,format); 506 | } 507 | 508 | bool plot(const std::vector& x, const std::vector& y, const std::map& keywords) { 509 | return plot(x,y,keywords); 510 | } 511 | 512 | bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::string& format = "") { 513 | return named_plot(name,x,y,format); 514 | } 515 | 516 | #endif 517 | 518 | 519 | 520 | 521 | } 522 | --------------------------------------------------------------------------------