How to set fine grained dependencies when setting options in the viewable function?

I am trying to construct something following the example at:

In particular the dashboard I am trying to create (semi-working version here: has a lot of elements being plotted, and I would like to avoid having to replot everything every time I change some widget. The dashboard example talks exactly about this. However, I am having some trouble if I try to set some options inside the final function (view/viewable) that plots things. The dashboard example seems to do exactly that, but I am not sure why it is not working for me (and I am not able to get the dashboard example to run on my computer to check whether the example still works with the latest versions).

Here is a minimal example:

import xarray as xr
import hvplot.xarray  # noqa
import panel as pn
import param
import holoviews as hv
from holoviews import opts
from holoviews import streams

air_ds = xr.tutorial.open_dataset('air_temperature').load()
air = air_ds.air

class LatSliderPlot(param.Parameterized):
    lat_slider = param.Range(label='Lat', 
                             bounds=(200, 330), 
                             default=(200, 220))
    def plot_image(self):
        image = hv.Image( (air.lon,, air.isel(time=0)) )

        return image 
    def viewable(self):
        img = hv.DynamicMap(self.plot_image)
        return img

test = LatSliderPlot()
          test.viewable()) # this create a non-responsive plot 
                                   # but is the suggested way in the dashboard example.

          test.viewable) # this create a responsive plot, 
                                #but replots the image everytime. 

In this toy example, I would like to be able to be change the xlim of the image without having to replot it every single time.

Could someone please help me identify what I am doing wrong? Or suggest some other examples to look at?

Thanks for mentioning the example notebook, its very useful and gave me some additional understanding. The subtelty in the the datashader example about optimizing computation on a plot is that it i not actually one plot but three separate plots in an Overlay. Specifically hv.DynamicMap(self.tiles) * dataplot * hv.DynamicMap(self.labels). While the end user sees one plot, the backend need only recompute one of the three depending on the user interaction. That said, I still think it is rerendering the entire plot, just in a computationally optimized way.

Your example is not an overlay of multiple plots, nor do you have multiple widgets that can lead to different computational intensity. There is no computational optimization to be had here. It may be possible to change the xlim on the client side with some javascript linking to avoid some of the server-client data transfer, but I think that would follow a different path than the Datashader example.

As view, a callable, vs view(), an executed function are concerned, I find the example somewhat confusing because they introduce a DynamicMap which itself acts like a callable (no parentheses). Outside of the DynamicMap, you have to pass the callable to panel if you want a plot to respond to widgets.

One thing that is not entirely clear to me is whether DynamicMap provides any performance advantages over carefully structured panel apps. It would be a shame if it did since DynamicMap is only useful in the context of holoviews backends.

The particular example above is just a minimal version of what I am trying to do. In the actual dashboard I am building, I do have multiple overlays (, and In the code above I tried to boil down the problem into something simpler - hope I did a decent job at it. It did not seem to me that the problem was coming from having or not having multiple plots being combined.

I created the particular example because it does set some parameter dependencies in the final function (viewable), and similar to the example the dependencies are not explicitly defined.

I would not know how to do anything with javascript on the client-side, since I never use it. One of the appeals of holoviz was that it was entirely pythonic, as advertised.

Maybe @jbednar or @philippjfr have something to say about the dashboard example and the other questions you raise since it is the only example I can find that tries to explain this idea of dependencies (and I have not actually been able to get the example to run on my machine).