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

Skip to content

Commit eb4b3f8

Browse files
authored
remove ipywidget code from selectors and cleanup docstrings (#644)
* remove ipywidget code from linear selector and cleanup docstrings * remove ipywidget code from LinearRegionSelector, cleanup docstrings * remove a method * update API docs
1 parent a691be2 commit eb4b3f8

File tree

4 files changed

+51
-328
lines changed

4 files changed

+51
-328
lines changed

docs/source/api/selectors/LinearRegionSelector.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,10 @@ Methods
4343

4444
LinearRegionSelector.add_axes
4545
LinearRegionSelector.add_event_handler
46-
LinearRegionSelector.add_ipywidget_handler
4746
LinearRegionSelector.clear_event_handlers
4847
LinearRegionSelector.get_selected_data
4948
LinearRegionSelector.get_selected_index
5049
LinearRegionSelector.get_selected_indices
51-
LinearRegionSelector.make_ipywidget_slider
5250
LinearRegionSelector.remove_event_handler
5351
LinearRegionSelector.rotate
5452
LinearRegionSelector.share_property

docs/source/api/selectors/LinearSelector.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,10 @@ Methods
4343

4444
LinearSelector.add_axes
4545
LinearSelector.add_event_handler
46-
LinearSelector.add_ipywidget_handler
4746
LinearSelector.clear_event_handlers
4847
LinearSelector.get_selected_data
4948
LinearSelector.get_selected_index
5049
LinearSelector.get_selected_indices
51-
LinearSelector.make_ipywidget_slider
5250
LinearSelector.remove_event_handler
5351
LinearSelector.rotate
5452
LinearSelector.share_property
Lines changed: 28 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
from typing import *
21
import math
32
from numbers import Real
3+
from typing import Sequence
44

55
import numpy as np
66
import pygfx
77

8-
from ...utils.gui import IS_JUPYTER
98
from .._base import Graphic
109
from .._collection_base import GraphicCollection
1110
from .._features._selection_features import LinearSelectionFeature
1211
from ._base_selector import BaseSelector
1312

1413

15-
if IS_JUPYTER:
16-
# If using the jupyter backend, user has jupyter_rfb, and thus also ipywidgets
17-
import ipywidgets
18-
19-
2014
class LinearSelector(BaseSelector):
2115
@property
2216
def parent(self) -> Graphic:
@@ -39,11 +33,11 @@ def selection(self, value: int):
3933
self._selection.set_value(self, value)
4034

4135
@property
42-
def limits(self) -> Tuple[float, float]:
36+
def limits(self) -> tuple[float, float]:
4337
return self._limits
4438

4539
@limits.setter
46-
def limits(self, values: Tuple[float, float]):
40+
def limits(self, values: tuple[float, float]):
4741
# check that `values` is an iterable of two real numbers
4842
# using `Real` here allows it to work with builtin `int` and `float` types, and numpy scaler types
4943
if len(values) != 2 or not all(map(lambda v: isinstance(v, Real), values)):
@@ -62,46 +56,50 @@ def __init__(
6256
center: float,
6357
axis: str = "x",
6458
parent: Graphic = None,
65-
color: str | tuple = "w",
59+
color: str | Sequence[float] | np.ndarray = "w",
6660
thickness: float = 2.5,
6761
arrow_keys_modifier: str = "Shift",
6862
name: str = None,
6963
):
7064
"""
71-
Create a horizontal or vertical line slider that is synced to an ipywidget IntSlider
65+
Create a horizontal or vertical line that can be used to select a value along an axis.
7266
7367
Parameters
7468
----------
7569
selection: int
76-
initial x or y selected position for the slider, in world space
70+
initial x or y selected position for the selector, in data space
7771
7872
limits: (int, int)
79-
(min, max) limits along the x or y axis for the selector, in world space
73+
(min, max) limits along the x or y-axis for the selector, in data space
8074
81-
axis: str, default "x"
82-
"x" | "y", the axis which the slider can move along
75+
size: float
76+
size of the selector, usually the range of the data
8377
8478
center: float
85-
center offset of the selector on the orthogonal axis, by default the data mean
79+
center offset of the selector on the orthogonal axis, usually the data mean
80+
81+
axis: str, default "x"
82+
"x" | "y", the axis along which the selector can move
8683
8784
parent: Graphic
88-
parent graphic for this LineSelector
85+
parent graphic for this LinearSelector
8986
9087
arrow_keys_modifier: str
9188
modifier key that must be pressed to initiate movement using arrow keys, must be one of:
92-
"Control", "Shift", "Alt" or ``None``. Double click on the selector first to enable the
89+
"Control", "Shift", "Alt" or ``None``. Double-click the selector first to enable the
9390
arrow key movements, or set the attribute ``arrow_key_events_enabled = True``
9491
9592
thickness: float, default 2.5
96-
thickness of the slider
93+
thickness of the selector
9794
98-
color: Any, default "w"
99-
selection to set the color of the slider
95+
color: str | tuple | np.ndarray, default "w"
96+
color of the selector
10097
10198
name: str, optional
102-
name of line slider
99+
name of linear selector
103100
104101
"""
102+
105103
if len(limits) != 2:
106104
raise ValueError("limits must be a tuple of 2 integers, i.e. (int, int)")
107105

@@ -155,10 +153,6 @@ def __init__(
155153

156154
self._move_info: dict = None
157155

158-
self._block_ipywidget_call = False
159-
160-
self._handled_widgets = list()
161-
162156
if axis == "x":
163157
offset = (parent.offset[0], center + parent.offset[1], 0)
164158
elif axis == "y":
@@ -187,149 +181,22 @@ def __init__(
187181
else:
188182
self._selection.set_value(self, selection)
189183

190-
# update any ipywidgets
191-
self.add_event_handler(self._update_ipywidgets, "selection")
192-
193-
def _setup_ipywidget_slider(self, widget):
194-
# setup an ipywidget slider with bidirectional callbacks to this LinearSelector
195-
value = self.selection
196-
197-
if isinstance(widget, ipywidgets.IntSlider):
198-
value = int(value)
199-
200-
widget.value = value
201-
202-
# user changes widget -> linear selection changes
203-
widget.observe(self._ipywidget_callback, "value")
204-
205-
self._handled_widgets.append(widget)
206-
207-
def _update_ipywidgets(self, ev):
208-
# update the ipywidget sliders when LinearSelector value changes
209-
self._block_ipywidget_call = True # prevent infinite recursion
210-
211-
value = ev.info["value"]
212-
# update all the handled slider widgets
213-
for widget in self._handled_widgets:
214-
if isinstance(widget, ipywidgets.IntSlider):
215-
widget.value = int(value)
216-
else:
217-
widget.value = value
218-
219-
self._block_ipywidget_call = False
220-
221-
def _ipywidget_callback(self, change):
222-
# update the LinearSelector when the ipywidget value changes
223-
if self._block_ipywidget_call or self._moving:
224-
return
225-
226-
self.selection = change["new"]
227-
228-
def _fpl_add_plot_area_hook(self, plot_area):
229-
super()._fpl_add_plot_area_hook(plot_area=plot_area)
230-
231-
# resize the slider widgets when the canvas is resized
232-
self._plot_area.renderer.add_event_handler(self._set_slider_layout, "resize")
233-
234-
def _set_slider_layout(self, *args):
235-
w, h = self._plot_area.renderer.logical_size
236-
237-
for widget in self._handled_widgets:
238-
widget.layout = ipywidgets.Layout(width=f"{w}px")
239-
240-
def make_ipywidget_slider(self, kind: str = "IntSlider", **kwargs):
184+
def get_selected_index(self, graphic: Graphic = None) -> int | list[int]:
241185
"""
242-
Makes and returns an ipywidget slider that is associated to this LinearSelector
186+
Data index the selector is currently at w.r.t. the Graphic data.
243187
244-
Parameters
245-
----------
246-
kind: str
247-
"IntSlider", "FloatSlider" or "FloatLogSlider"
248-
249-
kwargs
250-
passed to the ipywidget slider constructor
251-
252-
Returns
253-
-------
254-
ipywidgets.Intslider or ipywidgets.FloatSlider
255-
256-
"""
257-
258-
if not IS_JUPYTER:
259-
raise ImportError(
260-
"Must installed `ipywidgets` to use `make_ipywidget_slider()`"
261-
)
262-
263-
if kind not in ["IntSlider", "FloatSlider", "FloatLogSlider"]:
264-
raise TypeError(
265-
f"`kind` must be one of: 'IntSlider', 'FloatSlider' or 'FloatLogSlider'\n"
266-
f"You have passed: '{kind}'"
267-
)
268-
269-
cls = getattr(ipywidgets, kind)
270-
271-
value = self.selection
272-
if "Int" in kind:
273-
value = int(self.selection)
274-
275-
slider = cls(
276-
min=self.limits[0],
277-
max=self.limits[1],
278-
value=value,
279-
**kwargs,
280-
)
281-
self.add_ipywidget_handler(slider)
282-
283-
return slider
284-
285-
def add_ipywidget_handler(self, widget, step: Union[int, float] = None):
286-
"""
287-
Bidirectionally connect events with a ipywidget slider
288-
289-
Parameters
290-
----------
291-
widget: ipywidgets.IntSlider, ipywidgets.FloatSlider, or ipywidgets.FloatLogSlider
292-
ipywidget slider to connect to
293-
294-
step: int or float, default ``None``
295-
step size, if ``None`` 100 steps are created
296-
297-
"""
298-
299-
if not isinstance(
300-
widget,
301-
(ipywidgets.IntSlider, ipywidgets.FloatSlider, ipywidgets.FloatLogSlider),
302-
):
303-
raise TypeError(
304-
f"`widget` must be one of: ipywidgets.IntSlider, ipywidgets.FloatSlider, or ipywidgets.FloatLogSlider\n"
305-
f"You have passed a: <{type(widget)}"
306-
)
307-
308-
if step is None:
309-
step = (self.limits[1] - self.limits[0]) / 100
310-
311-
if isinstance(widget, ipywidgets.IntSlider):
312-
step = int(step)
313-
314-
widget.step = step
315-
316-
self._setup_ipywidget_slider(widget)
317-
318-
def get_selected_index(self, graphic: Graphic = None) -> Union[int, List[int]]:
319-
"""
320-
Data index the slider is currently at w.r.t. the Graphic data. With LineGraphic data, the geometry x or y
321-
position is not always the data position, for example if plotting data using np.linspace. Use this to get
322-
the data index of the slider.
188+
With LineGraphic data, the geometry x or y position is not always the data position, for example if plotting
189+
data using np.linspace. Use this to get the data index of the selector.
323190
324191
Parameters
325192
----------
326193
graphic: Graphic, optional
327-
Graphic to get the selected data index from. Default is the parent graphic associated to the slider.
194+
Graphic to get the selected data index from. Default is the parent graphic associated to the selector.
328195
329196
Returns
330197
-------
331198
int or List[int]
332-
data index the slider is currently at, list of ``int`` if a Collection
199+
data index the selector is currently at, list of ``int`` if a Collection
333200
"""
334201

335202
source = self._get_source(graphic)
@@ -354,10 +221,10 @@ def _get_selected_index(self, graphic):
354221
"Line" in graphic.__class__.__name__
355222
or "Scatter" in graphic.__class__.__name__
356223
):
357-
# we want to find the index of the data closest to the slider position
224+
# we want to find the index of the data closest to the selector position
358225
find_value = self.selection
359226

360-
# get closest data index to the world space position of the slider
227+
# get closest data index to the world space position of the selector
361228
idx = np.searchsorted(data, find_value, side="left")
362229

363230
if idx > 0 and (
@@ -398,9 +265,3 @@ def _move_graphic(self, delta: np.ndarray):
398265
self.selection = self.selection + delta[0]
399266
else:
400267
self.selection = self.selection + delta[1]
401-
402-
def _fpl_prepare_del(self):
403-
for widget in self._handled_widgets:
404-
widget.unobserve(self._ipywidget_callback, "value")
405-
406-
super()._fpl_prepare_del()

0 commit comments

Comments
 (0)