Repository: ipython/ipython

Issue:
Widgets: skip intermediate callbacks during throttling
Suppose you have a slider, with a callback function (`interact`) that takes 2 seconds to display a plot (intensive calculations). If you move the slider for a few seconds, many `on_change` callbacks will be called successively. The throttle queue becomes longer and longer, the widget goes through many changes, and you have to wait dozens of seconds before the widget stops updating.

In this case, shouldn't the intermediate steps be killed _before_ they are processed, so that only the most recent callbacks in the queue stay alive?



Discussion:
Maybe it would be possible to use something like an mouse-up event instead.

I thought the design was that after 3 queued up messages or so, changes would be merged into a final queued message.  It shouldn't be queuing up _every_ change.

> I thought the design was that after 3 queued up messages or so, changes would be merged into a final queued message. It shouldn't be queuing up every change.

You're right, it does seem that only three updates occur after the end of the interaction (i.e. when I stop moving the slider). Here is the test script I used:

``` python
import time
from IPython.html import widgets
@widgets.interact(x=(0, 255))
def f(x):
    time.sleep(3)
    print(x)
```

However, when the function takes a few seconds (or more) to complete, it does seem a bit weird to see three updates during the 10 seconds that follow the end of the interaction. Maybe this arbitrary number 3 should depend on the execution duration of the function? Or could there be a single update after the end of the interaction?

> I thought the design was that after 3 queued up messages or so, changes would be merged into a final queued message. It shouldn't be queuing up every change.

@jasongrout is right, this is how it was designed to work,

There is a property of the JS widget model that allows you to change this, `this.msg_throttle = 3;`.  

Perhaps this throttle number should be exposed on the python side.

> Perhaps this throttle number should be exposed on the python side.

I was just about to say the same thing. @jdfreder is there any reason not to add `msg_throttle = Int(3, sync=True)` on the Python side?


Resolving patch:
diff --git a/IPython/html/widgets/widget.py b/IPython/html/widgets/widget.py
--- a/IPython/html/widgets/widget.py
+++ b/IPython/html/widgets/widget.py
@@ -17,7 +17,7 @@
 from IPython.core.getipython import get_ipython
 from IPython.kernel.comm import Comm
 from IPython.config import LoggingConfigurable
-from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple
+from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple, Int
 from IPython.utils.py3compat import string_types
 
 #-----------------------------------------------------------------------------
@@ -103,6 +103,8 @@ def _call_widget_constructed(widget):
     _comm = Instance('IPython.kernel.comm.Comm')
     
     closed = Bool(False)
+    msg_throttle = Int(3, sync=True, help="""Maximum number of msgs the 
+        front-end can send before receiving an idle msg from the back-end.""")
     
     keys = List()
     def _keys_default(self):


Test patch: