Source code for panel.widgets.widget

from __future__ import annotations

from collections.abc import Iterable, Mapping
from inspect import Parameter
from numbers import Integral, Number, Real
from typing import Any, Optional, Tuple

empty = Parameter.empty

import param

from .base import Widget
from .input import Checkbox, TextInput
from .select import Select
from .slider import DiscreteSlider, FloatSlider, IntSlider


[docs]class fixed(param.Parameterized): """ A pseudo-widget whose value is fixed and never synced to the client. """ description = param.String(default='') value = param.Parameter(doc="Any Python object") def __init__(self, value: Any, **kwargs: Any): super().__init__(value=value, **kwargs)
[docs] def get_interact_value(self): """ Return the value for this widget which should be passed to interactive functions. Custom widgets can change this method to process the raw value ``self.value``. """ return self.value
def _get_min_max_value( min: Number, max: Number, value: Optional[Number] = None, step: Optional[Number] = None ) -> Tuple[Number, Number, Number]: """Return min, max, value given input values with possible None.""" # Either min and max need to be given, or value needs to be given if value is None: if min is None or max is None: raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value)) diff = max - min value = min + (diff / 2) # Ensure that value has the same type as diff if not isinstance(value, type(diff)): value = min + (diff // 2) else: # value is not None if not isinstance(value, Real): raise TypeError('expected a real number, got: %r' % value) # Infer min/max from value if value == 0: # This gives (0, 1) of the correct type vrange = (value, value + 1) elif value > 0: vrange = (-value, 3*value) else: vrange = (3*value, -value) if min is None: min = vrange[0] if max is None: max = vrange[1] if step is not None: # ensure value is on a step tick = int((value - min) / step) value = min + tick * step if not min <= value <= max: raise ValueError('value must be between min and max (min={0}, value={1}, max={2})'.format(min, value, max)) return min, max, value def _matches(o: str, pattern: str) -> bool: """Match a pattern of types in a sequence.""" if not len(o) == len(pattern): return False comps = zip(o,pattern) return all(isinstance(obj,kind) for obj,kind in comps)
[docs]class widget(param.ParameterizedFunction): """ Attempts to find a widget appropriate for a given value. Arguments --------- name: str The name of the resulting widget. value: Any The value to deduce a widget from. default: Any The default value for the resulting widget. **params: Any Additional keyword arguments to pass to the widget. Returns ------- Widget """ def __call__(self, value: Any, name: str, default=empty, **params): """Build a ValueWidget instance given an abbreviation or Widget.""" if isinstance(value, Widget): widget = value elif isinstance(value, tuple): widget = self.widget_from_tuple(value, name, default) if default is not empty: try: widget.value = default except Exception: # ignore failure to set default pass else: # Try single value widget = self.widget_from_single_value(value, name) # Something iterable (list, dict, generator, ...). Note that str and # tuple should be handled before, that is why we check this case last. if widget is None and isinstance(value, Iterable): widget = self.widget_from_iterable(value, name) if default is not empty: try: widget.value = default except Exception: # ignore failure to set default pass if widget is None: widget = fixed(value) if params: widget.param.update(**params) return widget
[docs] @staticmethod def widget_from_single_value(o, name): """Make widgets from single values, which can be used as parameter defaults.""" if isinstance(o, str): return TextInput(value=str(o), name=name) elif isinstance(o, bool): return Checkbox(value=o, name=name) elif isinstance(o, Integral): min, max, value = _get_min_max_value(None, None, o) return IntSlider(value=o, start=min, end=max, name=name) elif isinstance(o, Real): min, max, value = _get_min_max_value(None, None, o) return FloatSlider(value=o, start=min, end=max, name=name) else: return None
[docs] @staticmethod def widget_from_tuple(o, name, default=empty): """Make widgets from a tuple abbreviation.""" int_default = (default is empty or isinstance(default, int)) if _matches(o, (Real, Real)): min, max, value = _get_min_max_value(o[0], o[1]) if all(isinstance(_, Integral) for _ in o) and int_default: cls = IntSlider else: cls = FloatSlider return cls(value=value, start=min, end=max, name=name) elif _matches(o, (Real, Real, Real)): step = o[2] if step <= 0: raise ValueError("step must be >= 0, not %r" % step) min, max, value = _get_min_max_value(o[0], o[1], step=step) if all(isinstance(_, Integral) for _ in o) and int_default: cls = IntSlider else: cls = FloatSlider return cls(value=value, start=min, end=max, step=step, name=name) elif _matches(o, (Real, Real, Real, Real)): step = o[2] if step <= 0: raise ValueError("step must be >= 0, not %r" % step) min, max, value = _get_min_max_value(o[0], o[1], value=o[3], step=step) if all(isinstance(_, Integral) for _ in o): cls = IntSlider else: cls = FloatSlider return cls(value=value, start=min, end=max, step=step, name=name) elif len(o) == 4: min, max, value = _get_min_max_value(o[0], o[1], value=o[3]) if all(isinstance(_, Integral) for _ in [o[0], o[1], o[3]]): cls = IntSlider else: cls = FloatSlider return cls(value=value, start=min, end=max, name=name)
[docs] @staticmethod def widget_from_iterable(o, name): """Make widgets from an iterable. This should not be done for a string or tuple.""" # Select expects a dict or list, so we convert an arbitrary # iterable to either of those. values = list(o.values()) if isinstance(o, Mapping) else list(o) widget_type = DiscreteSlider if all(param._is_number(v) for v in values) else Select if isinstance(o, (list, dict)): return widget_type(options=o, name=name) elif isinstance(o, Mapping): return widget_type(options=list(o.items()), name=name) else: return widget_type(options=list(o), name=name)