Content-Length: 941282 | pFad | http://github.com/fastplotlib/fastplotlib/commit/ce5edd0ddedaa6dbfa7270c3c95d84d10581cbdf

DD histogram lut widget (#344) · fastplotlib/fastplotlib@ce5edd0 · GitHub
Skip to content

Commit ce5edd0

Browse files
authored
histogram lut widget (#344)
* move render and animation methods from Subplot to PlotBase * edge_thickness param for linear_region * histogram LUT widget basically works! * bidirectional vmin vmax with linear region and image graphic, start imagewidget integration * more hlut functionality, integrate in imagewidget * fix image widget example nb
1 parent 2cd6d52 commit ce5edd0

File tree

7 files changed

+360
-179
lines changed

7 files changed

+360
-179
lines changed

examples/notebooks/image_widget.ipynb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"source": [
4545
"iw = ImageWidget(\n",
4646
" data=a,\n",
47-
" vmin_vmax_sliders=True,\n",
4847
" cmap=\"viridis\"\n",
4948
")"
5049
]
@@ -113,7 +112,6 @@
113112
"iw = ImageWidget(\n",
114113
" data=a, \n",
115114
" slider_dims=[\"t\"],\n",
116-
" vmin_vmax_sliders=True,\n",
117115
" cmap=\"gnuplot2\"\n",
118116
")"
119117
]
@@ -247,7 +245,6 @@
247245
" data=data, \n",
248246
" slider_dims=[\"t\"], \n",
249247
" # dims_order=\"txy\", # you can set this manually if dim order is not the usual\n",
250-
" vmin_vmax_sliders=True,\n",
251248
" names=[\"zero\", \"one\", \"two\", \"three\"],\n",
252249
" window_funcs={\"t\": (np.mean, 5)},\n",
253250
" cmap=\"gnuplot2\", \n",
@@ -338,7 +335,6 @@
338335
" data=data, \n",
339336
" slider_dims=[\"t\", \"z\"], \n",
340337
" dims_order=\"xyzt\", # example of how you can set this for non-standard orders\n",
341-
" vmin_vmax_sliders=True,\n",
342338
" names=[\"zero\", \"one\", \"two\", \"three\"],\n",
343339
" # window_funcs={\"t\": (np.mean, 5)}, # window functions can be slow when indexing multiple dims\n",
344340
" cmap=\"gnuplot2\", \n",
@@ -402,7 +398,7 @@
402398
"name": "python",
403399
"nbconvert_exporter": "python",
404400
"pygments_lexer": "ipython3",
405-
"version": "3.11.3"
401+
"version": "3.11.2"
406402
}
407403
},
408404
"nbformat": 4,

