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