示例#1
0
def table_selections_layout(
    uuid: str, volumemodel: InplaceVolumesModel, tab: str
) -> wcc.Selectors:
    responses = volumemodel.volume_columns + volumemodel.property_columns
    return wcc.Selectors(
        label="TABLE CONTROLS",
        open_details=True,
        children=[
            wcc.Dropdown(
                label="Table type",
                id={"id": uuid, "tab": tab, "selector": "Table type"},
                options=[
                    {"label": elm, "value": elm}
                    for elm in ["Statistics table", "Mean table"]
                ],
                value="Mean table",
                clearable=False,
            ),
            wcc.Dropdown(
                label="Group by",
                id={"id": uuid, "tab": tab, "selector": "Group by"},
                options=[{"label": elm, "value": elm} for elm in volumemodel.selectors],
                value=None,
                multi=True,
                clearable=False,
            ),
            wcc.SelectWithLabel(
                label="Responses",
                id={"id": uuid, "tab": tab, "selector": "table_responses"},
                options=[{"label": i, "value": i} for i in responses],
                value=responses,
                size=min(20, len(responses)),
            ),
        ],
    )
    def _update_selections_from_clickdata(
        corr_vector_clickdata: Union[None, dict],
        corrtype: str,
        well: str,
        date: str,
        zone: str,
    ) -> Tuple[str, wcc.Dropdown, wcc.Dropdown]:
        """Update well, date and zone from clickdata"""
        if corr_vector_clickdata is None or corrtype == "sim_vs_param":
            raise PreventUpdate

        clickdata = corr_vector_clickdata.get("points", [{}])[0].get("y")
        ls_clickdata = clickdata.split()

        dates_in_well, zones_in_well = datamodel.well_dates_and_zones(well)
        dates_dropdown = wcc.Dropdown(
            label="Date",
            id=get_uuid(LayoutElements.PARAMRESP_DATE),
            options=[{"label": date, "value": date} for date in dates_in_well],
            value=ls_clickdata[1],
            clearable=False,
        )
        zones_dropdown = wcc.Dropdown(
            label="Zone",
            id=get_uuid(LayoutElements.PARAMRESP_ZONE),
            options=[{"label": zone, "value": zone} for zone in zones_in_well],
            value=ls_clickdata[2],
            clearable=False,
        )

        return ls_clickdata[0], dates_dropdown, zones_dropdown
示例#3
0
def make_map_selectors(
    uuid: str,
    map_id: str,
    surface_attributes: List[str],
    surface_names: List[str],
    ensembles: List[str],
    realizations: List[int],
    use_wells: bool,
) -> html.Div:
    return html.Div(
        children=[
            wcc.Dropdown(
                label="Surface attribute",
                id={"id": uuid, "map_id": map_id, "element": "surfaceattribute"},
                options=[{"label": val, "value": val} for val in surface_attributes],
                value=surface_attributes[0],
                clearable=False,
            ),
            wcc.Dropdown(
                label="Surface name",
                id={"id": uuid, "map_id": map_id, "element": "surfacename"},
                options=[{"label": val, "value": val} for val in surface_names],
                value=surface_names[0],
                clearable=False,
            ),
            html.Div(
                style={"display": ("inline" if len(ensembles) > 1 else "none")},
                children=[
                    wcc.Dropdown(
                        label="Ensemble",
                        id={"id": uuid, "map_id": map_id, "element": "ensemble"},
                        options=[{"label": val, "value": val} for val in ensembles],
                        value=ensembles[0],
                        clearable=False,
                    ),
                ],
            ),
            wcc.Dropdown(
                label="Calculation/Realization",
                id={"id": uuid, "map_id": map_id, "element": "calculation"},
                options=[
                    {"label": val, "value": val}
                    for val in ["Mean", "StdDev", "Max", "Min", "P90", "P10"]
                    + [str(real) for real in realizations]
                ],
                value=realizations[0],
                clearable=False,
            ),
            wcc.Checklist(
                id={"id": uuid, "map_id": map_id, "element": "options"},
                options=[
                    {"label": "Calculate well intersections", "value": "intersect_well"}
                ]
                if use_wells
                else [],
                value=[],
            ),
        ]
    )
