Throttling, `pn.bind` and using button to reset values

I want to have some sliders, and a button that resets them to default values. Currently the code looks like this:

xrange_slider = pn.widgets.RangeSlider(
    name='X Range Slider', start=-10, end=+10, value=(-3, +3), step=0.01)
yrange_slider = pn.widgets.RangeSlider(
    name='Y Range Slider', start=-10, end=+10, value=(-3, +3), step=0.01)

def reset_range_sliders(_event):
    xrange_slider.value = (-3, +3)
    yrange_slider.value = (-3, +3)

reset_button = pn.widgets.Button(
    name='Reset ranges',
    button_type='primary',
    on_click=reset_range_sliders,
)

bound_plot = pn.bind(
    plot, xrange_slider, yrange_slider
)

The problem is that when I move sliders, I get not one, but a few (lagged) updates.

However, when I tried to follow the recommendation in Enable Throttling subsection in _ Improve the Performance_ How-To, namely when I change the definition of bound_plot to the following:

bound_plot = pn.bind(
    plot, xrange_slider.param.value_throttled, yrange_slider.param.value_throttled
)

I got much smoother updates… but the reset_button stopped working, and I was not able to enable it, and make it work again.

Could you please tell me how to force redraw of a specific panel.param.ParamFunction?

I tried to use template.main[1].param.trigger('object') inside on_click function for reset_button, but it did not work. This is different to the Is there a way to update value_throttled in slider through code/programmatically?, where setting value made it work.

By the way, if it matters, the plot function in question returns pn.pane.Matplotlib.

Panel 1.5.2

Few suggestions:

  1. try using throttled=True
  2. if using value_throttled, maybe you can set xrange_slider.value_throttled = (-3, 3) if it complains about constant, use param.edit_constant maybe

To redraw, I think you can simply trigger one of the dependent widgets
xrange_slider.param.trigger("value")

If you can provide a fully copy/pastable/runnable example I can test

Thanks for suggestions, but so far I couldn’t get them to work:

  1. Where I should pass throttled=True? I cannot pass it as parameter to the widget.
  2. I get the TypeError: Constant parameter 'value_throttled' cannot be modified error
    • I don’t know where to put param.edit_constant; I have tried both xrange_slider.param.edit_constant = True and pn.param.edit_constant = True, and neither works; neither silences the error.
  3. Using xrange_slider.param.trigger("value") and xrange_slider.param.trigger("value_throttled") both do not make it work as intended - the rest button just resets the state of the widget, but does not redraw the plot / re-run the bound function, which uses xrange_slider.param.throttled_value (in place of xrange_slider or xrange_slider.value).

Here is the whole (non-minified) example:

import numpy as np
import panel as pn
from matplotlib.figure import Figure
from matplotlib import cm

pn.extension('ipywidgets', design="material", sizing_mode="stretch_width")

def plot_streamplot(xrange, yrange):
    xmin, xmax = xrange
    ymin, ymax = yrange
    Y, X = np.mgrid[ymin:ymax:100j, xmin:xmax:100j]
    U = -1 - X**2 + Y
    V = 1 + X - Y**2

    fig = Figure(figsize=(4, 3))
    ax = fig.subplots()

    strm = ax.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=cm.autumn)
    fig.colorbar(strm.lines)

    mpl_pane = pn.pane.Matplotlib(fig, dpi=144)
    return mpl_pane

xrange_slider = pn.widgets.RangeSlider(
    name='X Range Slider', start=-10, end=+10, value=(-3, +3), step=0.01)
yrange_slider = pn.widgets.RangeSlider(
    name='Y Range Slider', start=-10, end=+10, value=(-3, +3), step=0.01)

def reset_range_sliders(_event):
    xrange_slider.value = (-3, +3)
    yrange_slider.value = (-3, +3)

    #xrange_slider.value_throttled = (-3, +3)
    #yrange_slider.value_throttled = (-3, +3)

    xrange_slider.param.trigger("value")
    yrange_slider.param.trigger("value")
    xrange_slider.param.trigger("value_throttled")
    yrange_slider.param.trigger("value_throttled")

reset_button = pn.widgets.Button(
    name='Reset ranges',
    button_type='primary',
    on_click=reset_range_sliders,
)

bound_plot_streamplot = pn.bind(
    plot_streamplot, xrange_slider.param.value_throttled, yrange_slider.param.value_throttled
)

# Instantiate the template with widgets displayed in the sidebar
template = pn.template.EditableTemplate(
    editable=True,
    title='Matplotlib Streamlines demo (EditableTemplate)',
    sidebar=[
        xrange_slider, 
        yrange_slider, 
        reset_button
    ],
)
# Append a layout to the main area, to demonstrate the list-like API
template.main.extend([
    bound_plot_streamplot
])

template.servable();

You can use param.edit_constant context manager to reset .value_throttled. The below works for me:

import numpy as np
import panel as pn
from matplotlib.figure import Figure
from matplotlib import cm
import param

pn.extension(sizing_mode="stretch_width")


def plot_streamplot(xrange, yrange):
    xmin, xmax = xrange
    ymin, ymax = yrange
    Y, X = np.mgrid[ymin:ymax:100j, xmin:xmax:100j]
    U = -1 - X**2 + Y
    V = 1 + X - Y**2

    fig = Figure(figsize=(4, 3))
    ax = fig.subplots()

    strm = ax.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=cm.autumn)
    fig.colorbar(strm.lines)

    mpl_pane = pn.pane.Matplotlib(fig, dpi=144)
    return mpl_pane


xrange_slider = pn.widgets.RangeSlider(
    name="X Range Slider", start=-10, end=+10, value=(-3, +3), step=0.01
)
yrange_slider = pn.widgets.RangeSlider(
    name="Y Range Slider", start=-10, end=+10, value=(-3, +3), step=0.01
)


def reset_range_sliders(_event):
    with param.edit_constant(xrange_slider):
        xrange_slider.value_throttled = xrange_slider.value = (-3, +3)
    with param.edit_constant(yrange_slider):
        yrange_slider.value_throttled = yrange_slider.value = (-3, +3)


reset_button = pn.widgets.Button(
    name="Reset ranges",
    button_type="primary",
    on_click=reset_range_sliders,
    margin=(20,10)
)

bound_plot_streamplot = pn.bind(
    plot_streamplot,
    xrange_slider.param.value_throttled,
    yrange_slider.param.value_throttled,
)

# Instantiate the template with widgets displayed in the sidebar
pn.template.EditableTemplate(
    editable=True,
    title="Matplotlib Streamlines demo (EditableTemplate)",
    sidebar=[xrange_slider, yrange_slider, reset_button],
    main=[bound_plot_streamplot],
).servable()

Try it on PY.CAFE

1 Like

An alternative is to set pn.extension(..., throttled=True) as below and bind to .value parameters:

import numpy as np
import panel as pn
from matplotlib.figure import Figure
from matplotlib import cm
import param

pn.extension(sizing_mode="stretch_width", throttled=True)


def plot_streamplot(xrange, yrange):
    xmin, xmax = xrange
    ymin, ymax = yrange
    Y, X = np.mgrid[ymin:ymax:100j, xmin:xmax:100j]
    U = -1 - X**2 + Y
    V = 1 + X - Y**2

    fig = Figure(figsize=(4, 3))
    ax = fig.subplots()

    strm = ax.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=cm.autumn)
    fig.colorbar(strm.lines)

    mpl_pane = pn.pane.Matplotlib(fig, dpi=144)
    return mpl_pane


xrange_slider = pn.widgets.RangeSlider(
    name="X Range Slider", start=-10, end=+10, value=(-3, +3), step=0.01
)
yrange_slider = pn.widgets.RangeSlider(
    name="Y Range Slider", start=-10, end=+10, value=(-3, +3), step=0.01
)


def reset_range_sliders(_event):
    xrange_slider.value = (-3, +3)
    yrange_slider.value = (-3, +3)


reset_button = pn.widgets.Button(
    name="Reset ranges",
    button_type="primary",
    on_click=reset_range_sliders,
    margin=(20,10)
)

bound_plot_streamplot = pn.bind(
    plot_streamplot,
    xrange_slider.param.value,
    yrange_slider.param.value,
)

# Instantiate the template with widgets displayed in the sidebar
pn.template.EditableTemplate(
    editable=True,
    title="Matplotlib Streamlines demo (EditableTemplate)",
    sidebar=[xrange_slider, yrange_slider, reset_button],
    main=[bound_plot_streamplot],
).servable()

Try on PY.CAFE

1 Like

Thanks! That works.

It is a pity that this trick (technique) is not described in Panel documentation.

This also works (and is described in Panel documentation - see last line in How-to > … > Improve the Performance > Enable Throttling