holoviz / hvplot

A high-level plotting API for pandas, dask, xarray, and networkx built on HoloViews
https://hvplot.holoviz.org
BSD 3-Clause "New" or "Revised" License
1.08k stars 105 forks source link

Zoom reset when the slider of an Image is moved #667

Open maximlt opened 2 years ago

maximlt commented 2 years ago

When an image has sliders, moving the sliders when zoomed in resets the zoom to the initial view.

import xarray as xr
import holoviews as hv
import hvplot.xarray

ds = xr.tutorial.open_dataset('air_temperature')
hvplot_dn_image = ds.hvplot('lon', 'lat')
hvplot_dn_image

This does not happen with this piece of code using Holoviews directly, i.e. the zoom is not changed when zoomed in and the slider is moved.

hvds = hv.Dataset(ds)
hv_dn_image = hvds.to(hv.Image, kdims=['lon', 'lat'], dynamic=True)
hv_dn_image

hvplot_zoom

ZZMitch commented 1 year ago

Hello,

Is there an equivalent way to work around this bug if the Image is RGB (https://hvplot.holoviz.org/reference/xarray/rgb.html)? For example, I have an image time-series visualized with hvplot.rgb and the zoom resets when image slider for time is moved.

    tsPlot = imgCube.hvplot.rgb(x = 'x', 
                                y = 'y', 
                                bands = 'band', 
                                data_aspect = 1, 
                                frame_width = 600,
                                yaxis = None,
                                xaxis = None).opts(tools = ['crosshair'])

This works great (imgCube is an xarray.DataArray with 3 bands and various number of steps in time/x/y dimensions) and displays within a second or two even for large/long time-series - the only issue I have is with the zoom resetting described in this Issue.

I could not work out an equivalent set up to your second example with dataset.to(hv.Image ...) using hv.RGB instead. I found this example (https://stackoverflow.com/questions/60613662/holoviews-how-to-wrap-multiple-rgb-images-into-a-dataset-and-display-them-corre) that could work in theory, but it is very slow if the time-series has hundreds of images.

Thanks for your great work on this package!

hoxbro commented 1 year ago

To not update the axis in the original example, you can set

In the original example, the reset can be stopped by .opts(framewise=False). I would assume that would also be the case for RGB.

https://user-images.githubusercontent.com/19758978/233304871-30d5c422-4e11-4317-9918-7e213b508781.mp4

ZZMitch commented 1 year ago

That worked great, thanks for the quick response!

iuryt commented 11 months ago

Is this really a bug? Maybe setting up framewise = False by default would solve it?

Evidlo commented 10 months ago

This is not working for me, though the API I'm using is slightly different:

#!/usr/bin/env python3
# Very basic test with hvplot and fake data

import panel as pn
import xarray as xr
import hvplot.xarray
import hvplot
import numpy as np
import holoviews as hv

shape = (20, 100, 100)
dst = xr.Dataset(
    {
        'image': (['time', 'x', 'y'], np.random.random((5, 10, 10))),
        'profile': (['time', 'r'], np.random.random((5, 10)))
    },
    coords={
        'time': np.arange(5),
        'x': np.arange(10),
        'y': np.arange(10),
        'r': np.arange(10),
    }
)

slider = pn.widgets.DiscreteSlider(name='Time', options=list(dst.time.data))

im = dst.image.interactive.isel(time=slider).hvplot.image(
    colorbar=True,
    data_aspect=1
).opts(framewise=False)
li = dst.profile.interactive.isel(time=slider).hvplot.line(
    x='r'
)

row = pn.Row(im.panel(), li.panel())
app = pn.Column(im.widgets(), row)
app.show()

out