Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Cursor tool #662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions examples/selection_tools/image_grid_cursor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Grid of images with a cursor
============================

Example showing a grid of images in a single subplot and an interactive cursor
that marks the same position in each image
"""

# test_example = false
# sphinx_gallery_pygfx_docs = 'screenshot'

import fastplotlib as fpl
import numpy as np


figure = fpl.Figure(size=(700, 560))

# make 12 images
images = np.random.rand(12, 100, 100)

# we will display 3 rows and 4 columns
rows = 3
columns = 4

# spacing between each image
spacing = 25

# interactive cursor
cursor = fpl.Cursor(size=15, color="magenta")

index = 0
for i in range(rows):
for j in range(columns):
img = images[index]
# offset is x, y, z position
offset = (j * img.shape[1] + spacing * j, i * img.shape[0] + spacing * i, 0)
img_graphic = figure[0, 0].add_image(img, cmap="viridis", offset=offset)
cursor.add(img_graphic)

text_label = figure[0, 0].add_text(
str(index),
face_color="r",
font_size=25,
outline_color="w",
outline_thickness=0.05,
anchor="bottom-right",
offset=offset
)

index += 1

figure.show()


# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively
# please see our docs for using fastplotlib interactively in ipython and jupyter
if __name__ == "__main__":
print(__doc__)
fpl.run()
16 changes: 8 additions & 8 deletions fastplotlib/graphics/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def __init__(
# store hex id str of Graphic instance mem location
self._fpl_address: HexStr = hex(id(self))

self._plot_area = None
self._fpl_plot_area = None

# event handlers
self._event_handlers = defaultdict(set)
Expand Down Expand Up @@ -362,7 +362,7 @@ def my_handler(event):
feature.remove_event_handler(wrapper)

def _fpl_add_plot_area_hook(self, plot_area):
self._plot_area = plot_area
self._fpl_plot_area = plot_area

def __repr__(self):
rval = f"{self.__class__.__name__} @ {hex(id(self))}"
Expand All @@ -380,8 +380,8 @@ def _fpl_prepare_del(self):
"""
# remove axes if added to this graphic
if self._axes is not None:
self._plot_area.scene.remove(self._axes)
self._plot_area.remove_animation(self._update_axes)
self._fpl_plot_area.scene.remove(self._axes)
self._fpl_plot_area.remove_animation(self._update_axes)
self._axes.world_object.clear()

# signal that a deletion has been requested
Expand All @@ -402,12 +402,12 @@ def _fpl_prepare_del(self):

for ev_type in PYGFX_EVENTS:
try:
self._plot_area.renderer.remove_event_handler(method, ev_type)
self._fpl_plot_area.renderer.remove_event_handler(method, ev_type)
except (KeyError, TypeError):
pass

try:
self._plot_area.remove_animation(method)
self._fpl_plot_area.remove_animation(method)
except KeyError:
pass

Expand Down Expand Up @@ -452,10 +452,10 @@ def add_axes(self):
if self._axes is not None:
raise AttributeError("Axes already added onto this graphic")

self._axes = Axes(self._plot_area, offset=self.offset, grids=False)
self._axes = Axes(self._fpl_plot_area, offset=self.offset, grids=False)
self._axes.world_object.local.rotation = self.world_object.local.rotation

self._plot_area.scene.add(self.axes.world_object)
self._fpl_plot_area.scene.add(self.axes.world_object)
self._axes.update_using_bbox(self.world_object.get_world_bounding_box())

@property
Expand Down
4 changes: 2 additions & 2 deletions fastplotlib/graphics/_features/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def set_value(self, graphic, value: str):
if not isinstance(value, str):
raise TypeError("`Graphic` name must be of type <str>")

if graphic._plot_area is not None:
graphic._plot_area._check_graphic_name_exists(value)
if graphic._fpl_plot_area is not None:
graphic._fpl_plot_area._check_graphic_name_exists(value)

self._value = value

Expand Down
6 changes: 3 additions & 3 deletions fastplotlib/graphics/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def add_linear_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place selector above this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] + 1)
Expand Down Expand Up @@ -388,7 +388,7 @@ def add_linear_region_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place above this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] + 1)
Expand Down Expand Up @@ -430,7 +430,7 @@ def add_rectangle_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place above this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] + 1)
Expand Down
6 changes: 3 additions & 3 deletions fastplotlib/graphics/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def add_linear_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place selector above this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] + 1)
Expand Down Expand Up @@ -207,7 +207,7 @@ def add_linear_region_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place selector below this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] - 1)
Expand Down Expand Up @@ -257,7 +257,7 @@ def add_rectangle_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

return selector

Expand Down
6 changes: 3 additions & 3 deletions fastplotlib/graphics/line_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def add_linear_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place selector above this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] + 1)
Expand Down Expand Up @@ -438,7 +438,7 @@ def add_linear_region_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

# place selector below this graphic
selector.offset = selector.offset + (0.0, 0.0, self.offset[-1] - 1)
Expand Down Expand Up @@ -484,7 +484,7 @@ def add_rectangle_selector(
**kwargs,
)

