From efc14f6174992ed47edc325680386d9133c36092 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Sun, 5 Dec 2021 11:09:28 +0000 Subject: [PATCH 1/9] Fix: subplot()'s arguments should be ints, not doubles Currently, calls to matplotlibcpp::subplot() always fail as Python complains about the type mismatch. --- matplotlibcpp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d95d46ad..b30b87f7 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2255,9 +2255,9 @@ inline void subplot(long nrows, long ncols, long plot_number) // 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)); + PyTuple_SetItem(args, 0, PyLong_FromLong(nrows)); + PyTuple_SetItem(args, 1, PyLong_FromLong(ncols)); + PyTuple_SetItem(args, 2, PyLong_FromLong(plot_number)); PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_subplot, args); if(!res) throw std::runtime_error("Call to subplot() failed."); From f0fb30681d6f0fffe2d7dd40afb8a148a65b2675 Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Sat, 13 Aug 2022 09:56:13 +0200 Subject: [PATCH 2/9] added alpha for normal plots. --- .gitignore | 3 +++ examples/modern.cpp | 55 ++++++++++++++++++++++++++++++++------------- matplotlibcpp.h | 11 ++++++--- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 1c4a1b0a..d389ccb0 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ # Build /examples/build/* +.idea/ +build/ +cmake-build-debug/ # vim temp files *.sw* diff --git a/examples/modern.cpp b/examples/modern.cpp index 871ef2b0..8e980cf7 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -8,26 +8,49 @@ namespace plt = matplotlibcpp; int main() { // plot(y) - the x-coordinates are implicitly set to [0,1,...,n) - //plt::plot({1,2,3,4}); - + //plt::plot({1,2,3,4}); + + // Prepare data for parametric plot. - int n = 5000; // number of data points - vector x(n),y(n); - for(int i=0; i x(n),y(n); +// for(int i=0; i x(n),y(n); + x[0] = 0; + x[1] = 20; + y[0] = 0; + y[1] = 20; +// plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); +// plt::plot(x, y, "r", alpha); +// plt::xlim(0, 20); +// plt::ylim(0, 20); +// //plt::set_aspect(0.5); +//// plt::set_aspect_equal(); +// +// +// +// // show plots +// plt::show(); + plt::figure_size(1200, 500); + plt::title("Bias Distribution compared to HSPICE."); + // + "\nOP(" + std::to_string(op_[0]) + "V/" + std::to_string(op_[1]) + "°C)"); - // show plots - plt::show(); + plt::scatter(x, y,1.0, {{"color","r"}, {"label", "FinFET-SLS"}}); + y[1] = 40; + plt::scatter(x, y,1.0, {{"color","g"}, {"label", "Fin-SLS"}}); + // plt::xlim(-400.0f, 400.0f); + // plt::xlim(-400.0f, 400.0f); + // plt::ylim(-0.3, static_cast(op_[0]) + 0.3); + plt::legend(); + plt::show(); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index b30b87f7..d0d25041 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -439,7 +439,7 @@ PyObject* get_listlist(const std::vector>& ll) /// /// See: https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.plot.html template -bool plot(const std::vector &x, const std::vector &y, const std::map& keywords) +bool plot(const std::vector &x, const std::vector &y, const std::map& keywords)//, double alpha=1.0) { assert(x.size() == y.size()); @@ -460,6 +460,7 @@ bool plot(const std::vector &x, const std::vector &y, const st { PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } +// PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_plot, args, kwargs); @@ -1355,7 +1356,7 @@ bool named_hist(std::string label,const std::vector& y, long bins=10, s } template -bool plot(const std::vector& x, const std::vector& y, const std::string& s = "") +bool plot(const std::vector& x, const std::vector& y, const std::string& s = "", double alpha=1.0f) { assert(x.size() == y.size()); @@ -1371,8 +1372,12 @@ bool plot(const std::vector& x, const std::vector& y, const PyTuple_SetItem(plot_args, 1, yarray); PyTuple_SetItem(plot_args, 2, pystring); - PyObject* res = PyObject_CallObject(detail::_interpreter::get().s_python_function_plot, plot_args); + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "alpha", PyFloat_FromDouble(alpha)); + 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); From 86414b3bad6a1e33fd59aa849e346ca3390e901f Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Mon, 22 Aug 2022 13:44:26 +0200 Subject: [PATCH 3/9] rc params now able to adjust font --- matplotlibcpp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index d0d25041..e140f98b 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2656,7 +2656,7 @@ inline void rcparams(const std::map& keywords = {}) { PyObject* args = PyTuple_New(0); PyObject* kwargs = PyDict_New(); for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if ("text.usetex" == it->first) + if ("text.usetex" == it->first or "font" == it->first) PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } From 9ac8014292d8ca5badf0db1642d1dc0d7c1e28aa Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Mon, 22 Aug 2022 13:47:45 +0200 Subject: [PATCH 4/9] Fixed: rc params now able to adjust font --- examples/bar.cpp | 3 ++- matplotlibcpp.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/bar.cpp b/examples/bar.cpp index 86423adf..c2bc0367 100644 --- a/examples/bar.cpp +++ b/examples/bar.cpp @@ -10,9 +10,10 @@ int main(int argc, char **argv) { for (int i = 0; i < 20; i++) { test_data.push_back(i); } - + plt::rcparams({{"font.size", "55"}}); plt::bar(test_data); plt::show(); + plt::save("bar_size.png"); return (0); } diff --git a/matplotlibcpp.h b/matplotlibcpp.h index e140f98b..93e3e1a3 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2656,7 +2656,7 @@ inline void rcparams(const std::map& keywords = {}) { PyObject* args = PyTuple_New(0); PyObject* kwargs = PyDict_New(); for (auto it = keywords.begin(); it != keywords.end(); ++it) { - if ("text.usetex" == it->first or "font" == it->first) + if ("text.usetex" == it->first or "font.size" == it->first) PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); } From ededcc04d33eacd3d25d578915a0baaed76a25be Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Fri, 11 Nov 2022 21:58:33 +0100 Subject: [PATCH 5/9] added rcparam lines.markersize --- examples/modern.cpp | 3 ++- matplotlibcpp.h | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/modern.cpp b/examples/modern.cpp index 8e980cf7..9689f97c 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -44,7 +44,8 @@ int main() plt::figure_size(1200, 500); plt::title("Bias Distribution compared to HSPICE."); // + "\nOP(" + std::to_string(op_[0]) + "V/" + std::to_string(op_[1]) + "°C)"); - + plt::rcparams({{"lines.markersize", "10"}}); + plt::plot(x,y, "ko-"); plt::scatter(x, y,1.0, {{"color","r"}, {"label", "FinFET-SLS"}}); y[1] = 40; plt::scatter(x, y,1.0, {{"color","g"}, {"label", "Fin-SLS"}}); diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 93e3e1a3..7154cf1e 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -2657,8 +2657,17 @@ inline void rcparams(const std::map& keywords = {}) { PyObject* kwargs = PyDict_New(); for (auto it = keywords.begin(); it != keywords.end(); ++it) { if ("text.usetex" == it->first or "font.size" == it->first) - PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); - else PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyLong_FromLong(std::stoi(it->second.c_str()))); + + } + else if ("lines.markersize" == it->first) + { + PyDict_SetItemString(kwargs, "lines.markersize", PyFloat_FromDouble(std::stoi(it->second.c_str()))); + }else + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } } PyObject * update = PyObject_GetAttrString(detail::_interpreter::get().s_python_function_rcparams, "update"); From 1ab9b3df6f5c67f16ea40159814046f1232b35d0 Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Fri, 5 Jul 2024 09:21:24 +0200 Subject: [PATCH 6/9] fixed python 3.11 --- matplotlibcpp.h | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 7154cf1e..a8681bb4 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -14,7 +14,7 @@ #include // requires c++11 support #include #include // std::stod - +#define PY_MAJOR_VERSION 3 #ifndef WITHOUT_NUMPY # define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION # include @@ -164,13 +164,13 @@ struct _interpreter { #endif _interpreter() { - // optional but recommended #if PY_MAJOR_VERSION >= 3 wchar_t name[] = L"plotting"; #else char name[] = "plotting"; #endif +#if PY_MINOR_VERSION < 11 Py_SetProgramName(name); Py_Initialize(); @@ -178,6 +178,31 @@ struct _interpreter { wchar_t const **argv = dummy_args; int argc = sizeof(dummy_args)/sizeof(dummy_args[0])-1; +#else + PyStatus status; + PyConfig config; + PyConfig_InitPythonConfig(&config); + wchar_t const* dummy_args[] = { L"Python", NULL }; // const is needed because literals must not be modified + wchar_t* const* argv = const_cast(dummy_args); + int argc = sizeof(dummy_args) / sizeof(dummy_args[0]) - 1; + if (argc && argv) { + status = PyConfig_SetString(&config, &config.program_name, name); + if (PyStatus_Exception(status)) { + PyConfig_Clear(&config); + } + status = PyConfig_SetArgv(&config, argc, argv); + if (PyStatus_Exception(status)) { + PyConfig_Clear(&config); + } + } + status = Py_InitializeFromConfig(&config); + if (PyStatus_Exception(status)) { + PyConfig_Clear(&config); + } + PyConfig_Clear(&config); +#endif + + #if PY_MAJOR_VERSION >= 3 PySys_SetArgv(argc, const_cast(argv)); #else @@ -2998,3 +3023,4 @@ class Plot }; } // end namespace matplotlibcpp + From bef787e2a34509acba9f12a32221d5a21e281c5c Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Sat, 6 Jul 2024 09:51:13 +0200 Subject: [PATCH 7/9] added bbox_on_anchor for legend. --- matplotlibcpp.h | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index a8681bb4..183726f3 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1981,22 +1981,31 @@ inline void legend() Py_DECREF(res); } -inline void legend(const std::map& keywords) +inline void legend(const std::map& keywords, const std::map>& tuple_keywords = {}) { - detail::_interpreter::get(); + detail::_interpreter::get(); - // construct keyword args - PyObject* kwargs = PyDict_New(); - for(std::map::const_iterator it = keywords.begin(); it != keywords.end(); ++it) - { - PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); - } + // construct keyword args + PyObject* kwargs = PyDict_New(); + for(auto it = keywords.begin(); it != keywords.end(); ++it) + { + PyDict_SetItemString(kwargs, it->first.c_str(), PyString_FromString(it->second.c_str())); + } - PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); - if(!res) throw std::runtime_error("Call to legend() failed."); + for(auto it = tuple_keywords.begin(); it != tuple_keywords.end(); ++it) + { + PyObject* tuple = PyTuple_New(2); + PyTuple_SetItem(tuple, 0, PyFloat_FromDouble(it->second.first)); + PyTuple_SetItem(tuple, 1, PyFloat_FromDouble(it->second.second)); + PyDict_SetItemString(kwargs, it->first.c_str(), tuple); + Py_DECREF(tuple); + } - Py_DECREF(kwargs); - Py_DECREF(res); + PyObject* res = PyObject_Call(detail::_interpreter::get().s_python_function_legend, detail::_interpreter::get().s_python_empty_tuple, kwargs); + if(!res) throw std::runtime_error("Call to legend() failed."); + + Py_DECREF(kwargs); + Py_DECREF(res); } template From 452893fd1c11988a48a40730b4976164eeddf58a Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Sat, 6 Jul 2024 14:12:38 +0200 Subject: [PATCH 8/9] added named_plot with keywords --- matplotlibcpp.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 183726f3..28156584 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -1702,7 +1702,34 @@ bool errorbar(const std::vector &x, const std::vector &y, co return res; } +template +bool named_plot(const std::string& name, const std::vector& x, const std::vector& y, const std::map& keywords = {}) +{ + detail::_interpreter::get(); + + PyObject* kwargs = PyDict_New(); + PyDict_SetItemString(kwargs, "label", PyString_FromString(name.c_str())); + + for (const auto& keyword : keywords) + { + PyDict_SetItemString(kwargs, keyword.first.c_str(), PyString_FromString(keyword.second.c_str())); + } + + PyObject* xarray = detail::get_array(x); + PyObject* yarray = detail::get_array(y); + PyObject* plot_args = PyTuple_New(2); + PyTuple_SetItem(plot_args, 0, xarray); + PyTuple_SetItem(plot_args, 1, yarray); + + 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 != nullptr; +} template bool named_plot(const std::string& name, const std::vector& y, const std::string& format = "") { From 0d1ba2024645eeec6242cbd99d8017a7195bbfa9 Mon Sep 17 00:00:00 2001 From: Jan Dennis Reimer Date: Fri, 21 Feb 2025 10:49:24 +0100 Subject: [PATCH 9/9] added subplots and reformat. --- .clang-format | 115 ++++++++++++++++++++++++++++++++++++ examples/animation.cpp | 53 +++++++++-------- examples/bar.cpp | 25 ++++---- examples/basic.cpp | 77 ++++++++++++------------ examples/colorbar.cpp | 41 +++++++------ examples/contour.cpp | 31 +++++----- examples/fill.cpp | 43 +++++++------- examples/fill_inbetween.cpp | 7 ++- examples/imshow.cpp | 35 ++++++----- examples/lines3d.cpp | 43 +++++++------- examples/minimal.cpp | 8 ++- examples/modern.cpp | 92 ++++++++++++++--------------- examples/nonblock.cpp | 73 ++++++++++++----------- examples/quiver.cpp | 27 +++++---- examples/spy.cpp | 37 ++++++------ examples/subplot.cpp | 43 +++++++------- examples/subplot2grid.cpp | 73 ++++++++++++----------- examples/surface.cpp | 31 +++++----- examples/update.cpp | 79 +++++++++++++------------ examples/xkcd.cpp | 28 +++++---- format.sh | 3 + matplotlibcpp.h | 49 +++++++++++++++ 22 files changed, 613 insertions(+), 400 deletions(-) create mode 100755 .clang-format create mode 100755 format.sh diff --git a/.clang-format b/.clang-format new file mode 100755 index 00000000..27de441f --- /dev/null +++ b/.clang-format @@ -0,0 +1,115 @@ +--- +Language: Cpp +# BasedOnStyle: GNU +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: All +AlwaysBreakAfterReturnType: AllDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: true + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 140 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +AlignOperands: true +RawStringFormats: + - Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: Never +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... + diff --git a/examples/animation.cpp b/examples/animation.cpp index d9794300..7cdc3b93 100644 --- a/examples/animation.cpp +++ b/examples/animation.cpp @@ -1,36 +1,39 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; -int main() +int +main() { - int n = 1000; - std::vector x, y, z; + int n = 1000; + std::vector x, y, z; - for(int i=0; i #include -#include "../matplotlibcpp.h" namespace plt = matplotlibcpp; -int main(int argc, char **argv) { - std::vector test_data; - for (int i = 0; i < 20; i++) { - test_data.push_back(i); - } - plt::rcparams({{"font.size", "55"}}); - plt::bar(test_data); - plt::show(); - plt::save("bar_size.png"); +int +main(int argc, char **argv) +{ + std::vector test_data; + for(int i = 0; i < 20; i++) + { + test_data.push_back(i); + } + plt::rcparams({ { "font.size", "55" } }); + plt::bar(test_data); + plt::show(); + plt::save("bar_size.png"); - return (0); + return (0); } diff --git a/examples/basic.cpp b/examples/basic.cpp index 2dc34c74..3f5e3074 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -1,44 +1,47 @@ #define _USE_MATH_DEFINES -#include -#include #include "../matplotlibcpp.h" +#include +#include namespace plt = matplotlibcpp; -int main() +int +main() { - // Prepare data. - int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i x(n), y(n), z(n), w(n, 2); + for(int i = 0; i < n; ++i) + { + x.at(i) = i * i; + y.at(i) = sin(2 * M_PI * i / 360.0); + z.at(i) = log(i); + } + + // Set the size of output image = 1200x780 pixels + plt::figure_size(1200, 780); + + // Plot line from given x and y data. Color is selected automatically. + plt::plot(x, y); + + // Plot a red dashed line from given x and y data. + plt::plot(x, w, "r--"); + + // Plot a line whose name will show up as "log(x)" in the legend. + plt::named_plot("log(x)", x, z); + + // Set x-axis to interval [0,1000000] + plt::xlim(0, 1000 * 1000); + + // Add graph title + plt::title("Sample figure"); + + // Enable legend. + plt::legend(); + + // save figure + const char *filename = "./basic.png"; + std::cout << "Saving result to " << filename << std::endl; + ; + plt::save(filename); } diff --git a/examples/colorbar.cpp b/examples/colorbar.cpp index f53e01da..3374ffc9 100644 --- a/examples/colorbar.cpp +++ b/examples/colorbar.cpp @@ -1,32 +1,35 @@ #define _USE_MATH_DEFINES +#include "../matplotlibcpp.h" #include #include -#include "../matplotlibcpp.h" using namespace std; namespace plt = matplotlibcpp; -int main() +int +main() { - // Prepare data - int ncols = 500, nrows = 300; - std::vector z(ncols * nrows); - for (int j=0; j z(ncols * nrows); + for(int j = 0; j < nrows; ++j) + { + for(int i = 0; i < ncols; ++i) + { + z.at(ncols * j + i) = std::sin(std::hypot(i - ncols / 2, j - nrows / 2)); } + } - const float* zptr = &(z[0]); - const int colors = 1; + const float *zptr = &(z[0]); + const int colors = 1; - plt::title("My matrix"); - PyObject* mat; - plt::imshow(zptr, nrows, ncols, colors, {}, &mat); - plt::colorbar(mat); + plt::title("My matrix"); + PyObject *mat; + plt::imshow(zptr, nrows, ncols, colors, {}, &mat); + plt::colorbar(mat); - // Show plots - plt::show(); - plt::close(); - Py_DECREF(mat); + // Show plots + plt::show(); + plt::close(); + Py_DECREF(mat); } diff --git a/examples/contour.cpp b/examples/contour.cpp index 9289d0a0..771e4133 100644 --- a/examples/contour.cpp +++ b/examples/contour.cpp @@ -4,21 +4,24 @@ namespace plt = matplotlibcpp; -int main() +int +main() { - std::vector> x, y, z; - for (double i = -5; i <= 5; i += 0.25) { - std::vector x_row, y_row, z_row; - for (double j = -5; j <= 5; j += 0.25) { - x_row.push_back(i); - y_row.push_back(j); - z_row.push_back(::std::sin(::std::hypot(i, j))); - } - x.push_back(x_row); - y.push_back(y_row); - z.push_back(z_row); + std::vector> x, y, z; + for(double i = -5; i <= 5; i += 0.25) + { + std::vector x_row, y_row, z_row; + for(double j = -5; j <= 5; j += 0.25) + { + x_row.push_back(i); + y_row.push_back(j); + z_row.push_back(::std::sin(::std::hypot(i, j))); } + x.push_back(x_row); + y.push_back(y_row); + z.push_back(z_row); + } - plt::contour(x, y, z); - plt::show(); + plt::contour(x, y, z); + plt::show(); } diff --git a/examples/fill.cpp b/examples/fill.cpp index 6059b475..884d2768 100644 --- a/examples/fill.cpp +++ b/examples/fill.cpp @@ -7,29 +7,32 @@ namespace plt = matplotlibcpp; // Example fill plot taken from: // https://matplotlib.org/gallery/misc/fill_spiral.html -int main() { - // Prepare data. - vector theta; - for (double d = 0; d < 8 * M_PI; d += 0.1) - theta.push_back(d); +int +main() +{ + // Prepare data. + vector theta; + for(double d = 0; d < 8 * M_PI; d += 0.1) theta.push_back(d); - const int a = 1; - const double b = 0.2; + const int a = 1; + const double b = 0.2; - for (double dt = 0; dt < 2 * M_PI; dt += M_PI/2.0) { - vector x1, y1, x2, y2; - for (double th : theta) { - x1.push_back( a*cos(th + dt) * exp(b*th) ); - y1.push_back( a*sin(th + dt) * exp(b*th) ); + for(double dt = 0; dt < 2 * M_PI; dt += M_PI / 2.0) + { + vector x1, y1, x2, y2; + for(double th : theta) + { + x1.push_back(a * cos(th + dt) * exp(b * th)); + y1.push_back(a * sin(th + dt) * exp(b * th)); - x2.push_back( a*cos(th + dt + M_PI/4.0) * exp(b*th) ); - y2.push_back( a*sin(th + dt + M_PI/4.0) * exp(b*th) ); - } + x2.push_back(a * cos(th + dt + M_PI / 4.0) * exp(b * th)); + y2.push_back(a * sin(th + dt + M_PI / 4.0) * exp(b * th)); + } - x1.insert(x1.end(), x2.rbegin(), x2.rend()); - y1.insert(y1.end(), y2.rbegin(), y2.rend()); + x1.insert(x1.end(), x2.rbegin(), x2.rend()); + y1.insert(y1.end(), y2.rbegin(), y2.rend()); - plt::fill(x1, y1, {}); - } - plt::show(); + plt::fill(x1, y1, {}); + } + plt::show(); } diff --git a/examples/fill_inbetween.cpp b/examples/fill_inbetween.cpp index 788d0086..2493e96a 100644 --- a/examples/fill_inbetween.cpp +++ b/examples/fill_inbetween.cpp @@ -6,11 +6,14 @@ using namespace std; namespace plt = matplotlibcpp; -int main() { +int +main() +{ // Prepare data. int n = 5000; std::vector x(n), y(n), z(n), w(n, 2); - for (int i = 0; i < n; ++i) { + for(int i = 0; i < n; ++i) + { x.at(i) = i * i; y.at(i) = sin(2 * M_PI * i / 360.0); z.at(i) = log(i); diff --git a/examples/imshow.cpp b/examples/imshow.cpp index b11661e4..5b81eb1e 100644 --- a/examples/imshow.cpp +++ b/examples/imshow.cpp @@ -1,29 +1,32 @@ #define _USE_MATH_DEFINES +#include "../matplotlibcpp.h" #include #include -#include "../matplotlibcpp.h" using namespace std; namespace plt = matplotlibcpp; -int main() +int +main() { - // Prepare data - int ncols = 500, nrows = 300; - std::vector z(ncols * nrows); - for (int j=0; j z(ncols * nrows); + for(int j = 0; j < nrows; ++j) + { + for(int i = 0; i < ncols; ++i) + { + z.at(ncols * j + i) = std::sin(std::hypot(i - ncols / 2, j - nrows / 2)); } + } - const float* zptr = &(z[0]); - const int colors = 1; + const float *zptr = &(z[0]); + const int colors = 1; - plt::title("My matrix"); - plt::imshow(zptr, nrows, ncols, colors); + plt::title("My matrix"); + plt::imshow(zptr, nrows, ncols, colors); - // Show plots - plt::save("imshow.png"); - std::cout << "Result saved to 'imshow.png'.\n"; + // Show plots + plt::save("imshow.png"); + std::cout << "Result saved to 'imshow.png'.\n"; } diff --git a/examples/lines3d.cpp b/examples/lines3d.cpp index fd4610d2..25acb355 100644 --- a/examples/lines3d.cpp +++ b/examples/lines3d.cpp @@ -4,27 +4,30 @@ namespace plt = matplotlibcpp; -int main() +int +main() { - std::vector x, y, z; - double theta, r; - double z_inc = 4.0/99.0; double theta_inc = (8.0 * M_PI)/99.0; - - for (double i = 0; i < 100; i += 1) { - theta = -4.0 * M_PI + theta_inc*i; - z.push_back(-2.0 + z_inc*i); - r = z[i]*z[i] + 1; - x.push_back(r * sin(theta)); - y.push_back(r * cos(theta)); - } + std::vector x, y, z; + double theta, r; + double z_inc = 4.0 / 99.0; + double theta_inc = (8.0 * M_PI) / 99.0; - std::map keywords; - keywords.insert(std::pair("label", "parametric curve") ); + for(double i = 0; i < 100; i += 1) + { + theta = -4.0 * M_PI + theta_inc * i; + z.push_back(-2.0 + z_inc * i); + r = z[i] * z[i] + 1; + x.push_back(r * sin(theta)); + y.push_back(r * cos(theta)); + } - plt::plot3(x, y, z, keywords); - plt::xlabel("x label"); - plt::ylabel("y label"); - plt::set_zlabel("z label"); // set_zlabel rather than just zlabel, in accordance with the Axes3D method - plt::legend(); - plt::show(); + std::map keywords; + keywords.insert(std::pair("label", "parametric curve")); + + plt::plot3(x, y, z, keywords); + plt::xlabel("x label"); + plt::ylabel("y label"); + plt::set_zlabel("z label"); // set_zlabel rather than just zlabel, in accordance with the Axes3D method + plt::legend(); + plt::show(); } diff --git a/examples/minimal.cpp b/examples/minimal.cpp index fbe1e1cd..2bfb73bd 100644 --- a/examples/minimal.cpp +++ b/examples/minimal.cpp @@ -2,7 +2,9 @@ namespace plt = matplotlibcpp; -int main() { - plt::plot({1,3,2,4}); - plt::show(); +int +main() +{ + plt::plot({ 1, 3, 2, 4 }); + plt::show(); } diff --git a/examples/modern.cpp b/examples/modern.cpp index 9689f97c..534b1a7c 100644 --- a/examples/modern.cpp +++ b/examples/modern.cpp @@ -1,57 +1,57 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" +#include using namespace std; namespace plt = matplotlibcpp; -int main() +int +main() { - // plot(y) - the x-coordinates are implicitly set to [0,1,...,n) - //plt::plot({1,2,3,4}); - + // plot(y) - the x-coordinates are implicitly set to [0,1,...,n) + // plt::plot({1,2,3,4}); - // Prepare data for parametric plot. - int n = 2; // number of data points -// vector x(n),y(n); -// for(int i=0; i x(n),y(n); + // for(int i=0; i x(n),y(n); - x[0] = 0; - x[1] = 20; - y[0] = 0; - y[1] = 20; -// plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); -// plt::plot(x, y, "r", alpha); -// plt::xlim(0, 20); -// plt::ylim(0, 20); -// //plt::set_aspect(0.5); -//// plt::set_aspect_equal(); -// -// -// -// // show plots -// plt::show(); + // plot() takes an arbitrary number of (x,y,format)-triples. + // x must be iterable (that is, anything providing begin(x) and end(x)), + // y must either be callable (providing operator() const) or iterable. + double alpha = 0.1f; + vector x(n), y(n); + x[0] = 0; + x[1] = 20; + y[0] = 0; + y[1] = 20; + // plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-"); + // plt::plot(x, y, "r", alpha); + // plt::xlim(0, 20); + // plt::ylim(0, 20); + // //plt::set_aspect(0.5); + //// plt::set_aspect_equal(); + // + // + // + // // show plots + // plt::show(); - plt::figure_size(1200, 500); - plt::title("Bias Distribution compared to HSPICE."); - // + "\nOP(" + std::to_string(op_[0]) + "V/" + std::to_string(op_[1]) + "°C)"); - plt::rcparams({{"lines.markersize", "10"}}); - plt::plot(x,y, "ko-"); - plt::scatter(x, y,1.0, {{"color","r"}, {"label", "FinFET-SLS"}}); - y[1] = 40; - plt::scatter(x, y,1.0, {{"color","g"}, {"label", "Fin-SLS"}}); - // plt::xlim(-400.0f, 400.0f); - // plt::xlim(-400.0f, 400.0f); - // plt::ylim(-0.3, static_cast(op_[0]) + 0.3); - plt::legend(); - plt::show(); + plt::figure_size(1200, 500); + plt::title("Bias Distribution compared to HSPICE."); + // + "\nOP(" + std::to_string(op_[0]) + "V/" + std::to_string(op_[1]) + "°C)"); + plt::rcparams({ { "lines.markersize", "10" } }); + plt::plot(x, y, "ko-"); + plt::scatter(x, y, 1.0, { { "color", "r" }, { "label", "FinFET-SLS" } }); + y[1] = 40; + plt::scatter(x, y, 1.0, { { "color", "g" }, { "label", "Fin-SLS" } }); + // plt::xlim(-400.0f, 400.0f); + // plt::xlim(-400.0f, 400.0f); + // plt::ylim(-0.3, static_cast(op_[0]) + 0.3); + plt::legend(); + plt::show(); } diff --git a/examples/nonblock.cpp b/examples/nonblock.cpp index 327d96c7..06997a55 100644 --- a/examples/nonblock.cpp +++ b/examples/nonblock.cpp @@ -1,46 +1,47 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" +#include namespace plt = matplotlibcpp; - using namespace matplotlibcpp; using namespace std; -int main() +int +main() { - // Prepare data. - int n = 5000; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i x(n), y(n), z(n), w(n, 2); + for(int i = 0; i < n; ++i) + { + x.at(i) = i * i; + y.at(i) = sin(2 * M_PI * i / 360.0); + z.at(i) = log(i); + } + + // Plot line from given x and y data. Color is selected automatically. + plt::subplot(2, 2, 1); + plt::plot(x, y); + + // Plot a red dashed line from given x and y data. + plt::subplot(2, 2, 2); + plt::plot(x, w, "r--"); + + // Plot a line whose name will show up as "log(x)" in the legend. + plt::subplot(2, 2, 3); + plt::named_plot("log(x)", x, z); + + // Set x-axis to interval [0,1000000] + plt::xlim(0, 1000 * 1000); + + // Add graph title + plt::title("Sample figure"); + // Enable legend. + plt::legend(); + + plt::show(false); + + cout << "matplotlibcpp::show() is working in an non-blocking mode" << endl; + getchar(); } diff --git a/examples/quiver.cpp b/examples/quiver.cpp index ea3c3eca..56913c0b 100644 --- a/examples/quiver.cpp +++ b/examples/quiver.cpp @@ -2,19 +2,22 @@ namespace plt = matplotlibcpp; -int main() +int +main() { - // u and v are respectively the x and y components of the arrows we're plotting - std::vector x, y, u, v; - for (int i = -5; i <= 5; i++) { - for (int j = -5; j <= 5; j++) { - x.push_back(i); - u.push_back(-i); - y.push_back(j); - v.push_back(-j); - } + // u and v are respectively the x and y components of the arrows we're plotting + std::vector x, y, u, v; + for(int i = -5; i <= 5; i++) + { + for(int j = -5; j <= 5; j++) + { + x.push_back(i); + u.push_back(-i); + y.push_back(j); + v.push_back(-j); } + } - plt::quiver(x, y, u, v); - plt::show(); + plt::quiver(x, y, u, v); + plt::show(); } \ No newline at end of file diff --git a/examples/spy.cpp b/examples/spy.cpp index 6027a487..7968c91d 100644 --- a/examples/spy.cpp +++ b/examples/spy.cpp @@ -5,26 +5,29 @@ namespace plt = matplotlibcpp; -int main() +int +main() { - const int n = 20; - std::vector> matrix; + const int n = 20; + std::vector> matrix; - for (int i = 0; i < n; ++i) { - std::vector row; - for (int j = 0; j < n; ++j) { - if (i == j) - row.push_back(-2); - else if (j == i - 1 || j == i + 1) - row.push_back(1); - else - row.push_back(0); - } - matrix.push_back(row); + for(int i = 0; i < n; ++i) + { + std::vector row; + for(int j = 0; j < n; ++j) + { + if(i == j) + row.push_back(-2); + else if(j == i - 1 || j == i + 1) + row.push_back(1); + else + row.push_back(0); } + matrix.push_back(row); + } - plt::spy(matrix, 5, {{"marker", "o"}}); - plt::show(); + plt::spy(matrix, 5, { { "marker", "o" } }); + plt::show(); - return 0; + return 0; } diff --git a/examples/subplot.cpp b/examples/subplot.cpp index bee322e0..82ca096a 100644 --- a/examples/subplot.cpp +++ b/examples/subplot.cpp @@ -1,31 +1,32 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" +#include using namespace std; namespace plt = matplotlibcpp; -int main() +int +main() { - // Prepare data - int n = 500; - std::vector x(n), y(n), z(n), w(n,2); - for(int i=0; i x(n), y(n), z(n), w(n, 2); + for(int i = 0; i < n; ++i) + { + x.at(i) = i; + y.at(i) = sin(2 * M_PI * i / 360.0); + z.at(i) = 100.0 / i; + } + // Set the "super title" + plt::suptitle("My plot"); + plt::subplot(1, 2, 1); + plt::plot(x, y, "r-"); + plt::subplot(1, 2, 2); + plt::plot(x, z, "k-"); + // Add some text to the plot + plt::text(100, 90, "Hello!"); - // Show plots - plt::show(); + // Show plots + plt::show(); } diff --git a/examples/subplot2grid.cpp b/examples/subplot2grid.cpp index f590e51c..befe4f65 100644 --- a/examples/subplot2grid.cpp +++ b/examples/subplot2grid.cpp @@ -1,44 +1,45 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" +#include using namespace std; namespace plt = matplotlibcpp; -int main() +int +main() { - // Prepare data - int n = 500; - std::vector x(n), u(n), v(n), w(n); - for(int i=0; i x(n), u(n), v(n), w(n); + for(int i = 0; i < n; ++i) + { + x.at(i) = i; + u.at(i) = sin(2 * M_PI * i / 500.0); + v.at(i) = 100.0 / i; + w.at(i) = sin(2 * M_PI * i / 1000.0); + } + + // Set the "super title" + plt::suptitle("My plot"); + + const long nrows = 3, ncols = 3; + long row = 2, col = 2; + + plt::subplot2grid(nrows, ncols, row, col); + plt::plot(x, w, "g-"); + + long spanr = 1, spanc = 2; + col = 0; + plt::subplot2grid(nrows, ncols, row, col, spanr, spanc); + plt::plot(x, v, "r-"); + + spanr = 2, spanc = 3; + row = 0, col = 0; + plt::subplot2grid(nrows, ncols, row, col, spanr, spanc); + plt::plot(x, u, "b-"); + // Add some text to the plot + plt::text(100., -0.5, "Hello!"); + + // Show plots + plt::show(); } diff --git a/examples/surface.cpp b/examples/surface.cpp index 4865f061..f6d71158 100644 --- a/examples/surface.cpp +++ b/examples/surface.cpp @@ -4,21 +4,24 @@ namespace plt = matplotlibcpp; -int main() +int +main() { - std::vector> x, y, z; - for (double i = -5; i <= 5; i += 0.25) { - std::vector x_row, y_row, z_row; - for (double j = -5; j <= 5; j += 0.25) { - x_row.push_back(i); - y_row.push_back(j); - z_row.push_back(::std::sin(::std::hypot(i, j))); - } - x.push_back(x_row); - y.push_back(y_row); - z.push_back(z_row); + std::vector> x, y, z; + for(double i = -5; i <= 5; i += 0.25) + { + std::vector x_row, y_row, z_row; + for(double j = -5; j <= 5; j += 0.25) + { + x_row.push_back(i); + y_row.push_back(j); + z_row.push_back(::std::sin(::std::hypot(i, j))); } + x.push_back(x_row); + y.push_back(y_row); + z.push_back(z_row); + } - plt::plot_surface(x, y, z); - plt::show(); + plt::plot_surface(x, y, z); + plt::show(); } diff --git a/examples/update.cpp b/examples/update.cpp index 64f49067..4c8813bc 100644 --- a/examples/update.cpp +++ b/examples/update.cpp @@ -1,60 +1,63 @@ #define _USE_MATH_DEFINES -#include #include "../matplotlibcpp.h" #include +#include namespace plt = matplotlibcpp; -void update_window(const double x, const double y, const double t, - std::vector &xt, std::vector &yt) +void +update_window(const double x, const double y, const double t, std::vector &xt, std::vector &yt) { - const double target_length = 300; - const double half_win = (target_length/(2.*sqrt(1.+t*t))); + const double target_length = 300; + const double half_win = (target_length / (2. * sqrt(1. + t * t))); - xt[0] = x - half_win; - xt[1] = x + half_win; - yt[0] = y - half_win*t; - yt[1] = y + half_win*t; + xt[0] = x - half_win; + xt[1] = x + half_win; + yt[0] = y - half_win * t; + yt[1] = y + half_win * t; } - -int main() +int +main() { - size_t n = 1000; - std::vector x, y; + size_t n = 1000; + std::vector x, y; - const double w = 0.05; - const double a = n/2; + const double w = 0.05; + const double a = n / 2; - for (size_t i=0; i xt(2), yt(2); + std::vector xt(2), yt(2); - plt::title("Tangent of a sine curve"); - plt::xlim(x.front(), x.back()); - plt::ylim(-a, a); - plt::axis("equal"); + plt::title("Tangent of a sine curve"); + plt::xlim(x.front(), x.back()); + plt::ylim(-a, a); + plt::axis("equal"); - // Plot sin once and for all. - plt::named_plot("sin", x, y); + // Plot sin once and for all. + plt::named_plot("sin", x, y); - // Prepare plotting the tangent. - plt::Plot plot("tangent"); + // Prepare plotting the tangent. + plt::Plot plot("tangent"); - plt::legend(); + plt::legend(); - for (size_t i=0; i #include "../matplotlibcpp.h" +#include #include namespace plt = matplotlibcpp; -int main() { - std::vector t(1000); - std::vector x(t.size()); +int +main() +{ + std::vector t(1000); + std::vector x(t.size()); - for(size_t i = 0; i < t.size(); i++) { - t[i] = i / 100.0; - x[i] = sin(2.0 * M_PI * 1.0 * t[i]); - } + for(size_t i = 0; i < t.size(); i++) + { + t[i] = i / 100.0; + x[i] = sin(2.0 * M_PI * 1.0 * t[i]); + } - plt::xkcd(); - plt::plot(t, x); - plt::title("AN ORDINARY SIN WAVE"); - plt::show(); + plt::xkcd(); + plt::plot(t, x); + plt::title("AN ORDINARY SIN WAVE"); + plt::show(); } - diff --git a/format.sh b/format.sh new file mode 100755 index 00000000..5bf18336 --- /dev/null +++ b/format.sh @@ -0,0 +1,3 @@ +#!/bin/bash +find -regex '.*[c,h]pp' | xargs clang-format --style=file:.clang-format -i --verbose +find -regex '.*cu' | xargs clang-format --style=file:.clang-format -i --verbose \ No newline at end of file diff --git a/matplotlibcpp.h b/matplotlibcpp.h index 28156584..8d9392c3 100644 --- a/matplotlibcpp.h +++ b/matplotlibcpp.h @@ -67,6 +67,7 @@ struct _interpreter { PyObject *s_python_function_scatter; PyObject *s_python_function_boxplot; PyObject *s_python_function_subplot; + PyObject *s_python_function_subplots; PyObject *s_python_function_subplot2grid; PyObject *s_python_function_legend; PyObject *s_python_function_xlim; @@ -268,6 +269,7 @@ struct _interpreter { s_python_function_scatter = safe_import(pymod,"scatter"); s_python_function_boxplot = safe_import(pymod,"boxplot"); s_python_function_subplot = safe_import(pymod, "subplot"); + s_python_function_subplots = safe_import(pymod, "subplots"); s_python_function_subplot2grid = safe_import(pymod, "subplot2grid"); s_python_function_legend = safe_import(pymod, "legend"); s_python_function_xlim = safe_import(pymod, "xlim"); @@ -2314,7 +2316,54 @@ inline void tick_params(const std::map& keywords, cons Py_DECREF(res); } +inline std::pair subplots(long nrows=1, long ncols=1, bool sharex=false) +{ + // Ensure the Python interpreter is loaded + matplotlibcpp::detail::_interpreter::get(); + + // Prepare arguments + PyObject* args = PyTuple_New(0); + PyObject* kwargs = PyDict_New(); + + // Set "nrows" and "ncols" + PyDict_SetItemString(kwargs, "nrows", PyLong_FromLong(nrows)); + PyDict_SetItemString(kwargs, "ncols", PyLong_FromLong(ncols)); + + // If we want sharex, pass True + if (sharex) { + PyDict_SetItemString(kwargs, "sharex", Py_True); + } + + // Call Python’s subplots(nrows=..., ncols=..., sharex=...). Returns (fig, axes). + PyObject* res = PyObject_Call(matplotlibcpp::detail::_interpreter::get().s_python_function_subplots, + args, kwargs); + if (!res) { + Py_DECREF(args); + Py_DECREF(kwargs); + throw std::runtime_error("Call to subplots() failed."); + } + // Clean up + Py_DECREF(args); + Py_DECREF(kwargs); + + // Make sure we got a (fig, axes) tuple + if (!PyTuple_Check(res) || PyTuple_Size(res) != 2) { + Py_DECREF(res); + throw std::runtime_error("Expected subplots() to return (fig, axes)."); + } + + // Extract the figure and axes, increment reference counts + PyObject* fig = PyTuple_GetItem(res, 0); + PyObject* axes = PyTuple_GetItem(res, 1); + Py_INCREF(fig); + Py_INCREF(axes); + + // We no longer need `res`, so decrement its reference + Py_DECREF(res); + + return {fig, axes}; +} inline void subplot(long nrows, long ncols, long plot_number) { detail::_interpreter::get();