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
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.938 seconds)