Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1fea4aa
started implementation of ImageWidget, nothing is tested yet
kushalkolar Dec 2, 2022
1bc65a0
basic stuff finished for single plot with a slider, need to test
kushalkolar Dec 2, 2022
6592cc3
basic image widget works
kushalkolar Dec 2, 2022
658f298
docs
kushalkolar Dec 2, 2022
5cc91ae
splitting imagewidget into two classes
kushalkolar Dec 4, 2022
7a6a136
split ImageWidget into ImageWidgetSingle and later ImageWidgetGrid
kushalkolar Dec 4, 2022
7cce91f
combined single and grid ImageWidget into single class
kushalkolar Dec 4, 2022
56a9b1c
simple and grid image widget works, tested with simple args, need to …
kushalkolar Dec 4, 2022
79f4452
catch another user error
kushalkolar Dec 4, 2022
e4f6b12
fix type annotation
kushalkolar Dec 4, 2022
5028ce7
docstrings, started slice_avg implementation
kushalkolar Dec 4, 2022
5ef32eb
slice averaging on single and multiple dimensions works perfectly
kushalkolar Dec 5, 2022
eca6599
is_array() checks for and attr, better error messages
kushalkolar Dec 8, 2022
0e3cf16
rename axis -> dims
kushalkolar Dec 10, 2022
570c076
make most imagewidget methods private, most attributes as read-only p…
kushalkolar Dec 10, 2022
4764b84
quick_min_max() returns pre-computed min max if int or float, imagewi…
kushalkolar Dec 10, 2022
afc0378
vmin vmax for gridplot
kushalkolar Dec 10, 2022
fc3365b
Merge branch 'master' into high-level-widgets
kushalkolar Dec 11, 2022
b1e922c
update Image -> ImageGraphic
kushalkolar Dec 11, 2022
e6c5d3a
refactor, window_funcs now works very well, slow with multiple dims b…
kushalkolar Dec 11, 2022
64faffd
vminmax works, also added names for subplots, everything works
kushalkolar Dec 11, 2022
8fc63b3
proper-ish image widget example
kushalkolar Dec 11, 2022
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
Prev Previous commit
Next Next commit
vminmax works, also added names for subplots, everything works
  • Loading branch information
kushalkolar committed Dec 11, 2022
commit 64faffdd4eb4d1d1104f9415253aa2e11462eb5f
94 changes: 89 additions & 5 deletions fastplotlib/widgets/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from ..layouts import GridPlot
from ..graphics import ImageGraphic
from ..utils import quick_min_max
from ipywidgets.widgets import IntSlider, VBox, HBox, Layout
from ipywidgets.widgets import IntSlider, VBox, HBox, Layout, FloatRangeSlider
import numpy as np
from typing import *
from warnings import warn
Expand Down Expand Up @@ -166,7 +166,9 @@ def __init__(
slider_dims: Union[str, int, List[Union[str, int]]] = None,
window_funcs: Union[int, Dict[str, int]] = None,
frame_apply: Union[callable, Dict[int, callable]] = None,
vmin_vmax_sliders: bool = False,
grid_shape: Tuple[int, int] = None,
names: List[str] = None,
**kwargs
):
"""
Expand Down Expand Up @@ -224,9 +226,14 @@ def __init__(
grid_shape: Optional[Tuple[int, int]]
manually provide the shape for a gridplot, otherwise a square gridplot is approximated.

names: Optional[str]
gives names to the subplots

kwargs: Any
passed to fastplotlib.graphics.Image
"""
self._names = None

if isinstance(data, list):
# verify that it's a list of np.ndarray
if all([_is_arraylike(d) for d in data]):
Expand All @@ -250,6 +257,16 @@ def __init__(
self._data: List[np.ndarray] = data
self._ndim = self.data[0].ndim # all ndim must be same

if names is not None:
if not all([isinstance(n, str) for n in names]):
raise TypeError("optinal argument `names` must be a list of str")

if len(names) != len(self.data):
raise ValueError(
"number of `names` for subplots must be same as the number of data arrays"
)
self._names = names

self._plot_type = "grid"

else:
Expand Down Expand Up @@ -428,6 +445,8 @@ def __init__(
# current_index stores {dimension_index: slice_index} for every dimension
self._current_index: Dict[str, int] = {sax: 0 for sax in self.slider_dims}

self.vmin_vmax_sliders: List[FloatRangeSlider] = list()

# get max bound for all data arrays for all dimensions
self._dims_max_bounds: Dict[str, int] = {k: np.inf for k in self.slider_dims}
for _dim in list(self._dims_max_bounds.keys()):
Expand All @@ -437,8 +456,31 @@ def __init__(
if self._plot_type == "single":
self._plot: Plot = Plot()

minmax = quick_min_max(self.data[0])

if vmin_vmax_sliders:
data_range = np.ptp(minmax)
data_range_30p = np.ptp(minmax) * 0.3

minmax_slider = FloatRangeSlider(
value=minmax,
min=minmax[0] - data_range_30p,
max=minmax[1] + data_range_30p,
step=data_range / 150,
description=f"min-max",
readout = True,
readout_format = '.3f',
)

minmax_slider.observe(
partial(self._vmin_vmax_slider_changed, 0),
names="value"
)

self.vmin_vmax_sliders.append(minmax_slider)

if ("vmin" not in kwargs.keys()) or ("vmax" not in kwargs.keys()):
kwargs["vmin"], kwargs["vmax"] = quick_min_max(self.data[0])
kwargs["vmin"], kwargs["vmax"] = minmax

frame = self._process_indices(self.data[0], slice_indices=self._current_index)

Expand All @@ -448,13 +490,44 @@ def __init__(
self._plot: GridPlot = GridPlot(shape=grid_shape, controllers="sync")

self.image_graphics = list()
for d, subplot in zip(self.data, self.plot):
for i, (d, subplot) in enumerate(zip(self.data, self.plot)):
minmax = quick_min_max(self.data[0])

if self._names is not None:
name = self._names[i]
name_slider = name
else:
name = None
name_slider = ""

if vmin_vmax_sliders:
data_range = np.ptp(minmax)
data_range_30p = np.ptp(minmax) * 0.4

minmax_slider = FloatRangeSlider(
value=minmax,
min=minmax[0] - data_range_30p,
max=minmax[1] + data_range_30p,
step=data_range / 150,
description=f"mm ['{name_slider}']",
readout=True,
readout_format='.3f',
)

minmax_slider.observe(
partial(self._vmin_vmax_slider_changed, i),
names="value"
)

self.vmin_vmax_sliders.append(minmax_slider)

if ("vmin" not in kwargs.keys()) or ("vmax" not in kwargs.keys()):
kwargs["vmin"], kwargs["vmax"] = quick_min_max(self.data[0])
kwargs["vmin"], kwargs["vmax"] = minmax

frame = self._process_indices(d, slice_indices=self._current_index)
ig = ImageGraphic(frame, **kwargs)
subplot.add_graphic(ig)
subplot.name = name
self.image_graphics.append(ig)

self.plot.renderer.add_event_handler(self._set_slider_layout, "resize")
Expand Down Expand Up @@ -494,7 +567,8 @@ def __init__(
# TODO: So just stack everything vertically for now
self.widget = VBox([
self.plot.canvas,
*list(self._sliders.values())
*list(self._sliders.values()),
*self.vmin_vmax_sliders
])

# TODO: there is currently an issue with ipywidgets or jupyter-rfb and HBox doesn't work with RFB canvas
Expand Down Expand Up @@ -692,6 +766,13 @@ def _slider_value_changed(
return
self.current_index = {dimension: change["new"]}

def _vmin_vmax_slider_changed(
self,
data_ix: int,
change: dict
):
self.image_graphics[data_ix].clim = change["new"]

def _set_slider_layout(self, *args):
w, h = self.plot.renderer.logical_size
for hs in self._horizontal_sliders:
Expand All @@ -700,6 +781,9 @@ def _set_slider_layout(self, *args):
for vs in self._vertical_sliders:
vs.layout = Layout(height=f"{h}px")

for mm in self.vmin_vmax_sliders:
mm.layout = Layout(width=f"{w}px")

def show(self):
"""
Show the widget
Expand Down