示例#4
0
def comparison_selections(
    uuid: str, volumemodel: InplaceVolumesModel, tab: str, compare_on: str
) -> html.Div:
    options = comparison_options(compare_on, volumemodel)
    return html.Div(
        children=[
            wcc.Selectors(
                label="CONTROLS",
                open_details=True,
                children=[
                    wcc.Dropdown(
                        id={"id": uuid, "tab": tab, "selector": "value1"},
                        label=f"{compare_on} A",
                        optionHeight=50,
                        options=options,
                        value=options[0]["value"],
                        clearable=False,
                    ),
                    wcc.Dropdown(
                        id={"id": uuid, "tab": tab, "selector": "value2"},
                        optionHeight=50,
                        label=f"{compare_on} B",
                        options=options,
                        value=options[-1]["value"],
                        clearable=False,
                    ),
                    dcc.Input(
                        style={"display": "none"},
                        id={"id": uuid, "tab": tab, "selector": "compare_on"},
                        value=compare_on,
                    ),
                    html.Div(
                        f"Difference = {compare_on} B - {compare_on} A",
                        style={
                            "font-size": "15px",
                            "margin-top": "5px",
                            "color": "#007079",
                        },
                    ),
                    response_selector(volumemodel, uuid, tab),
                    group_by_selector(volumemodel, uuid, tab),
                    diff_mode_selector(uuid, tab),
                    highlight_controls(uuid, tab),
                ],
            ),
            wcc.Selectors(
                label="⚙️ SETTINGS",
                open_details=False,
                children=[
                    colorby_selector(uuid, tab),
                    axis_focus_selector(uuid, tab),
                    remove_zero_responses(uuid, tab),
                    remove_non_highlighted_data(uuid, tab),
                ],
            ),
        ]
    )
    def response_layout(self):
        """Layout to display selectors for response filters"""

        if self.no_responses:
            return []
        children = [
            wcc.Dropdown(
                label="Response",
                id=self.uuid("responses"),
                options=[{
                    "label": ens,
                    "value": ens
                } for ens in self.response_columns],
                clearable=False,
                value=self.response_columns[0],
                style={"marginBottom": "20px"},
            ),
        ]

        if self.response_filters is not None:
            for col_name, col_type in self.response_filters.items():
                values = list(self.responsedf[col_name].unique())
                if col_type == "multi":
                    children.append(
                        wcc.SelectWithLabel(
                            label=col_name,
                            id=self.uuid(f"filter-{col_name}"),
                            options=[{
                                "label": val,
                                "value": val
                            } for val in values],
                            value=values,
                            multi=True,
                            size=min(20, len(values)),
                        ))
                elif col_type == "single":
                    children.append(
                        wcc.Dropdown(
                            label=col_name,
                            id=self.uuid(f"filter-{col_name}"),
                            options=[{
                                "label": val,
                                "value": val
                            } for val in values],
                            value=values[0],
                            multi=False,
                            clearable=False,
                        ))

        return [
            html.Div(
                id=self.uuid("view_response"),
                style={"display": "none"},
                children=children,
            ),
        ]
示例#6
0
 def layout(self) -> html.Div:
     return wcc.FlexBox([
         wcc.Frame(
             style={
                 "height": "90vh",
                 "flex": 1
             },
             children=[
                 wcc.Dropdown(
                     label="Well",
                     id=self.uuid("well"),
                     options=[{
                         "label": name,
                         "value": name
                     } for name in self._well_set_model.well_names],
                     value=self.initial_well_name,
                     clearable=False,
                 ),
                 wcc.Dropdown(
                     label="Log template",
                     id=self.uuid("template"),
                     options=[{
                         "label": name,
                         "value": name
                     } for name in list(self._log_templates.keys())],
                     value=self.initial_log_template,
                     clearable=False,
                 ),
             ],
         ),
         wcc.Frame(
             style={
                 "flex": 6,
                 "height": "90vh"
             },
             children=[
                 WellLogViewerComponent(
                     id=self.uuid("well-log-viewer"),
                     template=self._log_templates.get(
                         self.initial_log_template),
                     welllog=xtgeo_well_logs_to_json_format(
                         well=self._well_set_model.get_well(
                             self.initial_well_name)),
                     colorTables=self.colortables,
                 )
             ],
         ),
     ])
