├── package.xml ├── CMakeLists.txt ├── README.md ├── LICENSE ├── src ├── mpl_example_node.cpp └── matplotlibcpp.cpp └── include └── plotty └── matplotlibcpp.hpp /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | plotty 4 | 0.1.4 5 | The plotty package. 6 | Copied from https://github.com/zurich-eye/ze_oss/tree/master/ze_matplotlib 7 | and removed all the dependencies. 8 | 9 | 10 | Michael Burri 11 | BSD 12 | 13 | catkin 14 | catkin_simple 15 | 16 | eigen_catkin 17 | glog_catkin 18 | 19 | gtest 20 | 21 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.3) 2 | project(plotty) 3 | 4 | find_package(catkin_simple REQUIRED) 5 | catkin_simple(ALL_DEPS_REQUIRED) 6 | 7 | add_definitions(-std=c++11 -Wno-sign-compare -Wno-unused-value) 8 | 9 | # The matplotlib-cpp headers are linked against 10 | find_package(PythonLibs) 11 | include_directories(${PYTHON_INCLUDE_DIRS}) 12 | 13 | add_definitions(-DPYTHON_VERSION_MAJOR=${PYTHON_VERSION_MAJOR}) 14 | 15 | ############# 16 | # LIBRARIES # 17 | ############# 18 | set(HEADERS 19 | include/plotty/matplotlibcpp.hpp 20 | ) 21 | 22 | set(SOURCES 23 | src/matplotlibcpp.cpp 24 | ) 25 | 26 | cs_add_library(${PROJECT_NAME} ${SOURCES} ${HEADERS}) 27 | target_link_libraries(${PROJECT_NAME} ${PYTHON_LIBRARY}) 28 | 29 | ############### 30 | # EXECUTABLES # 31 | ############### 32 | 33 | cs_add_executable(mpl_example_node src/mpl_example_node.cpp) 34 | target_link_libraries(mpl_example_node ${PROJECT_NAME}) 35 | 36 | ########## 37 | # EXPORT # 38 | ########## 39 | cs_install() 40 | cs_export() 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plotty: C++ Interface to Matplotlib 2 | ![image](https://cloud.githubusercontent.com/assets/5616392/23658485/10cd0098-0343-11e7-95b5-46d899d6d70e.png) 3 | 4 | ## Principles 5 | 6 | - `plotty::plot(...)` automatically creates a new figure 7 | - `plotty::show()` shows the results of the plot 8 | - calls to `plotty::plot(...)` go to the same plot until `plotty::show()` is called 9 | - by default, calls to `plotty::show()` are blocking and execution continues only after the plot window is closed 10 | 11 | ## Simple plot of a vector: 12 | ```c++ 13 | // Std Vector: 14 | std::vector v({1, 2, 3, 4}); 15 | plotty::plot(v); 16 | plotty::show(); 17 | 18 | // Eigen Types: 19 | Eigen::VectorXd w(100); 20 | w.setRandom(); 21 | plotty::plot(w) 22 | plotty::show(); 23 | ``` 24 | 25 | ## Plot x and y 26 | ```c++ 27 | Eigen::VectorXd t(100); 28 | t.setLinSpaced(100, 0, 20); 29 | Eigen::VectorXd v(100); 30 | v.setRandom(); 31 | plotty::plot(t, v); 32 | plotty::show(); 33 | ``` 34 | 35 | ## Subplots 36 | ```c++ 37 | plotty::subplot(3, 1, 1); 38 | plotty::plot(v1); 39 | plotty::subplot(3, 1, 2); 40 | plotty::plot(v2); 41 | plotty::subplot(3, 1, 3); 42 | plotty::plot(v2); 43 | plotty::plot(); 44 | ``` 45 | 46 | ## Histogram 47 | 48 | The histogram function only exposes the `bins`, `data` and `type` parameters of matplotlibs histogram function. 49 | ```c++ 50 | plotty::hist(v, 10, "bar"); 51 | plotty::show(); 52 | ``` 53 | 54 | ## Formatting 55 | 56 | All functions accept optional format arguments (`plotty::plot(x, y, format)` or `plotty::plot(y, format)`). The 57 | expected format strings are equivalent to the matplotlib format strings: 58 | ```c++ 59 | plotty::plot(t, v, "rx"); // red x'es 60 | plotty::show(); 61 | ``` 62 | 63 | ## Multiple open Plots 64 | 65 | `plotty::show(false)` opens a non-blocking window. You have to open a new figure to get a second plot ( `plotty::figure()`). 66 | The final figure should be opened in blocking mode to keep all windows open. 67 | 68 | ```c++ 69 | plotty::plot(v1); 70 | plotty::show(false); // show non-blocking 71 | 72 | ... 73 | 74 | plotty::figure(); // new figure 75 | plotty::plot(v2) 76 | plotty::show(false); // open non-blocking 77 | 78 | ... 79 | 80 | plotty::figure(); 81 | plotty::plot(v3); 82 | plotty::show(); // blocking to keep figures 1-3 open. 83 | 84 | 85 | ``` 86 | 87 | `plotty::figure()` accepts a string argument that labels / identifies a specific plot. 88 | 89 | ## Style and Labels 90 | 91 | ```c++ 92 | plotty::plot(t, x); 93 | plotty::xlabel("time [s]"); 94 | plotty::ylabel("Position [m]"); 95 | plotty::title("Position over time"); 96 | plotty::xlim(t_start, t_end); 97 | plotty::ylim(0, x_max); 98 | ``` 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, ETH Zurich, Wyss Zurich, Zurich Eye 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the ETH Zurich, Wyss Zurich, Zurich Eye nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL ETH Zurich, Wyss Zurich, Zurich Eye BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | Derived from work of Benno Evers licensed: 27 | 28 | The MIT License (MIT) 29 | 30 | Copyright (c) 2014 Benno Evers 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in all 40 | copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 48 | SOFTWARE. -------------------------------------------------------------------------------- /src/mpl_example_node.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016, ETH Zurich, Wyss Zurich, Zurich Eye 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the ETH Zurich, Wyss Zurich, Zurich Eye nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL ETH Zurich, Wyss Zurich, Zurich Eye BE LIABLE 20 | // FOR ANY 21 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | #include 29 | 30 | int main() { 31 | // Simple: 32 | std::vector v({1, 2, 3, 4}); 33 | plotty::plot(v); 34 | plotty::show(); 35 | 36 | // Eigen Vector Types: 37 | Eigen::VectorXd times(100); 38 | times.setLinSpaced(100, 0, 20); 39 | Eigen::VectorXd points(100); 40 | points.setRandom(); 41 | 42 | plotty::plot(times, points); 43 | plotty::show(); 44 | 45 | plotty::labelPlot("A Name", times, points); 46 | plotty::show(); 47 | 48 | // enable interactive mode as of now (only tests if it doesn't crash) 49 | plotty::ion(); 50 | 51 | // subplots 52 | plotty::subplot(3, 1, 1); 53 | plotty::plot(v); 54 | plotty::subplot(3, 1, 2); 55 | plotty::plot(v); 56 | plotty::subplot(3, 1, 3); 57 | plotty::plot(v); 58 | plotty::show(false); 59 | 60 | plotty::figure(); 61 | 62 | // plot multiple curves in a single graph 63 | std::vector w({4, 3, 2, 1}); 64 | plotty::plot(v, "x"); 65 | plotty::plot(w, "o"); 66 | plotty::show(); 67 | 68 | // Histogram 69 | plotty::hist(points, 3); 70 | plotty::show(); 71 | 72 | // Row vectors 73 | Eigen::MatrixXd matrix(2, 100); 74 | matrix.setRandom(); 75 | plotty::plot(matrix.row(0), matrix.row(1)); 76 | plotty::show(); 77 | 78 | // BoxPlot 79 | Eigen::MatrixXd data(2, 100); 80 | data.setRandom(); 81 | plotty::figure(); 82 | std::vector labels = {"A", "B"}; 83 | plotty::boxplot(data, labels); 84 | plotty::show(); 85 | 86 | // BoxPlot 87 | data.setRandom(); 88 | plotty::figure(); 89 | plotty::boxplot(data, {"A", "B"}); 90 | plotty::show(); 91 | 92 | // Boxplot unlabelled 93 | data.setRandom(); 94 | plotty::figure(); 95 | plotty::boxplot(data); 96 | plotty::show(); 97 | } 98 | -------------------------------------------------------------------------------- /include/plotty/matplotlibcpp.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016, ETH Zurich, Wyss Zurich, Zurich Eye 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the ETH Zurich, Wyss Zurich, Zurich Eye nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL ETH Zurich, Wyss Zurich, Zurich Eye BE LIABLE 20 | // FOR ANY 21 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Derived from work of Benno Evers licensed: 29 | // 30 | // The MIT License (MIT) 31 | // 32 | // Copyright (c) 2014 Benno Evers 33 | // 34 | // Permission is hereby granted, free of charge, to any person obtaining a copy 35 | // of this software and associated documentation files (the "Software"), to deal 36 | // in the Software without restriction, including without limitation the rights 37 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | // copies of the Software, and to permit persons to whom the Software is 39 | // furnished to do so, subject to the following conditions: 40 | // 41 | // The above copyright notice and this permission notice shall be included in 42 | // all 43 | // copies or substantial portions of the Software. 44 | // 45 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 51 | // SOFTWARE. 52 | 53 | #pragma once 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | namespace plotty { 65 | 66 | //! Enable interactive mode. 67 | bool ion(); 68 | 69 | //! Create a new figure. 70 | bool figure(std::string i = ""); 71 | 72 | //! Histogram. 73 | bool hist( 74 | const Eigen::Ref& x, const int bins = 10, 75 | const std::string histtype = "bar"); 76 | 77 | //! Every row of X is the data for a box. 78 | bool boxplot(const Eigen::Ref& x, 79 | const std::vector& labels); 80 | bool boxplot(const Eigen::Ref& x, 81 | std::initializer_list labels); 82 | bool boxplot(const Eigen::Ref& x); 83 | 84 | //! Create a subplot. 85 | bool subplot(const size_t nrows, const size_t ncols, const size_t plot_number); 86 | 87 | //! Create an x/y plot with properties as map. 88 | bool plot(const Eigen::Ref& x, 89 | const Eigen::Ref& y, 90 | const std::map& keywords); 91 | 92 | //! Create an x/y plot with properties in string. 93 | bool plot(const Eigen::Ref& x, 94 | const Eigen::Ref& y, 95 | const std::string& s = ""); 96 | 97 | //! Create an x/y plot with name as label. 98 | bool labelPlot(const std::string& name, 99 | const Eigen::Ref& x, 100 | const Eigen::Ref& y, 101 | const std::string& format = ""); 102 | bool labelPlot(const std::string& name, 103 | const Eigen::Ref& y, 104 | const std::string& format = ""); 105 | 106 | bool plot(const Eigen::Ref& x, 107 | const std::string& format = ""); 108 | 109 | // ----------------------------------------------------------------------------- 110 | //! @name std::vector wrappers. 111 | //! @{ 112 | bool plot(const std::vector& y, const std::string& format = ""); 113 | 114 | bool plot(const std::vector& x, const std::vector& y, 115 | const std::map& keywords); 116 | 117 | bool plot(const std::vector& x, 118 | const Eigen::Ref& y, 119 | const std::map& keywords); 120 | 121 | bool plot(const std::vector& x, const std::vector& y, 122 | const std::string& s = ""); 123 | bool plot(const std::vector& x, 124 | const Eigen::Ref& y, 125 | const std::string& s = ""); 126 | 127 | bool labelPlot(const std::string& name, const std::vector& x, 128 | const std::vector& y, const std::string& format = ""); 129 | 130 | bool labelPlot(const std::string& name, const std::vector& x, 131 | const Eigen::Ref& y, 132 | const std::string& format = ""); 133 | //! @} 134 | 135 | // ----------------------------------------------------------------------------- 136 | //! @name Plot settings. 137 | //! @{ 138 | void legend(); 139 | 140 | void ylim(double min, double max); 141 | 142 | void xlim(double xmin, double xmax); 143 | 144 | void title(const std::string& titlestr); 145 | 146 | void axis(const std::string& axisstr); 147 | 148 | void xlabel(const std::string& str); 149 | 150 | void ylabel(const std::string& str); 151 | 152 | void grid(bool flag); 153 | 154 | void show(bool block = true); 155 | 156 | void save(const std::string& filename); 157 | //! @} 158 | 159 | } // namespace plt 160 | -------------------------------------------------------------------------------- /src/matplotlibcpp.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016, ETH Zurich, Wyss Zurich, Zurich Eye 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of the ETH Zurich, Wyss Zurich, Zurich Eye nor the 12 | // names of its contributors may be used to endorse or promote products 13 | // derived from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | // AND 17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | // DISCLAIMED. IN NO EVENT SHALL ETH Zurich, Wyss Zurich, Zurich Eye BE LIABLE 20 | // FOR ANY 21 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // Derived from work of Benno Evers licensed: 29 | // 30 | // The MIT License (MIT) 31 | // 32 | // Copyright (c) 2014 Benno Evers 33 | // 34 | // Permission is hereby granted, free of charge, to any person obtaining a copy 35 | // of this software and associated documentation files (the "Software"), to deal 36 | // in the Software without restriction, including without limitation the rights 37 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | // copies of the Software, and to permit persons to whom the Software is 39 | // furnished to do so, subject to the following conditions: 40 | // 41 | // The above copyright notice and this permission notice shall be included in 42 | // all 43 | // copies or substantial portions of the Software. 44 | // 45 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 51 | // SOFTWARE. 52 | 53 | #define PY_SSIZE_T_CLEAN 54 | #include 55 | 56 | #include 57 | 58 | namespace plotty { 59 | namespace { 60 | 61 | // ----------------------------------------------------------------------------- 62 | struct Interpreter { 63 | PyObject* s_python_function_show; 64 | PyObject* s_python_function_save; 65 | PyObject* s_python_function_figure; 66 | PyObject* s_python_function_plot; 67 | PyObject* s_python_function_subplot; 68 | PyObject* s_python_function_hist; 69 | PyObject* s_python_function_boxplot; 70 | PyObject* s_python_function_legend; 71 | PyObject* s_python_function_xlim; 72 | PyObject* s_python_function_ylim; 73 | PyObject* s_python_function_title; 74 | PyObject* s_python_function_axis; 75 | PyObject* s_python_function_xlabel; 76 | PyObject* s_python_function_ylabel; 77 | PyObject* s_python_function_ion; 78 | PyObject* s_python_function_grid; 79 | PyObject* s_python_empty_tuple; 80 | 81 | /** For now, Interpreter is implemented as a singleton since its currently 82 | * not possible to have multiple independent embedded python interpreters 83 | * without patching the python source code or starting a seperate process 84 | * for each. 85 | * http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program 86 | */ 87 | 88 | static Interpreter& get() { 89 | static Interpreter ctx; 90 | return ctx; 91 | } 92 | 93 | private: 94 | Interpreter() { 95 | #if PYTHON_VERSION_MAJOR == 2 96 | #define ToPyStr(X) PyString_FromString(X) 97 | char name[] = "plotting"; 98 | #else 99 | #define ToPyStr(X) PyUnicode_FromString(X) 100 | const wchar_t name[] = L"plotting"; 101 | #endif 102 | Py_SetProgramName(name); // optional but recommended 103 | Py_Initialize(); 104 | 105 | PyObject* pyplotname = ToPyStr("matplotlib.pyplot"); 106 | PyObject* pylabname = ToPyStr("pylab"); 107 | if (!pyplotname || !pylabname) { 108 | throw std::runtime_error("couldnt create string"); 109 | } 110 | 111 | PyObject* pymod = PyImport_Import(pyplotname); 112 | Py_DECREF(pyplotname); 113 | if (!pymod) { 114 | throw std::runtime_error("Error loading module matplotlib.pyplot!"); 115 | } 116 | 117 | PyObject* pylabmod = PyImport_Import(pylabname); 118 | Py_DECREF(pylabname); 119 | if (!pymod) { 120 | throw std::runtime_error("Error loading module pylab!"); 121 | } 122 | 123 | s_python_function_show = PyObject_GetAttrString(pymod, "show"); 124 | s_python_function_figure = PyObject_GetAttrString(pymod, "figure"); 125 | s_python_function_plot = PyObject_GetAttrString(pymod, "plot"); 126 | s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot"); 127 | s_python_function_hist = PyObject_GetAttrString(pymod, "hist"); 128 | s_python_function_boxplot = PyObject_GetAttrString(pymod, "boxplot"); 129 | s_python_function_legend = PyObject_GetAttrString(pymod, "legend"); 130 | s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim"); 131 | s_python_function_title = PyObject_GetAttrString(pymod, "title"); 132 | s_python_function_axis = PyObject_GetAttrString(pymod, "axis"); 133 | s_python_function_xlabel = PyObject_GetAttrString(pymod, "xlabel"); 134 | s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel"); 135 | s_python_function_grid = PyObject_GetAttrString(pymod, "grid"); 136 | s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim"); 137 | s_python_function_ion = PyObject_GetAttrString(pymod, "ion"); 138 | 139 | s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig"); 140 | 141 | if (!s_python_function_show || !s_python_function_save || 142 | !s_python_function_figure || !s_python_function_plot || 143 | !s_python_function_subplot || !s_python_function_hist || 144 | !s_python_function_boxplot || !s_python_function_legend || 145 | !s_python_function_xlim || !s_python_function_ylim || 146 | !s_python_function_title || !s_python_function_axis || 147 | !s_python_function_xlabel || !s_python_function_ylabel || 148 | !s_python_function_ion || !s_python_function_grid) { 149 | throw std::runtime_error("Couldnt find required function!"); 150 | } 151 | 152 | if (!PyFunction_Check(s_python_function_show) || 153 | !PyFunction_Check(s_python_function_save) || 154 | !PyFunction_Check(s_python_function_figure) || 155 | !PyFunction_Check(s_python_function_plot) || 156 | !PyFunction_Check(s_python_function_subplot) || 157 | !PyFunction_Check(s_python_function_hist) || 158 | !PyFunction_Check(s_python_function_boxplot) || 159 | !PyFunction_Check(s_python_function_legend) || 160 | !PyFunction_Check(s_python_function_xlim) || 161 | !PyFunction_Check(s_python_function_ylim) || 162 | !PyFunction_Check(s_python_function_title) || 163 | !PyFunction_Check(s_python_function_axis) || 164 | !PyFunction_Check(s_python_function_xlabel) || 165 | !PyFunction_Check(s_python_function_ylabel) || 166 | !PyFunction_Check(s_python_function_ion) || 167 | !PyFunction_Check(s_python_function_grid)) { 168 | throw std::runtime_error( 169 | "Python object is unexpectedly not a PyFunction."); 170 | } 171 | 172 | s_python_empty_tuple = PyTuple_New(0); 173 | } 174 | 175 | ~Interpreter() { 176 | Py_Finalize(); 177 | } 178 | }; 179 | 180 | void initPython() { 181 | Interpreter::get(); 182 | } 183 | 184 | } // namespace 185 | 186 | // ----------------------------------------------------------------------------- 187 | bool ion() { 188 | initPython(); 189 | 190 | PyObject* args = PyTuple_New(0); 191 | PyObject* res = 192 | PyObject_CallObject(Interpreter::get().s_python_function_ion, args); 193 | 194 | if (res) { 195 | Py_DECREF(res); 196 | } 197 | 198 | return res; 199 | } 200 | 201 | // ----------------------------------------------------------------------------- 202 | //! Create a new figure 203 | bool figure(std::string i) { 204 | initPython(); 205 | 206 | PyObject* args; 207 | if (i != "") { 208 | args = PyTuple_New(1); 209 | PyObject* i_py = ToPyStr(i.c_str()); 210 | PyTuple_SetItem(args, 0, i_py); 211 | } else { 212 | args = PyTuple_New(0); 213 | } 214 | 215 | PyObject* res = 216 | PyObject_CallObject(Interpreter::get().s_python_function_figure, args); 217 | 218 | if (res) { 219 | Py_DECREF(res); 220 | } 221 | 222 | return res; 223 | } 224 | 225 | // ----------------------------------------------------------------------------- 226 | bool hist( 227 | const Eigen::Ref& x, const int bins, 228 | const std::string histtype) { 229 | initPython(); 230 | 231 | // using python lists 232 | PyObject* xlist = PyList_New(x.size()); 233 | 234 | for (int i = 0; i < x.size(); ++i) { 235 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x(i))); 236 | } 237 | 238 | // construct positional args 239 | PyObject* args = PyTuple_New(8); 240 | PyTuple_SetItem(args, 0, xlist); 241 | PyTuple_SetItem(args, 1, PyLong_FromLong(bins)); 242 | PyTuple_SetItem(args, 2, Py_None); 243 | PyTuple_SetItem(args, 3, Py_False); 244 | PyTuple_SetItem(args, 4, Py_None); 245 | PyTuple_SetItem(args, 5, Py_False); 246 | PyTuple_SetItem(args, 6, Py_None); 247 | PyTuple_SetItem(args, 7, ToPyStr(histtype.c_str())); 248 | 249 | PyObject* res = 250 | PyObject_CallObject(Interpreter::get().s_python_function_hist, args); 251 | 252 | Py_DECREF(xlist); 253 | Py_DECREF(args); 254 | if (res) { 255 | Py_DECREF(res); 256 | } 257 | 258 | return res; 259 | } 260 | 261 | // ----------------------------------------------------------------------------- 262 | bool boxplot(const Eigen::Ref& x, 263 | const std::vector& labels) { 264 | initPython(); 265 | 266 | CHECK_EQ(x.rows(), static_cast(labels.size())); 267 | 268 | // using python lists 269 | PyObject* data = PyList_New(x.rows()); 270 | PyObject* py_labels = PyList_New(x.rows()); 271 | 272 | for (int i = 0; i < x.rows(); ++i) { 273 | PyObject* row = PyList_New(x.cols()); 274 | 275 | PyList_SetItem(py_labels, i, ToPyStr(labels[i].c_str())); 276 | 277 | for (int j = 0; j < x.cols(); ++j) { 278 | PyList_SetItem(row, j, PyFloat_FromDouble(x(i, j))); 279 | } 280 | PyList_SetItem(data, i, row); 281 | } 282 | 283 | // construct positional args 284 | PyObject* args = PyTuple_New(1); 285 | PyTuple_SetItem(args, 0, data); 286 | 287 | // construct keyword args 288 | PyObject* kwargs = PyDict_New(); 289 | PyDict_SetItemString(kwargs, "labels", py_labels); 290 | 291 | PyObject* res = 292 | PyObject_Call(Interpreter::get().s_python_function_boxplot, args, kwargs); 293 | 294 | Py_DECREF(data); 295 | if (res) { 296 | Py_DECREF(res); 297 | } 298 | 299 | return res; 300 | } 301 | 302 | // ----------------------------------------------------------------------------- 303 | bool boxplot(const Eigen::Ref& x, 304 | std::initializer_list labels) { 305 | std::vector labels_vector; 306 | labels_vector.insert(labels_vector.end(), labels.begin(), labels.end()); 307 | 308 | return boxplot(x, labels_vector); 309 | } 310 | 311 | // ----------------------------------------------------------------------------- 312 | bool boxplot(const Eigen::Ref& x) { 313 | std::vector labels; 314 | for (int i = 0; i < x.rows(); ++i) { 315 | labels.push_back(std::to_string(i)); 316 | } 317 | return boxplot(x, labels); 318 | } 319 | 320 | // ----------------------------------------------------------------------------- 321 | bool subplot(const size_t nrows, const size_t ncols, const size_t plot_number) { 322 | initPython(); 323 | 324 | PyObject* nrows_py = PyFloat_FromDouble(nrows); 325 | PyObject* ncols_py = PyFloat_FromDouble(ncols); 326 | PyObject* plot_number_py = PyFloat_FromDouble(plot_number); 327 | PyObject* subplot_args = PyTuple_New(3); 328 | PyTuple_SetItem(subplot_args, 0, nrows_py); 329 | PyTuple_SetItem(subplot_args, 1, ncols_py); 330 | PyTuple_SetItem(subplot_args, 2, plot_number_py); 331 | 332 | PyObject* res = PyObject_CallObject( 333 | Interpreter::get().s_python_function_subplot, subplot_args); 334 | 335 | Py_DECREF(nrows_py); 336 | Py_DECREF(ncols_py); 337 | Py_DECREF(plot_number_py); 338 | if (res) { 339 | Py_DECREF(res); 340 | } 341 | 342 | return res; 343 | } 344 | 345 | // ----------------------------------------------------------------------------- 346 | bool plot(const Eigen::Ref& x_raw, 347 | const Eigen::Ref& y_raw, 348 | const std::map& keywords) { 349 | initPython(); 350 | 351 | CHECK(x_raw.cols() == 1 || x_raw.rows() == 1); 352 | CHECK(y_raw.cols() == 1 || y_raw.rows() == 1); 353 | 354 | Eigen::Map x( 355 | x_raw.data(), x_raw.rows() == 1 ? x_raw.cols() : x_raw.rows()); 356 | Eigen::Map y( 357 | y_raw.data(), y_raw.rows() == 1 ? y_raw.cols() : y_raw.rows()); 358 | 359 | CHECK(x.size() == y.size()); 360 | 361 | // using python lists 362 | PyObject* xlist = PyList_New(x.size()); 363 | PyObject* ylist = PyList_New(y.size()); 364 | 365 | for (int i = 0; i < x.size(); ++i) { 366 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x(i))); 367 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y(i))); 368 | } 369 | 370 | // construct positional args 371 | PyObject* args = PyTuple_New(2); 372 | PyTuple_SetItem(args, 0, xlist); 373 | PyTuple_SetItem(args, 1, ylist); 374 | 375 | Py_DECREF(xlist); 376 | Py_DECREF(ylist); 377 | 378 | // construct keyword args 379 | PyObject* kwargs = PyDict_New(); 380 | for (std::map::const_iterator it = keywords.begin(); 381 | it != keywords.end(); ++it) { 382 | PyDict_SetItemString( 383 | kwargs, it->first.c_str(), ToPyStr(it->second.c_str())); 384 | } 385 | 386 | PyObject* res = 387 | PyObject_Call(Interpreter::get().s_python_function_plot, args, kwargs); 388 | 389 | Py_DECREF(args); 390 | Py_DECREF(kwargs); 391 | if (res) { 392 | Py_DECREF(res); 393 | } 394 | 395 | return res; 396 | } 397 | 398 | // ----------------------------------------------------------------------------- 399 | bool plot(const Eigen::Ref& x_raw, 400 | const Eigen::Ref& y_raw, 401 | const std::string& s) { 402 | initPython(); 403 | 404 | CHECK(x_raw.cols() == 1 || x_raw.rows() == 1); 405 | CHECK(y_raw.cols() == 1 || y_raw.rows() == 1); 406 | 407 | Eigen::Map x( 408 | x_raw.data(), x_raw.rows() == 1 ? x_raw.cols() : x_raw.rows()); 409 | Eigen::Map y( 410 | y_raw.data(), y_raw.rows() == 1 ? y_raw.cols() : y_raw.rows()); 411 | 412 | CHECK_EQ(x.size(), y.size()); 413 | PyObject* xlist = PyList_New(x.size()); 414 | PyObject* ylist = PyList_New(y.size()); 415 | 416 | PyObject* pystring = ToPyStr(s.c_str()); 417 | 418 | for (int i = 0; i < x.size(); ++i) { 419 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x(i))); 420 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y(i))); 421 | } 422 | 423 | PyObject* plot_args = PyTuple_New(3); 424 | PyTuple_SetItem(plot_args, 0, xlist); 425 | PyTuple_SetItem(plot_args, 1, ylist); 426 | PyTuple_SetItem(plot_args, 2, pystring); 427 | 428 | PyObject* res = 429 | PyObject_CallObject(Interpreter::get().s_python_function_plot, plot_args); 430 | 431 | Py_DECREF(xlist); 432 | Py_DECREF(ylist); 433 | Py_DECREF(plot_args); 434 | if (res) { 435 | Py_DECREF(res); 436 | } 437 | 438 | return res; 439 | } 440 | 441 | // ----------------------------------------------------------------------------- 442 | bool labelPlot(const std::string& name, 443 | const Eigen::Ref& x_raw, 444 | const Eigen::Ref& y_raw, 445 | const std::string& format) { 446 | initPython(); 447 | 448 | CHECK(x_raw.cols() == 1 || x_raw.rows() == 1); 449 | CHECK(y_raw.cols() == 1 || y_raw.rows() == 1); 450 | 451 | Eigen::Map x( 452 | x_raw.data(), x_raw.rows() == 1 ? x_raw.cols() : x_raw.rows()); 453 | Eigen::Map y( 454 | y_raw.data(), y_raw.rows() == 1 ? y_raw.cols() : y_raw.rows()); 455 | 456 | CHECK_EQ(x.size(), y.size()); 457 | 458 | PyObject* kwargs = PyDict_New(); 459 | PyDict_SetItemString(kwargs, "label", ToPyStr(name.c_str())); 460 | 461 | PyObject* xlist = PyList_New(x.size()); 462 | PyObject* ylist = PyList_New(y.size()); 463 | PyObject* pystring = ToPyStr(format.c_str()); 464 | 465 | for (int i = 0; i < x.size(); ++i) { 466 | PyObject* f_xi = PyFloat_FromDouble(x(i)); 467 | PyObject* f_yi = PyFloat_FromDouble(y(i)); 468 | if (!f_xi || !f_yi) { 469 | VLOG(1) << "MPL: value could not be converted to PyFloat:" << x(i) << ", " 470 | << y(i); 471 | continue; 472 | } 473 | PyList_SetItem(xlist, i, PyFloat_FromDouble(x(i))); 474 | PyList_SetItem(ylist, i, PyFloat_FromDouble(y(i))); 475 | } 476 | 477 | PyObject* plot_args = PyTuple_New(3); 478 | PyTuple_SetItem(plot_args, 0, xlist); 479 | PyTuple_SetItem(plot_args, 1, ylist); 480 | PyTuple_SetItem(plot_args, 2, pystring); 481 | 482 | PyObject* res = PyObject_Call( 483 | Interpreter::get().s_python_function_plot, plot_args, kwargs); 484 | 485 | Py_DECREF(kwargs); 486 | Py_DECREF(xlist); 487 | Py_DECREF(ylist); 488 | Py_DECREF(plot_args); 489 | if (res) { 490 | Py_DECREF(res); 491 | } 492 | 493 | return res; 494 | } 495 | 496 | // ----------------------------------------------------------------------------- 497 | bool labelPlot(const std::string& name, 498 | const Eigen::Ref& y, 499 | const std::string& format) { 500 | Eigen::Matrix x(y.size()); 501 | for (int i = 0; i < x.size(); ++i) { 502 | x(i) = i; 503 | } 504 | return labelPlot(name, x, y, format); 505 | } 506 | 507 | // ----------------------------------------------------------------------------- 508 | bool plot(const Eigen::Ref& y, 509 | const std::string& format) { 510 | Eigen::Matrix x(y.size()); 511 | for (int i = 0; i < x.size(); ++i) { 512 | x(i) = i; 513 | } 514 | return plot(x, y, format); 515 | } 516 | 517 | // ----------------------------------------------------------------------------- 518 | bool plot(const std::vector& y, const std::string& format) { 519 | Eigen::Map> y_e(y.data(), 520 | y.size()); 521 | return plot(y_e, format); 522 | } 523 | 524 | // ----------------------------------------------------------------------------- 525 | bool plot(const std::vector& x, const std::vector& y, 526 | const std::map& keywords) { 527 | Eigen::Map> x_e(x.data(), 528 | x.size()); 529 | Eigen::Map> y_e(y.data(), 530 | y.size()); 531 | return plot(x_e, y_e, keywords); 532 | } 533 | 534 | // ----------------------------------------------------------------------------- 535 | bool plot(const std::vector& x, 536 | const Eigen::Ref& y, 537 | const std::map& keywords) { 538 | Eigen::Map> x_e(x.data(), 539 | x.size()); 540 | return plot(x_e, y, keywords); 541 | } 542 | 543 | // ----------------------------------------------------------------------------- 544 | bool plot(const std::vector& x, const std::vector& y, 545 | const std::string& s) { 546 | Eigen::Map> x_e(x.data(), 547 | x.size()); 548 | Eigen::Map> y_e(y.data(), 549 | y.size()); 550 | return plot(x_e, y_e, s); 551 | } 552 | 553 | // ----------------------------------------------------------------------------- 554 | bool plot(const std::vector& x, 555 | const Eigen::Ref& y, const std::string& s) { 556 | Eigen::Map> x_e(x.data(), 557 | x.size()); 558 | return plot(x_e, y, s); 559 | } 560 | 561 | // ----------------------------------------------------------------------------- 562 | bool labelPlot(const std::string& name, const std::vector& x, 563 | const std::vector& y, const std::string& format) { 564 | Eigen::Map> x_e(x.data(), 565 | x.size()); 566 | Eigen::Map> y_e(y.data(), 567 | y.size()); 568 | return labelPlot(name, x_e, y_e, format); 569 | } 570 | 571 | // ----------------------------------------------------------------------------- 572 | bool labelPlot(const std::string& name, const std::vector& x, 573 | const Eigen::Ref& y, 574 | const std::string& format) { 575 | Eigen::Map> x_e(x.data(), 576 | x.size()); 577 | return labelPlot(name, x_e, y, format); 578 | } 579 | 580 | // ----------------------------------------------------------------------------- 581 | void legend() { 582 | initPython(); 583 | 584 | PyObject* res = PyObject_CallObject( 585 | Interpreter::get().s_python_function_legend, 586 | Interpreter::get().s_python_empty_tuple); 587 | 588 | if (!res) { 589 | throw std::runtime_error("Call to legend() failed."); 590 | } 591 | 592 | Py_DECREF(res); 593 | } 594 | 595 | // ----------------------------------------------------------------------------- 596 | void ylim(double ymin, double ymax) { 597 | initPython(); 598 | 599 | PyObject* list = PyList_New(2); 600 | PyList_SetItem(list, 0, PyFloat_FromDouble(ymin)); 601 | PyList_SetItem(list, 1, PyFloat_FromDouble(ymax)); 602 | 603 | PyObject* args = PyTuple_New(1); 604 | PyTuple_SetItem(args, 0, list); 605 | 606 | PyObject* res = 607 | PyObject_CallObject(Interpreter::get().s_python_function_ylim, args); 608 | if (!res) { 609 | throw std::runtime_error("Call to ylim() failed."); 610 | } 611 | 612 | Py_DECREF(list); 613 | Py_DECREF(args); 614 | Py_DECREF(res); 615 | } 616 | 617 | // ----------------------------------------------------------------------------- 618 | void xlim(double xmin, double xmax) { 619 | initPython(); 620 | 621 | PyObject* list = PyList_New(2); 622 | PyList_SetItem(list, 0, PyFloat_FromDouble(xmin)); 623 | PyList_SetItem(list, 1, PyFloat_FromDouble(xmax)); 624 | 625 | PyObject* args = PyTuple_New(1); 626 | PyTuple_SetItem(args, 0, list); 627 | 628 | PyObject* res = 629 | PyObject_CallObject(Interpreter::get().s_python_function_xlim, args); 630 | if (!res) { 631 | throw std::runtime_error("Call to xlim() failed."); 632 | } 633 | 634 | Py_DECREF(list); 635 | Py_DECREF(args); 636 | Py_DECREF(res); 637 | } 638 | 639 | // ----------------------------------------------------------------------------- 640 | void title(const std::string& titlestr) { 641 | initPython(); 642 | 643 | PyObject* pytitlestr = ToPyStr(titlestr.c_str()); 644 | PyObject* args = PyTuple_New(1); 645 | PyTuple_SetItem(args, 0, pytitlestr); 646 | 647 | PyObject* res = 648 | PyObject_CallObject(Interpreter::get().s_python_function_title, args); 649 | if (!res) { 650 | throw std::runtime_error("Call to title() failed."); 651 | } 652 | 653 | // if PyDeCRFF, the function doesn't work on Mac OS 654 | } 655 | 656 | // ----------------------------------------------------------------------------- 657 | void axis(const std::string& axisstr) { 658 | initPython(); 659 | 660 | PyObject* str = ToPyStr(axisstr.c_str()); 661 | PyObject* args = PyTuple_New(1); 662 | PyTuple_SetItem(args, 0, str); 663 | 664 | PyObject* res = 665 | PyObject_CallObject(Interpreter::get().s_python_function_axis, args); 666 | if (!res) { 667 | throw std::runtime_error("Call to title() failed."); 668 | } 669 | 670 | // if PyDeCRFF, the function doesn't work on Mac OS 671 | } 672 | 673 | // ----------------------------------------------------------------------------- 674 | void xlabel(const std::string& str) { 675 | initPython(); 676 | 677 | PyObject* pystr = ToPyStr(str.c_str()); 678 | PyObject* args = PyTuple_New(1); 679 | PyTuple_SetItem(args, 0, pystr); 680 | 681 | PyObject* res = 682 | PyObject_CallObject(Interpreter::get().s_python_function_xlabel, args); 683 | if (!res) { 684 | throw std::runtime_error("Call to xlabel() failed."); 685 | } 686 | 687 | // if PyDeCRFF, the function doesn't work on Mac OS 688 | } 689 | 690 | // ----------------------------------------------------------------------------- 691 | void ylabel(const std::string& str) { 692 | initPython(); 693 | 694 | PyObject* pystr = ToPyStr(str.c_str()); 695 | PyObject* args = PyTuple_New(1); 696 | PyTuple_SetItem(args, 0, pystr); 697 | 698 | PyObject* res = 699 | PyObject_CallObject(Interpreter::get().s_python_function_ylabel, args); 700 | if (!res) { 701 | throw std::runtime_error("Call to ylabel() failed."); 702 | } 703 | 704 | // if PyDeCRFF, the function doesn't work on Mac OS 705 | } 706 | 707 | // ----------------------------------------------------------------------------- 708 | void grid(bool flag) { 709 | initPython(); 710 | 711 | PyObject* pyflag = flag ? Py_True : Py_False; 712 | 713 | PyObject* args = PyTuple_New(1); 714 | PyTuple_SetItem(args, 0, pyflag); 715 | 716 | PyObject* res = 717 | PyObject_CallObject(Interpreter::get().s_python_function_grid, args); 718 | if (!res) { 719 | throw std::runtime_error("Call to grid() failed."); 720 | } 721 | 722 | // if PyDeCRFF, the function doesn't work on Mac OS 723 | } 724 | 725 | // ----------------------------------------------------------------------------- 726 | void show(bool block) { 727 | initPython(); 728 | 729 | PyObject* pyflag = block ? Py_True : Py_False; 730 | 731 | PyObject* kwargs = PyDict_New(); 732 | 733 | PyDict_SetItemString(kwargs, "block", pyflag); 734 | 735 | PyObject* res = PyObject_Call( 736 | Interpreter::get().s_python_function_show, 737 | Interpreter::get().s_python_empty_tuple, kwargs); 738 | if (!res) { 739 | throw std::runtime_error("Call to show() failed."); 740 | } 741 | 742 | Py_DECREF(res); 743 | Py_DECREF(kwargs); 744 | } 745 | 746 | // ----------------------------------------------------------------------------- 747 | void save(const std::string& filename) { 748 | initPython(); 749 | 750 | PyObject* pyfilename = ToPyStr(filename.c_str()); 751 | 752 | PyObject* args = PyTuple_New(1); 753 | PyTuple_SetItem(args, 0, pyfilename); 754 | 755 | PyObject* res = 756 | PyObject_CallObject(Interpreter::get().s_python_function_save, args); 757 | if (!res) { 758 | throw std::runtime_error("Call to save() failed."); 759 | } 760 | 761 | Py_DECREF(pyfilename); 762 | Py_DECREF(args); 763 | Py_DECREF(res); 764 | } 765 | 766 | } // namespace plotty 767 | --------------------------------------------------------------------------------