Skip to content

Viewer Events

Panopti exposes several event callbacks through Python decorators, which are accessible through viewer.events, the usage pattern looks like:

import panopti
viewer = panopti.connect(server_url="http://localhost:8080", viewer_id='client')

@viewer.events.camera(throttle=100)
def my_camera_event(viewer, camera_info):
    # this function is triggered when the viewer camera is manipulated
    # it can be triggered at most once every 100 milliseconds (see throttle argument)
    ...
These callbacks give user code access to various events in the default viewer -- not to be mistaken with the callbacks for user-defined controls (see Controls).

Throttling event callbacks

Many of the event decorators accept an optional throttle: int argument, which limits the frequency at which the callback can be triggered. This is extremely useful when a callback is compute heavy, or if large updates are being propagated from the callback (e.g. updating a mesh's vertex array). This argument accepts an integer time in milliseconds.

Note that many events have an innate throttle defined in Panopti's configuration file (see Customization). Any throttle specified in event decorators acts in tandem with those in the configuration file.


Available event decorators:

Camera - @viewer.events.camera()
Camera Event

The camera event is triggered when the user manipulates the viewer camera (e.g. orbit, pan, zoom). This event provides a CameraInfo object containing information about the camera's current state.

Parameters:

Name Type Description Default
throttle int

Throttle interval in milliseconds. If provided, the callback will only be called at most once per throttle interval.

None

Example usage:

@viewer.events.camera()
def camera_event(viewer, camera_info):
    print('Camera was updated!')
    # swivel scene mesh to always face the camera (in Y-axis):
    mesh = viewer.get('myMesh')
    mx, my, mz = mesh.position
    cx, cy, cz = camera_info.position  # dot-access notation
    yaw = math.atan2(cx - mx, cz - mz)
    mesh.rotation = [0, yaw, 0]
    mesh.update(rotation=[0, yaw, 0])

# Or with throttling (100ms interval)
@viewer.events.camera(throttle=100)
def throttled_camera_event(viewer, camera_info):
    print('Throttled camera update!')
camera_info is a CameraInfo object with the following attributes:

attribute meaning type
position camera world coords ndarray
rotation camera XYZ euler rotation ndarray
quaternion camera rotation as quaternion ndarray
up camera up-vector ndarray
target point the camera is looking at ndarray
fov vertical field-of-view (degrees) float
near near-plane distance float
far far-plane distance float
aspect viewport aspect ratio (w / h) float
projection_mode 'perspective' or 'orthographic' str
Inspect - @viewer.events.inspect()
Inspection Event

The inspect event is triggered when the inspection tool is used in the viewer (e.g. when clicking on a mesh to inspect its local vertex indices). Example usage:

@viewer.events.inspect()
def inspect_event(viewer, inspect_info):
    print(f"User clicked on a {inspect_info.object_type} object.")
    if inspect_info.object_type == 'mesh':
        print('Selected face index: ', inspect_info.inspect_result.face_index)
inspect_info is an InspectInfo object with the following attributes:

attribute meaning type
object_name name attribute of selected object str
object_type type of Panopti object selected (e.g., 'mesh', 'points') str
world_coords XYZ world coordinates of the pick point ndarray
screen_coords integer pixel coordinates of the pick point ndarray
inspect_result geometry-specific data at the pick point:

Mesh / AnimatedMesh: MeshInspectResult holding face_index and vertex_indices

PointCloud: PointCloudInspectResult holding point_index
Union[MeshInspectResult, PointCloudInspectResult]
Select Object - @viewer.events.select_object()
Select Object Event

The select_object event is triggered when a geometric structure is selected in the viewer -- either by clicking on the object directly or selecting it in the layers panel. Example usage:

@viewer.events.object_selection()
def object_selection_event(viewer, object_name):
    print(f"User selected {object_name}")
object_name: str is the selected object's name.

Control - @viewer.events.control()
Control Event

The control event is triggered when any control element is interacted with, e.g. when a slider is moved or a checkbox is toggled.

Parameters:

Name Type Description Default
throttle int

Throttle interval in milliseconds. If provided, the callback will only be called at most once per throttle interval.

None

Example usage:

@viewer.events.control()
def control_event(viewer, control_name, value):
    print(f"User updated {control_name} to {value}")

# Or with throttling (50ms interval)
@viewer.events.control(throttle=50)
def throttled_control_event(viewer, control_name, value):
    print(f"Throttled control update: {control_name} = {value}")
control_name: str is the name of the control element

value is the control element's new value

Update Object - @viewer.events.update_object()
Update Object Event

The update_object event is triggered when any geometric object has an attribute updated, e.g. through .update(...) or when the transformation panel is used.

Parameters:

Name Type Description Default
throttle int

Throttle interval in milliseconds. If provided, the callback will only be called at most once per throttle interval.

None

Example usage:

@viewer.events.update_object()
def update_object_event(viewer, object_name, data):
    print(f"Object {object_name} updated with attributes: {data.keys()}")

# Or with throttling (100ms interval)
@viewer.events.update_object(throttle=100)
def throttled_update_event(viewer, object_name, data):
    print(f"Throttled object update: {object_name}")
object_name: str is the updated object's name

data: dict holds the updated attributes of the object, e.g. {'vertices': ...}

Gizmo - @viewer.events.gizmo()
Gizmo Event

The gizmo event is triggered when the gizmo is used to transform an object.

Parameters:

Name Type Description Default
throttle int

Throttle interval in milliseconds. If provided, the callback will only be called at most once per throttle interval.

None

Example usage:

@viewer.events.gizmo()
def gizmo_event(viewer, gizmo_info):
    print(f"Gizmo was used to transform {gizmo_info.object_name}")

# Or with throttling (50ms interval)
@viewer.events.gizmo(throttle=50)
def throttled_gizmo_event(viewer, gizmo_info):
    print(f"Throttled gizmo transform: {gizmo_info.object_name}")
gizmo_info is a GizmoInfo object with the following attributes:

Attribute Type Description
object_name str Name of the transformed object
object_type str Type of Panopti object being transformed (e.g. 'mesh', 'points')
trans TransformData New transformation values with position, rotation, scale
prev_trans TransformData Previous transformation values when the drag event started