Skip to content

Commit 413c472

Browse files
authored
Fix ping lag in plot options (spacetelescope#2326)
* avoid updating stretch histogram if no expected updates * the browser can throttle pings, which can result in 'is_active' toggling "constantly", which with an expensive call to update the stretch histogram can result in extremely laggy behavior. This tracks whether there are any known changes since the last time is_active was toggled, and skips re-computing the histogram unless needed * minor layout fixes * number of bins and the stretch_hist_zoom_limits toggle were in the same row, resulting in undesired behavior for wide plugin width * changelog entry * fix zoom-limits callback not sending msg * fix/optimize compass behavior with is_active
1 parent 1f48493 commit 413c472

4 files changed

Lines changed: 76 additions & 38 deletions

File tree

CHANGES.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ Cubeviz
7272
Imviz
7373
^^^^^
7474

75+
- Fixes possible extreme lag when opening the Plot Options plugin. [#2326]
76+
77+
- Fixes minor layout issues in the Plot Options plugin. [#2326]
78+
79+
- Fixes compass updating in popout/inline mode. [#2326]
80+
7581
Mosviz
7682
^^^^^^
7783

jdaviz/configs/default/plugins/plot_options/plot_options.py

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ class PlotOptions(PluginTemplateMixin):
249249
show_viewer_labels = Bool(True).tag(sync=True)
250250

251251
def __init__(self, *args, **kwargs):
252+
# track whether the stretch histogram needs an update (some entry has changed) if is_active
253+
# becomes True, to address potential lag from a backlog of calls to
254+
# _update_stretch_histogram if the browser throttles pings
255+
# (https://github.com/spacetelescope/jdaviz/issues/2317)
256+
self._stretch_histogram_needs_update = True
257+
252258
super().__init__(*args, **kwargs)
253259
self.viewer = ViewerSelect(self, 'viewer_items', 'viewer_selected', 'multiselect')
254260
self.layer = LayerSelect(self, 'layer_items', 'layer_selected', 'viewer_selected', 'multiselect') # noqa
@@ -494,26 +500,37 @@ def vue_set_value(self, data):
494500
@observe('is_active', 'layer_selected', 'viewer_selected',
495501
'stretch_hist_zoom_limits')
496502
def _update_stretch_histogram(self, msg={}):
497-
# Import here to prevent circular import.
498-
from jdaviz.configs.imviz.plugins.viewers import ImvizImageView
499-
from jdaviz.configs.cubeviz.plugins.viewers import CubevizImageView
500-
501-
if not self.stretch_function_sync.get('in_subscribed_states'): # pragma: no cover
502-
# no (image) viewer with stretch function options
503-
return
504503
if not hasattr(self, 'viewer'): # pragma: no cover
505504
# plugin hasn't been fully initialized yet
506505
return
507-
if (not self.is_active
508-
or not self.viewer.selected
509-
or not self.layer.selected): # pragma: no cover
510-
# no need to make updates, updates will be redrawn when plugin is opened
511-
# NOTE: this won't update when the plugin is shown but not open in the tray
512-
return
513-
if not isinstance(msg, dict) and not self.stretch_hist_zoom_limits: # pragma: no cover
514-
# then this is from the limits callbacks and we don't want to waste resources
506+
507+
if not isinstance(msg, dict): # pragma: no cover
508+
# then this is from the limits callbacks
515509
# IMPORTANT: this assumes the only non-observe callback to this method comes
516510
# from state callbacks from zoom limits.
511+
if not self.stretch_hist_zoom_limits:
512+
# there isn't anything to update, let's not waste resources
513+
return
514+
# override msg as an empty dict so that the rest of the logic doesn't have to check
515+
# its type
516+
msg = {}
517+
518+
if msg.get('name', None) == 'is_active' and not self._stretch_histogram_needs_update:
519+
# this could be re-triggering if the browser is throttling pings on the js-side
520+
# and since this is expensive, could result in laggy behavior
521+
return
522+
elif msg.get('name', None) != 'is_active' and not self.is_active:
523+
# next time is_active becomes True, we need to update the histogram plot
524+
self._stretch_histogram_needs_update = True
525+
return
526+
527+
if not self.stretch_function_sync.get('in_subscribed_states'): # pragma: no cover
528+
# no (image) viewer with stretch function options
529+
return
530+
531+
if (not self.viewer.selected or not self.layer.selected): # pragma: no cover
532+
# nothing to plot
533+
self.stretch_histogram.clear_all_marks()
517534
return
518535

519536
if self.multiselect and (len(self.viewer.selected) > 1
@@ -523,6 +540,11 @@ def _update_stretch_histogram(self, msg={}):
523540
self.stretch_histogram.clear_all_marks()
524541
return
525542

543+
# Import here to prevent circular import (and not at the top of the method so the import
544+
# check is avoided, whenever possible).
545+
from jdaviz.configs.imviz.plugins.viewers import ImvizImageView
546+
from jdaviz.configs.cubeviz.plugins.viewers import CubevizImageView
547+
526548
if not isinstance(self.viewer.selected_obj, (ImvizImageView, CubevizImageView)):
527549
# don't update histogram if selected viewer is not an image viewer:
528550
return
@@ -552,6 +574,7 @@ def _update_stretch_histogram(self, msg={}):
552574

553575
comp = data.get_component(data.main_components[0])
554576

577+
# TODO: further optimization could be done by caching sub_data
555578
if self.stretch_hist_zoom_limits:
556579
if hasattr(viewer, '_get_zoom_limits'):
557580
# Viewer limits. This takes account of Imviz linking.
@@ -598,6 +621,8 @@ def _update_stretch_histogram(self, msg={}):
598621
# we'll force the traitlet to trigger a change
599622
hist_mark.send_state('sample')
600623

624+
self._stretch_histogram_needs_update = False
625+
601626
@observe('stretch_vmin_value')
602627
def _stretch_vmin_changed(self, msg=None):
603628
self.stretch_histogram.marks['vmin'].x = [self.stretch_vmin_value, self.stretch_vmin_value]

jdaviz/configs/default/plugins/plot_options/plot_options.vue

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -348,28 +348,32 @@
348348
<glue-float-field label="Stretch VMax" :value.sync="stretch_vmax_value" />
349349
</glue-state-sync-wrapper>
350350

351-
<v-row v-if="stretch_function_sync.in_subscribed_states">
352-
<!-- z-index to ensure on top of the jupyter widget with negative margin-top -->
353-
<v-text-field
354-
ref="stretch_hist_nbins"
355-
type="number"
356-
label="Number of Bins"
357-
v-model.number="stretch_hist_nbins"
358-
hint="The amount of bins used in the histogram."
359-
persistent-hint
360-
:rules="[() => stretch_hist_nbins !== '' || 'This field is required',
361-
() => stretch_hist_nbins > 0 || 'Number of Bins must be greater than zero']"
362-
></v-text-field>
363-
<v-switch
364-
v-model="stretch_hist_zoom_limits"
365-
class="hide-input"
366-
label="Limit histogram to current zoom limits"
367-
style="z-index: 1"
368-
></v-switch>
369-
<!-- NOTE: height defined here should match that in the custom CSS rules
370-
below for the bqplot class -->
371-
<jupyter-widget :widget="stretch_histogram_widget"/>
372-
</v-row>
351+
<div v-if="stretch_function_sync.in_subscribed_states">
352+
<v-row>
353+
<v-text-field
354+
ref="stretch_hist_nbins"
355+
type="number"
356+
label="Number of Bins"
357+
v-model.number="stretch_hist_nbins"
358+
hint="The amount of bins used in the histogram."
359+
persistent-hint
360+
:rules="[() => stretch_hist_nbins !== '' || 'This field is required',
361+
() => stretch_hist_nbins > 0 || 'Number of Bins must be greater than zero']"
362+
></v-text-field>
363+
</v-row>
364+
<v-row>
365+
<!-- z-index to ensure on top of the jupyter widget with negative margin-top -->
366+
<v-switch
367+
v-model="stretch_hist_zoom_limits"
368+
class="hide-input"
369+
label="Limit histogram to current zoom limits"
370+
style="z-index: 1"
371+
></v-switch>
372+
<!-- NOTE: height defined here should match that in the custom CSS rules
373+
below for the bqplot class -->
374+
</v-row>
375+
<jupyter-widget :widget="stretch_histogram_widget"/>
376+
</div>
373377

374378
<!-- IMAGE:IMAGE -->
375379
<j-plugin-section-header v-if="image_visible_sync.in_subscribed_states">Image</j-plugin-section-header>

jdaviz/configs/imviz/plugins/compass/compass.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,12 @@ def _compass_with_new_viewer(self, *args, **kwargs):
6565
# mixin object not yet initialized
6666
return
6767

68+
if not self.is_active:
69+
return
70+
6871
# There can be only one!
6972
for vid, viewer in self.app._viewer_store.items():
70-
if vid == self.viewer.selected_id and self.plugin_opened:
73+
if vid == self.viewer.selected_id:
7174
viewer.compass = self
7275
viewer.on_limits_change() # Force redraw
7376

0 commit comments

Comments
 (0)