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