GUI callbacksΒΆ

Asynchronous usage of GUI elements: we can attach callbacks that are called as soon as we get updates.

  1import time
  2
  3import numpy as np
  4from typing_extensions import assert_never
  5
  6import viser
  7
  8
  9def main() -> None:
 10    server = viser.ViserServer()
 11
 12    gui_reset_scene = server.gui.add_button("Reset Scene")
 13
 14    gui_plane = server.gui.add_dropdown(
 15        "Grid plane", ("xz", "xy", "yx", "yz", "zx", "zy")
 16    )
 17
 18    def update_plane() -> None:
 19        server.scene.add_grid(
 20            "/grid",
 21            width=10.0,
 22            height=20.0,
 23            width_segments=10,
 24            height_segments=20,
 25            plane=gui_plane.value,
 26        )
 27
 28    gui_plane.on_update(lambda _: update_plane())
 29
 30    with server.gui.add_folder("Control"):
 31        gui_show_frame = server.gui.add_checkbox("Show Frame", initial_value=True)
 32        gui_show_everything = server.gui.add_checkbox(
 33            "Show Everything", initial_value=True
 34        )
 35        gui_axis = server.gui.add_dropdown("Axis", ("x", "y", "z"))
 36        gui_include_z = server.gui.add_checkbox("Z in dropdown", initial_value=True)
 37
 38        @gui_include_z.on_update
 39        def _(_) -> None:
 40            gui_axis.options = ("x", "y", "z") if gui_include_z.value else ("x", "y")
 41
 42        with server.gui.add_folder("Sliders"):
 43            gui_location = server.gui.add_slider(
 44                "Location", min=-5.0, max=5.0, step=0.05, initial_value=0.0
 45            )
 46            gui_num_points = server.gui.add_slider(
 47                "# Points", min=1000, max=200_000, step=1000, initial_value=10_000
 48            )
 49
 50    def draw_frame() -> None:
 51        axis = gui_axis.value
 52        if axis == "x":
 53            pos = (gui_location.value, 0.0, 0.0)
 54        elif axis == "y":
 55            pos = (0.0, gui_location.value, 0.0)
 56        elif axis == "z":
 57            pos = (0.0, 0.0, gui_location.value)
 58        else:
 59            assert_never(axis)
 60
 61        server.scene.add_frame(
 62            "/frame",
 63            wxyz=(1.0, 0.0, 0.0, 0.0),
 64            position=pos,
 65            show_axes=gui_show_frame.value,
 66            axes_length=5.0,
 67        )
 68
 69    def draw_points() -> None:
 70        num_points = gui_num_points.value
 71        server.scene.add_point_cloud(
 72            "/frame/point_cloud",
 73            points=np.random.normal(size=(num_points, 3)),
 74            colors=np.random.randint(0, 256, size=(num_points, 3)),
 75        )
 76
 77    # We can (optionally) also attach callbacks!
 78    # Here, we update the point clouds + frames whenever any of the GUI items are updated.
 79    gui_show_frame.on_update(lambda _: draw_frame())
 80    gui_show_everything.on_update(
 81        lambda _: server.scene.set_global_visibility(gui_show_everything.value)
 82    )
 83    gui_axis.on_update(lambda _: draw_frame())
 84    gui_location.on_update(lambda _: draw_frame())
 85    gui_num_points.on_update(lambda _: draw_points())
 86
 87    @gui_reset_scene.on_click
 88    def _(_) -> None:
 89        """Reset the scene when the reset button is clicked."""
 90        gui_show_frame.value = True
 91        gui_location.value = 0.0
 92        gui_axis.value = "x"
 93        gui_num_points.value = 10_000
 94
 95        draw_frame()
 96        draw_points()
 97
 98    # Finally, let's add the initial frame + point cloud and just loop infinitely. :)
 99    update_plane()
100    draw_frame()
101    draw_points()
102    while True:
103        time.sleep(1.0)
104
105
106if __name__ == "__main__":
107    main()