示例#7
0
def main_layout(get_uuid: Callable, ensembles: list) -> html.Div:
    return html.Div(
        id=get_uuid(LayoutElements.LAYOUT),
        children=[
            dcc.Store(id=get_uuid(LayoutElements.ENSEMBLE_DROPDOWN),
                      storage_type="session"),
            wcc.FlexBox(children=[
                wcc.Selectors(
                    label="Ensemble",
                    children=[
                        wcc.Dropdown(
                            id=get_uuid(LayoutElements.ENSEMBLE_DROPDOWN),
                            options=[{
                                "label": ens,
                                "value": ens
                            } for ens in ensembles],
                            clearable=False,
                            value=ensembles[0],
                            persistence=True,
                            persistence_type="session",
                        ),
                    ],
                ),
                html.Div(style={"flex": 4}),
            ], ),
            html.Div(id=get_uuid(LayoutElements.WELL_COMPLETIONS_COMPONENT), ),
        ],
    )
示例#8
0
def source_layout(uuid: str, use_wells: bool = True) -> html.Div:
    options = [
        {
            "label": "Intersect polyline from Surface A",
            "value": "polyline"
        },
        {
            "label": "Intersect x-line from Surface A",
            "value": "xline"
        },
        {
            "label": "Intersect y-line from Surface A",
            "value": "yline"
        },
    ]
    if use_wells:
        options.append({"label": "Intersect well", "value": "well"})
    return wcc.Dropdown(
        label="Intersection source",
        id={
            "id": uuid,
            "element": "source"
        },
        options=options,
        value="well" if use_wells else "polyline",
        clearable=False,
    )
def dropdown_for_plotly_data(
    uuid: str,
    source: str,
    data_attribute: str,
    title: str,
    options: List[Dict],
    value: Union[List, str] = None,
    flex: int = 1,
    placeholder: str = "Select...",
    multi: bool = False,
    clearable: bool = False,
) -> html.Div:
    return html.Div(
        style={"flex": flex},
        children=[
            wcc.Dropdown(
                label=title,
                id={
                    "id": uuid,
                    "data_attribute": data_attribute,
                    "source": source
                },
                options=options,
                value=value,
                clearable=clearable,
                placeholder=placeholder,
                multi=multi,
            ),
        ],
    )
示例#10
0
def dropdown_vs_select(
    value: Union[List[str], str],
    options: List[str],
    component_id: dict,
    dropdown: bool = False,
    multi: bool = False,
) -> Union[wcc.Dropdown, wcc.SelectWithLabel]:
    if dropdown:
        if isinstance(value, list) and not multi:
            value = value[0]
        return wcc.Dropdown(
            id=component_id,
            options=[{
                "label": opt,
                "value": opt
            } for opt in options],
            value=value,
            clearable=False,
            multi=multi,
        )
    return wcc.SelectWithLabel(
        id=component_id,
        options=[{
            "label": opt,
            "value": opt
        } for opt in options],
        size=5,
        value=value,
        multi=multi,
    )
示例#11
0
 def __init__(self, tab: Tabs, get_uuid: Callable) -> None:
     super().__init__(
         style={
             "margin-bottom": "15px",
             "display": "block" if tab == Tabs.SPLIT else "none",
         },
         children=wcc.Dropdown(
             label="Create map for each:",
             id={
                 "id": get_uuid(LayoutElements.MULTI),
                 "tab": tab
             },
             options=[{
                 "label": LayoutLabels[selector.name],
                 "value": selector,
             } for selector in [
                 MapSelector.NAME,
                 MapSelector.DATE,
                 MapSelector.ENSEMBLE,
                 MapSelector.ATTRIBUTE,
                 MapSelector.REALIZATIONS,
             ]],
             value=MapSelector.NAME if tab == Tabs.SPLIT else None,
             clearable=False,
         ),
     )
示例#12
0
def selections_layout(get_uuid: Callable, ensembles: list) -> wcc.Selectors:
    """Layout for the component input options"""
    controls_uuid = get_uuid("controls")
    return wcc.Selectors(
        id=get_uuid("selections_layout"),
        label="Controls",
        children=[
            wcc.Dropdown(
                label="Ensemble",
                id={
                    "id": controls_uuid,
                    "element": "ensemble"
                },
                options=[{
                    "label": ens,
                    "value": ens
                } for ens in ensembles],
                clearable=False,
                value=ensembles[0],
            ),
            wcc.RadioItems(
                label="Mean or realization",
                id={
                    "id": controls_uuid,
                    "element": "tree_mode"
                },
            ),
        ],
    )
