Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heatmap Demo #81

Closed
nick-0 opened this issue Feb 16, 2023 · 2 comments
Closed

Heatmap Demo #81

nick-0 opened this issue Feb 16, 2023 · 2 comments

Comments

@nick-0
Copy link
Contributor

nick-0 commented Feb 16, 2023

Not sure how to do a PR with the auto-generator, so I thought i would leave this here.

image

Minimal example:

from imgui_bundle import imgui, immapp, implot
import numpy as np


def gui():
    imgui.text("Hello, heatmap!")
    x = np.linspace(-4,4, 401)
    xx = np.outer(x,x)
    yy = np.sinc(xx)
    rows,cols = yy.shape
    n_ticks = 5
    x_ticks = y_ticks =[str(x) for x in np.linspace(-4,4,n_ticks)]

    axis_flags = implot.AxisFlags_.lock | implot.AxisFlags_.no_grid_lines | implot.AxisFlags_.no_tick_marks
    cmap = implot.Colormap_.viridis
    implot.push_colormap(cmap)
    imgui.begin_group()
    if implot.begin_plot("Sinc Function",[imgui.get_content_region_avail().x -70,-1],implot.Flags_.no_legend | implot.Flags_.no_mouse_text):
        implot.setup_axes(None,None, axis_flags, axis_flags)
        implot.setup_axis_ticks(implot.ImAxis_.x1,0,1,n_ticks,x_ticks,False)
        implot.setup_axis_ticks(implot.ImAxis_.y1,0,1,n_ticks,y_ticks,False)
        implot.plot_heatmap("##heatmap", yy, rows, cols, yy.min(), yy.max(), None, [0,1],[1,0],0)
        implot.end_plot()
    imgui.end_group()
    imgui.same_line()
    implot.colormap_scale("##heatmap_scale",yy.min(),yy.max(),imgui.ImVec2(60,-1),"%g", 0,cmap)
    implot.pop_colormap()



immapp.run(
    gui_function=gui,  # The Gui function to run
    window_title="Hello Heatmap",  # the window title
    window_size_auto=True,  # Auto size the application window given its widgets
    # Uncomment the next line to restore window position and size from previous run
    # window_restore_previous_geometry==True
    with_implot=True
)

And the bindings:

m.def("setup_axis_ticks", 
    [](ImAxis axis, double v_min, double v_max, int n_ticks, std::vector<std::string> labels, bool keep_default=false)
    {
        std::vector<const char*> label_char;
        for (std::string const& str : labels){
            label_char.push_back(str.data());
        }
        ImPlot::SetupAxisTicks(axis, v_min, v_max, n_ticks, label_char.data(), keep_default);
    }, py::arg("axis"), py::arg("v_min"), py::arg("v_max"), py::arg("n_ticks"), py::arg("labels"), py::arg("keep_default"),
    "Sets an axis' ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true."
    );

    m.def("plot_heatmap",
        [](const char * label_id, const py::array & values, int rows, int cols, double scale_min = 0, double scale_max=0, const char * label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1), ImPlotHeatmapFlags flags = 0)
        {
            auto PlotHeatmap_adapt_c_buffers = [](const char * label_id, const py::array & values, int rows, int cols, double scale_min = 0, double scale_max=0, const char * label_fmt="%.1f",  const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1),  ImPlotHeatmapFlags flags = 0)
            {
                // convert py::array to C standard buffer (const)
                const void * values_from_pyarray = values.data();

                #ifdef _WIN32
                using np_uint_l = uint32_t;
                using np_int_l = int32_t;
                #else
                using np_uint_l = uint64_t;
                using np_int_l = int64_t;
                #endif
                // call the correct template version by casting
                char values_type = values.dtype().char_();
                if (values_type == 'B')
                    ImPlot::PlotHeatmap(label_id, static_cast<const uint8_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'b')
                    ImPlot::PlotHeatmap(label_id, static_cast<const int8_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'H')
                    ImPlot::PlotHeatmap(label_id, static_cast<const uint16_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'h')
                    ImPlot::PlotHeatmap(label_id, static_cast<const int16_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'I')
                    ImPlot::PlotHeatmap(label_id, static_cast<const uint32_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'i')
                    ImPlot::PlotHeatmap(label_id, static_cast<const int32_t *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'L')
                    ImPlot::PlotHeatmap(label_id, static_cast<const np_uint_l *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'l')
                    ImPlot::PlotHeatmap(label_id, static_cast<const np_int_l *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'f')
                    ImPlot::PlotHeatmap(label_id, static_cast<const float *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'd')
                    ImPlot::PlotHeatmap(label_id, static_cast<const double *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'g')
                    ImPlot::PlotHeatmap(label_id, static_cast<const long double *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                else if (values_type == 'q')
                    ImPlot::PlotHeatmap(label_id, static_cast<const long long *>(values_from_pyarray), rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
                // If we reach this point, the array type is not supported!
                else
                    throw std::runtime_error(std::string("Bad array type ('") + values_type + "') for param values");
            };

            PlotHeatmap_adapt_c_buffers(label_id, values,  rows, cols, scale_min, scale_max, label_fmt, bounds_min, bounds_max, flags);
        },     py::arg("label_id"), py::arg("values"), py::arg("rows"), py::arg("cols"), py::arg("scale_min")= 0 , py::arg("scale_max") = 0, py::arg("label_fmt")="%.1f", py::arg("bounds_min")= (0,0), py::arg("bounds_max")=(1,1),py::arg("flags")=0 );

~Nick

@pthom
Copy link
Owner

pthom commented Feb 16, 2023

Hi,

Many thanks for this!

Those two functions were excluded by the generator because their signature is too convoluted: see where they were excluded in the generator options

So, I had to add these bindings manually, by adapting the code you provided.

See work in progress in this related PR

FYI, I had to do some adaptations, here is a summary:

e2d69aa demo_heatmap python / use dpi independent sizing
0002a33: rows and cols deduced from py array (i.e do not require those in the python bindings)
5be6292: add stubs (i.e. python signatures, to enable IDE autocomplete)

@pthom
Copy link
Owner

pthom commented Feb 17, 2023

Update: I merged the PR. thanks!

@pthom pthom closed this as completed Feb 18, 2023
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

No branches or pull requests

2 participants