<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Index - Back - Next
Widget Events
Special events
The Button is not used to represent a data type.  Instead the button widget is used to handle mouse clicks.  The on_click method of the Button can be used to register function to be called when the button is clicked.  The doc string of the on_click can be seen below.
Step1:  Example
Since button clicks are stateless, they are transmitted from the front-end to the back-end using custom messages.  By using the on_click method, a button that prints a message when it has been clicked is shown below. To capture prints (or any other kind of output) and ensure it is displayed, be sure to send it to an Output widget (or put the information you want to display into an HTML widget).
Step2:  Traitlet events
Widget properties are IPython traitlets and traitlets are eventful.  To handle  changes, the observe method of the widget can be used to register a callback.  The doc string for observe can be seen below.
Step3:  Signatures
Mentioned in the doc string, the callback registered must have the signature handler(change) where change is a dictionary holding the information about the change. 
Using this method, an example of how to output an IntSlider's value as it is changed can be seen below.
Step4:  Linking Widgets
Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. 
Linking traitlets attributes in the kernel
The first method is to use the link and dlink functions from the traitlets module (these two functions are re-exported by the ipywidgets module for convenience). This only works if we are interacting with a live kernel.
Step5:  Function traitlets.link and traitlets.dlink return a Link or DLink object. The link can be broken by calling the unlink method.
Step6:  Registering callbacks to trait changes in the kernel
Since attributes of widgets on the Python side are traitlets, you can register handlers to the change events whenever the model gets updates from the front-end.
The handler passed to observe will be called with one change argument. The change object holds at least a type key and a name key, corresponding respectively to the type of notification and the name of the attribute that triggered the notification.
Other keys may be passed depending on the value of type. In the case where type is change, we also have the following keys
Step7:  Linking widgets attributes from the client side
When synchronizing traitlets attributes, you may experience a lag because of the latency due to the roundtrip to the server side. You can also directly link widget attributes in the browser using the link widgets, in either a unidirectional or a bidirectional fashion.
Javascript links persist when embedding widgets in html web pages without a kernel.
Step8:  Function widgets.jslink returns a Link widget. The link can be broken by calling the unlink method.
Step9:  The difference between linking in the kernel and linking in the client
Linking in the kernel means linking via python. If two sliders are linked in the kernel, when one slider is changed the browser sends a message to the kernel (python in this case) updating the changed slider, the link widget in the kernel then propagates the change to the other slider object in the kernel, and then the other slider's kernel object sends a message to the browser to update the other slider's views in the browser. If the kernel is not running (as in a static web page), then the controls will not be linked.
Linking using jslink (i.e., on the browser side) means contructing the link in Javascript. When one slider is changed, Javascript running in the browser changes the value of the other slider in the browser, without needing to communicate with the kernel at all. If the sliders are attached to kernel objects, each slider will update their kernel-side objects independently.
To see the difference between the two, go to the static version of this page in the ipywidgets documentation and try out the sliders near the bottom. The ones linked in the kernel with link and dlink are no longer linked, but the ones linked in the browser with jslink and jsdlink are still linked.
Continuous updates
Some widgets offer a choice with their continuous_update attribute between continually updating values or only updating values when a user submits the value (for example, by pressing Enter or navigating away from the control). In the next example, we see the "Delayed" controls only transmit their value after the user finishes dragging the slider or submitting the textbox. The "Continuous" controls continually transmit their values as they are changed. Try typing a two-digit number into each of the text boxes, or dragging each of the sliders, to see the difference.
Step11:  Sliders, Text, and Textarea controls default to continuous_update=True. IntText and other text boxes for entering integer or float numbers default to continuous_update=False (since often you'll want to type an entire number before submitting the value by pressing enter or navigating out of the box).
Debouncing
When trait changes trigger a callback that performs a heavy computation, you may want to not do the computation as often as the value is updated. For instance, if the trait is driven by a slider which has its continuous_update set to True, the user will trigger a bunch of computations in rapid succession.
Debouncing solves this problem by delaying callback execution until the value has not changed for a certain time, after which the callback is called with the latest value. The effect is that the callback is only called when the trait pauses changing for a certain amount of time.
Debouncing can be implemented using an asynchronous loop or threads. We show an asynchronous solution below, which is more suited for ipywidgets. If you would like to instead use threads to do the debouncing, replace the Timer class with from threading import Timer.
Step12:  Here is how we use the debounce function as a decorator. Try changing the value of the slider. The text box will only update after the slider has paused for about 0.2 seconds.
Step14:  Throttling
Throttling is another technique that can be used to limit callbacks. Whereas debouncing ignores calls to a function if a certain amount of time has not passed since the last (attempt of) call to the function, throttling will just limit the rate of calls. This ensures that the function is regularly called.
We show an synchronous solution below. Likewise, you can replace the Timer class with from threading import Timer if you want to use threads instead of asynchronous programming.
Step15:  To see how different it behaves compared to the debouncer, here is the same slider example with its throttled value displayed in the text box. Notice how much more interactive it is, while still limiting the callback rate.
<ASSISTANT_TASK:>
Python Code:
import ipywidgets as widgets
print(widgets.Button.on_click.__doc__)
Explanation: Index - Back - Next
Widget Events
Special events
The Button is not used to represent a data type.  Instead the button widget is used to handle mouse clicks.  The on_click method of the Button can be used to register function to be called when the button is clicked.  The doc string of the on_click can be seen below.
End of explanation
from IPython.display import display
button = widgets.Button(description="Click Me!")
output = widgets.Output()
display(button, output)
def on_button_clicked(b):
    with output:
        print("Button clicked.")
button.on_click(on_button_clicked)
Explanation: Example
Since button clicks are stateless, they are transmitted from the front-end to the back-end using custom messages.  By using the on_click method, a button that prints a message when it has been clicked is shown below. To capture prints (or any other kind of output) and ensure it is displayed, be sure to send it to an Output widget (or put the information you want to display into an HTML widget).
End of explanation
print(widgets.Widget.observe.__doc__)
Explanation: Traitlet events
Widget properties are IPython traitlets and traitlets are eventful.  To handle  changes, the observe method of the widget can be used to register a callback.  The doc string for observe can be seen below.
End of explanation
int_range = widgets.IntSlider()
output2 = widgets.Output()
display(int_range, output2)
def on_value_change(change):
    with output2:
        print(change['new'])
int_range.observe(on_value_change, names='value')
Explanation: Signatures
Mentioned in the doc string, the callback registered must have the signature handler(change) where change is a dictionary holding the information about the change. 
Using this method, an example of how to output an IntSlider's value as it is changed can be seen below.
End of explanation
caption = widgets.Label(value='The values of slider1 and slider2 are synchronized')
sliders1, slider2 = widgets.IntSlider(description='Slider 1'),\
                    widgets.IntSlider(description='Slider 2')
l = widgets.link((sliders1, 'value'), (slider2, 'value'))
display(caption, sliders1, slider2)
caption = widgets.Label(value='Changes in source values are reflected in target1')
source, target1 = widgets.IntSlider(description='Source'),\
                  widgets.IntSlider(description='Target 1')
dl = widgets.dlink((source, 'value'), (target1, 'value'))
display(caption, source, target1)
Explanation: Linking Widgets
Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. 
Linking traitlets attributes in the kernel
The first method is to use the link and dlink functions from the traitlets module (these two functions are re-exported by the ipywidgets module for convenience). This only works if we are interacting with a live kernel.
End of explanation
l.unlink()
dl.unlink()
Explanation: Function traitlets.link and traitlets.dlink return a Link or DLink object. The link can be broken by calling the unlink method.
End of explanation
caption = widgets.Label(value='The values of range1 and range2 are synchronized')
slider = widgets.IntSlider(min=-5, max=5, value=1, description='Slider')
def handle_slider_change(change):
    caption.value = 'The slider value is ' + (
        'negative' if change.new < 0 else 'nonnegative'
    )
slider.observe(handle_slider_change, names='value')
display(caption, slider)
Explanation: Registering callbacks to trait changes in the kernel
Since attributes of widgets on the Python side are traitlets, you can register handlers to the change events whenever the model gets updates from the front-end.
The handler passed to observe will be called with one change argument. The change object holds at least a type key and a name key, corresponding respectively to the type of notification and the name of the attribute that triggered the notification.
Other keys may be passed depending on the value of type. In the case where type is change, we also have the following keys:
owner : the HasTraits instance
old : the old value of the modified trait attribute
new : the new value of the modified trait attribute
name : the name of the modified trait attribute.
End of explanation
caption = widgets.Label(value='The values of range1 and range2 are synchronized')
range1, range2 = widgets.IntSlider(description='Range 1'),\
                 widgets.IntSlider(description='Range 2')
l = widgets.jslink((range1, 'value'), (range2, 'value'))
display(caption, range1, range2)
caption = widgets.Label(value='Changes in source_range values are reflected in target_range1')
source_range, target_range1 = widgets.IntSlider(description='Source range'),\
                              widgets.IntSlider(description='Target range 1')
dl = widgets.jsdlink((source_range, 'value'), (target_range1, 'value'))
display(caption, source_range, target_range1)
Explanation: Linking widgets attributes from the client side
When synchronizing traitlets attributes, you may experience a lag because of the latency due to the roundtrip to the server side. You can also directly link widget attributes in the browser using the link widgets, in either a unidirectional or a bidirectional fashion.
Javascript links persist when embedding widgets in html web pages without a kernel.
End of explanation
# l.unlink()
# dl.unlink()
Explanation: Function widgets.jslink returns a Link widget. The link can be broken by calling the unlink method.
End of explanation
a = widgets.IntSlider(description="Delayed", continuous_update=False)
b = widgets.IntText(description="Delayed", continuous_update=False)
c = widgets.IntSlider(description="Continuous", continuous_update=True)
d = widgets.IntText(description="Continuous", continuous_update=True)
widgets.link((a, 'value'), (b, 'value'))
widgets.link((a, 'value'), (c, 'value'))
widgets.link((a, 'value'), (d, 'value'))
widgets.VBox([a,b,c,d])
Explanation: The difference between linking in the kernel and linking in the client
Linking in the kernel means linking via python. If two sliders are linked in the kernel, when one slider is changed the browser sends a message to the kernel (python in this case) updating the changed slider, the link widget in the kernel then propagates the change to the other slider object in the kernel, and then the other slider's kernel object sends a message to the browser to update the other slider's views in the browser. If the kernel is not running (as in a static web page), then the controls will not be linked.
Linking using jslink (i.e., on the browser side) means contructing the link in Javascript. When one slider is changed, Javascript running in the browser changes the value of the other slider in the browser, without needing to communicate with the kernel at all. If the sliders are attached to kernel objects, each slider will update their kernel-side objects independently.
To see the difference between the two, go to the static version of this page in the ipywidgets documentation and try out the sliders near the bottom. The ones linked in the kernel with link and dlink are no longer linked, but the ones linked in the browser with jslink and jsdlink are still linked.
Continuous updates
Some widgets offer a choice with their continuous_update attribute between continually updating values or only updating values when a user submits the value (for example, by pressing Enter or navigating away from the control). In the next example, we see the "Delayed" controls only transmit their value after the user finishes dragging the slider or submitting the textbox. The "Continuous" controls continually transmit their values as they are changed. Try typing a two-digit number into each of the text boxes, or dragging each of the sliders, to see the difference.
End of explanation
import asyncio
class Timer:
    def __init__(self, timeout, callback):
        self._timeout = timeout
        self._callback = callback
        self._task = asyncio.ensure_future(self._job())
    async def _job(self):
        await asyncio.sleep(self._timeout)
        self._callback()
    def cancel(self):
        self._task.cancel()
def debounce(wait):
     Decorator that will postpone a function's
        execution until after `wait` seconds
        have elapsed since the last time it was invoked. 
    def decorator(fn):
        timer = None
        def debounced(*args, **kwargs):
            nonlocal timer
            def call_it():
                fn(*args, **kwargs)
            if timer is not None:
                timer.cancel()
            timer = Timer(wait, call_it)
        return debounced
    return decorator
Explanation: Sliders, Text, and Textarea controls default to continuous_update=True. IntText and other text boxes for entering integer or float numbers default to continuous_update=False (since often you'll want to type an entire number before submitting the value by pressing enter or navigating out of the box).
Debouncing
When trait changes trigger a callback that performs a heavy computation, you may want to not do the computation as often as the value is updated. For instance, if the trait is driven by a slider which has its continuous_update set to True, the user will trigger a bunch of computations in rapid succession.
Debouncing solves this problem by delaying callback execution until the value has not changed for a certain time, after which the callback is called with the latest value. The effect is that the callback is only called when the trait pauses changing for a certain amount of time.
Debouncing can be implemented using an asynchronous loop or threads. We show an asynchronous solution below, which is more suited for ipywidgets. If you would like to instead use threads to do the debouncing, replace the Timer class with from threading import Timer.
End of explanation
slider = widgets.IntSlider()
text = widgets.IntText()
@debounce(0.2)
def value_changed(change):
    text.value = change.new
slider.observe(value_changed, 'value')
widgets.VBox([slider, text])
Explanation: Here is how we use the debounce function as a decorator. Try changing the value of the slider. The text box will only update after the slider has paused for about 0.2 seconds.
End of explanation
import asyncio
from time import time
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 = False
        new_args, new_kwargs = None, None
        def throttled(*args, **kwargs):
            nonlocal new_args, new_kwargs, time_of_last_call, scheduled
            def call_it():
                nonlocal new_args, new_kwargs, time_of_last_call, scheduled
                time_of_last_call = time()
                fn(*new_args, **new_kwargs)
                scheduled = False
            time_since_last_call = time() - time_of_last_call
            new_args = args
            new_kwargs = kwargs
            if not scheduled:
                new_wait = max(0, wait - time_since_last_call)
                Timer(new_wait, call_it)
                scheduled = True
        return throttled
    return decorator
Explanation: Throttling
Throttling is another technique that can be used to limit callbacks. Whereas debouncing ignores calls to a function if a certain amount of time has not passed since the last (attempt of) call to the function, throttling will just limit the rate of calls. This ensures that the function is regularly called.
We show an synchronous solution below. Likewise, you can replace the Timer class with from threading import Timer if you want to use threads instead of asynchronous programming.
End of explanation
slider = widgets.IntSlider()
text = widgets.IntText()
@throttle(0.2)
def value_changed(change):
    text.value = change.new
slider.observe(value_changed, 'value')
widgets.VBox([slider, text])
Explanation: To see how different it behaves compared to the debouncer, here is the same slider example with its throttled value displayed in the text box. Notice how much more interactive it is, while still limiting the callback rate.
End of explanation
<END_TASK>