Visual Data Update¶
This example replaces all arrays on one point 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/update_visual_data (build and run), or rerun ./build/examples/c/features/update_visual_data |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.update_visual_data |
| Browser | Live WebGPU route | Open live example |
This example is approved as a starting point for user code and coding agents. Keep the object lifetimes and data shapes intact while adapting the data and styling.
What To Look For¶
The initial upload draws seven small gray points in a line. After one second, the example replaces the full position, color, and diameter_px arrays with a colored arc of larger points. This shows the simple full-data update path, which is useful when the whole dataset changes but the same visual, panel attachment, and style should remain in place.
Source¶
#!/usr/bin/env python3
"""Replace all point arrays on an existing visual."""
from __future__ import annotations
import numpy as np
import datoviz as dvz
from examples.python.gallery import common as ex
POINT_COUNT = 7
def _point_arrays(updated: bool):
initial_positions = np.array(
[
[-0.72, -0.32, 0.0],
[-0.48, -0.32, 0.0],
[-0.24, -0.32, 0.0],
[+0.00, -0.32, 0.0],
[+0.24, -0.32, 0.0],
[+0.48, -0.32, 0.0],
[+0.72, -0.32, 0.0],
],
dtype=np.float32,
)
updated_positions = np.array(
[
[-0.72, +0.18, 0.0],
[-0.48, -0.02, 0.0],
[-0.24, +0.30, 0.0],
[+0.00, +0.04, 0.0],
[+0.24, +0.30, 0.0],
[+0.48, -0.02, 0.0],
[+0.72, +0.18, 0.0],
],
dtype=np.float32,
)
initial_colors = ex.color_array(*(ex.TEXT for _ in range(POINT_COUNT)))
updated_colors = ex.color_array(ex.CYAN, ex.GREEN, ex.YELLOW, ex.TEXT, ex.YELLOW, ex.GREEN, ex.CYAN)
initial_diameters = np.full(POINT_COUNT, 18.0, dtype=np.float32)
updated_diameters = np.array([26.0, 34.0, 44.0, 58.0, 44.0, 34.0, 26.0], dtype=np.float32)
if updated:
return updated_positions, updated_colors, updated_diameters
return initial_positions, initial_colors, initial_diameters
def _upload(point, updated: bool) -> None:
positions, colors, diameters = _point_arrays(updated)
if dvz.dvz_visual_set_data_many(
point,
{
"position": positions,
"color": colors,
"diameter_px": diameters,
},
) != 0:
raise RuntimeError("dvz_visual_set_data_many() failed")
def main() -> None:
scene, figure, panel = ex.scene_panel()
point = dvz.dvz_point(scene, 0)
if not point:
raise RuntimeError("dvz_point() failed")
_upload(point, False)
ex.set_filled_point_style(point)
dvz.dvz_visual_set_depth_test(point, False)
ex.add_visual(panel, point)
state = {"updated": False}
def on_frame(_view, _frame_index: int, elapsed: float) -> None:
if not state["updated"] and elapsed >= 1.0:
_upload(point, True)
state["updated"] = True
ex.run_with_frame_callback(scene, figure, "Visual Data Update", on_frame)
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
*/
/* This example replaces all arrays on one retained point visual.
*
* What to look for: the initial upload draws seven small gray points in a line. After one second,
* the example replaces the full position, color, and diameter_px arrays with a colored arc of
* larger points. This shows the simple full-data update path, which is useful when the whole
* dataset changes but the same visual, panel attachment, and style should remain in place.
*
* Scenario: features_update_visual_data
* Style: features, graphite_cyan, 1280x720 window target
*
* Build: just example-c features/update_visual_data
* Run: ./build/examples/c/features/update_visual_data --live
* Smoke: ./build/examples/c/features/update_visual_data --png
* Video: ./build/examples/c/features/update_visual_data --offscreen-record 120
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "_alloc.h"
#include "datoviz/scene.h"
#include "example_style.h"
#include "runner/scenario_runner.h"
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define POINT_COUNT 7u
/*************************************************************************************************/
/* Structs */
/*************************************************************************************************/
typedef struct UpdateVisualDataState
{
DvzVisual* point;
bool updated;
} UpdateVisualDataState;
/*************************************************************************************************/
/* Forward declarations */
/*************************************************************************************************/
DvzScenarioSpec dvz_example_update_visual_data_scenario(void);
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Upload either the initial or replacement point arrays to one retained point visual.
*
* @param visual point visual
* @param updated whether to upload the replacement data
* @return true when the upload succeeds
*/
static bool _upload_points(DvzVisual* visual, bool updated)
{
if (visual == NULL)
return false;
const vec3 initial_positions[POINT_COUNT] = {
{-0.72f, -0.40f, 0.0f}, {-0.48f, -0.40f, 0.0f}, {-0.24f, -0.40f, 0.0f},
{+0.00f, -0.40f, 0.0f}, {+0.24f, -0.40f, 0.0f}, {+0.48f, -0.40f, 0.0f},
{+0.72f, -0.40f, 0.0f},
};
const vec3 updated_positions[POINT_COUNT] = {
{-0.72f, +0.24f, 0.0f}, {-0.48f, +0.02f, 0.0f}, {-0.24f, +0.42f, 0.0f},
{+0.00f, +0.10f, 0.0f}, {+0.24f, +0.42f, 0.0f}, {+0.48f, +0.02f, 0.0f},
{+0.72f, +0.24f, 0.0f},
};
DvzColor initial_colors[POINT_COUNT] = {
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
};
DvzColor updated_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),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
};
const float initial_diameters[POINT_COUNT] = {26.0f, 26.0f, 26.0f, 26.0f, 26.0f, 26.0f, 26.0f};
const float updated_diameters[POINT_COUNT] = {34.0f, 42.0f, 54.0f, 68.0f, 54.0f, 42.0f, 34.0f};
for (uint32_t i = 0; i < POINT_COUNT; i++)
initial_colors[i].a = 210u;
DvzVisualDataUpdate updates[] = {
{
.attr_name = "position",
.data = updated ? updated_positions : initial_positions,
.item_count = POINT_COUNT,
},
{
.attr_name = "color",
.data = updated ? updated_colors : initial_colors,
.item_count = POINT_COUNT,
},
{
.attr_name = "diameter_px",
.data = updated ? updated_diameters : initial_diameters,
.item_count = POINT_COUNT,
},
};
return dvz_visual_set_data_many(visual, updates, 3) == 0;
}
/**
* Apply one idempotent state of the retained full-data update.
*
* @param state scenario state
* @param updated whether the replacement data should be active
* @return true when the state is already active or the upload succeeds
*/
static bool _set_update_state(UpdateVisualDataState* state, bool updated)
{
if (state == NULL)
return false;
if (state->updated == updated)
return true;
const bool ok = _upload_points(state->point, updated);
if (ok)
state->updated = updated;
return ok;
}
/*************************************************************************************************/
/* Scenario callbacks */
/*************************************************************************************************/
/**
* Initialize the retained visual data update scenario.
*
* @param ctx scenario context
* @param out_user scenario state output
* @return true on success
*/
static bool _scenario_init(DvzScenarioContext* ctx, void** out_user)
{
if (ctx == NULL || out_user == NULL)
return false;
UpdateVisualDataState* state =
(UpdateVisualDataState*)dvz_calloc(1, sizeof(UpdateVisualDataState));
if (state == NULL)
return false;
ctx->figure = dvz_figure(ctx->scene, ctx->width, ctx->height, 0);
if (ctx->figure == NULL)
goto error;
DvzPanel* panel = dvz_panel_full(ctx->figure);
if (panel == NULL)
goto error;
example_graphite_cyan_set_panel_background(panel);
state->point = dvz_point(ctx->scene, 0);
if (state->point == NULL)
goto error;
if (!_upload_points(state->point, false))
goto error;
DvzPointStyleDesc style = dvz_point_style_desc();
style.aspect = DVZ_SHAPE_ASPECT_FILLED;
style.stroke_width_px = 0.0f;
if (dvz_point_set_style(state->point, &style) != 0)
goto error;
if (dvz_visual_set_depth_test(state->point, false) != 0)
goto error;
if (dvz_panel_add_visual(panel, state->point, NULL) != 0)
goto error;
*out_user = state;
return true;
error:
dvz_free(state);
return false;
}
/**
* Replace retained point data once after one second of scenario time.
*
* @param ctx scenario context
* @param user scenario state
*/
static void _scenario_frame(DvzScenarioContext* ctx, void* user)
{
if (ctx == NULL || user == NULL)
return;
UpdateVisualDataState* state = (UpdateVisualDataState*)user;
if (ctx->preview_mode && ctx->preview_segment_id != NULL)
{
(void)_set_update_state(state, strcmp(ctx->preview_segment_id, "after") == 0);
return;
}
const double time = ctx->preview_mode ? dvz_scenario_preview_time(ctx) : ctx->time;
if (time >= 1.0)
(void)_set_update_state(state, true);
}
/**
* Destroy the retained visual data update scenario.
*
* @param ctx scenario context
* @param user scenario state
*/
static void _scenario_destroy(DvzScenarioContext* ctx, void* user)
{
(void)ctx;
dvz_free(user);
}
/**
* Return the retained visual data update scenario specification.
*
* @return scenario specification
*/
DvzScenarioSpec dvz_example_update_visual_data_scenario(void)
{
return (DvzScenarioSpec){
.id = "features_update_visual_data",
.title = "Visual Data Update",
.width = WIDTH,
.height = HEIGHT,
.fps = 60.0,
.init = _scenario_init,
.frame = _scenario_frame,
.destroy = _scenario_destroy,
};
}
/*************************************************************************************************/
/* Functions */
/*************************************************************************************************/
/**
* Run the full retained visual data update feature example through the native scenario runner.
*
* @param argc command-line argument count
* @param argv command-line argument vector
* @return process exit code
*/
#ifndef DVZ_EXAMPLE_NO_MAIN
int main(int argc, char** argv)
{
DvzScenarioSpec spec = dvz_example_update_visual_data_scenario();
return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details
- ID:
features_update_visual_data - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/update_visual_data.c - Approved adaptation starter:
yes - Python source:
examples/python/gallery/features/update_visual_data.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Live in browser
- WebGPU live route:
examples/webgpu/live.html?id=features_update_visual_data - Browser capability tags:
buffer-update,visual-update,point,frame-callbacks - Validation:
smoke+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |
