Zoom in FigureWidget goes to wrong region

There seems to be an offset on some parts of the image while others are fine. I guess it has something to do with how jupyter lays out the objects and how the mouse position is recorded

com-video-to-gif

Minimal Viable code

import plotly, ipywidgets
print('PLOTLY', plotly.__version__)
print('IPW', ipywidgets.__version__)
import plotly.graph_objs as go
fig = go.FigureWidget()
fig.layout.xaxis.visible = False
fig.layout.xaxis.range = [0, 1600]
fig.layout.yaxis.visible = False
fig.layout.yaxis.range = [0, 900]
fig.layout.width = 512
image_dict = dict(x=0,sizex=1600,
     y=900,sizey=900,
    xref="x",
    yref="y",
    opacity=1.0,
    layer="below",
    source='https://res.cloudinary.com/active-bridge/image/upload/slide1.jpg')
fig.layout.images = [image_dict]
fig

On versions PLOTLY 3.1.1 and IPW 7.2.1

Real example

https://mybinder.org/v2/gh/chestrays/jupyanno/plotly-viewer?urlpath=%2Fmuapps%2Frandom_forum%2Fanno_app.ipynb

The associated notebook and code are here: https://github.com/chestrays/jupyanno/blob/32e7781a8dbd84a3554210043440b072b8e33ffa/anno_app.ipynb

Hi @KevinM,

Wow, this is a really awesome example :slightly_smiling_face:

To get consistent zooming behavior on images you need to set the image.sizing property to stretch. This will resize the image to exactly fit into the sizex by sizey area of the initial plot. Here are a few more tips that might be helpful for your use case.

  1. Set image.sizing to 'stretch' (as stated above)
  2. Set all of the layout margins of the figure to zero. This way the layout width/height will exactly match the resulting image width height. Otherwise you’ll get some aspect ratio distortion.
  3. Add a scatter trace with two points, positioned on opposite corners of the image, with opacity 0 so they’re not visible. This will give the autosize logic something to work with, so the Autoscale button will work to reset the zoom.
  4. Set layout.yaxis.scaleanchor to 'x'. This will constrain the zoom tool to preserve the aspect ratio, which I expect would be desirable when looking at medical imaging :slightly_smiling_face:

Here’s an update to your example with 1-4.

import plotly, ipywidgets
print('PLOTLY', plotly.__version__)
print('IPW', ipywidgets.__version__)
import plotly.graph_objs as go

img_width = 1600
img_height = 900
scale_factor = 0.5

fig = go.FigureWidget(data=[{
    'x': [0, img_width*scale_factor], 
    'y': [0, img_height*scale_factor], 
    'mode': 'markers',
    'marker': {'opacity': 0}}])

fig.layout.xaxis.visible = False
fig.layout.xaxis.range = [0, img_width*scale_factor]
fig.layout.yaxis.visible = False
fig.layout.yaxis.range = [0, img_height*scale_factor]
fig.layout.yaxis.scaleanchor = 'x'
fig.layout.width = img_width*scale_factor
fig.layout.margin = {'l': 0, 'r': 0, 't': 0, 'b': 0}
fig.layout.height = img_height*scale_factor
image_dict = dict(
    x=0,
    sizex=img_width*scale_factor,
    y=img_height*scale_factor,sizey=img_height*scale_factor,
    xref="x",
    yref="y",
    opacity=1.0,
    layer="below",
    sizing="stretch",
    source='https://res.cloudinary.com/active-bridge/image/upload/slide1.jpg')
fig.layout.images = [image_dict]
fig

Hope that help!
-Jon

3 Likes

Awesome! It works much better now! Thanks! https://mybinder.org/v2/gh/chestrays/jupyanno/master?urlpath=%2Fmuapps%2Frandom_forumer%2Fanno_app.ipynb

1 Like