/* * Nomad Instrument Control Software * * Copyright 2011 Institut Laue-Langevin * * Licensed under the EUPL, Version 1.1 only (the "License"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://joinup.ec.europa.eu/software/page/eupl * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. */ #include "Mpl.h" #include #include #include #include #include #include #include #include #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #define PY_ARRAY_UNIQUE_SYMBOL CORE_ARRAY_API #include #include "MplLock.h" #include "Trace.h" using namespace std; namespace bp = boost::python; namespace view { namespace mpl { PyMODINIT_FUNC PyInit_module_event(void); // Definition of the PyInit of the own module event /* * constructor */ Mpl::Mpl() throw (Error) { // Add single module event need to get gui event if (PyImport_AppendInittab("module_event", PyInit_module_event) < 0) { throw Error("Mpl", "constructor", "Add a single module to the existing table of built-in modules failed for module_event"); } // Initialize the Python interpreter Py_Initialize(); // Initialize and acquire the global interpreter lock for multi-thread management PyEval_InitThreads(); // Import the matplotlib module PythonObject matplotlib; try { matplotlib = bp::import(bp::str("matplotlib")); } catch(...) { throw Error("Mpl", "constructor", "Error when importing the module matplotlib"); } // Import the pyplot of matplotlib module try { m_PyPlot = bp::import(bp::str("matplotlib.pyplot")); } catch(...) { throw Error("Mpl", "constructor", "Error when importing the module matplotlib.pyplot"); } try { m_FigureModule = bp::import(bp::str("matplotlib.figure")); } catch (...) { throw Error("Mpl", "constructor", "Error when getting the figure module"); } try { m_LinesModule = bp::import(bp::str("matplotlib.lines")); } catch (...) { throw Error("Mpl", "constructor", "Error when getting the Lines module"); } try { m_TextModule = bp::import(bp::str("matplotlib.text")); } catch (...) { throw Error("Mpl", "constructor", "Error when getting the Text module"); } try { m_WidgetsModule = bp::import(bp::str("matplotlib.widgets")); } catch (...) { throw Error("Mpl", "constructor", "Error when getting the widgets module"); } try { m_PatchesModule = bp::import(bp::str("matplotlib.patches")); } catch (...) { throw Error("Mpl", "constructor", "Error when getting the patches module"); } try { PythonObject widgetsModule = bp::import(bp::str("matplotlib.colors")); m_NormalNorm = widgetsModule.attr("Normalize")(); m_LogNorm = widgetsModule.attr("LogNorm")(); } catch (...) { throw Error("Mpl", "contructor", "Error when creating the log norm object"); } // Use Qt5Agg for toolbar look and feel auto args = bp::make_tuple("Qt5Agg"); try { matplotlib.attr("use")(*args); } catch(...) { throw Error("Mpl", "constructor", "Error when activating QT5Agg"); } // Get Py QT5 for forcine QT5 try { auto qt5Module = bp::import(bp::str("PyQt5")); } catch (...) { throw Error("Mpl", "Mpl", "Error when getting PyQt5"); } // Get matplotlib BackEnd for qt5 try { m_BackendsModule = bp::import(bp::str("matplotlib.backends.backend_qt5agg")); } catch (...) { throw Error("Mpl", "Mpl", "Error when getting Qt5 AGG backend"); } // Get try { m_GarbageCollector = bp::import(bp::str("gc")); } catch (...) { throw Error("Mpl", "Mpl", "Error when getting gc"); } if (_import_array() < 0) { throw Error("Mpl", "Mpl", "numpy.core.multiarray failed to import"); } } /* * destructor */ Mpl::~Mpl() { { m_PyPlot.reset(); m_FigureModule.reset(); m_LinesModule.reset(); m_TextModule.reset(); m_NormalNorm.reset(); m_LogNorm.reset(); m_BackendsModule.reset(); m_WidgetsModule.reset(); m_PatchesModule.reset(); m_GarbageCollector.reset(); } Py_Finalize(); } /* * close */ void Mpl::close(const PythonObject& figure) throw (Error) { MplLock lock; // Create matplotlib figure object auto args = bp::make_tuple(figure()); try { m_PyPlot.attr("close")(*args); } catch (...) { throw Error("Mpl", "close", "Error when executing close method"); } } /* * garbageCollect */ void Mpl::garbageCollect() throw (Error) { try { m_GarbageCollector.attr("collect")(); } catch (...) { throw Error("Mpl", "garbageCollect", "Error when executing collect method on garbage collector"); } } /* * xlabel */ void Mpl::xlabel(const PythonObject& axis, const std::string& name) throw (Error) { mpl::MplLock lock; try { bp::call_method(axis().ptr(), "set_xlabel", name.c_str()); } catch (...) { throw Error("Mpl", "xlabel", "Error when executing xlabel method"); } } /* * ylabel */ void Mpl::ylabel(const PythonObject& axis, const std::string& name) throw (Error) { mpl::MplLock lock; try { bp::call_method(axis().ptr(), "set_ylabel", name.c_str()); } catch (...) { throw Error("Mpl", "ylabel", "Error when executing ylabel method"); } } /* * grid */ void Mpl::grid(const PythonObject& axis, bool show) throw (Error) { mpl::MplLock lock; bp::tuple args; if (show == true) { args = bp::make_tuple(true); } else { args = bp::make_tuple(false); } try { axis.attr("grid")(*args); } catch(...) { throw Error("Mpl", "grid", "Error when executing grid method"); } } /* * savefig */ void Mpl::savefig(const PythonObject& figure, const std::string& filename, uint32 dpi, float64 pad) throw (Error) { mpl::MplLock lock; auto args = bp::make_tuple(filename); bp::dict kwargs; kwargs["format"] = "png"; kwargs["dpi"] = dpi; if (pad == 0) { kwargs["bbox_inches"] = "tight"; kwargs["pad_inches"] = pad; } try { figure.attr("savefig")(*args, **kwargs); } catch (...) { throw Error("Mpl", "savefig", "Error saving png file ", filename); } } /* * get_xlim */ std::pair Mpl::get_xlim(const PythonObject& axis) throw (Error) { mpl::MplLock lock; try { bp::tuple res(axis.attr("get_xlim")()); float64 min = bp::extract(res[0]); float64 max = bp::extract(res[1]); return std::make_pair(min, max); } catch (...) { throw Error("Mpl", "get_xlim", "Error when executing the get_xlim method"); } } /* * get_ylim */ std::pair Mpl::get_ylim(const PythonObject& axis) throw (Error) { mpl::MplLock lock; try { bp::tuple res(axis.attr("get_ylim")()); float64 min = bp::extract(res[0]); float64 max = bp::extract(res[1]); return std::make_pair(min, max); } catch (...) { throw Error("Mpl", "get_ylim", "Error when executing the get_ylim method"); } } /* * set_xdata */ void Mpl::set_xdata(const PythonObject& line, const std::vector &x) throw (Error) { mpl::MplLock lock; // using numpy arrays boost::python::list xarray; for (float64 val : x) { xarray.append(val); } // construct positional args auto args = bp::make_tuple(xarray); // construct keyword args try { line.attr("set_xdata")(*args); } catch (...) { throw Error("Mpl", "set_xdata", "Error when executing the set_xdata method"); } } /* * set_ydata */ void Mpl::set_ydata(const PythonObject& line, const std::vector &y) throw (Error) { mpl::MplLock lock; // using numpy arrays boost::python::list yarray; for (float64 val : y) { yarray.append(val); } // construct positional args auto args = bp::make_tuple(yarray); try { line.attr("set_ydata")(*args); } catch (...) { throw Error("Mpl", "set_ydata", "Error when executing the set_ydata method"); } } /* * set_xlim */ void Mpl::set_xlim(const PythonObject& axis, float64 min, float64 max, float64 marge) throw (Error) { mpl::MplLock lock; float64 tot = max - min; min -= tot * marge; max += tot * marge; auto args = bp::make_tuple(min, max); try { axis.attr("set_xlim")(*args); } catch (...) { throw Error("Mpl", "set_xlim", "Error when executing the set_xlim method"); } } /* * set_ylim */ void Mpl::set_ylim(const PythonObject& axis, float64 min, float64 max, float64 marge) throw (Error) { mpl::MplLock lock; float64 tot = max - min; min -= tot * marge; max += tot * marge; auto args = bp::make_tuple(min, max); try { axis.attr("set_ylim")(*args); } catch (...) { throw Error("Mpl", "set_ylim", "Error when executing the set_ylim method"); } } } }