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
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

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
