Skip to content

Commit bdd6a75

Browse files
committed
Add a rate limiter on the slicer index
1 parent cbd299e commit bdd6a75

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

dash_slicer/slicer.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from plotly.graph_objects import Figure
33
from dash import Dash
44
from dash.dependencies import Input, Output, State, ALL
5-
from dash_core_components import Graph, Slider, Store
5+
from dash_core_components import Graph, Slider, Store, Interval
66

77
from .utils import img_array_to_uri, get_thumbnail_size, shape3d_to_size2d
88

@@ -290,6 +290,9 @@ def _create_dash_components(self):
290290
self._overlay_data = Store(id=self._subid("overlay"), data=[])
291291
self._img_traces = Store(id=self._subid("img-traces"), data=[])
292292
self._indicator_traces = Store(id=self._subid("indicator-traces"), data=[])
293+
self._interval = Interval(
294+
id=self._subid("interval"), interval=100, disabled=True
295+
)
293296
self._stores = [
294297
self._info,
295298
self._position,
@@ -300,6 +303,7 @@ def _create_dash_components(self):
300303
self._overlay_data,
301304
self._img_traces,
302305
self._indicator_traces,
306+
self._interval,
303307
]
304308

305309
def _create_server_callbacks(self):
@@ -378,9 +382,11 @@ def _create_client_callbacks(self):
378382
function update_position(index, info) {
379383
return info.origin[2] + index * info.spacing[2];
380384
}
381-
""",
385+
""".replace(
386+
"{{ID}}", self._context_id
387+
),
382388
Output(self._position.id, "data"),
383-
[Input(self._slider.id, "value")],
389+
[Input(self._requested_index.id, "data")],
384390
[State(self._info.id, "data")],
385391
)
386392

@@ -391,26 +397,61 @@ def _create_client_callbacks(self):
391397

392398
app.clientside_callback(
393399
"""
394-
function update_request(index) {
400+
function rate_limit_index(index, _, interval) {
401+
if (!window._slicer_{{ID}}) window._slicer_{{ID}} = {};
402+
let slicer_info = window._slicer_{{ID}};
403+
let now = window.performance.now();
395404
396-
// Clear the cache?
397-
if (!window.slicecache_for_{{ID}}) { window.slicecache_for_{{ID}} = {}; }
398-
let slice_cache = window.slicecache_for_{{ID}};
405+
// Get whether the slider was moved
406+
let slider_was_moved = false;
407+
for (let trigger of dash_clientside.callback_context.triggered) {
408+
if (trigger.prop_id.indexOf('slider') >= 0) slider_was_moved = true;
409+
}
399410
400-
// Request a new slice (or not)
401-
let request_index = index;
402-
if (slice_cache[index]) {
403-
return window.dash_clientside.no_update;
404-
} else {
405-
console.log('requesting slice ' + index);
406-
return index;
411+
// Initialize return values
412+
let req_index = dash_clientside.no_update;
413+
let disable_interval = false;
414+
415+
// If the slider moved, remember the time when this happened
416+
slicer_info.new_time = slicer_info.new_time || 0;
417+
418+
if (slider_was_moved) {
419+
slicer_info.new_time = now;
420+
}
421+
422+
// We can either update the rate-limited index interval ms after
423+
// the real index changed, or interval ms after it stopped
424+
// changing. The former makes the indicators come along while
425+
// dragging the slider, the latter is better for a smooth
426+
// experience, and the interval can be set much lower.
427+
if (index != slicer_info.req_index) {
428+
if (now - slicer_info.new_time >= interval) {
429+
req_index = slicer_info.req_index = index;
430+
disable_interval = true;
431+
432+
// Get cache
433+
// todo: _requested_index is now our rate-limited index, so we need to always apply
434+
//if (!window.slicecache_for_{{ID}}) { window.slicecache_for_{{ID}} = {}; }
435+
//let slice_cache = window.slicecache_for_{{ID}};
436+
//if (slice_cache[req_index]) {
437+
// req_index = dash_clientside.no_update;
438+
//} else {
439+
console.log('requesting slice ' + req_index);
440+
//}
441+
}
407442
}
443+
444+
return [req_index, disable_interval];
408445
}
409446
""".replace(
410447
"{{ID}}", self._context_id
411448
),
412-
Output(self._requested_index.id, "data"),
413-
[Input(self.slider.id, "value")],
449+
[
450+
Output(self._requested_index.id, "data"),
451+
Output(self._interval.id, "disabled"),
452+
],
453+
[Input(self._slider.id, "value"), Input(self._interval.id, "n_intervals")],
454+
[State(self._interval.id, "interval")],
414455
)
415456

416457
# ----------------------------------------------------------------------
@@ -473,7 +514,7 @@ def _create_client_callbacks(self):
473514
),
474515
Output(self._img_traces.id, "data"),
475516
[
476-
Input(self.slider.id, "value"),
517+
Input(self._slider.id, "value"),
477518
Input(self._request_data.id, "data"),
478519
Input(self._overlay_data.id, "data"),
479520
],

0 commit comments

Comments
 (0)