diff --git a/CMakeLists.txt b/CMakeLists.txt index ed28f45..efbd6a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,10 @@ pybind11_add_module(polyscope_bindings src/cpp/implicit_helpers.cpp src/cpp/managed_buffer.cpp src/cpp/imgui.cpp + src/cpp/implot.cpp + + src/cpp/utils.h + src/cpp/imgui_utils.h ) set_target_properties(polyscope_bindings PROPERTIES CXX_VISIBILITY_PRESET "default") diff --git a/deps/polyscope b/deps/polyscope index d7a2a04..aba5043 160000 --- a/deps/polyscope +++ b/deps/polyscope @@ -1 +1 @@ -Subproject commit d7a2a043759b28bf29e839f9c4276c352a2f1bf7 +Subproject commit aba50436d7d138ab6e1e9b6e498a3ae736366ae8 diff --git a/src/cpp/core.cpp b/src/cpp/core.cpp index a2f656f..0e9dc20 100644 --- a/src/cpp/core.cpp +++ b/src/cpp/core.cpp @@ -39,6 +39,7 @@ void bind_floating_quantities(py::module& m); void bind_implicit_helpers(py::module& m); void bind_managed_buffer(py::module& m); void bind_imgui(py::module& m); +void bind_implot(py::module& m); // Signal handler (makes ctrl-c work, etc) void checkSignals() { @@ -607,6 +608,7 @@ PYBIND11_MODULE(polyscope_bindings, m) { bind_camera_view(m); bind_managed_buffer(m); bind_imgui(m); + bind_implot(m); } diff --git a/src/cpp/imgui.cpp b/src/cpp/imgui.cpp index 2c252e4..5648a77 100644 --- a/src/cpp/imgui.cpp +++ b/src/cpp/imgui.cpp @@ -1,22 +1,29 @@ #include "imgui.h" +#include "implot.h" #include #include #include #include -namespace py = pybind11; +#include "Eigen/Dense" -// Type translations between Python and ImGui. Prefer native Python types (tuples, arrays), translating into ImGui -// equivalents. -using Vec2T = std::tuple; -using Vec4T = std::tuple; +#include "utils.h" +#include "imgui_utils.h" -ImVec2 to_vec2(const Vec2T& v) { return ImVec2(std::get<0>(v), std::get<1>(v)); } -ImVec4 to_vec4(const Vec4T& v) { return ImVec4(std::get<0>(v), std::get<1>(v), std::get<2>(v), std::get<3>(v)); } -Vec2T from_vec2(const ImVec2& v) { return std::make_tuple(v.x, v.y); } -Vec4T from_vec4(const ImVec4& v) { return std::make_tuple(v.x, v.y, v.z, v.w); } +void bind_imgui_structs(py::module& m); +void bind_imgui_methods(py::module& m); +void bind_imgui_enums(py::module& m); + +void bind_imgui(py::module& m) { + auto imgui_module = m.def_submodule("imgui", "ImGui bindings"); + bind_imgui_structs(imgui_module); + bind_imgui_methods(imgui_module); + bind_imgui_enums(imgui_module); +} + +// clang-format off struct InputTextCallback_UserData { std::string* str; @@ -24,15 +31,6 @@ struct InputTextCallback_UserData { void* chain_callback_user_data; }; -std::vector convert_string_items(const std::vector& items) { - auto _items = std::vector(); - _items.reserve(items.size()); - for (const auto& item : items) { - _items.push_back(item.data()); - } - return _items; -} - static int input_text_callback(ImGuiInputTextCallbackData* data) { auto* user_data = reinterpret_cast(data->UserData); if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { @@ -52,20 +50,6 @@ static int input_text_callback(ImGuiInputTextCallbackData* data) { } -void bind_imgui_structs(py::module& m); -void bind_imgui_methods(py::module& m); -void bind_imgui_enums(py::module& m); - -void bind_imgui(py::module& m) { - auto imgui_module = m.def_submodule("imgui", "ImGui bindings"); - bind_imgui_structs(imgui_module); - bind_imgui_methods(imgui_module); - bind_imgui_enums(imgui_module); -} - -// clang-format off - - // clang-format off void bind_imgui_structs(py::module& m) { @@ -2322,3 +2306,5 @@ void bind_imgui_enums(py::module& m) { m.attr("ImGuiCond_FirstUseEver") = static_cast(ImGuiCond_FirstUseEver); m.attr("ImGuiCond_Appearing") = static_cast(ImGuiCond_Appearing); } + + diff --git a/src/cpp/imgui_utils.h b/src/cpp/imgui_utils.h new file mode 100644 index 0000000..ed9503a --- /dev/null +++ b/src/cpp/imgui_utils.h @@ -0,0 +1,25 @@ +#pragma once + +namespace py = pybind11; +namespace ps = polyscope; + +// Type translations between Python and ImGui. Prefer native Python types (tuples, arrays), translating into ImGui +// equivalents. +using Vec2T = std::tuple; +using Vec4T = std::tuple; + +inline ImVec2 to_vec2(const Vec2T& v) { return ImVec2(std::get<0>(v), std::get<1>(v)); } +inline ImVec4 to_vec4(const Vec4T& v) { return ImVec4(std::get<0>(v), std::get<1>(v), std::get<2>(v), std::get<3>(v)); } + +inline Vec2T from_vec2(const ImVec2& v) { return std::make_tuple(v.x, v.y); } +inline Vec4T from_vec4(const ImVec4& v) { return std::make_tuple(v.x, v.y, v.z, v.w); } + + +inline std::vector convert_string_items(const std::vector& items) { + auto _items = std::vector(); + _items.reserve(items.size()); + for (const auto& item : items) { + _items.push_back(item.data()); + } + return _items; +} \ No newline at end of file diff --git a/src/cpp/implot.cpp b/src/cpp/implot.cpp new file mode 100644 index 0000000..363f852 --- /dev/null +++ b/src/cpp/implot.cpp @@ -0,0 +1,729 @@ +#include "imgui.h" +#include "implot.h" + +#include +#include +#include +#include + +#include "Eigen/Dense" + +#include "utils.h" +#include "imgui_utils.h" + +namespace py = pybind11; + +void bind_implot_structs(py::module& m); +void bind_implot_methods(py::module& m); +void bind_implot_enums(py::module& m); + +void bind_implot(py::module& m) { + auto implot_module = m.def_submodule("implot", "ImPlot bindings"); + + bind_implot_structs(implot_module); + bind_implot_methods(implot_module); + bind_implot_enums(implot_module); +} + +// clang-format off + +void bind_implot_structs(py::module& m) { + + + +} + +void bind_implot_methods(py::module& m) { + + //----------------------------------------------------------------------------- + // [SECTION] Begin/End Plot + //----------------------------------------------------------------------------- + + m.def( + "BeginPlot", + [](const char* title_id, const Vec2T& size, ImPlotFlags flags) { + return ImPlot::BeginPlot(title_id, to_vec2(size), flags); + }, + py::arg("title_id"), + py::arg("size") = std::make_tuple(-1.f, 0.f), + py::arg("flags") = 0 + ); + + m.def("EndPlot", []() { ImPlot::EndPlot(); }); + + m.def( + "BeginSubplots", + [](const char* title_id, int rows, int cols, const Vec2T& size, ImPlotSubplotFlags flags, std::vector row_ratios, std::vector col_ratios) { + + float* row_ratios_ptr = nullptr; + float* col_ratios_ptr = nullptr; + if(row_ratios.size() > 0) { + if((int)row_ratios.size() != rows) throw std::runtime_error("invalid row_ratios size"); + row_ratios_ptr = row_ratios.data(); + } + if(col_ratios.size() > 0) { + if((int)col_ratios.size() != cols) throw std::runtime_error("invalid col_ratios size"); + col_ratios_ptr = col_ratios.data(); + } + + return ImPlot::BeginSubplots(title_id, rows, cols, to_vec2(size), flags, row_ratios_ptr, col_ratios_ptr); + }, + py::arg("title_id"), + py::arg("rows"), + py::arg("cols"), + py::arg("size") = std::make_tuple(-1.f, 0.f), + py::arg("flags") = 0, + py::arg("row_ratios") = std::vector(), + py::arg("col_ratios") = std::vector() + ); + + m.def("EndSubplots", []() { ImPlot::EndSubplots(); }); + + + //----------------------------------------------------------------------------- + // [SECTION] Setup + //----------------------------------------------------------------------------- + + m.def( + "SetupAxis", + [](ImAxis axis, const char* label, ImPlotAxisFlags flags) { + ImPlot::SetupAxis(axis, label, flags); + }, + py::arg("axis"), + py::arg("label") = "", + py::arg("flags") = 0 + ); + + m.def( + "SetupAxisLimits", + [](ImAxis axis, double v_min, double v_max, ImPlotCond cond) { + ImPlot::SetupAxisLimits(axis, v_min, v_max, cond); + }, + py::arg("axis"), + py::arg("vmin"), + py::arg("vmax"), + py::arg("cond") = (int)ImPlotCond_Once + ); + + m.def( + "SetupAxisFormat", + [](ImAxis axis, const char* fmt) { + ImPlot::SetupAxisFormat(axis, fmt); + }, + py::arg("axis"), + py::arg("fmt") + ); + + m.def( + "SetupAxisTicks", + [](ImAxis axis, const Eigen::VectorXd& values, const std::vector& labels, bool keep_default) { + if(labels.size() > 0 && (labels.size() != values.size())) throw std::runtime_error("input sizes don't match"); + const auto _labels = convert_string_items(labels); + ImPlot::SetupAxisTicks(axis, values.data(), values.size(), labels.size() == 0 ? nullptr : _labels.data(), keep_default); + }, + py::arg("axis"), + py::arg("values"), + py::arg("labels") = std::vector(), + py::arg("keep_default") = false + ); + + m.def( + "SetupAxisTicks", + [](ImAxis axis, double v_min, double v_max, int n_ticks, const std::vector& labels, bool keep_default) { + if(labels.size() > 0 && (labels.size() != n_ticks)) throw std::runtime_error("input sizes don't match"); + const auto _labels = convert_string_items(labels); + ImPlot::SetupAxisTicks(axis, v_min, v_max, n_ticks, labels.size() == 0 ? nullptr : _labels.data(), keep_default); + }, + py::arg("axis"), + py::arg("v_min"), + py::arg("v_max"), + py::arg("n_ticks"), + py::arg("labels") = std::vector(), + py::arg("keep_default") = false + ); + + m.def( + "SetupAxisScale", + [](ImAxis axis, ImPlotScale scale) { + ImPlot::SetupAxisScale(axis, scale); + }, + py::arg("axis"), + py::arg("scale") + ); + + m.def( + "SetupAxisLimitsConstraints", + [](ImAxis axis, double v_min, double v_max) { + ImPlot::SetupAxisLimitsConstraints(axis, v_min, v_max); + }, + py::arg("axis"), + py::arg("v_min"), + py::arg("v_max") + ); + + m.def( + "SetupAxisZoomConstraints", + [](ImAxis axis, double z_min, double z_max) { + ImPlot::SetupAxisZoomConstraints(axis, z_min, z_max); + }, + py::arg("axis"), + py::arg("z_min"), + py::arg("z_max") + ); + + m.def( + "SetupAxes", + [](const char* x_label, const char* y_label, ImPlotAxisFlags x_flags, ImPlotAxisFlags y_flags) { + ImPlot::SetupAxes(x_label, y_label, x_flags, y_flags); + }, + py::arg("x_label"), + py::arg("y_label"), + py::arg("x_flags") = 0, + py::arg("y_flags") = 0 + ); + + m.def( + "SetupAxesLimits", + [](double x_min, double x_max, double y_min, double y_max, ImPlotCond cond) { + ImPlot::SetupAxesLimits(x_min, x_max, y_min, y_max, cond); + }, + py::arg("x_min"), + py::arg("x_max"), + py::arg("y_min"), + py::arg("y_max"), + py::arg("cond") = (int)ImPlotCond_Once + ); + + m.def( + "SetupLegend", + [](ImPlotLocation location, ImPlotLegendFlags flags) { + ImPlot::SetupLegend(location, flags); + }, + py::arg("location"), + py::arg("flags") = 0 + ); + + m.def( + "SetupMouseText", + [](ImPlotLocation location, ImPlotMouseTextFlags flags) { + ImPlot::SetupMouseText(location, flags); + }, + py::arg("location"), + py::arg("flags") = 0 + ); + + + m.def( + "SetupFinish", + []() { + ImPlot::SetupFinish(); + } + ); + + + //----------------------------------------------------------------------------- + // [SECTION] Plot Items + //----------------------------------------------------------------------------- + + // PlotLine + + m.def( + "PlotLine", + [](const char* label_id, const Eigen::VectorXd& values, double xscale, double xstart, ImPlotLineFlags flags) { + ImPlot::PlotLine(label_id, values.data(), values.size(), xscale, xstart, flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("xscale")=1., + py::arg("xstart")=0., + py::arg("flags")=0 + ); + + m.def( + "PlotLine", + [](const char* label_id, const Eigen::VectorXd& xs, const Eigen::VectorXd& ys, ImPlotLineFlags flags) { + if(xs.size() != ys.size()) throw std::runtime_error("invalid input sizes"); + ImPlot::PlotLine(label_id, xs.data(), ys.data(), xs.size(), flags); + }, + py::arg("label_id"), + py::arg("xs"), + py::arg("ys"), + py::arg("flags") = 0 + ); + + // PlotScatter + + m.def( + "PlotScatter", + [](const char* label_id, const Eigen::VectorXd& values, double xscale, double xstart, ImPlotScatterFlags flags) { + ImPlot::PlotScatter(label_id, values.data(), values.size(), xscale, xstart, flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("xscale")=1., + py::arg("xstart")=0., + py::arg("flags")=0 + ); + + m.def( + "PlotScatter", + [](const char* label_id, const Eigen::VectorXd& xs, const Eigen::VectorXd& ys, ImPlotScatterFlags flags) { + if(xs.size() != ys.size()) throw std::runtime_error("invalid input sizes"); + ImPlot::PlotScatter(label_id, xs.data(), ys.data(), xs.size(), flags); + }, + py::arg("label_id"), + py::arg("xs"), + py::arg("ys"), + py::arg("flags") = 0 + ); + + // PlotStairs + + m.def( + "PlotStairs", + [](const char* label_id, const Eigen::VectorXd& values, double xscale, double xstart, ImPlotStairsFlags flags) { + ImPlot::PlotStairs(label_id, values.data(), values.size(), xscale, xstart, flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("xscale")=1., + py::arg("xstart")=0., + py::arg("flags")=0 + ); + + m.def( + "PlotStairs", + [](const char* label_id, const Eigen::VectorXd& xs, const Eigen::VectorXd& ys, ImPlotStairsFlags flags) { + if(xs.size() != ys.size()) throw std::runtime_error("invalid input sizes"); + ImPlot::PlotStairs(label_id, xs.data(), ys.data(), xs.size(), flags); + }, + py::arg("label_id"), + py::arg("xs"), + py::arg("ys"), + py::arg("flags") = 0 + ); + + // PlotShaded TODO + + m.def( + "PlotShaded", + [](const char* label_id, const Eigen::VectorXd& values, double yref, double xscale, double xstart, ImPlotShadedFlags flags) { + ImPlot::PlotShaded(label_id, values.data(), values.size(), yref, xscale, xstart, flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("yref")=0., + py::arg("xscale")=1., + py::arg("xstart")=0., + py::arg("flags")=0 + ); + + m.def( + "PlotShaded", + [](const char* label_id, const Eigen::VectorXd& xs, const Eigen::VectorXd& ys, double yref, ImPlotShadedFlags flags) { + if(xs.size() != ys.size()) throw std::runtime_error("invalid input sizes"); + ImPlot::PlotShaded(label_id, xs.data(), ys.data(), xs.size(), yref, flags); + }, + py::arg("label_id"), + py::arg("xs"), + py::arg("ys"), + py::arg("yref")=0., + py::arg("flags") = 0 + ); + + m.def( + "PlotShaded", + [](const char* label_id, const Eigen::VectorXd& xs, const Eigen::VectorXd& ys1, const Eigen::VectorXd& ys2, ImPlotShadedFlags flags) { + if(xs.size() != ys1.size()) throw std::runtime_error("invalid input sizes"); + if(xs.size() != ys2.size()) throw std::runtime_error("invalid input sizes"); + ImPlot::PlotShaded(label_id, xs.data(), ys1.data(), ys2.data(), xs.size(), flags); + }, + py::arg("label_id"), + py::arg("xs"), + py::arg("ys1"), + py::arg("ys2"), + py::arg("flags") = 0 + ); + + // PlotBars TODO + + // PlotBarGroups TODO + + // PlotErrorBars TODO + + // PlotStems TODO + + // PlotInfLines + + m.def( + "PlotInfLines", + [](const char* label_id, const Eigen::VectorXd& values, ImPlotInfLinesFlags flags) { + ImPlot::PlotInfLines(label_id, values.data(), values.size(), flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("flags")=0 + ); + + // PlotPieChart + m.def( + "PlotPieChart", + [](const std::vector& label_ids, const Eigen::VectorXd& values, double x, double y, double radius, const char* label_fmt, double angle0, ImPlotPieChartFlags flags) { + if(label_ids.size() != values.size()) throw std::runtime_error("input sizes don't match"); + const auto _label_ids = convert_string_items(label_ids); + ImPlot::PlotPieChart(_label_ids.data(), values.data(), values.size(), x, y, radius, label_fmt, angle0, flags); + }, + py::arg("label_ids"), + py::arg("values"), + py::arg("x"), + py::arg("y"), + py::arg("radius"), + py::arg("label_fmt") = "%.1f", + py::arg("angle0") = 90, + py::arg("flags") = 0 + ); + + + // PlotHeatMap TODO + + // PlotHistogram + + m.def( + "PlotHistogram", + [](const char* label_id, const Eigen::VectorXd& values, int bins, double bar_scale, const Vec2T& range, ImPlotHistogramFlags flags) { + ImPlotRange imrange(std::get<0>(range), std::get<1>(range)); + ImPlot::PlotHistogram(label_id, values.data(), values.size(), bins, bar_scale, imrange, flags); + }, + py::arg("label_id"), + py::arg("values"), + py::arg("bins") = (int)ImPlotBin_Sturges, + py::arg("bar_scale") = 1.0, + py::arg("range") = std::make_tuple(0.f, 0.f), + py::arg("flags") = 0 + ); + + // PlotHistogram2D TODO + + // PlotDigital TODO + + // PlotImage TODO + + // PlotText TODO + + // PlotDummy TODO + + + //----------------------------------------------------------------------------- + // [SECTION] Plot Tools + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Plot Utils + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Legend Utils + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Drag and Drop + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Styling + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Colormaps + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // [SECTION] Miscellaneous + //----------------------------------------------------------------------------- +} + +void bind_implot_enums(py::module& m) { + + // ImAxis + m.attr("ImAxis_X1") = static_cast(ImAxis_X1); + m.attr("ImAxis_X2") = static_cast(ImAxis_X2); + m.attr("ImAxis_X3") = static_cast(ImAxis_X3); + m.attr("ImAxis_Y1") = static_cast(ImAxis_Y1); + m.attr("ImAxis_Y2") = static_cast(ImAxis_Y2); + m.attr("ImAxis_Y3") = static_cast(ImAxis_Y3); + m.attr("ImAxis_COUNT") = static_cast(ImAxis_COUNT); + + // ImPlotFlags + m.attr("ImPlotLineFlags_None") = static_cast(ImPlotLineFlags_None); + m.attr("ImPlotFlags_None") = static_cast(ImPlotFlags_None); + m.attr("ImPlotFlags_NoTitle") = static_cast(ImPlotFlags_NoTitle); + m.attr("ImPlotFlags_NoLegend") = static_cast(ImPlotFlags_NoLegend); + m.attr("ImPlotFlags_NoMouseText") = static_cast(ImPlotFlags_NoMouseText); + m.attr("ImPlotFlags_NoInputs") = static_cast(ImPlotFlags_NoInputs); + m.attr("ImPlotFlags_NoMenus") = static_cast(ImPlotFlags_NoMenus); + m.attr("ImPlotFlags_NoBoxSelect") = static_cast(ImPlotFlags_NoBoxSelect); + m.attr("ImPlotFlags_NoFrame") = static_cast(ImPlotFlags_NoFrame); + m.attr("ImPlotFlags_Equal") = static_cast(ImPlotFlags_Equal); + m.attr("ImPlotFlags_Crosshairs") = static_cast(ImPlotFlags_Crosshairs); + m.attr("ImPlotFlags_CanvasOnly") = static_cast(ImPlotFlags_CanvasOnly); + + // ImPlotAxisFlags + m.attr("ImPlotAxisFlags_None") = static_cast(ImPlotAxisFlags_None); + m.attr("ImPlotAxisFlags_NoLabel") = static_cast(ImPlotAxisFlags_NoLabel); + m.attr("ImPlotAxisFlags_NoGridLines") = static_cast(ImPlotAxisFlags_NoGridLines); + m.attr("ImPlotAxisFlags_NoTickMarks") = static_cast(ImPlotAxisFlags_NoTickMarks); + m.attr("ImPlotAxisFlags_NoTickLabels") = static_cast(ImPlotAxisFlags_NoTickLabels); + m.attr("ImPlotAxisFlags_NoInitialFit") = static_cast(ImPlotAxisFlags_NoInitialFit); + m.attr("ImPlotAxisFlags_NoMenus") = static_cast(ImPlotAxisFlags_NoMenus); + m.attr("ImPlotAxisFlags_NoSideSwitch") = static_cast(ImPlotAxisFlags_NoSideSwitch); + m.attr("ImPlotAxisFlags_NoHighlight") = static_cast(ImPlotAxisFlags_NoHighlight); + m.attr("ImPlotAxisFlags_Opposite") = static_cast(ImPlotAxisFlags_Opposite); + m.attr("ImPlotAxisFlags_Foreground") = static_cast(ImPlotAxisFlags_Foreground); + m.attr("ImPlotAxisFlags_Invert") = static_cast(ImPlotAxisFlags_Invert); + m.attr("ImPlotAxisFlags_AutoFit") = static_cast(ImPlotAxisFlags_AutoFit); + m.attr("ImPlotAxisFlags_RangeFit") = static_cast(ImPlotAxisFlags_RangeFit); + m.attr("ImPlotAxisFlags_PanStretch") = static_cast(ImPlotAxisFlags_PanStretch); + m.attr("ImPlotAxisFlags_LockMin") = static_cast(ImPlotAxisFlags_LockMin); + m.attr("ImPlotAxisFlags_LockMax") = static_cast(ImPlotAxisFlags_LockMax); + m.attr("ImPlotAxisFlags_Lock") = static_cast(ImPlotAxisFlags_Lock); + m.attr("ImPlotAxisFlags_NoDecorations") = static_cast(ImPlotAxisFlags_NoDecorations); + m.attr("ImPlotAxisFlags_AuxDefault") = static_cast(ImPlotAxisFlags_AuxDefault); + + // ImPlotSubplotFlags + m.attr("ImPlotSubplotFlags_None") = static_cast(ImPlotSubplotFlags_None); + m.attr("ImPlotSubplotFlags_NoTitle") = static_cast(ImPlotSubplotFlags_NoTitle); + m.attr("ImPlotSubplotFlags_NoLegend") = static_cast(ImPlotSubplotFlags_NoLegend); + m.attr("ImPlotSubplotFlags_NoMenus") = static_cast(ImPlotSubplotFlags_NoMenus); + m.attr("ImPlotSubplotFlags_NoResize") = static_cast(ImPlotSubplotFlags_NoResize); + m.attr("ImPlotSubplotFlags_NoAlign") = static_cast(ImPlotSubplotFlags_NoAlign); + m.attr("ImPlotSubplotFlags_ShareItems") = static_cast(ImPlotSubplotFlags_ShareItems); + m.attr("ImPlotSubplotFlags_LinkRows") = static_cast(ImPlotSubplotFlags_LinkRows); + m.attr("ImPlotSubplotFlags_LinkCols") = static_cast(ImPlotSubplotFlags_LinkCols); + m.attr("ImPlotSubplotFlags_LinkAllX") = static_cast(ImPlotSubplotFlags_LinkAllX); + m.attr("ImPlotSubplotFlags_LinkAllY") = static_cast(ImPlotSubplotFlags_LinkAllY); + m.attr("ImPlotSubplotFlags_ColMajor") = static_cast(ImPlotSubplotFlags_ColMajor); + + // ImPlotLegendFlags + m.attr("ImPlotLegendFlags_None") = static_cast(ImPlotLegendFlags_None); + m.attr("ImPlotLegendFlags_NoButtons") = static_cast(ImPlotLegendFlags_NoButtons); + m.attr("ImPlotLegendFlags_NoHighlightItem") = static_cast(ImPlotLegendFlags_NoHighlightItem); + m.attr("ImPlotLegendFlags_NoHighlightAxis") = static_cast(ImPlotLegendFlags_NoHighlightAxis); + m.attr("ImPlotLegendFlags_NoMenus") = static_cast(ImPlotLegendFlags_NoMenus); + m.attr("ImPlotLegendFlags_Outside") = static_cast(ImPlotLegendFlags_Outside); + m.attr("ImPlotLegendFlags_Horizontal") = static_cast(ImPlotLegendFlags_Horizontal); + m.attr("ImPlotLegendFlags_Sort") = static_cast(ImPlotLegendFlags_Sort); + + // ImPlotMouseTextFlags + m.attr("ImPlotMouseTextFlags_None") = static_cast(ImPlotMouseTextFlags_None); + m.attr("ImPlotMouseTextFlags_NoAuxAxes") = static_cast(ImPlotMouseTextFlags_NoAuxAxes); + m.attr("ImPlotMouseTextFlags_NoFormat") = static_cast(ImPlotMouseTextFlags_NoFormat); + m.attr("ImPlotMouseTextFlags_ShowAlways") = static_cast(ImPlotMouseTextFlags_ShowAlways); + + // ImPlotDragToolFlags + m.attr("ImPlotDragToolFlags_None") = static_cast(ImPlotDragToolFlags_None); + m.attr("ImPlotDragToolFlags_NoCursors") = static_cast(ImPlotDragToolFlags_NoCursors); + m.attr("ImPlotDragToolFlags_NoFit") = static_cast(ImPlotDragToolFlags_NoFit); + m.attr("ImPlotDragToolFlags_NoInputs") = static_cast(ImPlotDragToolFlags_NoInputs); + m.attr("ImPlotDragToolFlags_Delayed") = static_cast(ImPlotDragToolFlags_Delayed); + + // ImPlotColormapScaleFlags + m.attr("ImPlotColormapScaleFlags_None") = static_cast(ImPlotColormapScaleFlags_None); + m.attr("ImPlotColormapScaleFlags_NoLabel") = static_cast(ImPlotColormapScaleFlags_NoLabel); + m.attr("ImPlotColormapScaleFlags_Opposite") = static_cast(ImPlotColormapScaleFlags_Opposite); + m.attr("ImPlotColormapScaleFlags_Invert") = static_cast(ImPlotColormapScaleFlags_Invert); + + // ImPlotItemFlags + m.attr("ImPlotItemFlags_None") = static_cast(ImPlotItemFlags_None); + m.attr("ImPlotItemFlags_NoLegend") = static_cast(ImPlotItemFlags_NoLegend); + m.attr("ImPlotItemFlags_NoFit") = static_cast(ImPlotItemFlags_NoFit); + + // ImPlotLineFlags + m.attr("ImPlotLineFlags_None") = static_cast(ImPlotLineFlags_None); + m.attr("ImPlotLineFlags_Segments") = static_cast(ImPlotLineFlags_Segments); + m.attr("ImPlotLineFlags_Loop") = static_cast(ImPlotLineFlags_Loop); + m.attr("ImPlotLineFlags_SkipNaN") = static_cast(ImPlotLineFlags_SkipNaN); + m.attr("ImPlotLineFlags_NoClip") = static_cast(ImPlotLineFlags_NoClip); + m.attr("ImPlotLineFlags_Shaded") = static_cast(ImPlotLineFlags_Shaded); + + // ImPlotScatterFlags + m.attr("ImPlotScatterFlags_None") = static_cast(ImPlotScatterFlags_None); + m.attr("ImPlotScatterFlags_NoClip") = static_cast(ImPlotScatterFlags_NoClip); + + // ImPlotStairsFlags + m.attr("ImPlotStairsFlags_None") = static_cast(ImPlotStairsFlags_None); + m.attr("ImPlotStairsFlags_PreStep") = static_cast(ImPlotStairsFlags_PreStep); + m.attr("ImPlotStairsFlags_Shaded") = static_cast(ImPlotStairsFlags_Shaded); + + // ImPlotShadedFlags + m.attr("ImPlotShadedFlags_None") = static_cast(ImPlotShadedFlags_None); + + // ImPlotBarsFlags + m.attr("ImPlotBarsFlags_None") = static_cast(ImPlotBarsFlags_None); + m.attr("ImPlotBarsFlags_Horizontal") = static_cast(ImPlotBarsFlags_Horizontal); + + // ImPlotBarGroupsFlags + m.attr("ImPlotBarGroupsFlags_None") = static_cast(ImPlotBarGroupsFlags_None); + m.attr("ImPlotBarGroupsFlags_Horizontal") = static_cast(ImPlotBarGroupsFlags_Horizontal); + m.attr("ImPlotBarGroupsFlags_Stacked") = static_cast(ImPlotBarGroupsFlags_Stacked); + + // ImPlotErrorBarsFlags + m.attr("ImPlotErrorBarsFlags_None") = static_cast(ImPlotErrorBarsFlags_None); + m.attr("ImPlotErrorBarsFlags_Horizontal") = static_cast(ImPlotErrorBarsFlags_Horizontal); + + // ImPlotStemsFlags + m.attr("ImPlotStemsFlags_None") = static_cast(ImPlotStemsFlags_None); + m.attr("ImPlotStemsFlags_Horizontal") = static_cast(ImPlotStemsFlags_Horizontal); + + // ImPlotInfLinesFlags + m.attr("ImPlotInfLinesFlags_None") = static_cast(ImPlotInfLinesFlags_None); + m.attr("ImPlotInfLinesFlags_Horizontal") = static_cast(ImPlotInfLinesFlags_Horizontal); + + // ImPlotPieChartFlags + m.attr("ImPlotPieChartFlags_None") = static_cast(ImPlotPieChartFlags_None); + m.attr("ImPlotPieChartFlags_Normalize") = static_cast(ImPlotPieChartFlags_Normalize); + m.attr("ImPlotPieChartFlags_IgnoreHidden") = static_cast(ImPlotPieChartFlags_IgnoreHidden); + m.attr("ImPlotPieChartFlags_Exploding") = static_cast(ImPlotPieChartFlags_Exploding); + + // ImPlotHeatmapFlags + m.attr("ImPlotHeatmapFlags_None") = static_cast(ImPlotHeatmapFlags_None); + m.attr("ImPlotHeatmapFlags_ColMajor") = static_cast(ImPlotHeatmapFlags_ColMajor); + + // ImPlotHistogramFlags + m.attr("ImPlotHistogramFlags_None") = static_cast(ImPlotHistogramFlags_None); + m.attr("ImPlotHistogramFlags_Horizontal") = static_cast(ImPlotHistogramFlags_Horizontal); + m.attr("ImPlotHistogramFlags_Cumulative") = static_cast(ImPlotHistogramFlags_Cumulative); + m.attr("ImPlotHistogramFlags_Density") = static_cast(ImPlotHistogramFlags_Density); + m.attr("ImPlotHistogramFlags_NoOutliers") = static_cast(ImPlotHistogramFlags_NoOutliers); + m.attr("ImPlotHistogramFlags_ColMajor") = static_cast(ImPlotHistogramFlags_ColMajor); + + // ImPlotDigitalFlags + m.attr("ImPlotDigitalFlags_None") = static_cast(ImPlotDigitalFlags_None); + + // ImPlotImageFlags + m.attr("ImPlotImageFlags_None") = static_cast(ImPlotImageFlags_None); + + // ImPlotTextFlags + m.attr("ImPlotTextFlags_None") = static_cast(ImPlotTextFlags_None); + m.attr("ImPlotTextFlags_Vertical") = static_cast(ImPlotTextFlags_Vertical); + + // ImPlotDummyFlags + m.attr("ImPlotDummyFlags_None") = static_cast(ImPlotDummyFlags_None); + + // ImPlotCond + m.attr("ImPlotCond_None") = static_cast(ImPlotCond_None); + m.attr("ImPlotCond_Always") = static_cast(ImPlotCond_Always); + m.attr("ImPlotCond_Once") = static_cast(ImPlotCond_Once); + + // ImPlotCol + m.attr("ImPlotCol_Line") = static_cast(ImPlotCol_Line); + m.attr("ImPlotCol_Fill") = static_cast(ImPlotCol_Fill); + m.attr("ImPlotCol_MarkerOutline") = static_cast(ImPlotCol_MarkerOutline); + m.attr("ImPlotCol_MarkerFill") = static_cast(ImPlotCol_MarkerFill); + m.attr("ImPlotCol_ErrorBar") = static_cast(ImPlotCol_ErrorBar); + m.attr("ImPlotCol_FrameBg") = static_cast(ImPlotCol_FrameBg); + m.attr("ImPlotCol_PlotBg") = static_cast(ImPlotCol_PlotBg); + m.attr("ImPlotCol_PlotBorder") = static_cast(ImPlotCol_PlotBorder); + m.attr("ImPlotCol_LegendBg") = static_cast(ImPlotCol_LegendBg); + m.attr("ImPlotCol_LegendBorder") = static_cast(ImPlotCol_LegendBorder); + m.attr("ImPlotCol_LegendText") = static_cast(ImPlotCol_LegendText); + m.attr("ImPlotCol_TitleText") = static_cast(ImPlotCol_TitleText); + m.attr("ImPlotCol_InlayText") = static_cast(ImPlotCol_InlayText); + m.attr("ImPlotCol_AxisText") = static_cast(ImPlotCol_AxisText); + m.attr("ImPlotCol_AxisGrid") = static_cast(ImPlotCol_AxisGrid); + m.attr("ImPlotCol_AxisTick") = static_cast(ImPlotCol_AxisTick); + m.attr("ImPlotCol_AxisBg") = static_cast(ImPlotCol_AxisBg); + m.attr("ImPlotCol_AxisBgHovered") = static_cast(ImPlotCol_AxisBgHovered); + m.attr("ImPlotCol_AxisBgActive") = static_cast(ImPlotCol_AxisBgActive); + m.attr("ImPlotCol_Selection") = static_cast(ImPlotCol_Selection); + m.attr("ImPlotCol_Crosshairs") = static_cast(ImPlotCol_Crosshairs); + m.attr("ImPlotCol_COUNT") = static_cast(ImPlotCol_COUNT); + + // ImPlotStyleVar + m.attr("ImPlotStyleVar_LineWeight") = static_cast(ImPlotStyleVar_LineWeight); + m.attr("ImPlotStyleVar_Marker") = static_cast(ImPlotStyleVar_Marker); + m.attr("ImPlotStyleVar_MarkerSize") = static_cast(ImPlotStyleVar_MarkerSize); + m.attr("ImPlotStyleVar_MarkerWeight") = static_cast(ImPlotStyleVar_MarkerWeight); + m.attr("ImPlotStyleVar_FillAlpha") = static_cast(ImPlotStyleVar_FillAlpha); + m.attr("ImPlotStyleVar_ErrorBarSize") = static_cast(ImPlotStyleVar_ErrorBarSize); + m.attr("ImPlotStyleVar_ErrorBarWeight") = static_cast(ImPlotStyleVar_ErrorBarWeight); + m.attr("ImPlotStyleVar_DigitalBitHeight") = static_cast(ImPlotStyleVar_DigitalBitHeight); + m.attr("ImPlotStyleVar_DigitalBitGap") = static_cast(ImPlotStyleVar_DigitalBitGap); + m.attr("ImPlotStyleVar_PlotBorderSize") = static_cast(ImPlotStyleVar_PlotBorderSize); + m.attr("ImPlotStyleVar_MinorAlpha") = static_cast(ImPlotStyleVar_MinorAlpha); + m.attr("ImPlotStyleVar_MajorTickLen") = static_cast(ImPlotStyleVar_MajorTickLen); + m.attr("ImPlotStyleVar_MinorTickLen") = static_cast(ImPlotStyleVar_MinorTickLen); + m.attr("ImPlotStyleVar_MajorTickSize") = static_cast(ImPlotStyleVar_MajorTickSize); + m.attr("ImPlotStyleVar_MinorTickSize") = static_cast(ImPlotStyleVar_MinorTickSize); + m.attr("ImPlotStyleVar_MajorGridSize") = static_cast(ImPlotStyleVar_MajorGridSize); + m.attr("ImPlotStyleVar_MinorGridSize") = static_cast(ImPlotStyleVar_MinorGridSize); + m.attr("ImPlotStyleVar_PlotPadding") = static_cast(ImPlotStyleVar_PlotPadding); + m.attr("ImPlotStyleVar_LabelPadding") = static_cast(ImPlotStyleVar_LabelPadding); + m.attr("ImPlotStyleVar_LegendPadding") = static_cast(ImPlotStyleVar_LegendPadding); + m.attr("ImPlotStyleVar_LegendInnerPadding") = static_cast(ImPlotStyleVar_LegendInnerPadding); + m.attr("ImPlotStyleVar_LegendSpacing") = static_cast(ImPlotStyleVar_LegendSpacing); + m.attr("ImPlotStyleVar_MousePosPadding") = static_cast(ImPlotStyleVar_MousePosPadding); + m.attr("ImPlotStyleVar_AnnotationPadding") = static_cast(ImPlotStyleVar_AnnotationPadding); + m.attr("ImPlotStyleVar_FitPadding") = static_cast(ImPlotStyleVar_FitPadding); + m.attr("ImPlotStyleVar_PlotDefaultSize") = static_cast(ImPlotStyleVar_PlotDefaultSize); + m.attr("ImPlotStyleVar_PlotMinSize") = static_cast(ImPlotStyleVar_PlotMinSize); + m.attr("ImPlotStyleVar_COUNT") = static_cast(ImPlotStyleVar_COUNT); + + // ImPlotScale + m.attr("ImPlotScale_Linear") = static_cast(ImPlotScale_Linear); + m.attr("ImPlotScale_Time") = static_cast(ImPlotScale_Time); + m.attr("ImPlotScale_Log10") = static_cast(ImPlotScale_Log10); + m.attr("ImPlotScale_SymLog") = static_cast(ImPlotScale_SymLog); + + // ImPlotMarker + m.attr("ImPlotMarker_None") = static_cast(ImPlotMarker_None); + m.attr("ImPlotMarker_Circle") = static_cast(ImPlotMarker_Circle); + m.attr("ImPlotMarker_Square") = static_cast(ImPlotMarker_Square); + m.attr("ImPlotMarker_Diamond") = static_cast(ImPlotMarker_Diamond); + m.attr("ImPlotMarker_Up") = static_cast(ImPlotMarker_Up); + m.attr("ImPlotMarker_Down") = static_cast(ImPlotMarker_Down); + m.attr("ImPlotMarker_Left") = static_cast(ImPlotMarker_Left); + m.attr("ImPlotMarker_Right") = static_cast(ImPlotMarker_Right); + m.attr("ImPlotMarker_Cross") = static_cast(ImPlotMarker_Cross); + m.attr("ImPlotMarker_Plus") = static_cast(ImPlotMarker_Plus); + m.attr("ImPlotMarker_Asterisk") = static_cast(ImPlotMarker_Asterisk); + m.attr("ImPlotMarker_COUNT") = static_cast(ImPlotMarker_COUNT); + + + // ImPlotColormap + m.attr("ImPlotColormap_Deep") = static_cast(ImPlotColormap_Deep); + m.attr("ImPlotColormap_Dark") = static_cast(ImPlotColormap_Dark); + m.attr("ImPlotColormap_Pastel") = static_cast(ImPlotColormap_Pastel); + m.attr("ImPlotColormap_Paired") = static_cast(ImPlotColormap_Paired); + m.attr("ImPlotColormap_Viridis") = static_cast(ImPlotColormap_Viridis); + m.attr("ImPlotColormap_Plasma") = static_cast(ImPlotColormap_Plasma); + m.attr("ImPlotColormap_Hot") = static_cast(ImPlotColormap_Hot); + m.attr("ImPlotColormap_Cool") = static_cast(ImPlotColormap_Cool); + m.attr("ImPlotColormap_Pink") = static_cast(ImPlotColormap_Pink); + m.attr("ImPlotColormap_Jet") = static_cast(ImPlotColormap_Jet); + m.attr("ImPlotColormap_Twilight") = static_cast(ImPlotColormap_Twilight); + m.attr("ImPlotColormap_RdBu") = static_cast(ImPlotColormap_RdBu); + m.attr("ImPlotColormap_BrBG") = static_cast(ImPlotColormap_BrBG); + m.attr("ImPlotColormap_PiYG") = static_cast(ImPlotColormap_PiYG); + m.attr("ImPlotColormap_Spectral") = static_cast(ImPlotColormap_Spectral); + m.attr("ImPlotColormap_Greys") = static_cast(ImPlotColormap_Greys); + + // ImPlotLocation + m.attr("ImPlotLocation_Center") = static_cast(ImPlotLocation_Center); + m.attr("ImPlotLocation_North") = static_cast(ImPlotLocation_North); + m.attr("ImPlotLocation_South") = static_cast(ImPlotLocation_South); + m.attr("ImPlotLocation_West") = static_cast(ImPlotLocation_West); + m.attr("ImPlotLocation_East") = static_cast(ImPlotLocation_East); + m.attr("ImPlotLocation_NorthWest") = static_cast(ImPlotLocation_NorthWest); + m.attr("ImPlotLocation_NorthEast") = static_cast(ImPlotLocation_NorthEast); + m.attr("ImPlotLocation_SouthWest") = static_cast(ImPlotLocation_SouthWest); + m.attr("ImPlotLocation_SouthEast") = static_cast(ImPlotLocation_SouthEast); + + // ImPlotBin + m.attr("ImPlotBin_Sqrt") = static_cast(ImPlotBin_Sqrt); + m.attr("ImPlotBin_Sturges") = static_cast(ImPlotBin_Sturges); + m.attr("ImPlotBin_Rice") = static_cast(ImPlotBin_Rice); + m.attr("ImPlotBin_Scott") = static_cast(ImPlotBin_Scott); + +} + +// clang-format on diff --git a/src/polyscope/implot/__init__.py b/src/polyscope/implot/__init__.py new file mode 100644 index 0000000..4c5c2f3 --- /dev/null +++ b/src/polyscope/implot/__init__.py @@ -0,0 +1 @@ +from polyscope_bindings.implot import * diff --git a/test/polyscope_test.py b/test/polyscope_test.py index c32e5bd..d09bbe2 100644 --- a/test/polyscope_test.py +++ b/test/polyscope_test.py @@ -18,6 +18,7 @@ import polyscope as ps import polyscope.imgui as psim +import polyscope.implot as psimplot # Path to test assets assets_prefix = path.join(path.dirname(__file__), "assets/") @@ -542,7 +543,89 @@ def imgui_callback(): ps.show(3) ps.clear_user_callback() + + def test_implot(self): + + # smoke tests for implot + def imgui_callback(): + + # PlotLine + psim.SetCursorPos((0,0)) # these calls ensure it's not clipped out and disabled + if psimplot.BeginPlot("test line plot"): + psimplot.PlotLine("line plot1", np.random.rand(10)) + psimplot.PlotLine("line plot2", np.random.rand(10), np.random.rand(10)) + psimplot.PlotLine("line plot3", np.random.rand(10), psimplot.ImPlotLineFlags_Shaded + psimplot.ImPlotLineFlags_Loop) + + # test inf lines while we're at it + psimplot.PlotInfLines("inf line v", np.random.rand(3)) + psimplot.PlotInfLines("inf line h", np.random.rand(3), psimplot.ImPlotInfLinesFlags_Horizontal) + + psimplot.EndPlot() + + # PlotScatter + psim.SetCursorPos((0,0)) + if psimplot.BeginPlot("test scatter plot"): + psimplot.PlotScatter("scatter plot1", np.random.rand(10)) + psimplot.PlotScatter("scatter plot2", np.random.rand(10), np.random.rand(10)) + psimplot.PlotScatter("scatter plot3", np.random.rand(10), psimplot.ImPlotScatterFlags_NoClip) + psimplot.EndPlot() + + # PlotStairs + psim.SetCursorPos((0,0)) + if psimplot.BeginPlot("test stairs plot"): + psimplot.PlotStairs("stairs plot1", np.random.rand(10)) + psimplot.PlotStairs("stairs plot2", np.random.rand(10), np.random.rand(10)) + psimplot.PlotStairs("stairs plot3", np.random.rand(10), psimplot.ImPlotStairsFlags_Shaded) + psimplot.EndPlot() + + # PlotShaded + psim.SetCursorPos((0,0)) + if psimplot.BeginPlot("test shaded plot"): + psimplot.PlotShaded("shaded plot1", np.random.rand(10)) + psimplot.PlotShaded("shaded plot1", np.random.rand(10), yref=1.0) + psimplot.PlotShaded("shaded plot2", np.random.rand(10), np.random.rand(10), psimplot.ImPlotShadedFlags_None) + psimplot.PlotShaded("shaded plot3", np.random.rand(10), np.random.rand(10), np.random.rand(10)) + psimplot.EndPlot() + + # PlotBars TODO + + # PlotBarGroups TODO + + # PlotErrorBars TODO + + # PlotStems TODO + # PlotPieChart + psim.SetCursorPos((0,0)) + if psimplot.BeginPlot("test pie chart plot"): + psimplot.PlotPieChart(["cat1", "cat2"], np.random.rand(2,1)) + psimplot.PlotPieChart(["cat1", "cat2"], np.random.rand(2), x=2., y=3., radius=4.) + psimplot.PlotPieChart(["cat1", "cat2"], np.random.rand(2), 2., 3., 4., flags=psimplot.ImPlotPieChartFlags_Exploding) + psimplot.EndPlot() + + # PlotHeatMap TODO + + # PlotHistorgram + psim.SetCursorPos((0,0)) + if psimplot.BeginPlot("test historgram plot"): + psimplot.PlotHistogram("hist", np.random.rand(10)) + psimplot.PlotHistogram("hist2", np.random.rand(10), 3, range=(-2., 2.), flags=psimplot.ImPlotHistogramFlags_NoOutliers) + psimplot.EndPlot() + + # Subplots + psim.SetCursorPos((0,0)) + if psimplot.BeginSubplots("test subplot", 2, 3, (800,400)): + for i in range(6): + if psimplot.BeginPlot(f"test subplot_{i}"): + psimplot.PlotLine("line plot", np.random.rand(10)) + + psimplot.EndPlot() + + psimplot.EndSubplots() + + ps.set_user_callback(imgui_callback) + ps.show(3) + ps.clear_user_callback() class TestStructureManagement(unittest.TestCase):