ipywidgets: How to make a double slider widget that accepts a callback for its observe method

Issue

This Content is from Stack Overflow. Question asked by nvaytet

I am trying to create an object that behaves like an ipywidget, but contains two sliders instead of a single one. This object would have a value property that would return a dict of values (one entry for each slider).

I would also like this widget to be embeddable inside other container widgets (VBox, HBox).

I can create a custom class which contains two sliders, and looks like a widget by giving it the proper _repr_mimebundle_:

import ipywidgets as ipw

class SliderWidget:
    def __init__(self):
        self._sliders = {name: ipw.IntSlider(description=name) for name in ('slider1', 'slider2')}

    def observe(self, callback, **kwargs):
        for sl in self._sliders.values():
            sl.observe(callback, **kwargs)

    @property
    def value(self):
        return {name: sl.value for name, sl in self._sliders.items()}

    @value.setter
    def value(self, val):
        for name, v in val.items():
            self._sliders[name].value = v
    
    def _repr_mimebundle_(self, include=None, exclude=None):
        return ipw.VBox(list(self._sliders.values()))._repr_mimebundle_(include=include, exclude=exclude)

which then looks as it should

enter image description here

and also works well with the observe method

def func(change):
    print(change)

sw.observe(func, names='value')

However, it cannot be embedded in other widgets, because it is not a Widget itself:

ipw.HBox([sw, sw])

TraitError: The 'children' trait of a HBox instance contains an Instance of a TypedTuple which expected a Widget, not the SliderWidget at '0x7fbb10757b20'.

To fix this, I have tried to inherit from VBox, which works nicely

class SliderWidget(ipw.VBox):
    def __init__(self):
        self._sliders = {name: ipw.IntSlider(description=name) for name in ('slider1', 'slider2')}
        super().__init__(list(self._sliders.values()))

    # def observe(self, callback, **kwargs):
    #     for sl in self._sliders.values():
    #         sl.observe(callback, **kwargs)

    @property
    def value(self):
        return {name: sl.value for name, sl in self._sliders.items()}

    @value.setter
    def value(self, val):
        for name, v in val.items():
            self._sliders[name].value = v

and can be embedded inside other widgets
enter image description here

but unfortunately, I cannot seem to get the observe to work.
If I uncomment the overriding of the observe method, I get this error upon creating the widget:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [68], in <cell line: 1>()
----> 1 sw = SliderWidget()
      2 sw

File ~/software/miniconda3/envs/mini/lib/python3.9/site-packages/traitlets/traitlets.py:1183, in HasDescriptors.__new__(*args, **kwargs)
   1181 else:
   1182     inst = new_meth(cls, *args, **kwargs)
-> 1183 inst.setup_instance(*args, **kwargs)
   1184 return inst

File ~/software/miniconda3/envs/mini/lib/python3.9/site-packages/traitlets/traitlets.py:1224, in HasTraits.setup_instance(*args, **kwargs)
   1222 self._trait_validators = {}
   1223 self._cross_validation_lock = False
-> 1224 super(HasTraits, self).setup_instance(*args, **kwargs)

File ~/software/miniconda3/envs/mini/lib/python3.9/site-packages/traitlets/traitlets.py:1206, in HasDescriptors.setup_instance(*args, **kwargs)
   1204 else:
   1205     if isinstance(value, BaseDescriptor):
-> 1206         value.instance_init(self)

File ~/software/miniconda3/envs/mini/lib/python3.9/site-packages/traitlets/traitlets.py:1148, in ObserveHandler.instance_init(self, inst)
   1147 def instance_init(self, inst):
-> 1148     inst.observe(self, self.trait_names, type=self.type)

TypeError: observe() takes 2 positional arguments but 3 were given



Solution

This question is not yet answered, be the first one who answer using the comment. Later the confirmed answer will be published as the solution.

This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?