Skip to content
Open
Changes from 1 commit
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
27 changes: 27 additions & 0 deletions matplotlibcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,33 @@ bool named_plot(const std::string& name, const std::vector<Numeric>& x, const st
return res;
}

template<typename Numeric>
bool named_plot(const std::string& name, const std::vector<std::string>& x, const std::vector<Numeric>& y, const std::string& format = "")
{
detail::_interpreter::get();

PyObject* kwargs = PyDict_New();
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));

Comment on lines +1734 to +1736
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

PyDict_SetItemString does not steal a reference to the value; passing the temporary result of PyString_FromString(...) here leaks a reference. Store the created Python string in a local PyObject*, insert it into kwargs, then Py_DECREF it after insertion (same pattern as used elsewhere when the API doesn’t steal refs).

Copilot uses AI. Check for mistakes.
PyObject* xarray = detail::get_array(x);
PyObject* yarray = detail::get_array(y);

PyObject* pystring = PyString_FromString(format.c_str());

PyObject* plot_args = PyTuple_New(3);
PyTuple_SetItem(plot_args, 0, xarray);
PyTuple_SetItem(plot_args, 1, yarray);
PyTuple_SetItem(plot_args, 2, pystring);

PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);

Py_DECREF(kwargs);
Py_DECREF(plot_args);
if (res) Py_DECREF(res);

return res;
}

template<typename Numeric>
Comment on lines +1730 to +1756
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This overload appears redundant: the existing named_plot template taking std::vector<NumericX> already works with NumericX = std::string because detail::get_array(const std::vector<std::string>&) is defined. Keeping both copies increases maintenance surface; consider removing this overload and relying on the generic template (or factoring shared logic into a helper).

Suggested change
bool named_plot(const std::string& name, const std::vector<std::string>& x, const std::vector<Numeric>& y, const std::string& format = "")
{
detail::_interpreter::get();
PyObject* kwargs = PyDict_New();
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));
PyObject* xarray = detail::get_array(x);
PyObject* yarray = detail::get_array(y);
PyObject* pystring = PyString_FromString(format.c_str());
PyObject* plot_args = PyTuple_New(3);
PyTuple_SetItem(plot_args, 0, xarray);
PyTuple_SetItem(plot_args, 1, yarray);
PyTuple_SetItem(plot_args, 2, pystring);
PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, plot_args, kwargs);
Py_DECREF(kwargs);
Py_DECREF(plot_args);
if (res) Py_DECREF(res);
return res;
}
template<typename Numeric>

Copilot uses AI. Check for mistakes.
bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")
{
Expand Down