Skip to content

template to handle strings on x axis w/ legend#254

Open
im-hashim wants to merge 3 commits intolava:masterfrom
im-hashim:patch-1
Open

template to handle strings on x axis w/ legend#254
im-hashim wants to merge 3 commits intolava:masterfrom
im-hashim:patch-1

Conversation

@im-hashim
Copy link
Copy Markdown

bool named_plot(const std::string& name, const std::vectorstd::string& x, const std::vector& y, const std::string& format = "") { .. }

added template to be able to have named legend plotting: ex: time(x) vs signal(y) with legend.
Prior to this change, the current library implements simple plots with no legends and with this change the above should be possible.

bool named_plot(const std::string& name, const std::vector<std::string>& x, const std::vector<Numeric>& y, const std::string& format = "") { .. }

added template to be able to have named legend plotting: ex: time(x) vs signal(y) with legend. 
Prior to this change, the current library implements simple plots with no legends and with this change the above should be possible.
@lava
Copy link
Copy Markdown
Owner

lava commented Apr 2, 2021

Thanks for contributing!

I'm a bit confused if/why this works, it's not mentioned on the matplotlib docs that x can be a vector of strings: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html

Would you mind adding an example that uses this function, so I can check out that this works as it should?

@im-hashim
Copy link
Copy Markdown
Author

im-hashim commented Apr 3, 2021 via email

@im-hashim
Copy link
Copy Markdown
Author

@lava this is open for more than 2 years. if my response answers your question, can you please merge my pull request ?

Copilot AI review requested due to automatic review settings April 16, 2026 17:43
@im-hashim
Copy link
Copy Markdown
Author

Thanks for the review and for asking for a concrete example.

I added a small runnable example at:

  • examples/string_xaxis_named_plot.cpp

I also added a short README usage note and constraints under the examples section.

Expected behavior:

  • named_plot("Vehicle speed (max)", x, y, "o-") works with x as std::vector<std::string> and numeric y of matching length.
  • Matplotlib treats the string labels as categorical x-axis values.
  • Calling legend() shows the provided series label.
  • The example saves string_xaxis_named_plot.png (and can be switched to show() for interactive runs).

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an API/example intended to support named_plot() with std::vector<std::string> x-axis values so users can plot categorical/string x-values while still using legend labels.

Changes:

  • Introduces a new named_plot overload for x: std::vector<std::string> in matplotlibcpp.h.
  • Adds a new example demonstrating string x-axis + legend plotting.
  • Documents the new example/usage in the README.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
matplotlibcpp.h Adds a named_plot overload for string x-values (and accidentally adds a broken named_semilogx declaration).
examples/string_xaxis_named_plot.cpp New runnable example plotting categorical month labels with a legend and saving an image.
README.md Adds documentation snippet and build command for the new example.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md
Comment on lines +68 to +92
String x-axis labels with legend:
```cpp
#include "../matplotlibcpp.h"
#include <string>
#include <vector>

namespace plt = matplotlibcpp;

int main()
{
std::vector<std::string> x = {"Jan 2021", "Feb 2021", "Mar 2021"};
std::vector<double> y = {58.4, 61.2, 63.9};

plt::named_plot("Vehicle speed (max)", x, y, "o-");
plt::legend();
plt::save("./string_xaxis_named_plot.png");
}
```
g++ examples/string_xaxis_named_plot.cpp -std=c++11 -I. -I/usr/include/python2.7 -lpython2.7

Expected behavior and constraints:
- `x` is a `std::vector<std::string>` and `y` is numeric with matching length.
- String labels are mapped as categorical x values by matplotlib.
- Use `plt::save(...)` for headless runs or `plt::show()` for interactive runs.

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.

The PR description/README section implies legends (and/or string x-axis support) are newly enabled, but the library already provides named_plot(...) for legend labels and detail::get_array(std::vector<std::string>) for string data. Consider updating the README text to clarify what limitation is actually being addressed (e.g., providing a dedicated overload), or remove the claim that this capability was previously unavailable.

Copilot uses AI. Check for mistakes.
Comment thread matplotlibcpp.h
Comment on lines +1756 to +1758
template<typename Numeric>
bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")

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.

There is an incomplete named_semilogx template declaration here (no function body and no trailing ;). This will not compile and also duplicates the existing named_semilogx template immediately below—remove this line or provide a proper definition/forward declaration ending with ;.

Suggested change
template<typename Numeric>
bool named_semilogx(const std::string& name, const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::string& format = "")

Copilot uses AI. Check for mistakes.
Comment thread matplotlibcpp.h
Comment on lines +1734 to +1736
PyObject* kwargs = PyDict_New();
PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str()));

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.
Comment thread matplotlibcpp.h
Comment on lines +1730 to +1756
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>
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.
@im-hashim
Copy link
Copy Markdown
Author

Hi @lava, I added the requested runnable example and README note in commit 9eb18b0. Could you please merge if this looks good?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants