histogram lut widget by kushalkolar · Pull Request #344 · fastplotlib/fastplotlib · GitHub
Skip to content
Merged
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
6 changes: 1 addition & 5 deletions examples/notebooks/image_widget.ipynb
13 changes: 11 additions & 2 deletions fastplotlib/graphics/selectors/_base_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ def __init__(
# sets to `True` on "pointer_down", sets to `False` on "pointer_up"
self._moving = False #: indicates if the selector is currently being moved

self._initial_controller_state: bool = None

# used to disable fill area events if the edge is being actively hovered
# otherwise annoying and requires too much accuracy to move just an edge
self._edge_hovered: bool = False
Expand Down Expand Up @@ -201,6 +203,8 @@ def _move_start(self, event_source: WorldObject, ev):
self._move_info = MoveInfo(last_position=last_position, source=event_source)
self._moving = True

self._initial_controller_state = self._plot_area.controller.enabled

def _move(self, ev):
"""
Called on pointer move events
Expand Down Expand Up @@ -235,15 +239,20 @@ def _move(self, ev):
# update last position
self._move_info.last_position = world_pos

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

def _move_graphic(self, delta: np.ndarray):
raise NotImplementedError("Must be implemented in subclass")

def _move_end(self, ev):
self._move_info = None
self._moving = False
self._plot_area.controller.enabled = True

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

def _move_to_pointer(self, ev):
"""
Expand Down
12 changes: 8 additions & 4 deletions fastplotlib/graphics/selectors/_linear_region.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(
resizable: bool = True,
fill_color=(0, 0, 0.35),
edge_color=(0.8, 0.8, 0),
edge_thickness: int = 3,
arrow_keys_modifier: str = "Shift",
name: str = None,
):
Expand All @@ -56,6 +57,9 @@ def __init__(
Holding the right mouse button while dragging an edge will force the entire region selector to move. This is
a when using transparent fill areas due to ``pygfx`` picking limitations.

**Note:** Events get very weird if the values of bounds, limits and origin are close to zero. If you need
a linear selector with small data, we recommend scaling the data and then using the selector.

Parameters
----------
bounds: (int, int)
Expand Down Expand Up @@ -168,7 +172,7 @@ def __init__(

left_line = pygfx.Line(
pygfx.Geometry(positions=left_line_data),
pygfx.LineMaterial(thickness=3, color=edge_color),
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
)

# position data for the right edge line
Expand All @@ -181,7 +185,7 @@ def __init__(

right_line = pygfx.Line(
pygfx.Geometry(positions=right_line_data),
pygfx.LineMaterial(thickness=3, color=edge_color),
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
)

self.edges: Tuple[pygfx.Line, pygfx.Line] = (left_line, right_line)
Expand All @@ -197,7 +201,7 @@ def __init__(

bottom_line = pygfx.Line(
pygfx.Geometry(positions=bottom_line_data),
pygfx.LineMaterial(thickness=3, color=edge_color),
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
)

# position data for the right edge line
Expand All @@ -210,7 +214,7 @@ def __init__(

top_line = pygfx.Line(
pygfx.Geometry(positions=top_line_data),
pygfx.LineMaterial(thickness=3, color=edge_color),
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
)

self.edges: Tuple[pygfx.Line, pygfx.Line] = (bottom_line, top_line)
Expand Down
85 changes: 84 additions & 1 deletion fastplotlib/layouts/_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from inspect import getfullargspec
from typing import *
import weakref
from warnings import warn

import numpy as np

Expand Down Expand Up @@ -92,6 +94,9 @@ def __init__(
self.viewport,
)

self._animate_funcs_pre = list()
self._animate_funcs_post = list()
Comment thread
kushalkolar marked this conversation as resolved.

self.renderer.add_event_handler(self.set_viewport_rect, "resize")

# list of hex id strings for all graphics managed by this PlotArea
Expand Down Expand Up @@ -224,12 +229,90 @@ def set_viewport_rect(self, *args):
self.viewport.rect = self.get_rect()

def render(self):
# does not flush
self._call_animate_functions(self._animate_funcs_pre)

# does not flush, flush must be implemented in user-facing Plot objects
self.viewport.render(self.scene, self.camera)

for child in self.children:
child.render()

self._call_animate_functions(self._animate_funcs_post)

def _call_animate_functions(self, funcs: Iterable[callable]):
for fn in funcs:
try:
args = getfullargspec(fn).args

if len(args) > 0:
if args[0] == "self" and not len(args) > 1:
fn()
else:
fn(self)
else:
fn()
except (ValueError, TypeError):
warn(
f"Could not resolve argspec of {self.__class__.__name__} animation function: {fn}, "
f"calling it without arguments."
)
fn()

def add_animations(
self,
*funcs: Iterable[callable],
pre_render: bool = True,
post_render: bool = False,
):
"""
Add function(s) that are called on every render cycle.
These are called at the Subplot level.

Parameters
----------
*funcs: callable or iterable of callable
function(s) that are called on each render cycle

pre_render: bool, default ``True``, optional keyword-only argument
if true, these function(s) are called before a render cycle

post_render: bool, default ``False``, optional keyword-only argument
if true, these function(s) are called after a render cycle

"""
for f in funcs:
if not callable(f):
raise TypeError(
f"all positional arguments to add_animations() must be callable types, you have passed a: {type(f)}"
)
if pre_render:
self._animate_funcs_pre += funcs
if post_render:
self._animate_funcs_post += funcs
Comment thread
kushalkolar marked this conversation as resolved.

def remove_animation(self, func):
"""
Removes the passed animation function from both pre and post render.

Parameters
----------
func: callable
The function to remove, raises a error if it's not registered as a pre or post animation function.

"""
if func not in self._animate_funcs_pre and func not in self._animate_funcs_post:
raise KeyError(
f"The passed function: {func} is not registered as an animation function. These are the animation "
f" functions that are currently registered:\n"
f"pre: {self._animate_funcs_pre}\n\npost: {self._animate_funcs_post}"
)

if func in self._animate_funcs_pre:
self._animate_funcs_pre.remove(func)

if func in self._animate_funcs_post:
self._animate_funcs_post.remove(func)

def add_graphic(self, graphic: Graphic, center: bool = True):
"""
Add a Graphic to the scene
Expand Down
86 changes: 0 additions & 86 deletions fastplotlib/layouts/_subplot.py
Loading