|
"""The FeatureInput enables a user to select from a list of features and set their values""" |
|
|
|
import panel as pn |
|
import param |
|
|
|
|
|
class FeatureInput(pn.widgets.CompositeWidget): |
|
"""The FeatureInput enables a user to select from a list of features and set their values |
|
|
|
## Example |
|
|
|
```python |
|
features = { |
|
"A": 1.0, |
|
"B": 2.0, |
|
"C": 3.0, |
|
"D": 4.0, |
|
} |
|
selected_features = ["A", "C"] |
|
widget = FeatureInput(features=features, selected_features=selected_features) |
|
``` |
|
""" |
|
|
|
value = param.Dict( |
|
doc="The names of the features selected and their set values", allow_None=False |
|
) |
|
|
|
features = param.Dict( |
|
doc="The names of the available features and their default values", |
|
allow_None=False, |
|
) |
|
selected_features = param.ListSelector( |
|
doc="The list of selected features", allow_None=False |
|
) |
|
|
|
_selected_widgets = param.ClassSelector( |
|
class_=pn.Column, doc="The widgets used to edit the selected features" |
|
) |
|
|
|
_composite_type = pn.Column |
|
|
|
def __init__(self, **params): |
|
params["value"] = params.get("value", {}) |
|
params["features"] = params.get("features", {}) |
|
params["selected_features"] = params.get("selected_features", []) |
|
|
|
params["_selected_widgets"] = self.param._selected_widgets.class_() |
|
|
|
super().__init__(**params) |
|
|
|
selected_features_widget = pn.widgets.MultiChoice.from_param( |
|
self.param.selected_features, sizing_mode="stretch_width" |
|
) |
|
|
|
self._composite[:] = [selected_features_widget, self._selected_widgets] |
|
|
|
@param.depends("features", watch=True, on_init=True) |
|
def _reset_selected_features(self): |
|
selected_features = [] |
|
for feature in self.selected_features.copy(): |
|
if feature in self.features.copy(): |
|
selected_features.append(feature) |
|
|
|
self.param.selected_features.objects = list(self.features) |
|
self.selected_features = selected_features |
|
|
|
@param.depends("selected_features", watch=True, on_init=True) |
|
def _handle_selected_features_change(self): |
|
org_value = self.value |
|
|
|
self._update_selected_widgets(org_value) |
|
self._update_value() |
|
|
|
def _update_value(self, *args): |
|
new_value = {} |
|
|
|
for widget in self._selected_widgets: |
|
new_value[widget.name] = widget.value |
|
|
|
self.value = new_value |
|
|
|
def _update_selected_widgets(self, org_value): |
|
new_widgets = {} |
|
|
|
for feature in self.selected_features: |
|
value = org_value.get(feature, self.features[feature]) |
|
widget = self._new_widget(feature, value) |
|
new_widgets[feature] = widget |
|
|
|
self._selected_widgets[:] = list(new_widgets.values()) |
|
|
|
def _new_widget(self, feature, value): |
|
widget = pn.widgets.FloatInput( |
|
name=feature, value=value, sizing_mode="stretch_width" |
|
) |
|
pn.bind(self._update_value, widget, watch=True) |
|
return widget |
|
|
|
|
|
def create_app(): |
|
features = { |
|
"Blade Length (m)": 73.5, |
|
"Cut-in Wind Speed (m/s)": 3.5, |
|
"Cut-out Wind Speed (m/s)": 25, |
|
"Grid Connection Capacity (MW)": 5, |
|
"Hub Height (m)": 100, |
|
"Rated Wind Speed (m/s)": 12, |
|
"Rotor Diameter (m)": 150, |
|
"Turbine Efficiency (%)": 45, |
|
"Water Depth (m)": 30, |
|
"Wind Speed (m/s)": 10, |
|
} |
|
selected_features = ["Wind Speed (m/s)", "Rotor Diameter (m)"] |
|
widget = FeatureInput( |
|
features=features, |
|
selected_features=selected_features, |
|
width=500, |
|
) |
|
|
|
return pn.FlexBox( |
|
pn.Column( |
|
"## Widget", |
|
widget, |
|
), |
|
pn.Column( |
|
"## Value", |
|
pn.pane.JSON(widget.param.value, width=500, height=200), |
|
), |
|
) |
|
|
|
|
|
if pn.state.served: |
|
pn.extension(design="material") |
|
|
|
create_app().servable() |
|
|