Skip to content
Open
Show file tree
Hide file tree
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
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ int main()

![Basic example](./examples/basic.png)

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.
Comment on lines +68 to +92
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.
Alternatively, matplotlib-cpp also supports some C++11-powered syntactic sugar:
```cpp
#include <cmath>
Expand Down
25 changes: 25 additions & 0 deletions examples/string_xaxis_named_plot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "../matplotlibcpp.h"
#include <string>
#include <vector>

namespace plt = matplotlibcpp;

int main()
{
const std::vector<std::string> months = {
"Jan 2021", "Feb 2021", "Mar 2021", "Apr 2021", "May 2021"
};
const std::vector<double> speed_kmh = {58.4, 61.2, 63.9, 62.1, 65.0};

plt::figure_size(900, 500);
plt::named_plot("Vehicle speed (max)", months, speed_kmh, "o-");
plt::title("Monthly peak speed");
plt::xlabel("Month");
plt::ylabel("Speed (km/h)");
plt::legend();
plt::tight_layout();

// Use save() for CI/headless usage; replace with show() for interactive runs.
plt::save("./string_xaxis_named_plot.png");
return 0;
}
30 changes: 30 additions & 0 deletions matplotlibcpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,36 @@ bool named_plot(const std::string& name, const std::vector<NumericX>& x, const s
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 = "")

Comment on lines +1756 to +1758
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.
template<typename NumericX, typename NumericY>
bool named_semilogx(const std::string& name, const std::vector<NumericX>& x, const std::vector<NumericY>& y, const std::string& format = "")
{
Expand Down
Loading