Limit number of callback made by DynamicMap

I have function that is expensive to calculate (takes 10 seconds on my laptop), and I want to explore a 5D parameter space using a DynamicMap. However, when moving the sliders, it look likes all intermediate values are also calculated, creating a long queue. What can I do such that only the last request parameter set is calculated (reflecting the currently displayed values on the sliders)?

Hi @vascotenner!

If your computation is expensive, the trick would be to use another widget type instead of a slider, one that would allow you to directly type in values, hence selecting exactly which parameter combination you want to visualize.

I believe a solution would be to use the HoloViews pane provided by panel. You’ll find some relevant doc here. Since panel is now a dependency of holoviews, it’s likely you have it installed already.

Here is a minimal example inspired from the HoloViews and Panel docs.

First let’s build a DynamicMap.

import numpy as np
import holoviews as hv
import panel as pn

hv.extension('bokeh')
pn.extension()

frequencies = [0.5, 0.75, 1.0, 1.25]

def sine_curve(phase, freq):
    xvals = [0.1* i for i in range(100)]
    return hv.Curve((xvals, [np.sin(phase+freq*x) for x in xvals]))

dmap = hv.DynamicMap(sine_curve, kdims=['phase', 'frequency']).redim.range(phase=(0.5,1), frequency=(0.5,1.25))
dmap

The HoloViews pane provides a way to customize the widgets you wanna use. Here I’ve used a LiteralInput widgets that accept float values only.

hv_panel = pn.pane.HoloViews(dmap, widgets={
    'phase': pn.widgets.LiteralInput(value=0.5, type=float),
    'frequency': pn.widgets.LiteralInput(value=0.5, type=float)
}).layout
hv_panel

Using .layout gives you the Row panel layout, you can see what objects it contains with hv_panel.pprint().

Row
    [0] HoloViews(DynamicMap, widgets={'phase': LiteralInput(mar...})
    [1] Column
        [0] WidgetBox
            [0] LiteralInput(margin=(20, 20, 5, 20), name='phase', type=<class 'float'>, value=0.5, width=250)
            [1] LiteralInput(margin=(5, 20, 20, 20), name='frequency', type=<class 'float'>, value=0.5, width=250)
        [1] VSpacer()

Now we have our DynamicMap object put together with LiteralInput widgets instead of sliders.

Hope this helps! :slight_smile:

Thank you for the elaborate example. This looks a lot to my current approach, where I use a jupyter code cell and adjusting the values.

I can remember from long time back (3 years?) that there was an option to limit the amount of request, but I cannot find it back anymore

Ok I think I managed to get closer to what you want. I’ve found this relevant StackOverlow question and remembered some widgets have a value_throttled parameter. You can run the toy example below in a notebook to see how it behaves. The expected behavior is that it prints the slider value as soon as you release the mouse click, that’s what triggers the callback (here print_slider_value).

import panel as pn
pn.extension()

fs = pn.widgets.FloatSlider(value=0.5)

@pn.depends(fs.param.value_throttled)
def print_slider_value(slider_value):
    return slider_value

app = pn.Column(fs, print_slider_value)
app.servable()

Now you may have to tweak your use case with the DynamicMap since that I assume the widgets you automatically get are linked (depends on) the value of the linked dimension, not their value_throttled.