fastplotlib/graphics/selectors/_base_selector.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ def __init__(
8686
# sets to `True` on "pointer_down", sets to `False` on "pointer_up"
8787
self._moving = False #: indicates if the selector is currently being moved
8888

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

206+
self._initial_controller_state = self._plot_area.controller.enabled
207+
204208
def _move(self, ev):
205209
"""
206210
Called on pointer move events
@@ -235,15 +239,20 @@ def _move(self, ev):
235239
# update last position
236240
self._move_info.last_position = world_pos
237241

238-
self._plot_area.controller.enabled = True
242+
# restore the initial controller state
243+
# if it was disabled, keep it disabled
244+
self._plot_area.controller.enabled = self._initial_controller_state
239245

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

243249
def _move_end(self, ev):
244250
self._move_info = None
245251
self._moving = False
246-
self._plot_area.controller.enabled = True
252+
253+
# restore the initial controller state
254+
# if it was disabled, keep it disabled
255+
self._plot_area.controller.enabled = self._initial_controller_state
247256

248257
def _move_to_pointer(self, ev):
249258
"""

fastplotlib/graphics/selectors/_linear_region.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def __init__(
4444
resizable: bool = True,
4545
fill_color=(0, 0, 0.35),
4646
edge_color=(0.8, 0.8, 0),
47+
edge_thickness: int = 3,
4748
arrow_keys_modifier: str = "Shift",
4849
name: str = None,
4950
):
@@ -56,6 +57,9 @@ def __init__(
5657
Holding the right mouse button while dragging an edge will force the entire region selector to move. This is
5758
a when using transparent fill areas due to ``pygfx`` picking limitations.
5859
60+
**Note:** Events get very weird if the values of bounds, limits and origen are close to zero. If you need
61+
a linear selector with small data, we recommend scaling the data and then using the selector.
62+
5963
Parameters
6064
----------
6165
bounds: (int, int)
@@ -168,7 +172,7 @@ def __init__(
168172

169173
left_line = pygfx.Line(
170174
pygfx.Geometry(positions=left_line_data),
171-
pygfx.LineMaterial(thickness=3, color=edge_color),
175+
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
172176
)
173177

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

182186
right_line = pygfx.Line(
183187
pygfx.Geometry(positions=right_line_data),
184-
pygfx.LineMaterial(thickness=3, color=edge_color),
188+
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
185189
)
186190

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

198202
bottom_line = pygfx.Line(
199203
pygfx.Geometry(positions=bottom_line_data),
200-
pygfx.LineMaterial(thickness=3, color=edge_color),
204+
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
201205
)
202206

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

211215
top_line = pygfx.Line(
212216
pygfx.Geometry(positions=top_line_data),
213-
pygfx.LineMaterial(thickness=3, color=edge_color),
217+
pygfx.LineMaterial(thickness=edge_thickness, color=edge_color),
214218
)
215219

216220
self.edges: Tuple[pygfx.Line, pygfx.Line] = (bottom_line, top_line)

fastplotlib/layouts/_base.py

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from inspect import getfullargspec
12
from typing import *
23
import weakref
4+
from warnings import warn
35

46
import numpy as np
57

@@ -92,6 +94,9 @@ def __init__(
9294
self.viewport,
9395
)
9496

97+
self._animate_funcs_pre = list()
98+
self._animate_funcs_post = list()
99+
95100
self.renderer.add_event_handler(self.set_viewport_rect, "resize")
96101

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

226231
def render(self):
227-
# does not flush
232+
self._call_animate_functions(self._animate_funcs_pre)
233+
234+
# does not flush, flush must be implemented in user-facing Plot objects
228235
self.viewport.render(self.scene, self.camera)
229236

230237
for child in self.children:
231238
child.render()
232239

240+
self._call_animate_functions(self._animate_funcs_post)
241+
242+
def _call_animate_functions(self, funcs: Iterable[callable]):
243+
for fn in funcs:
244+
try:
245+
args = getfullargspec(fn).args
246+
247+
if len(args) > 0:
248+
if args[0] == "self" and not len(args) > 1:
249+
fn()
250+
else:
251+
fn(self)
252+
else:
253+
fn()
254+
except (ValueError, TypeError):
255+
warn(
256+
f"Could not resolve argspec of {self.__class__.__name__} animation function: {fn}, "
257+
f"calling it without arguments."
258+
)
259+
fn()
260+
261+
def add_animations(
262+
self,
263+
*funcs: Iterable[callable],
264+
pre_render: bool = True,
265+
post_render: bool = False,
266+
):
267+
"""
268+
Add function(s) that are called on every render cycle.
269+
These are called at the Subplot level.
270+
271+
Parameters
272+
----------
273+
*funcs: callable or iterable of callable
274+
function(s) that are called on each render cycle
275+
276+
pre_render: bool, default ``True``, optional keyword-only argument
277+
if true, these function(s) are called before a render cycle
278+
279+
post_render: bool, default ``False``, optional keyword-only argument
280+
if true, these function(s) are called after a render cycle
281+
282+
"""
283+
for f in funcs:
284+
if not callable(f):
285+
raise TypeError(
286+
f"all positional arguments to add_animations() must be callable types, you have passed a: {type(f)}"
287+
)
288+
if pre_render:
289+
self._animate_funcs_pre += funcs
290+
if post_render:
291+
self._animate_funcs_post += funcs
292+
293+
def remove_animation(self, func):
294+
"""
295+
Removes the passed animation function from both pre and post render.
296+
297+
Parameters
298+
----------
299+
func: callable
300+
The function to remove, raises a error if it's not registered as a pre or post animation function.
301+
302+
"""
303+
if func not in self._animate_funcs_pre and func not in self._animate_funcs_post:
304+
raise KeyError(
305+
f"The passed function: {func} is not registered as an animation function. These are the animation "
306+
f" functions that are currently registered:\n"
307+
f"pre: {self._animate_funcs_pre}\n\npost: {self._animate_funcs_post}"
308+
)
309+
310+
if func in self._animate_funcs_pre:
311+
self._animate_funcs_pre.remove(func)
312+
313+
if func in self._animate_funcs_post:
314+
self._animate_funcs_post.remove(func)
315+
233316
def add_graphic(self, graphic: Graphic, center: bool = True):
234317
"""
235318
Add a Graphic to the scene

fastplotlib/layouts/_subplot.py

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from typing import *
2-
from inspect import getfullargspec
3-
from warnings import warn
42

53
import numpy as np
64

@@ -97,9 +95,6 @@ def __init__(
9795

9896
self._grid: GridHelper = GridHelper(size=100, thickness=1)
9997

100-
self._animate_funcs_pre = list()
101-
self._animate_funcs_post = list()
102-
10398
super(Subplot, self).__init__(
10499
parent=parent,
105100
position=position,
@@ -192,87 +187,6 @@ def get_rect(self):
192187

193188
return rect
194189

195-
def render(self):
196-
self._call_animate_functions(self._animate_funcs_pre)
197-
198-
super(Subplot, self).render()
199-
200-
self._call_animate_functions(self._animate_funcs_post)
201-
202-
def _call_animate_functions(self, funcs: Iterable[callable]):
203-
for fn in funcs:
204-
try:
205-
args = getfullargspec(fn).args
206-
207-
if len(args) > 0:
208-
if args[0] == "self" and not len(args) > 1:
209-
fn()
210-
else:
211-
fn(self)
212-
else:
213-
fn()
214-
except (ValueError, TypeError):
215-
warn(
216-
f"Could not resolve argspec of {self.__class__.__name__} animation function: {fn}, "
217-
f"calling it without arguments."
218-
)
219-
fn()
220-
221-
def add_animations(
222-
self,
223-
*funcs: Iterable[callable],
224-
pre_render: bool = True,
225-
post_render: bool = False,
226-
):
227-
"""
228-
Add function(s) that are called on every render cycle.
229-
These are called at the Subplot level.
230-
231-
Parameters
232-
----------
233-
*funcs: callable or iterable of callable
234-
function(s) that are called on each render cycle
235-
236-
pre_render: bool, default ``True``, optional keyword-only argument
237-
if true, these function(s) are called before a render cycle
238-
239-
post_render: bool, default ``False``, optional keyword-only argument
240-
if true, these function(s) are called after a render cycle
241-
242-
"""
243-
for f in funcs:
244-
if not callable(f):
245-
raise TypeError(
246-
f"all positional arguments to add_animations() must be callable types, you have passed a: {type(f)}"
247-
)
248-
if pre_render:
249-
self._animate_funcs_pre += funcs
250-
if post_render:
251-
self._animate_funcs_post += funcs
252-
253-
def remove_animation(self, func):
254-
"""
255-
Removes the passed animation function from both pre and post render.
256-
257-
Parameters
258-
----------
259-
func: callable
260-
The function to remove, raises a error if it's not registered as a pre or post animation function.
261-
262-
"""
263-
if func not in self._animate_funcs_pre and func not in self._animate_funcs_post:
264-
raise KeyError(
265-
f"The passed function: {func} is not registered as an animation function. These are the animation "
266-
f" functions that are currently registered:\n"
267-
f"pre: {self._animate_funcs_pre}\n\npost: {self._animate_funcs_post}"
268-
)
269-
270-
if func in self._animate_funcs_pre:
271-
self._animate_funcs_pre.remove(func)
272-
273-
if func in self._animate_funcs_post:
274-
self._animate_funcs_post.remove(func)
275-
276190
def set_axes_visibility(self, visible: bool):
277191
"""Toggles axes visibility."""
278192
if visible:

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/fastplotlib/fastplotlib/commit/ce5edd0ddedaa6dbfa7270c3c95d84d10581cbdf

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy