question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Idea: Debounce and throttle options for observing traits

See original GitHub issue

Two use cases:

  1. Using interact or a slider that causes something to execute which say takes ~100 ms to complete, you don’t want events to be delivered all the time, but you may want to update it say every 250 ms, when a slider is changing value.
  2. I’m using bqplot and listening to a change in the min value of one of the axes. Only when it didn’t change for say 500msec, I expect the user to be done with zooming and panning and will start a heavy computation to rebuild the figure.

If this is done on the client side (js), this will also lead to less traffic/events.

I can imaging something like this

interact(f, x=10, throttle=250);

For the bqplot use case

scale_x.observe(f, "xmin", debounce=500)

See here for a visual explaination: http://benalman.com/projects/jquery-throttle-debounce-plugin/

throttle and debounced functions are also available in underscore

Having them in link and js(d)link could also be useful (say when a widget would make a ajax request)

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:2
  • Comments:20 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
gsteele13commented, Mar 1, 2021

(This workaround aside, I still support the incorporation of throttling directly into the interact functionality, I guess it’s a few lines of code)

1reaction
gsteele13commented, Mar 1, 2021

OK, for anyone who is interested, I found a workaround!

The solution is to code the interactivity yourself, having the sliders / controls use a throttled plot update function. The key trick to solve the flashing was to use wait=True when clearing the output widget. Here is a minimal code segment:

import ipywidgets as widgets 
import numpy as np
import matplotlib.pyplot as plt
import asyncio
from time import time

class Timer:
    def __init__(self, timeout, callback):
        self._timeout = timeout
        self._callback = callback

    async def _job(self):
        await asyncio.sleep(self._timeout)
        self._callback()

    def start(self):
        self._task = asyncio.ensure_future(self._job())

    def cancel(self):
        self._task.cancel()
        
def throttle(wait):
    """ Decorator that prevents a function from being called
        more than once every wait period. """
    def decorator(fn):
        time_of_last_call = 0
        scheduled, timer = False, None
        new_args, new_kwargs = None, None
        def throttled(*args, **kwargs):
            nonlocal new_args, new_kwargs, time_of_last_call, scheduled, timer
            def call_it():
                nonlocal new_args, new_kwargs, time_of_last_call, scheduled, timer
                time_of_last_call = time()
                fn(*new_args, **new_kwargs)
                scheduled = False
            time_since_last_call = time() - time_of_last_call
            new_args, new_kwargs = args, kwargs
            if not scheduled:
                scheduled = True
                new_wait = max(0, wait - time_since_last_call)
                timer = Timer(new_wait, call_it)
                timer.start()
        return throttled
    return decorator

x = np.linspace(0,1,100)

@throttle(0.2)
def update_plot(w):
    with out:
        # Without clear_output(), figures get appended below each other inside
        # the output widget
        # Ah ha! Got it! I need wait=True!
        out.clear_output(wait=True)
        plt.plot(x, x**p_widget.value)  
        plt.show()

out = widgets.Output(layout=widgets.Layout(height='300px'))
p_widget = widgets.FloatSlider(min=0, max=2, step=0.1, value = 1)
update_plot([])
p_widget.observe(update_plot)
display(p_widget, out)

This now no longer builds up an infinite queue of matplotlib updates! The refresh is not “instant” / video rate, but that is fine since for me it is more important that there is a visual indication of the interactivity as the slider is moved, and that when it stops moving, it goes quickly to the correct parameter. And this work at least 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Debounce and Throttle Callbacks in Vue
1. Debouncing a watcher ... Open the demo. Open the demo and type a few characters into the input. Each time you type,...
Read more >
Debouncing and Throttling Explained Through Examples
Debounce and throttle are two similar (but different!) techniques to control how many times we allow a function to be executed over time....
Read more >
Debounce and Throttle in Real Life Scenarios | by Kfir Zuberi
Debounce and throttle are recommended to use on events that fire more often than you need them to. You may have come across...
Read more >
Add event throttling and debouncing to ...
The change event fires multiple times in rapid succession, e.g., when the user's connection switches from Wi-Fi to cellular 2, so it would...
Read more >
How To Implement Debounce And Throttle In JavaScript
The reason throttle is ideal for these scenarios is that every time the delay ends you will get updated information on the event...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found