Note
Go to the end 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
![marker picking](../../_images/sphx_glr_marker_picking_001.png)
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.913 seconds)