| """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() |
|
|