Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking ipython widget button and slider values

I'm trying to figure out how to link the value of a counter controlled by button widgets to the value of a slider widget.

The goal here is use ipython widgets to create a simple "vcr-like" interface with three widgets: an IntSlider and two Buttons that increment a counter and decrement a counter. This is what I've got:

import ipywidgets as widgets
from functools import partial
from IPython.display import display
import traitlets

class Counter:
   def __init__(self, initial=0):
      self.value = initial

   def increment(self, amount=1):
      self.value += amount
      return self.value

def button_plus(counter, w):
    counter.increment(+1)  

def button_minus(counter, w):
    counter.increment(-1) 

counter = Counter()
# 1 step forward button
wplus = widgets.Button(description='>')
wplus.on_click(partial(button_plus, counter))
# 1 step backward button
wminus = widgets.Button(description='<')
wminus.on_click(partial(button_minus, counter))
# integer slider
wpick = widgets.IntSlider(value=0,min=0,max=10,step=1,description="time step")

display(wminus, wpick, wplus)

print(counter.value)
print(wpick.value)

and here's a screen grab where I've moved the IntSlider to 1 and clicked twice on the increment button: enter image description here

I'd obviously like there to be a single integer value being controlled by and be in sync with all 3 widgets.

I read about widget linking but I don't see how to do this since my button widgets don't have a value -- the counter object has the value I want to link.

This doesn't work:

l = traitlets.link((counter, 'value'), (wpick, 'value'))

because counter is not HasTraits.

How can I get counter.value to be linked to wpick.value so that clicking on one of the buttons will adjust the int on the slider?

like image 412
Rich Signell Avatar asked Feb 06 '26 11:02

Rich Signell


1 Answers

Following this guide, you need the Counter class to inheret from the DOMWidget class like this:

from traitlets import CInt, link
class Counter(widgets.DOMWidget):
    value = CInt(0, sync=True)

You can then define your counter widget and button callback methods:

counter = Counter()
def button_plus(name):
    counter.value += 1 if counter.value < 10 else 0
def button_minus(name):
    counter.value -= 1 if counter.value > 0 else 0

link the slider and counter widgets:

link((wpick, 'value'), (counter, 'value'))

and register the events on the buttons:

wplus.on_click(button_plus)
wminus.on_click(button_minus)

Clicking the buttons will now in/decrease the value of the counter.

like image 138
nluigi Avatar answered Feb 09 '26 00:02

nluigi