Skip to content

Commit 2c6eac5

Browse files
authored
add thumbnail_size property (#34)
* add thumbnail_size property * most recent black * add to use full res client-side * address review comments * fixed tests * added test * try to make black happy
1 parent 4550229 commit 2c6eac5

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

dash_slicer/slicer.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class VolumeSlicer:
3030
scene_id (str): the scene that this slicer is part of. Slicers
3131
that have the same scene-id show each-other's positions with
3232
line indicators. By default this is derived from ``id(volume)``.
33+
thumbnail (int or bool): linear size of low-resolution data to be
34+
uploaded to the client. If ``False``, the full-resolution data are
35+
uploaded client-side. If ``True`` (default), a default value of 32 is
36+
used.
3337
3438
This is a placeholder object, not a Dash component. The components
3539
that make up the slicer can be accessed as attributes. These must all
@@ -73,6 +77,7 @@ def __init__(
7377
axis=0,
7478
reverse_y=True,
7579
scene_id=None,
80+
thumbnail=True,
7681
):
7782

7883
if not isinstance(app, Dash):
@@ -97,6 +102,16 @@ def __init__(
97102
self._other_axii = [0, 1, 2]
98103
self._other_axii.pop(self._axis)
99104

105+
# Check and store thumbnail
106+
if not (isinstance(thumbnail, (int, bool))):
107+
raise ValueError("thumbnail must be a boolean or an integer.")
108+
# No thumbnail if thumbnail size is larger than image size
109+
if isinstance(thumbnail, int) and thumbnail > np.max(volume.shape):
110+
thumbnail = False
111+
if thumbnail is True:
112+
thumbnail = 32 # default size
113+
self._thumbnail = thumbnail
114+
100115
# Check and store scene id, and generate
101116
if scene_id is None:
102117
n = len(_assigned_scene_ids)
@@ -120,7 +135,8 @@ def __init__(
120135

121136
# Build the slicer
122137
self._create_dash_components()
123-
self._create_server_callbacks()
138+
if thumbnail:
139+
self._create_server_callbacks()
124140
self._create_client_callbacks()
125141

126142
# Note(AK): we could make some stores public, but let's do this only when actual use-cases arise?
@@ -260,12 +276,18 @@ def _create_dash_components(self):
260276
info = self._slice_info
261277

262278
# Prep low-res slices
263-
thumbnail_size = get_thumbnail_size(info["size"][:2], (32, 32))
279+
if self._thumbnail is False:
280+
thumbnail_size = None
281+
info["lowres_size"] = info["size"]
282+
else:
283+
thumbnail_size = get_thumbnail_size(
284+
info["size"][:2], (self._thumbnail, self._thumbnail)
285+
)
286+
info["lowres_size"] = thumbnail_size
264287
thumbnails = [
265288
img_array_to_uri(self._slice(i), thumbnail_size)
266289
for i in range(info["size"][2])
267290
]
268-
info["lowres_size"] = thumbnail_size
269291

270292
# Create the figure object - can be accessed by user via slicer.graph.figure
271293
self._fig = fig = Figure(data=[])
@@ -324,7 +346,9 @@ def _create_dash_components(self):
324346
self._overlay_data = Store(id=self._subid("overlay"), data=[])
325347

326348
# Slice data provided by the server
327-
self._server_data = Store(id=self._subid("server-data"), data="")
349+
self._server_data = Store(
350+
id=self._subid("server-data"), data={"index": -1, "slice": None}
351+
)
328352

329353
# Store image traces for the slicer.
330354
self._img_traces = Store(id=self._subid("img-traces"), data=[])

tests/test_slicer.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def test_slicer_init():
2121
with raises(ValueError):
2222
VolumeSlicer(app, vol, axis=4)
2323

24+
# Need a valide thumbnail
25+
with raises(ValueError):
26+
VolumeSlicer(app, vol, thumbnail=20.2)
27+
2428
# This works
2529
s = VolumeSlicer(app, vol)
2630

@@ -31,6 +35,20 @@ def test_slicer_init():
3135
assert all(isinstance(store, (dcc.Store, dcc.Interval)) for store in s.stores)
3236

3337

38+
def test_slicer_thumbnail():
39+
app = dash.Dash()
40+
vol = np.random.uniform(0, 255, (100, 100, 100)).astype(np.uint8)
41+
42+
_ = VolumeSlicer(app, vol)
43+
# Test for name pattern of server-side callback when thumbnails are used
44+
assert any(["server-data.data" in key for key in app.callback_map])
45+
46+
app = dash.Dash()
47+
_ = VolumeSlicer(app, vol, thumbnail=False)
48+
# No server-side callbacks when no thumbnails are used
49+
assert not any(["server-data.data" in key for key in app.callback_map])
50+
51+
3452
def test_scene_id_and_context_id():
3553
app = dash.Dash()
3654

0 commit comments

Comments
 (0)