8000 Subplot by torfinnberset · Pull Request #10 · lava/matplotlib-cpp · GitHub
[go: up one dir, main page]

Skip to content

Subplot #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 22, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 39 additions & 34 deletions matplotlibcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace matplotlibcpp {
PyObject *s_python_function_save;
PyObject *s_python_function_figure;
PyObject *s_python_function_plot;
PyObject *s_python_function_subplot;
PyObject *s_python_function_legend;
PyObject *s_python_function_xlim;
PyObject *s_python_function_ylim;
Expand All @@ -32,8 +33,8 @@ namespace matplotlibcpp {

/* For now, _interpreter is implemented as a singleton since its currently not possible to have
multiple independent embedded python interpreters without patching the python source code
or starting a seperate process for each.
or starting a separate process for each.

http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
*/

Expand All @@ -44,12 +45,12 @@ namespace matplotlibcpp {

private:
_interpreter() {
char name[] = "plotting"; // silence compiler warning abount const strings
char name[] = "plotting"; // silence compiler warning about const strings
Py_SetProgramName(name); // optional but recommended
Py_Initialize();

PyObject* pyplotname = PyString_FromString("matplotlib.pyplot");
PyObject* pylabname = PyString_FromString("pylab");
PyObject* pylabname = PyString_FromString("pylab");
if(!pyplotname || !pylabname) { throw std::runtime_error("couldnt create string"); }

PyObject* pymod = PyImport_Import(pyplotname);
Expand All @@ -63,6 +64,7 @@ namespace matplotlibcpp {
s_python_function_show = PyObject_GetAttrString(pymod, "show");
s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
s_python_function_plot = PyObject_GetAttrString(pymod, "plot");
s_python_function_subplot = PyObject_GetAttrString(pymod, "subplot");
s_python_function_legend = PyObject_GetAttrString(pymod, "legend");
s_python_function_ylim = PyObject_GetAttrString(pymod, "ylim");
s_python_function_title = PyObject_GetAttrString(pymod, "title");
Expand All @@ -71,36 +73,37 @@ namespace matplotlibcpp {
s_python_function_ylabel = PyObject_GetAttrString(pymod, "ylabel");
s_python_function_grid = PyObject_GetAttrString(pymod, "grid");
s_python_function_xlim = PyObject_GetAttrString(pymod, "xlim");

s_python_function_save = PyObject_GetAttrString(pylabmod, "savefig");

if(!s_python_function_show
|| !s_python_function_save
|| !s_python_function_figure
|| !s_python_function_plot
|| !s_python_function_legend
|| !s_python_function_xlim
if( !s_python_function_show
|| !s_python_function_figure
|| !s_python_function_plot
|| !s_python_function_subplot
|| !s_python_function_legend
|| !s_python_function_ylim
|| !s_python_function_title
|| !s_python_function_axis
|| !s_python_function_xlabel
|| !s_python_function_ylabel
|| !s_python_function_grid
)
{ throw std::runtime_error("Couldnt find required function!"); }
|| !s_python_function_xlim
|| !s_python_function_save
)
{ throw std::runtime_error("Couldn't find required function!"); }

if(!PyFunction_Check(s_python_function_show)
|| !PyFunction_Check(s_python_function_save)
if( !PyFunction_Check(s_python_function_show)
|| !PyFunction_Check(s_python_function_figure)
|| !PyFunction_Check(s_python_function_plot)
|| !PyFunction_Check(s_python_function_legend)
|| !PyFunction_Check(s_python_function_xlim)
|| !PyFunction_Check(s_python_function_ylim)
|| !PyFunction_Check(s_python_function_subplot)
|| !PyFunction_Check(s_python_function_legend)
|| !PyFunction_Check(s_python_function_ylim)
|| !PyFunction_Check(s_python_function_title)
|| !PyFunction_Check(s_python_function_axis)
|| !PyFunction_Check(s_python_function_xlabel)
|| !PyFunction_Check(s_python_function_ylabel)
|| !PyFunction_Check(s_python_function_grid)
|| !PyFunction_Check(s_python_function_xlim)
|| !PyFunction_Check(s_python_function_save)
)
{ throw std::runtime_error("Python object is unexpectedly not a PyFunction."); }

Expand All @@ -113,8 +116,6 @@ namespace matplotlibcpp {
};
}



template<typename Numeric>
bool plot(const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
{
Expand Down Expand Up @@ -153,7 +154,6 @@ namespace matplotlibcpp {
return res;
}


template<typename NumericX, typename NumericY>
bool plot(const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& s = "")
{
Expand Down Expand Up @@ -183,7 +183,6 @@ namespace matplotlibcpp {
return res;
}


template<typename Numeric>
bool named_plot(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "") {
PyObject* kwargs = PyDict_New();
Expand Down Expand Up @@ -223,7 +222,7 @@ namespace matplotlibcpp {
}


inline void legend() {
inline void legend() {
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple);
if(!res) throw std::runtime_error("Call to legend() failed.");

Expand Down Expand Up @@ -266,7 +265,20 @@ namespace matplotlibcpp {
Py_DECREF(res);
}


inline void subplot(long nrows, long ncols, long plot_number) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, thanks! But I think this function could be improved if

  • there was a check that args is not nullptr after calling PyTuple_New()
  • Py_DECREF(args) would be called before throwing the exception to avoid a memory leak

// construct positional args
PyObject* args = PyTuple_New(3);
PyTuple_SetItem(args, 0, PyFloat_FromDouble(nrows));
PyTuple_SetItem(args, 1, PyFloat_FromDouble(ncols));
PyTuple_SetItem(args, 2, PyFloat_FromDouble(plot_number));

PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args);
if(!res) throw std::runtime_error("Call to subplot() failed.");

Py_DECREF(args);
Py_DECREF(res);
}

inline void title(const std::string &titlestr)
{
PyObject* pytitlestr = PyString_FromString(titlestr.c_str());
Expand All @@ -291,8 +303,6 @@ namespace matplotlibcpp {
// if PyDeCRFF, the function doesn't work on Mac OS
}



inline void xlabel(const std::string &str)
{
PyObject* pystr = PyString_FromString(str.c_str());
Expand Down Expand Up @@ -330,8 +340,6 @@ namespace matplotlibcpp {
// if PyDeCRFF, the function doesn't work on Mac OS
}



inline void show()
{
PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_show, detail::_interpreter::get().s_python_empty_tuple);
Expand Down Expand Up @@ -368,7 +376,7 @@ namespace matplotlibcpp {
template<typename T>
struct is_callable_impl<false, T>
{
typedef is_function<T> type;
typedef is_function<T> type;
}; // a non-object is callable iff it is a function

template<typename T>
Expand Down Expand Up @@ -452,10 +460,10 @@ namespace matplotlibcpp {

if(begin(ticks) == end(ticks)) return true;

// We could use additional meta-programming to deduce the correct element type of y,
// We could use additional meta-programming to deduce the correct element type of y,
// but all values have to be convertible to double anyways
std::vector<double> y;
for(auto x : ticks) y.push_back(f(x));
for(auto x : ticks) y.push_back(f(x));
return plot_impl<std::false_type>()(ticks,y,format);
}
};
Expand Down Expand Up @@ -493,7 +501,4 @@ namespace matplotlibcpp {

#endif




}
0