示例#13
0
 def layout(self) -> html.Div:
     return html.Div(
         id=self.uuid("layout"),
         children=[
             wcc.FlexBox(children=[
                 wcc.Selectors(
                     label="Ensemble",
                     children=[
                         wcc.Dropdown(
                             id=self.uuid("ensemble_dropdown"),
                             options=[{
                                 "label": ens,
                                 "value": ens
                             } for ens in self.ensembles],
                             clearable=False,
                             value=self.ensembles[0],
                             persistence=True,
                             persistence_type="session",
                         ),
                     ],
                 ),
                 html.Div(style={"flex": 4}),
             ], ),
             html.Div(id=self.uuid("well_completions_wrapper"), ),
         ],
     )
示例#14
0
def scale_selector(uuid: str, tab: str) -> wcc.Dropdown:
    return wcc.Dropdown(
        label="Scale:",
        id={
            "id": uuid,
            "tab": tab,
            "selector": "Scale"
        },
        options=[
            {
                "label": "Relative value (%)",
                "value": "Percentage"
            },
            {
                "label": "Relative value",
                "value": "Absolute"
            },
            {
                "label": "True value",
                "value": "True"
            },
        ],
        value="Percentage",
        clearable=False,
    )
示例#15
0
def well_layout(uuid: str,
                well_names: List[str],
                value: Optional[str] = None) -> html.Div:
    return html.Div(
        style={
            "display": "none",
        } if value is None else {},
        id={
            "id": uuid,
            "element": "well-wrapper"
        },
        children=wcc.Dropdown(
            label="Well",
            id={
                "id": uuid,
                "element": "well"
            },
            options=[{
                "label": well,
                "value": well
            } for well in well_names],
            value=value,
            clearable=False,
        ),
    )
示例#16
0
def ensemble_selector(
    get_uuid: Callable,
    parametermodel: ParametersModel,
    tab: str,
    id_string: str,
    multi: bool = False,
    value: str = None,
    heading: str = None,
) -> html.Div:
    children = []

    children.append(
        wcc.Dropdown(
            label=heading,
            id={
                "id": get_uuid(id_string),
                "tab": tab
            },
            options=[{
                "label": ens,
                "value": ens
            } for ens in parametermodel.ensembles],
            multi=multi,
            value=value if value is not None else parametermodel.ensembles[0],
            clearable=False,
        ))
    return html.Div(children)
示例#17
0
def property_selector(
    get_uuid: Callable,
    properties: List[str],
    tab: str,
    multi: bool = False,
    initial_property: str = None,
) -> html.Div:
    display = "none" if len(properties) < 2 else "inline"
    return html.Div(
        style={"display": display},
        children=[
            wcc.Dropdown(
                label="Property",
                id={
                    "id": get_uuid("property-selector"),
                    "tab": tab
                },
                options=[{
                    "label": prop,
                    "value": prop
                } for prop in properties],
                multi=multi,
                value=initial_property
                if initial_property is not None else properties[0],
                clearable=False,
            )
        ],
    )
示例#18
0
def source_selector(
    get_uuid: Callable,
    sources: List[str],
    tab: str,
    multi: bool = False,
    initial_source: str = None,
) -> html.Div:
    display = "none" if len(sources) < 2 else "inline"
    return html.Div(
        style={"display": display},
        children=[
            wcc.Dropdown(
                label="Source",
                id={
                    "id": get_uuid("source-selector"),
                    "tab": tab
                },
                options=[{
                    "label": source,
                    "value": source
                } for source in sources],
                multi=multi,
                value=initial_source
                if initial_source is not None else sources[0],
                clearable=False,
            ),
        ],
    )
 def layout(self) -> html.Div:
     return wcc.FlexBox([
         wcc.Frame(
             style={
                 "height": "90vh",
                 "flex": 1
             },
             children=[
                 wcc.Dropdown(
                     label="Well",
                     id=self.uuid("well"),
                     options=[{
                         "label": name,
                         "value": name
                     } for name in self._well_set_model.well_names],
                     value=self._initial_settings.get(
                         "well_name", self._well_set_model.well_names[0]),
                     clearable=False,
                 ),
                 wcc.Dropdown(
                     label="Log template",
                     id=self.uuid("template"),
                     options=[{
                         "label": name,
                         "value": name
                     } for name in list(self._log_templates.keys())],
                     value=self._initial_settings.get(
                         "logtemplate",
                         list(self._log_templates.keys())[0]),
                     clearable=False,
                 ),
             ],
         ),
         wcc.Frame(
             style={
                 "flex": 6,
                 "height": "90vh"
             },
             children=[
                 WellLogViewerComponent(
                     id=self.uuid("well-log-viewer"),
                     template=self._log_templates[list(
                         self._log_templates.keys())[0]],
                 )
             ],
         ),
     ])