self._plot_area.add_graphic(selector, center=False)
self._fpl_plot_area.add_graphic(selector, center=False)

return selector

Expand Down
34 changes: 17 additions & 17 deletions fastplotlib/graphics/selectors/_base_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def _get_source(self, graphic):
return source

def _fpl_add_plot_area_hook(self, plot_area):
self._plot_area = plot_area
self._fpl_plot_area = plot_area

# when the pointer is pressed on a fill, edge or vertex
for wo in self._world_objects:
Expand All @@ -147,35 +147,35 @@ def _fpl_add_plot_area_hook(self, plot_area):
for fill in self._fill:
if fill.material.color_is_transparent:
self._pfunc_fill = partial(self._check_fill_pointer_event, fill)
self._plot_area.renderer.add_event_handler(
self._fpl_plot_area.renderer.add_event_handler(
self._pfunc_fill, "pointer_down"
)

# when the pointer moves
self._plot_area.renderer.add_event_handler(self._move, "pointer_move")
self._fpl_plot_area.renderer.add_event_handler(self._move, "pointer_move")

# when the pointer is released
self._plot_area.renderer.add_event_handler(self._move_end, "pointer_up")
self._fpl_plot_area.renderer.add_event_handler(self._move_end, "pointer_up")

# move directly to location of center mouse button click
self._plot_area.renderer.add_event_handler(self._move_to_pointer, "click")
self._fpl_plot_area.renderer.add_event_handler(self._move_to_pointer, "click")

# mouse hover color events
for wo in self._hover_responsive:
wo.add_event_handler(self._pointer_enter, "pointer_enter")
wo.add_event_handler(self._pointer_leave, "pointer_leave")

# arrow key bindings
self._plot_area.renderer.add_event_handler(self._key_down, "key_down")
self._plot_area.renderer.add_event_handler(self._key_up, "key_up")
self._plot_area.add_animations(self._key_hold)
self._fpl_plot_area.renderer.add_event_handler(self._key_down, "key_down")
self._fpl_plot_area.renderer.add_event_handler(self._key_up, "key_up")
self._fpl_plot_area.add_animations(self._key_hold)

def _check_fill_pointer_event(self, event_source: WorldObject, ev):
if self._edge_hovered:
# if edge is hovered, prefer edge events, disable fill moves
return

world_pos = self._plot_area.map_screen_to_world(ev)
world_pos = self._fpl_plot_area.map_screen_to_world(ev)
# outside viewport, ignore
# this shouldn't be possible since the event handler is registered to the fill mesh world object
# but I like sanity checks anyways
Expand Down Expand Up @@ -210,12 +210,12 @@ def _move_start(self, event_source: WorldObject, ev):
pygfx ``Event``

"""
last_position = self._plot_area.map_screen_to_world(ev)
last_position = self._fpl_plot_area.map_screen_to_world(ev)

self._move_info = MoveInfo(last_position=last_position, source=event_source)
self._moving = True

self._initial_controller_state = self._plot_area.controller.enabled
self._initial_controller_state = self._fpl_plot_area.controller.enabled

def _move(self, ev):
"""
Expand All @@ -233,10 +233,10 @@ def _move(self, ev):
return

# disable controller during moves
self._plot_area.controller.enabled = False
self._fpl_plot_area.controller.enabled = False

# get pointer current world position
world_pos = self._plot_area.map_screen_to_world(ev)
world_pos = self._fpl_plot_area.map_screen_to_world(ev)

# outside this viewport
if world_pos is None:
Expand All @@ -253,7 +253,7 @@ def _move(self, ev):

# restore the initial controller state
# if it was disabled, keep it disabled
self._plot_area.controller.enabled = self._initial_controller_state
self._fpl_plot_area.controller.enabled = self._initial_controller_state

def _move_graphic(self, delta: np.ndarray):
raise NotImplementedError("Must be implemented in subclass")
Expand All @@ -265,7 +265,7 @@ def _move_end(self, ev):
# restore the initial controller state
# if it was disabled, keep it disabled
if self._initial_controller_state is not None:
self._plot_area.controller.enabled = self._initial_controller_state
self._fpl_plot_area.controller.enabled = self._initial_controller_state

def _move_to_pointer(self, ev):
"""
Expand All @@ -291,7 +291,7 @@ def _move_to_pointer(self, ev):

current_pos_world: np.ndarray = center + offset

world_pos = self._plot_area.map_screen_to_world(ev)
world_pos = self._fpl_plot_area.map_screen_to_world(ev)

# outside this viewport
if world_pos is None:
Expand Down Expand Up @@ -382,7 +382,7 @@ def _key_up(self, ev):

def _fpl_prepare_del(self):
if hasattr(self, "_pfunc_fill"):
self._plot_area.renderer.remove_event_handler(
self._fpl_plot_area.renderer.remove_event_handler(
self._pfunc_fill, "pointer_down"
)
del self._pfunc_fill
Expand Down
1 change: 1 addition & 0 deletions fastplotlib/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from ._histogram_lut import HistogramLUTTool
from ._cursor import Cursor
Loading