Note

Click here to download the full example code

# Picking Markers

Demonstrates how to identify (pick) markers. Hover markers to change their symbol and color.

Controls: * p - Toggle picking view - shows the colors encoding marker ID * r - Reset marker symbols and colors

    import random
    import time
    import numpy as np
    from scipy.constants import golden as GOLDEN

    from vispy import app, scene
    from vispy.scene.visuals import Markers
    from vispy.visuals.filters import MarkerPickingFilter

    canvas = scene.SceneCanvas(keys='interactive', bgcolor='black')
    view = canvas.central_widget.add_view(camera="panzoom")
    view.camera.rect = (-1, -1, 2, 2)

    # floret pattern
    n = 10_000
    radius = np.linspace(0, 0.9, n)**0.6  # prevent extreme density at center
    theta = np.arange(n) * GOLDEN
    pos = np.column_stack([radius * np.cos(theta), radius * np.sin(theta)])

    COLORS = [
        (1, 0, 0, 1),  # red
        (1, 0.5, 0, 1),  # orange
        (1, 1, 0, 1),  # yellow
        (0, 1, 0, 1),  # green
        (0, 0, 1, 1),  # blue
        (0.29, 0, 0.51, 1),  # indigo
        (0.93, 0.51, 0.93, 1),  # violet
    ]

    colors = np.zeros((n, 4), dtype=np.float32)
    colors[:, 0] = 1  # red
    colors[:, -1] = 1  # alpha
    _colors = colors.copy()

    symbols = list(Markers._symbol_shader_values.keys())
    symbols_ring = dict(zip(symbols, symbols[1:]))
    symbols_ring[symbols[-1]] = symbols[0]

    EDGE_COLOR = "white"
    MARKER_SIZE = 0.0125
    EDGE_WDITH = MARKER_SIZE / 10

    markers = Markers(
        pos=pos,
        edge_color=EDGE_COLOR,
        face_color=colors,
        size=MARKER_SIZE,
        edge_width=EDGE_WDITH,
        scaling="scene",
    )
    markers.update_gl_state(depth_test=True)
    view.add(markers)

    # Use filters to affect the rendering of the mesh.
    picking_filter = MarkerPickingFilter()
    markers.attach(picking_filter)

    @view.events.connect
    def on_viewbox_change(event):
        # workaround for vispy/#2501
        markers.update_gl_state(blend=not picking_filter.enabled)

    throttle = time.monotonic()

    @canvas.events.mouse_move.connect
    def on_mouse_move(event):
        global throttle
        # throttle mouse events to 50ms
        if time.monotonic() - throttle < 0.05:
            return
        throttle = time.monotonic()

        # adjust the event position for hidpi screens
        render_size = tuple(d * canvas.pixel_scale for d in canvas.size)
        x_pos = event.pos[0] * canvas.pixel_scale
        y_pos = render_size[1] - (event.pos[1] * canvas.pixel_scale)

        # render a small patch around the mouse cursor
        restore_state = not picking_filter.enabled
        picking_filter.enabled = True
        markers.update_gl_state(blend=False)
        picking_render = canvas.render(
            crop=(x_pos - 2, y_pos - 2, 5, 5),
            bgcolor=(0, 0, 0, 0),
            alpha=True,
        )
        if restore_state:
            picking_filter.enabled = False
        markers.update_gl_state(blend=not picking_filter.enabled)

        # unpack the face index from the color in the center pixel
        marker_idx = (picking_render.view(np.uint32) - 1)[2, 2, 0]

        if marker_idx >= 0 and marker_idx < len(pos):
            new_symbols = list(markers.symbol)
            new_symbol = symbols_ring[new_symbols[marker_idx]]
            new_symbols[marker_idx] = new_symbol

            colors[marker_idx] = random.choice(COLORS)
            markers.set_data(
                pos=pos,
                edge_color=EDGE_COLOR,
                face_color=colors,
                size=MARKER_SIZE,
                edge_width=EDGE_WDITH,
                symbol=new_symbols,
            )

    @canvas.events.key_press.connect
    def on_key_press(event):
        global colors
        if event.key == 'p':
            # toggle face picking view
            picking_filter.enabled = not picking_filter.enabled
            markers.update_gl_state(blend=not picking_filter.enabled)
            markers.update()
        if event.key == 'r':
            # reset marker symbols
            colors = _colors.copy()
            markers.set_data(
                pos=pos,
                edge_color=EDGE_COLOR,
                face_color=colors,
                size=MARKER_SIZE,
                edge_width=EDGE_WDITH,
            )

    canvas.show()

    if __name__ == "__main__":
        print(__doc__)
        app.run()

Total running time of the script: ( 0 minutes 1.896 seconds)

Gallery generated by Sphinx-Gallery