jdaviz icon indicating copy to clipboard operation
jdaviz copied to clipboard

[BUG] Centering/Zooming on a hidden viewer leads to a traceback

Open eteq opened this issue 2 years ago • 4 comments
trafficstars

Jdaviz component

Imviz

Description

I have a workflow where I create several viewers and then want to immediately programmatically set them to specific zoom and centering settings. (I note there might be some way to fix my specific use case by using WCS linking instead of manually centering, but I have other cases where the WCS is not reliable enough to do that, so this is needed regardless of whether the specific case I'm working from can be linked.)

The problem is: it doesn't work! See below for details on how to trigger it.

How to Reproduce

  1. Do something like: imviz.create_image_viewer(name); imviz.load_data(data, show_in_viewer=name)
  2. Do v = imviz.app.get_viewer(vnm);v.center_on((1493, 1996));v.zoom_level = 3
  3. Yield the traceback below.
  4. Note that if I re-position the windows before I run step 2 so that they're visible, the error does not occur. Also in some cases the centering doesn't seem to work right, although that's not always reproducible, while this traceback is.
...
File <redacted>/lib/python3.11/site-packages/glue/viewers/matplotlib/state.py:194, in MatplotlibDataViewerState._adjust_limits_aspect(self, *args, **kwargs)
    191 y_min, y_max = self.y_min, self.y_max
    193 # Find current data ratio
--> 194 data_ratio = abs(y_max - y_min) / abs(x_max - x_min)
    196 # Only do something if the data ratio is sufficiently different
    197 # from the axes ratio.
    198 if abs(data_ratio - axes_ratio) / (0.5 * (data_ratio + axes_ratio)) > 0.0001:
    199 
    200     # We now adjust the limits - which ones we adjust depends on
    201     # the adjust keyword. We also make sure we preserve the
    202     # mid-point of the current coordinates.

ZeroDivisionError: float division by zero

Expected behavior

When I click on the tab I should see the viewer centered and zoomed at the level I asked for.

Browser

No response

Jupyter

IPython : 8.14.0 ipykernel : 6.23.3 ipywidgets : 8.0.6 jupyter_client : 7.4.1 jupyter_core : 5.3.1 jupyter_server : 1.24.0 jupyterlab : 3.6.5 nbclient : 0.7.4 nbconvert : 7.6.0 nbformat : 5.9.0 notebook : 6.5.4 qtconsole : 5.4.3 traitlets : 5.9.0

Software versions

>>> import numpy; print("Numpy", numpy.__version__)
Numpy 1.25.0
>>> import astropy; print("astropy", astropy.__version__)
astropy 5.3
>>> import matplotlib; print("matplotlib", matplotlib.__version__)
matplotlib 3.7.1
>>> import scipy; print("scipy", scipy.__version__)
scipy 1.9.3
>>> import skimage; print("scikit-image", skimage.__version__)
scikit-image 0.21.0
>>> import asdf; print("asdf", asdf.__version__)
asdf 2.15.0
>>> import stdatamodels; print("stdatamodels", stdatamodels.__version__)
stdatamodels 1.7.0
>>> import gwcs; print("gwcs", gwcs.__version__)
gwcs 0.18.3
>>> import regions; print("regions", regions.__version__)
regions 0.7
>>> import specutils; print("specutils", specutils.__version__)
specutils 1.11.0
>>> import specreduce; print("specreduce", specreduce.__version__)
specreduce 1.3.0
>>> import photutils; print("photutils", photutils.__version__)
photutils 1.8.0
>>> import astroquery; print("astroquery", astroquery.__version__)
astroquery 0.4.6
>>> import yaml; print("pyyaml", yaml.__version__)
pyyaml 6.0
>>> import asteval; print("asteval", asteval.__version__)
asteval 0.9.30
>>> import idna; print("idna", idna.__version__)
idna 3.4
>>> import traitlets; print("traitlets", traitlets.__version__)
traitlets 5.9.0
>>> import bqplot; print("bqplot", bqplot.__version__)
bqplot 0.12.39
>>> import bqplot_image_gl; print("bqplot-image-gl", bqplot_image_gl.__version__)
bqplot-image-gl 1.4.11
>>> import glue; print("glue-core", glue.__version__)
glue-core 1.12.0
>>> import glue_jupyter; print("glue-jupyter", glue_jupyter.__version__)
glue-jupyter 0.17.0
>>> import glue_astronomy; print("glue-astronomy", glue_astronomy.__version__)
glue-astronomy 0.10.0
>>> import echo; print("echo", echo.__version__)
echo 0.8.0
>>> import ipyvue; print("ipyvue", ipyvue.__version__)
ipyvue 1.9.2
>>> import ipyvuetify; print("ipyvuetify", ipyvuetify.__version__)
ipyvuetify 1.8.10
>>> import ipysplitpanes; print("ipysplitpanes", ipysplitpanes.__version__)
ipysplitpanes 0.2.0
>>> import ipygoldenlayout; print("ipygoldenlayout", ipygoldenlayout.__version__)
ipygoldenlayout 0.4.0
>>> import jinja2; print("Jinja2", jinja2.__version__)
Jinja2 3.1.2
>>> import voila; print("voila", voila.__version__)
voila 0.4.1
>>> import vispy; print("vispy", vispy.__version__)
vispy 0.13.0
>>> import sidecar; print("sidecar", sidecar.__version__)
sidecar 0.5.2
>>> import jdaviz; print("Jdaviz", jdaviz.__version__)
Jdaviz 3.5.0

🐱

eteq avatar Jul 31 '23 17:07 eteq

Oh and may or may not be related, but I notice that if I do

for l in v.layers:
    if hasattr(l, 'ImageLayer'):
        l.view.stretch = 'arcsinh'
        l.state.percentile = 99.5

on the hidden viewer, it silently proceeds but the stretch is not updated. I can make a separate issue for that if it's a different though though.

eteq avatar Jul 31 '23 17:07 eteq

The original traceback suggests that abs(x_max - x_min) is somehow zero. 🤔

pllim avatar Aug 01 '23 23:08 pllim

If I understood this correct, it is not that the viewer is hidden as much as it has not finished initializing yet. I am not sure if there is any sane way to make this work the way you want it to work. To some degree, this is a visualization tool, so you have to visualize it first before doing the next step. Would asking you to put in a time.sleep(...) command be a reasonable solution here?

pllim avatar Aug 01 '23 23:08 pllim

If I understood this correct, it is not that the viewer is hidden as much as it has not finished initializing yet.

From a different scenario (calling reset_limits or trying to export the plot programmatically from the API), we have been brainstorming how to make viz.show() blocking until the app is fully rendered, or perhaps having some accessible boolean property for when things are currently in "loading state", so that you could sit in a while loop until its fully initialized. It sounds like those ideas might be applicable to this use-case as well?

kecnry avatar Aug 01 '23 23:08 kecnry