示例#20
0
def vector_selector(get_uuid: Callable,
                    vectormodel: SimulationTimeSeriesModel) -> html.Div:
    first_vector_group: str = ("Field" if "Field" in list(
        vectormodel.vector_groups.keys()) else list(
            vectormodel.vector_groups.keys())[0])
    return html.Div(
        style={"margin": "10px 0px"},
        children=[
            html.Span(wcc.Label("Vector type")),
            html.Div(
                id=get_uuid("vtype-container"),
                children=[
                    dcc.RadioItems(
                        id={
                            "id": get_uuid("vtype-select"),
                            "state": "initial"
                        },
                        options=[{
                            "label": i,
                            "value": i
                        } for i in vectormodel.vector_groups],
                        value=first_vector_group,
                        labelStyle={
                            "display": "inline-block",
                            "margin-right": "10px"
                        },
                    )
                ],
            ),
            html.Div(
                style={"margin-top": "5px"},
                children=[
                    html.Span(wcc.Label("Vector")),
                    html.Div(
                        id=get_uuid("vshort-container"),
                        children=[
                            wcc.Dropdown(
                                id=get_uuid("vshort-select"),
                                options=[{
                                    "label": i,
                                    "value": i
                                } for i in vectormodel.
                                         vector_groups[first_vector_group]
                                         ["shortnames"]],
                                value=vectormodel.vector_groups[
                                    first_vector_group]["shortnames"][0],
                                placeholder="Select a vector...",
                                clearable=False,
                            ),
                        ],
                    ),
                ],
            ),
            html.Div(id=get_uuid("vitems-container"), children=[]),
            html.Div(id=get_uuid("vector-select"), style={"display": "none"}),
            html.Div(id=get_uuid("clickdata-store"), style={"display":
                                                            "none"}),
        ],
    )
def controls(
    get_uuid: Callable, data_models: Dict[str, EnsembleWellAnalysisData]
) -> wcc.Selectors:
    ensembles = list(data_models.keys())
    dates: Set[datetime.datetime] = set()
    for _, ens_data_model in data_models.items():
        dates = dates.union(ens_data_model.dates)
    sorted_dates: List[datetime.datetime] = sorted(list(dates))

    return wcc.Selectors(
        label="Plot Controls",
        children=[
            wcc.Dropdown(
                label="Ensembles",
                id=get_uuid(WellOverviewLayoutElements.ENSEMBLES),
                options=[{"label": col, "value": col} for col in ensembles],
                value=ensembles,
                multi=True,
            ),
            wcc.Dropdown(
                label="Response",
                id=get_uuid(WellOverviewLayoutElements.SUMVEC),
                options=[
                    {"label": "Oil production", "value": "WOPT"},
                    {"label": "Gas production", "value": "WGPT"},
                    {"label": "Water production", "value": "WWPT"},
                ],
                value="WOPT",
                multi=False,
                clearable=False,
            ),
            wcc.Dropdown(
                label="Only Production after date",
                id=get_uuid(WellOverviewLayoutElements.DATE),
                options=[
                    {
                        "label": dte.strftime("%Y-%m-%d"),
                        "value": dte.strftime("%Y-%m-%d"),
                    }
                    for dte in sorted_dates
                ],
                multi=False,
            ),
        ],
    )
示例#22
0
def parameter_selector(
    get_uuid: Callable, parametermodel: ParametersModel, tab: str
) -> html.Div:
    return wcc.Dropdown(
        label="Parameter",
        id={"id": get_uuid("parameter-select"), "tab": tab},
        options=[{"label": i, "value": i} for i in parametermodel.parameters],
        placeholder="Select a parameter...",
        clearable=False,
    )
 def selector(self, label: str, id_name: str, column: str) -> html.Div:
     return wcc.Dropdown(
         label=label,
         id=self.uuid(id_name),
         options=[
             {"label": i, "value": i} for i in list(self.volumes[column].unique())
         ],
         clearable=False,
         value=list(self.volumes[column])[0],
     )
