Raw cimgui GUI¶
This example shows raw cimgui widgets controlling a Datoviz visual.
Preview¶

Run And Adapt¶
Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.
| Route | Availability | Command or action |
|---|---|---|
| C | Canonical native source | just example-c features/gui_cimgui (build and run), or rerun ./build/examples/c/features/gui_cimgui |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.gui_cimgui |
| Browser | Native only | raw cimgui access requires the native ImGui app path |
Use this example as capability or integration evidence, not as a minimal copy-paste template. Start from the nearest supported, copy-safe example and add this feature after verifying the linked API reference.
What To Look For¶
Four point positions and colors are uploaded once, while the GUI slider rewrites the diameter_px attribute for all points. The raw cimgui window also displays a small status table and can open the Dear ImGui demo. Move the diameter slider and compare the live marker sizes with the unchanged positions and colors; this demonstrates how advanced users can mix direct imgui calls with Datoviz data updates.
Source¶
#!/usr/bin/env python3
"""Raw cimgui widgets updating a retained point visual."""
from __future__ import annotations
import ctypes
import numpy as np
import datoviz as dvz
import datoviz._ctypes as raw
from examples.python.gallery import common as ex
POINT_COUNT = 4
IMGUI_TABLE_FLAGS_ROW_BG = 1 << 6
IMGUI_TABLE_FLAGS_BORDERS_INNER = (1 << 7) | (1 << 9)
class ImVec2(ctypes.Structure):
_fields_ = [
("x", ctypes.c_float),
("y", ctypes.c_float),
]
class _RawImGui:
def __init__(self) -> None:
lib = raw.dvz
self.begin = lib.igBegin
self.begin.argtypes = [
ctypes.c_char_p,
ctypes.POINTER(ctypes.c_bool),
ctypes.c_int,
]
self.begin.restype = ctypes.c_bool
self.end = lib.igEnd
self.end.argtypes = []
self.end.restype = None
self.text_unformatted = lib.igTextUnformatted
self.text_unformatted.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
self.text_unformatted.restype = None
self.get_version = lib.igGetVersion
self.get_version.argtypes = []
self.get_version.restype = ctypes.c_char_p
self.begin_table = lib.igBeginTable
self.begin_table.argtypes = [
ctypes.c_char_p,
ctypes.c_int,
ctypes.c_int,
ImVec2,
ctypes.c_float,
]
self.begin_table.restype = ctypes.c_bool
self.end_table = lib.igEndTable
self.end_table.argtypes = []
self.end_table.restype = None
self.table_next_row = lib.igTableNextRow
self.table_next_row.argtypes = [ctypes.c_int, ctypes.c_float]
self.table_next_row.restype = None
self.table_set_column_index = lib.igTableSetColumnIndex
self.table_set_column_index.argtypes = [ctypes.c_int]
self.table_set_column_index.restype = ctypes.c_bool
self.slider_float = lib.igSliderFloat
self.slider_float.argtypes = [
ctypes.c_char_p,
ctypes.POINTER(ctypes.c_float),
ctypes.c_float,
ctypes.c_float,
ctypes.c_char_p,
ctypes.c_int,
]
self.slider_float.restype = ctypes.c_bool
self.checkbox = lib.igCheckbox
self.checkbox.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_bool)]
self.checkbox.restype = ctypes.c_bool
self.show_demo_window = lib.igShowDemoWindow
self.show_demo_window.argtypes = [ctypes.POINTER(ctypes.c_bool)]
self.show_demo_window.restype = None
IMGUI = _RawImGui()
class GuiCimguiState:
def __init__(self, point) -> None:
self.point = point
self.diameter_px = ctypes.c_float(44.0)
self.show_demo = ctypes.c_bool(False)
def _positions() -> np.ndarray:
return np.array(
[
[-0.60, -0.30, 0.0],
[-0.20, +0.30, 0.0],
[+0.20, -0.30, 0.0],
[+0.60, +0.30, 0.0],
],
dtype=np.float32,
)
def _colors() -> np.ndarray:
return ex.color_array(ex.CYAN, ex.GREEN, ex.YELLOW, ex.TEXT)
def _upload(state: GuiCimguiState) -> None:
diameters = np.full(POINT_COUNT, state.diameter_px.value, dtype=np.float32)
if dvz.dvz_visual_set_data(state.point, "diameter_px", diameters) != 0:
raise RuntimeError("dvz_visual_set_data(diameter_px) failed")
def _build_scene():
scene, figure, panel = ex.scene_panel()
point = dvz.dvz_point(scene, 0)
if not point:
raise RuntimeError("dvz_point() failed")
state = GuiCimguiState(point)
if dvz.dvz_visual_set_data_many(
point,
{
"position": _positions(),
"color": _colors(),
},
) != 0:
raise RuntimeError("dvz_visual_set_data_many(point) failed")
_upload(state)
ex.set_filled_point_style(point)
if dvz.dvz_visual_set_depth_test(point, False) != 0:
raise RuntimeError("dvz_visual_set_depth_test() failed")
ex.add_visual(panel, point)
return scene, figure, panel, state
def _table_row(label: bytes, value: bytes) -> None:
IMGUI.table_next_row(0, 0.0)
IMGUI.table_set_column_index(0)
IMGUI.text_unformatted(label, None)
IMGUI.table_set_column_index(1)
IMGUI.text_unformatted(value, None)
def _gui_callback_factory(state: GuiCimguiState):
def gui_callback(_gui, _view, _user_data) -> None:
open_window = ctypes.c_bool(True)
if IMGUI.begin(b"Raw cimgui", ctypes.byref(open_window), 0):
version = IMGUI.get_version() or b"unknown"
IMGUI.text_unformatted(b"Dear ImGui " + version, None)
table_flags = IMGUI_TABLE_FLAGS_ROW_BG | IMGUI_TABLE_FLAGS_BORDERS_INNER
if IMGUI.begin_table(b"status", 2, table_flags, ImVec2(0.0, 0.0), 0.0):
_table_row(b"binding", b"datoviz/imgui.h")
_table_row(b"visual", b"retained point")
IMGUI.end_table()
if IMGUI.slider_float(
b"Diameter", ctypes.byref(state.diameter_px), 8.0, 90.0, b"%.1f", 0
):
_upload(state)
IMGUI.checkbox(b"ImGui demo", ctypes.byref(state.show_demo))
IMGUI.end()
if state.show_demo.value:
IMGUI.show_demo_window(ctypes.byref(state.show_demo))
return gui_callback
def _configure_view(view, state: GuiCimguiState, *, gui: bool = True) -> None:
if not gui:
return
overlay = dvz.dvz_view_gui(view, None)
if not overlay:
return
if dvz.dvz_view_set_gui_callback(view, _gui_callback_factory(state), None) != 0:
raise RuntimeError("dvz_view_set_gui_callback() failed")
def main() -> None:
scene, figure, _panel, state = _build_scene()
def configure(view) -> None:
_configure_view(view, state)
ex.run_with_view(scene, figure, "Raw cimgui GUI", configure)
if __name__ == "__main__":
main()
/*
* Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for details.
* SPDX-License-Identifier: MIT
*/
/* gui_cimgui - This example shows raw cimgui widgets controlling a Datoviz visual.
*
* Scenario: features_gui_cimgui
* Style: features, native GUI/app
*
* Build: just example-c features/gui_cimgui
* Run: ./build/examples/c/features/gui_cimgui
*
* What to look for: four point positions and colors are uploaded once, while the GUI slider
* rewrites the diameter_px attribute for all points. The raw cimgui window also displays a small
* status table and can open the Dear ImGui demo. Move the diameter slider and compare the live
* marker sizes with the unchanged positions and colors; this demonstrates how advanced users can
* mix direct imgui calls with retained Datoviz data updates.
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "datoviz/app.h"
#include "datoviz/gui.h"
#include "datoviz/imgui.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define POINT_COUNT 4u
/*************************************************************************************************/
/* Structs */
/*************************************************************************************************/
typedef struct GuiCimguiState
{
DvzVisual* point;
float diameter_px;
bool show_demo;
} GuiCimguiState;
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Upload a uniform point diameter_px.
*
* @param state cimgui example state
*/
static void _gui_cimgui_upload(GuiCimguiState* state)
{
if (state == NULL || state->point == NULL)
return;
float diameters[POINT_COUNT] = {
state->diameter_px,
state->diameter_px,
state->diameter_px,
state->diameter_px,
};
if (dvz_visual_set_data(state->point, "diameter_px", diameters, POINT_COUNT) != 0)
dvz_fprintf(stderr, "gui_cimgui: failed to upload point diameters\n");
}
/**
* Build the raw cimgui panel.
*
* @param gui Datoviz GUI overlay
* @param view app view
* @param user_data cimgui example state
*/
static void _gui_cimgui_callback(DvzGui* gui, DvzView* view, void* user_data)
{
(void)gui;
(void)view;
GuiCimguiState* state = (GuiCimguiState*)user_data;
if (state == NULL)
return;
bool open = true;
if (igBegin("Raw cimgui", &open, 0))
{
igText("Dear ImGui %s", igGetVersion());
if (igBeginTable(
"status", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInner,
(ImVec2){0.0f, 0.0f}, 0.0f))
{
igTableNextRow(0, 0.0f);
(void)igTableSetColumnIndex(0);
igText("binding");
(void)igTableSetColumnIndex(1);
igText("datoviz/imgui.h");
igTableNextRow(0, 0.0f);
(void)igTableSetColumnIndex(0);
igText("visual");
(void)igTableSetColumnIndex(1);
igText("retained point");
igEndTable();
}
if (igSliderFloat("Diameter", &state->diameter_px, 8.0f, 90.0f, "%.1f", 0))
_gui_cimgui_upload(state);
(void)igCheckbox("ImGui demo", &state->show_demo);
}
igEnd();
if (state->show_demo)
igShowDemoWindow(&state->show_demo);
}
/*************************************************************************************************/
/* Main */
/*************************************************************************************************/
int main(int argc, char** argv)
{
int ret = 1;
DvzScene* scene = NULL;
DvzApp* app = NULL;
scene = dvz_scene();
EXAMPLE_CHECK(scene != NULL, "dvz_scene() failed");
DvzFigure* figure = dvz_figure(scene, WIDTH, HEIGHT, 0);
DvzPanel* panel = figure != NULL ? dvz_panel_full(figure) : NULL;
DvzVisual* point = dvz_point(scene, 0);
EXAMPLE_CHECK(
figure != NULL && panel != NULL && point != NULL, "failed to create scene objects");
example_graphite_cyan_set_panel_background(panel);
GuiCimguiState state = {
.point = point,
.diameter_px = 44.0f,
};
vec3 positions[POINT_COUNT] = {
{-0.60f, -0.30f, 0.0f},
{-0.20f, +0.30f, 0.0f},
{+0.20f, -0.30f, 0.0f},
{+0.60f, +0.30f, 0.0f},
};
DvzColor colors[POINT_COUNT] = {
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
};
DvzVisualDataUpdate updates[] = {
{.attr_name = "position", .data = positions, .item_count = POINT_COUNT},
{.attr_name = "color", .data = colors, .item_count = POINT_COUNT},
};
EXAMPLE_CHECK(dvz_visual_set_data_many(point, updates, 2) == 0, "failed to upload point data");
_gui_cimgui_upload(&state);
EXAMPLE_CHECK(dvz_panel_add_visual(panel, point, NULL) == 0, "dvz_panel_add_visual() failed");
app = dvz_app(scene);
EXAMPLE_CHECK(app != NULL, "dvz_app() failed (no GPU or display?)");
DvzView* view = dvz_view_window(app, figure, WIDTH, HEIGHT, "gui_cimgui");
EXAMPLE_CHECK(view != NULL, "dvz_view_window() failed (GLFW unavailable?)");
DvzGui* gui = dvz_view_gui(view, NULL);
EXAMPLE_CHECK(gui != NULL, "dvz_view_gui() failed");
dvz_view_set_gui_callback(view, _gui_cimgui_callback, &state);
if (example_png_capture_requested(argc, argv))
{
DvzAppCaptureConfig capture = {0};
EXAMPLE_CHECK(
example_png_capture_config("feature_gui_cimgui", &capture),
"failed to configure PNG capture");
EXAMPLE_CHECK(
example_run_with_capture(
app, view, example_frame_count_any_or_default(argc, argv, 4), &capture),
"PNG capture failed");
}
else
{
dvz_app_run(app, example_frame_count(argc, argv));
}
ret = 0;
cleanup:
if (app != NULL)
dvz_app_destroy(app);
if (scene != NULL)
dvz_scene_destroy(scene);
return ret;
}
Example details
- ID:
features_gui_cimgui - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/gui_cimgui.c - Approved adaptation starter:
no - Python source:
examples/python/gallery/features/gui_cimgui.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Native only
- Browser note: raw cimgui access requires the native ImGui app path
- Browser capability tags:
gui - Validation:
smoke+interaction+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |