File: marker_picking.py

package info (click to toggle)
python-vispy 0.15.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,868 kB
  • sloc: python: 59,799; javascript: 6,800; makefile: 69; sh: 6
file content (155 lines) | stat: -rw-r--r-- 4,341 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# -*- coding: utf-8 -*-
# vispy: gallery 30
# -----------------------------------------------------------------------------
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------
"""
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()