示例#24
0
def __delta_ensemble_creator_layout(get_uuid: Callable,
                                    ensembles: List[str]) -> html.Div:
    return html.Div(children=[
        wcc.Dropdown(
            label="Ensemble A",
            id=get_uuid(LayoutElements.DELTA_ENSEMBLE_A_DROPDOWN),
            clearable=False,
            options=[{
                "label": i,
                "value": i
            } for i in ensembles],
            value=ensembles[0],
            style={"min-width": "60px"},
        ),
        wcc.Dropdown(
            label="Ensemble B",
            id=get_uuid(LayoutElements.DELTA_ENSEMBLE_B_DROPDOWN),
            clearable=False,
            options=[{
                "label": i,
                "value": i
            } for i in ensembles],
            value=ensembles[-1],
            style={"min-width": "60px"},
        ),
        html.Button(
            "Create",
            id=get_uuid(LayoutElements.DELTA_ENSEMBLE_CREATE_BUTTON),
            n_clicks=0,
            style={
                "margin-top": "5px",
                "margin-bottom": "5px",
                "min-width": "20px",
            },
        ),
        __delta_ensemble_table_layout(get_uuid),
        dcc.Store(
            id=get_uuid(LayoutElements.CREATED_DELTA_ENSEMBLES),
            data=[],
        ),  # TODO: Add predefined deltas?
    ])
 def smry_selector(self) -> html.Div:
     """Dropdown to select ensemble"""
     return wcc.Dropdown(
         label="Time series",
         id=self.ids("vector"),
         options=[{
             "label": f"{simulation_vector_description(vec)} ({vec})",
             "value": vec,
         } for vec in self.smry_cols],
         clearable=False,
         value=self.initial_vector,
     )
 def ensemble_selector(self) -> html.Div:
     """Dropdown to select ensemble"""
     return wcc.Dropdown(
         label="Ensemble",
         id=self.ids("ensemble"),
         options=[{
             "label": i,
             "value": i
         } for i in self.ensembles],
         clearable=False,
         value=self.ensembles[0],
     )
    def filter_layout(self) -> List[Any]:
        """Layout to display selectors for response filters"""
        children = []
        for col_name, col_type in self.response_filters.items():
            domid = self.uuid(f"filter-{col_name}")
            values = list(self.responsedf[col_name].unique())
            if col_type == "multi":
                selector = wcc.SelectWithLabel(
                    label=f"{col_name}:",
                    id=domid,
                    options=[{
                        "label": val,
                        "value": val
                    } for val in values],
                    value=values,
                    multi=True,
                    size=min(10, len(values)),
                    collapsible=True,
                )
            elif col_type == "single":
                selector = wcc.Dropdown(
                    label=f"{col_name}:",
                    id=domid,
                    options=[{
                        "label": val,
                        "value": val
                    } for val in values],
                    value=values[-1],
                    multi=False,
                    clearable=False,
                )
            elif col_type == "range":
                selector = make_range_slider(domid, self.responsedf[col_name],
                                             col_name)
            else:
                return children
            children.append(selector)

        children.append(
            wcc.SelectWithLabel(
                label="Parameters:",
                id=self.uuid("parameter-filter"),
                options=[{
                    "label": val,
                    "value": val
                } for val in self.parameter_columns],
                value=self.parameter_columns,
                multi=True,
                size=min(10, len(self.parameter_columns)),
                collapsible=True,
            ))

        return children
示例#28
0
 def response_layout(self) -> html.Div:
     """Creates a labelled dropdown with all response columns"""
     return wcc.Dropdown(
         label="Response",
         id=self.uuid("response"),
         options=[{
             "label": response,
             "value": response
         } for response in self._responses],
         value=self._initial_response,
         clearable=False,
     )
示例#29
0
def surface_attribute_layout(
    uuid: str, surface_attributes: List[str], value: str
) -> html.Div:
    return wcc.Dropdown(
        label="Surface attribute",
        id={"id": uuid, "element": "surface_attribute"},
        options=[
            {"label": attribute, "value": attribute} for attribute in surface_attributes
        ],
        value=value,
        clearable=False,
        multi=False,
    )
 def response_selector(self) -> html.Div:
     """Dropdown to select volumetric response"""
     return wcc.Dropdown(
         label="Volumetric calculation",
         id=self.uuid("response"),
         options=[
             {"label": volume_description(i), "value": i} for i in self.responses
         ],
         clearable=False,
         value=self.initial_response
         if self.initial_response in self.responses
         else self.responses[0],
     )