From 967ed64deb0001592de222e73ad100d0c4dcc339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Tue, 4 Apr 2023 11:42:04 +0200 Subject: [PATCH 01/16] Added option to display observations in time series plot --- .../_figures/timeseries_figure.py | 37 ++++++++++++++++++- .../plugins/_parameter_analysis/_plugin.py | 14 ++++++- .../_settings/_vizualisation.py | 5 ++- .../_views/_parameter_response_view/_view.py | 17 ++++++++- 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/webviz_subsurface/_figures/timeseries_figure.py b/webviz_subsurface/_figures/timeseries_figure.py index 0b68f5402..f3a0d0d1a 100644 --- a/webviz_subsurface/_figures/timeseries_figure.py +++ b/webviz_subsurface/_figures/timeseries_figure.py @@ -1,6 +1,6 @@ import datetime from enum import Enum -from typing import List, Optional +from typing import List, Optional, Dict import numpy as np import pandas as pd @@ -30,6 +30,7 @@ def __init__( ensemble: str, color_col: Optional[str], line_shape_fallback: str, + observations: Dict, historical_vector_df: Optional[pd.DataFrame] = None, dateline: Optional[datetime.datetime] = None, ): @@ -40,10 +41,14 @@ def __init__( self.visualization = visualization self.historical_vector_df = historical_vector_df self.date = dateline + self.observations = observations self.line_shape = self.get_line_shape(line_shape_fallback) self.create_traces() + if self.observations: + self.create_vector_observation_traces() + @property def figure(self) -> dict: title = self.vector @@ -214,6 +219,36 @@ def create_vectors_statistics_df(self) -> pd.DataFrame: .reset_index() ) + def create_vector_observation_traces(self) -> None: + """Adds observations to the plot""" + + legend_group = "Observation" + name = "Observation" + color = "black" + show_legend = False + + for observation in self.observations.get("observations", []): + hovertext = observation.get("comment") + hovertemplate = ( + "(%{x}, %{y})
" + hovertext if hovertext else "(%{x}, %{y})
" + ) + self.traces.append( + { + "name": name, + "legendgroup": legend_group, + "x": [observation.get("date"), []], + "y": [observation.get("value"), []], + "marker": {"color": color}, + "hovertemplate": hovertemplate, + "showlegend": show_legend, + "error_y": { + "type": "data", + "array": [observation.get("error"), []], + "visible": True, + }, + } + ) + @staticmethod def set_real_color(norm_value: float, mean_param_value: float) -> str: """ diff --git a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py index daf59dee3..219e0f960 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py @@ -1,3 +1,4 @@ +from pathlib import Path from typing import Dict, List, Optional import pandas as pd @@ -11,6 +12,8 @@ Frequency, ) +from ..._utils.simulation_timeseries import check_and_format_observations +from ..._utils.webvizstore_functions import get_path from ._utils import ParametersModel, ProviderTimeSeriesDataModel from ._views._parameter_distributions_view import ParameterDistributionView from ._views._parameter_response_view import ParameterResponseView @@ -64,11 +67,17 @@ def __init__( column_keys: Optional[list] = None, drop_constants: bool = True, rel_file_pattern: str = "share/results/unsmry/*.arrow", + obsfile: Path = None, ): super().__init__() self._ensembles = ensembles self._theme = webviz_settings.theme + self._obsfile = obsfile + + self._observations = {} + if self._obsfile: + self._observations = check_and_format_observations(get_path(self._obsfile)) if ensembles is None: raise ValueError('Incorrect argument, must provide "ensembles"') @@ -112,7 +121,10 @@ def __init__( self.add_view( ParameterResponseView( - parametermodel=self._pmodel, vectormodel=self._vmodel, theme=self._theme + parametermodel=self._pmodel, + vectormodel=self._vmodel, + observations=self._observations, + theme=self._theme, ), self.Ids.PARAM_RESP_VIEW, ) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_vizualisation.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_vizualisation.py index 60a96b7f6..93886d79e 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_vizualisation.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_vizualisation.py @@ -46,9 +46,10 @@ def layout(self) -> List[Component]: wcc.Checklist( id=self.register_component_unique_id(self.Ids.CHECKBOX_OPTIONS), options=[ - {"label": "Dateline visible", "value": "DateLine"}, + {"label": "Dateline", "value": "DateLine"}, + {"label": "Observations", "value": "Observations"}, ], - value=["DateLine"], + value=["DateLine", "Observations"], ), dcc.Store( id=self.register_component_unique_id(self.Ids.CHECKBOX_OPTIONS_STORE), diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index 30398aac2..9aa137419 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -39,12 +39,14 @@ def __init__( self, parametermodel: ParametersModel, vectormodel: ProviderTimeSeriesDataModel, + observations: Dict, theme: WebvizConfigTheme, ) -> None: super().__init__("Parameter Response Analysis") self._parametermodel = parametermodel self._vectormodel = vectormodel + self._observations = observations self._theme = theme self.add_settings_groups( @@ -325,6 +327,10 @@ def _update_graphs( historical_vector_df=self._vectormodel.get_historical_vector_df( selected_vector, ensemble ), + observations=self._observations[selected_vector] + if options["show_observations"] + and selected_vector in self._observations + else {}, color_col=param, line_shape_fallback=self._vectormodel.line_shape_fallback, ).figure @@ -356,12 +362,18 @@ def _update_date_from_clickdata( timeseries_clickdata: Union[None, dict], date: str ) -> int: """Update date-slider from clickdata""" - date = ( + date_str = ( timeseries_clickdata.get("points", [{}])[0]["x"] if timeseries_clickdata is not None else date ) - return self._vectormodel.dates.index(datetime_utils.from_str(date)) + date_obj = datetime_utils.from_str(date_str) + if date_obj not in self._vectormodel.dates: + # This will happen if the click is on an observation that is on + # a date that is not in the sampled vector dates. It could be + # by somehow finding the nearest date. + raise PreventUpdate + return self._vectormodel.dates.index(date_obj) @callback( Output( @@ -521,6 +533,7 @@ def _update_plot_options( "color": None if color_clickdata is None else color, "opacity": opacity, "ctx": ctx, + "show_observations": "Observations" in checkbox_options, } @callback( From 42f4bf1e7a11f4b2c37a346ca4764453a84f5a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Tue, 4 Apr 2023 11:47:08 +0200 Subject: [PATCH 02/16] Added line about obsfile parameter in documentation --- webviz_subsurface/plugins/_parameter_analysis/_plugin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py index 219e0f960..b5a10c977 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py @@ -35,6 +35,7 @@ class ParameterAnalysis(WebvizPluginABC): Default is True. * **`column_keys`:** List of vectors to extract. If not given, all vectors \ from the simulations will be extracted. Wild card asterisk `*` can be used. +* **`obsfile`:** `.yaml` file with observations to be displayed in the time series plot \ --- ?> `Arrow` format for simulation time series data can be generated using the `ECL2CSV` forward \ From 73e185fdae89513f7b0e41d9c9da50feb8bba347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 5 Apr 2023 10:09:12 +0200 Subject: [PATCH 03/16] Resampling frequency option implemented in settings group, but not in callback --- .../plugins/_parameter_analysis/_plugin.py | 1 + .../_settings/_selections.py | 23 ++++++++++++++++++- .../_views/_parameter_response_view/_view.py | 9 ++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py index b5a10c977..3d63a1e0f 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py @@ -125,6 +125,7 @@ def __init__( parametermodel=self._pmodel, vectormodel=self._vmodel, observations=self._observations, + selected_resampling_frequency=resampling_frequency, theme=self._theme, ), self.Ids.PARAM_RESP_VIEW, diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py index 414c521a8..50860ffb6 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py @@ -7,6 +7,7 @@ from webviz_config.utils import StrEnum from webviz_config.webviz_plugin_subclasses import SettingsGroupABC +from ......_providers import Frequency from ...._utils import ParametersModel, ProviderTimeSeriesDataModel from ...._utils import _datetime_utils as datetime_utils @@ -19,13 +20,18 @@ class Ids(StrEnum): DATE_SELECTED = "date-selected" DATE_SLIDER = "date-slider" PARAMETER_SELECT = "parameter-select" + RESAMPLING_FREQUENCY_DROPDOWN = "resampling-frequency-dropdown" def __init__( - self, parametermodel: ParametersModel, vectormodel: ProviderTimeSeriesDataModel + self, + parametermodel: ParametersModel, + vectormodel: ProviderTimeSeriesDataModel, + selected_resampling_frequency: Frequency, ) -> None: super().__init__("Selections") self._parametermodel = parametermodel self._vectormodel = vectormodel + self._selected_resampling_frequency = selected_resampling_frequency def layout(self) -> List[Component]: dates = self._vectormodel.dates @@ -101,4 +107,19 @@ def layout(self) -> List[Component]: placeholder="Select a parameter...", clearable=False, ), + wcc.Dropdown( + label="Resampling frequency", + id=self.register_component_unique_id( + self.Ids.RESAMPLING_FREQUENCY_DROPDOWN + ), + clearable=False, + options=[ + { + "label": frequency.value, + "value": frequency.value, + } + for frequency in Frequency + ], + value=self._selected_resampling_frequency, + ), ] diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index 9aa137419..152fdba59 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -8,6 +8,7 @@ from webviz_config.webviz_plugin_subclasses import ViewABC from ....._figures import BarChart, ScatterPlot, TimeSeriesFigure +from ....._providers import Frequency from ....._utils.colors import hex_to_rgba_str, rgba_to_hex from ....._utils.dataframe_utils import ( correlate_response_with_dataframe, @@ -40,6 +41,7 @@ def __init__( parametermodel: ParametersModel, vectormodel: ProviderTimeSeriesDataModel, observations: Dict, + selected_resampling_frequency: Frequency, theme: WebvizConfigTheme, ) -> None: super().__init__("Parameter Response Analysis") @@ -52,7 +54,9 @@ def __init__( self.add_settings_groups( { self.Ids.SELECTIONS: ParamRespSelections( - self._parametermodel, self._vectormodel + parametermodel=self._parametermodel, + vectormodel=self._vectormodel, + selected_resampling_frequency=selected_resampling_frequency, ), self.Ids.OPTIONS: ParamRespOptions(), self.Ids.VIZUALISATION: ParamRespVizualisation(self._theme), @@ -328,7 +332,8 @@ def _update_graphs( selected_vector, ensemble ), observations=self._observations[selected_vector] - if options["show_observations"] + if options + and options["show_observations"] and selected_vector in self._observations else {}, color_col=param, From 05784d7e252173e63baeb13cadc81109fd0c4712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 5 Apr 2023 17:43:16 +0200 Subject: [PATCH 04/16] More work on the resampling frequency options --- .../plugins/_parameter_analysis/_plugin.py | 33 ++++++--- .../_utils/_provider_timesseries_datamodel.py | 19 ++++-- .../_settings/_selections.py | 7 +- .../_views/_parameter_response_view/_view.py | 68 +++++++++++++++---- 4 files changed, 97 insertions(+), 30 deletions(-) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py index 3d63a1e0f..655eb379f 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_plugin.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_plugin.py @@ -36,6 +36,8 @@ class ParameterAnalysis(WebvizPluginABC): * **`column_keys`:** List of vectors to extract. If not given, all vectors \ from the simulations will be extracted. Wild card asterisk `*` can be used. * **`obsfile`:** `.yaml` file with observations to be displayed in the time series plot \ +* **`perform_presampled`:** Summary data will be presampled when loading the plugin, \ + and the resampling dropdown will be disabled. --- ?> `Arrow` format for simulation time series data can be generated using the `ECL2CSV` forward \ @@ -60,15 +62,17 @@ class Ids(StrEnum): PARAM_DIST_VIEW = "param-dist-view" PARAM_RESP_VIEW = "param-resp-view" + # pylint: disable=too-many-arguments def __init__( self, webviz_settings: WebvizSettings, ensembles: List[str] = None, - time_index: str = "monthly", + time_index: str = Frequency.MONTHLY.value, column_keys: Optional[list] = None, drop_constants: bool = True, rel_file_pattern: str = "share/results/unsmry/*.arrow", obsfile: Path = None, + perform_presampling: bool = False, ): super().__init__() @@ -95,14 +99,26 @@ def __init__( resampling_frequency = Frequency(time_index) provider_factory = EnsembleSummaryProviderFactory.instance() - provider_set = { - ens: provider_factory.create_from_arrow_unsmry_presampled( - str(ens_path), rel_file_pattern, resampling_frequency - ) - for ens, ens_path in ensemble_paths.items() - } + if perform_presampling: + self._input_provider_set = { + ens: provider_factory.create_from_arrow_unsmry_presampled( + str(ens_path), rel_file_pattern, resampling_frequency + ) + for ens, ens_path in ensemble_paths.items() + } + else: + self._input_provider_set = { + ens: provider_factory.create_from_arrow_unsmry_lazy( + str(ens_path), rel_file_pattern + ) + for ens, ens_path in ensemble_paths.items() + } + self._vmodel = ProviderTimeSeriesDataModel( - provider_set=provider_set, column_keys=column_keys + provider_set=self._input_provider_set, column_keys=column_keys + ) + self._vmodel.set_dates( + self._vmodel.get_dates(resampling_frequency=resampling_frequency) ) parameter_df = create_df_from_table_provider( @@ -126,6 +142,7 @@ def __init__( vectormodel=self._vmodel, observations=self._observations, selected_resampling_frequency=resampling_frequency, + disable_resampling_dropdown=perform_presampling, theme=self._theme, ), self.Ids.PARAM_RESP_VIEW, diff --git a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py index badb532bf..8489d2457 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py @@ -6,7 +6,7 @@ import pandas as pd from webviz_subsurface._abbreviations.reservoir_simulation import historical_vector -from webviz_subsurface._providers import EnsembleSummaryProvider +from webviz_subsurface._providers import EnsembleSummaryProvider, Frequency from webviz_subsurface._utils.simulation_timeseries import ( set_simulation_line_shape_fallback, ) @@ -34,8 +34,6 @@ def __init__( if not self._vector_names: raise ValueError("No vectors match the selected 'column_keys' criteria") - self._dates = self.all_dates() - # add vectors to vector selector self.vector_selector_data: list = [] for vector in self.get_non_historical_vector_names(): @@ -56,15 +54,19 @@ def get_non_historical_vector_names(self) -> list: if historical_vector(vector, None, False) not in self._vector_names ] - def all_dates(self) -> List[datetime.datetime]: + def get_dates(self, resampling_frequency: Frequency) -> List[datetime.datetime]: """List with the union of dates among providers""" # TODO: Adjust when providers are updated! dates_union: Set[datetime.datetime] = set() for provider in list(self._provider_set.values()): - _dates = set(provider.dates(None)) + _dates = set(provider.dates(resampling_frequency=resampling_frequency)) dates_union.update(_dates) return list(sorted(dates_union)) + def set_dates(self, dates: List[datetime.datetime]) -> None: + #pylint: disable=attribute-defined-outside-init + self._dates = dates + @staticmethod def _create_union_of_vector_names_from_providers( providers: List[EnsembleSummaryProvider], @@ -122,10 +124,15 @@ def get_vector_df( ensemble: str, realizations: List[int], vectors: List[str], + resampling_frequency: Frequency, ) -> pd.DataFrame: provider = self._provider_set[ensemble] ens_vectors = [vec for vec in vectors if vec in provider.vector_names()] - return provider.get_vectors_df(ens_vectors, None, realizations) + return provider.get_vectors_df( + vector_names=ens_vectors, + resampling_frequency=resampling_frequency, + realizations=realizations, + ) def get_last_date(self, ensemble: str) -> datetime.datetime: return max(self._provider_set[ensemble].dates(None)) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py index 50860ffb6..a6a42973e 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_selections.py @@ -27,11 +27,13 @@ def __init__( parametermodel: ParametersModel, vectormodel: ProviderTimeSeriesDataModel, selected_resampling_frequency: Frequency, + disable_resampling_dropdown: bool, ) -> None: super().__init__("Selections") self._parametermodel = parametermodel self._vectormodel = vectormodel self._selected_resampling_frequency = selected_resampling_frequency + self._disable_resampling_dropdown = disable_resampling_dropdown def layout(self) -> List[Component]: dates = self._vectormodel.dates @@ -113,10 +115,11 @@ def layout(self) -> List[Component]: self.Ids.RESAMPLING_FREQUENCY_DROPDOWN ), clearable=False, + disabled=self._disable_resampling_dropdown, options=[ { - "label": frequency.value, - "value": frequency.value, + "label": frequency, + "value": frequency, } for frequency in Frequency ], diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index 152fdba59..de9e04730 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -42,6 +42,7 @@ def __init__( vectormodel: ProviderTimeSeriesDataModel, observations: Dict, selected_resampling_frequency: Frequency, + disable_resampling_dropdown: bool, theme: WebvizConfigTheme, ) -> None: super().__init__("Parameter Response Analysis") @@ -49,6 +50,7 @@ def __init__( self._parametermodel = parametermodel self._vectormodel = vectormodel self._observations = observations + self._disable_resampling_dropdown = disable_resampling_dropdown self._theme = theme self.add_settings_groups( @@ -57,6 +59,7 @@ def __init__( parametermodel=self._parametermodel, vectormodel=self._vectormodel, selected_resampling_frequency=selected_resampling_frequency, + disable_resampling_dropdown=disable_resampling_dropdown, ), self.Ids.OPTIONS: ParamRespOptions(), self.Ids.VIZUALISATION: ParamRespVizualisation(self._theme), @@ -160,6 +163,13 @@ def set_callbacks(self) -> None: }, "data", ), + State( + self.settings_group_unique_id( + self.Ids.SELECTIONS, + ParamRespSelections.Ids.RESAMPLING_FREQUENCY_DROPDOWN, + ), + "value", + ), State( self.view_element(self.Ids.PARAM_CORR_GRAPH) .component_unique_id(ParamRespViewElement.Ids.GRAPH) @@ -184,6 +194,7 @@ def _update_graphs( visualization: str, options: Union[None, Dict[str, Any]], real_filter: Dict[str, List[int]], + resampling_frequency: Frequency, corr_p_fig: Union[None, dict], corr_v_fig: Union[None, dict], ) -> List[Any]: @@ -215,10 +226,15 @@ def _update_graphs( ) # Get dataframe with vectors and dataframe with parameters and merge + # If the resampling dropdown is disable it means the data is presampled, + # in which case we pass None as resampling frequency vector_df = self._vectormodel.get_vector_df( ensemble=ensemble, realizations=realizations, vectors=vectors_for_param_corr + [selected_vector], + resampling_frequency=resampling_frequency + if not self._disable_resampling_dropdown + else None, ) if date not in vector_df["DATE"].values: return [empty_figure("Selected date does not exist for ensemble")] * 4 @@ -355,6 +371,13 @@ def _update_graphs( .to_string(), "clickData", ), + Input( + self.settings_group_unique_id( + self.Ids.SELECTIONS, + ParamRespSelections.Ids.RESAMPLING_FREQUENCY_DROPDOWN, + ), + "value", + ), State( self.settings_group_unique_id( self.Ids.SELECTIONS, ParamRespSelections.Ids.DATE_SELECTED @@ -363,22 +386,39 @@ def _update_graphs( ), ) @callback_typecheck - def _update_date_from_clickdata( - timeseries_clickdata: Union[None, dict], date: str + def _update_date_from_clickdata_or_resampling_freq( + timeseries_clickdata: Union[None, dict], + resampling_frequency: Frequency, + datestr: str, ) -> int: """Update date-slider from clickdata""" - date_str = ( - timeseries_clickdata.get("points", [{}])[0]["x"] - if timeseries_clickdata is not None - else date - ) - date_obj = datetime_utils.from_str(date_str) - if date_obj not in self._vectormodel.dates: - # This will happen if the click is on an observation that is on - # a date that is not in the sampled vector dates. It could be - # by somehow finding the nearest date. - raise PreventUpdate - return self._vectormodel.dates.index(date_obj) + ctx = callback_context.triggered[0]["prop_id"] + if self.Ids.TIME_SERIES_CHART.value in ctx: + # The event is a click in the time series chart + date = datetime_utils.from_str( + timeseries_clickdata.get("points", [{}])[0]["x"] + if timeseries_clickdata is not None + else datestr + ) + if date not in self._vectormodel.dates: + # This will happen if the click is on an observation that is on + # a date that is not in the sampled vector dates. It could be + # by somehow finding the nearest date. + raise PreventUpdate + return self._vectormodel.dates.index(date) + + if ParamRespSelections.Ids.RESAMPLING_FREQUENCY_DROPDOWN.value in ctx: + # The event is a change of resampling frequency + dates = self._vectormodel.get_dates( + resampling_frequency=resampling_frequency + ) + self._vectormodel.set_dates(dates) + if date not in dates: + print("Find closest") + return self._vectormodel.dates.index(dates[-1]) + return self._vectormodel.dates.index(datetime_utils.from_str(date)) + + raise PreventUpdate("Event not recognized.") @callback( Output( From 50058795c15ea1a758eda329b0f6fb7e5c9cdc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Mon, 10 Apr 2023 21:04:31 +0200 Subject: [PATCH 05/16] Further improvements of the resampling callback --- .../_utils/_provider_timesseries_datamodel.py | 4 +- .../_views/_parameter_response_view/_view.py | 57 +++++++++++++++++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py index 8489d2457..4d4e4b684 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py @@ -64,7 +64,7 @@ def get_dates(self, resampling_frequency: Frequency) -> List[datetime.datetime]: return list(sorted(dates_union)) def set_dates(self, dates: List[datetime.datetime]) -> None: - #pylint: disable=attribute-defined-outside-init + # pylint: disable=attribute-defined-outside-init self._dates = dates @staticmethod @@ -124,7 +124,7 @@ def get_vector_df( ensemble: str, realizations: List[int], vectors: List[str], - resampling_frequency: Frequency, + resampling_frequency: Optional[Frequency], ) -> pd.DataFrame: provider = self._provider_set[ensemble] ens_vectors = [vec for vec in vectors if vec in provider.vector_names()] diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index de9e04730..04558733d 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -1,3 +1,4 @@ +import datetime from typing import Any, Dict, List, Tuple, Union import plotly.graph_objects as go @@ -365,6 +366,18 @@ def _update_graphs( ), "value", ), + Output( + self.settings_group_unique_id( + self.Ids.SELECTIONS, ParamRespSelections.Ids.DATE_SLIDER + ), + "max", + ), + Output( + self.settings_group_unique_id( + self.Ids.SELECTIONS, ParamRespSelections.Ids.DATE_SLIDER + ), + "marks", + ), Input( self.view_element(self.Ids.TIME_SERIES_CHART) .component_unique_id(ParamRespViewElement.Ids.GRAPH) @@ -384,13 +397,27 @@ def _update_graphs( ), "data", ), + State( + self.settings_group_unique_id( + self.Ids.SELECTIONS, ParamRespSelections.Ids.DATE_SLIDER + ), + "max", + ), + State( + self.settings_group_unique_id( + self.Ids.SELECTIONS, ParamRespSelections.Ids.DATE_SLIDER + ), + "marks", + ), ) @callback_typecheck def _update_date_from_clickdata_or_resampling_freq( timeseries_clickdata: Union[None, dict], resampling_frequency: Frequency, datestr: str, - ) -> int: + state_maxvalue: int, + state_marks: Dict, + ) -> Tuple[int, int, Dict]: """Update date-slider from clickdata""" ctx = callback_context.triggered[0]["prop_id"] if self.Ids.TIME_SERIES_CHART.value in ctx: @@ -402,21 +429,30 @@ def _update_date_from_clickdata_or_resampling_freq( ) if date not in self._vectormodel.dates: # This will happen if the click is on an observation that is on - # a date that is not in the sampled vector dates. It could be + # a date that is not in the sampled vector dates. It could be fixed # by somehow finding the nearest date. raise PreventUpdate - return self._vectormodel.dates.index(date) + return self._vectormodel.dates.index(date), state_maxvalue, state_marks if ParamRespSelections.Ids.RESAMPLING_FREQUENCY_DROPDOWN.value in ctx: # The event is a change of resampling frequency + date = datetime_utils.from_str(datestr) dates = self._vectormodel.get_dates( resampling_frequency=resampling_frequency ) self._vectormodel.set_dates(dates) if date not in dates: print("Find closest") - return self._vectormodel.dates.index(dates[-1]) - return self._vectormodel.dates.index(datetime_utils.from_str(date)) + return ( + self._vectormodel.dates.index(dates[-1]), + len(dates) - 1, + get_slider_marks(dates), + ) + return ( + self._vectormodel.dates.index(date), + len(dates) - 1, + get_slider_marks(dates), + ) raise PreventUpdate("Event not recognized.") @@ -725,3 +761,14 @@ def empty_figure(text: str = "No data available for figure") -> go.Figure: ], } ) + + +def get_slider_marks(dates: List[datetime.datetime]) -> Dict[int, Dict[str, Any]]: + """Formats the marks parameter to the date slider""" + return { + idx: { + "label": datetime_utils.to_str(dates[idx]), + "style": {"white-space": "nowrap"}, + } + for idx in [0, len(dates) - 1] + } From 9aba6d648c41fe3110a0073b8d86931cfc52688d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Tue, 11 Apr 2023 09:28:54 +0200 Subject: [PATCH 06/16] fixed the problem of current date not existing in dates list --- .../_utils/_provider_timesseries_datamodel.py | 4 ++++ .../_views/_parameter_response_view/_view.py | 12 ++---------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py index 4d4e4b684..9ed39ec24 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_utils/_provider_timesseries_datamodel.py @@ -67,6 +67,10 @@ def set_dates(self, dates: List[datetime.datetime]) -> None: # pylint: disable=attribute-defined-outside-init self._dates = dates + def get_closest_date(self, date: datetime.datetime) -> datetime.datetime: + # Returns the closest date to the input date in the dates list. + return min(self._dates, key=lambda dte: abs(dte - date)) + @staticmethod def _create_union_of_vector_names_from_providers( providers: List[EnsembleSummaryProvider], diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index 04558733d..94f8b7abc 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -428,10 +428,7 @@ def _update_date_from_clickdata_or_resampling_freq( else datestr ) if date not in self._vectormodel.dates: - # This will happen if the click is on an observation that is on - # a date that is not in the sampled vector dates. It could be fixed - # by somehow finding the nearest date. - raise PreventUpdate + date = self._vectormodel.get_closest_date(date) return self._vectormodel.dates.index(date), state_maxvalue, state_marks if ParamRespSelections.Ids.RESAMPLING_FREQUENCY_DROPDOWN.value in ctx: @@ -442,12 +439,7 @@ def _update_date_from_clickdata_or_resampling_freq( ) self._vectormodel.set_dates(dates) if date not in dates: - print("Find closest") - return ( - self._vectormodel.dates.index(dates[-1]), - len(dates) - 1, - get_slider_marks(dates), - ) + date = self._vectormodel.get_closest_date(date) return ( self._vectormodel.dates.index(date), len(dates) - 1, From c9e1649feb794f94f3392c4a5994b6d336337b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Tue, 11 Apr 2023 15:13:18 +0200 Subject: [PATCH 07/16] handling rare cornercase --- .../_views/_parameter_response_view/_view.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index 94f8b7abc..ff0d55235 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -541,6 +541,10 @@ def _update_date(dateidx: int) -> str: @callback_typecheck def _update_date_drag_value(dateidx: int) -> str: """Update selected date text on date-slider drag""" + if dateidx >= len(self._vectormodel.dates): + # This is not supposed to happen if callbacks are triggered + # in the right order + return datetime_utils.to_str(self._vectormodel.dates[-1]) return datetime_utils.to_str(self._vectormodel.dates[dateidx]) @callback( From c296be4bdf2690061fba8b65f83b0ae3a3a3280c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 12:49:44 +0200 Subject: [PATCH 08/16] Included SENSNAME as filtering parameter in the parameter filter --- .../_figures/timeseries_figure.py | 2 +- webviz_subsurface/_models/parameter_model.py | 34 ++++++++++++------- .../_utils/_parameters_model.py | 8 ++++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/webviz_subsurface/_figures/timeseries_figure.py b/webviz_subsurface/_figures/timeseries_figure.py index f3a0d0d1a..dc38cd1fe 100644 --- a/webviz_subsurface/_figures/timeseries_figure.py +++ b/webviz_subsurface/_figures/timeseries_figure.py @@ -1,6 +1,6 @@ import datetime from enum import Enum -from typing import List, Optional, Dict +from typing import Dict, List, Optional import numpy as np import pandas as pd diff --git a/webviz_subsurface/_models/parameter_model.py b/webviz_subsurface/_models/parameter_model.py index 03bed8963..92bb7cb88 100644 --- a/webviz_subsurface/_models/parameter_model.py +++ b/webviz_subsurface/_models/parameter_model.py @@ -5,28 +5,36 @@ class ParametersModel: """Class to process ensemble parameter data""" - POSSIBLE_SELECTORS = [ - "ENSEMBLE", - "REAL", - "SENSNAME", - "SENSCASE", - "SENSTYPE", - "SENSNAME_CASE", - ] - def __init__( self, dataframe: pd.DataFrame, drop_constants: bool = True, keep_numeric_only: bool = True, drop_parameters_with_nan: bool = False, + include_sens_filter: bool = False, ) -> None: self._dataframe = dataframe if dataframe is not None else pd.DataFrame() + + self._possible_selectors = [ + "ENSEMBLE", + "REAL", + "SENSNAME", + "SENSCASE", + "SENSTYPE", + "SENSNAME_CASE", + ] + + if include_sens_filter: + self._possible_selectors = [ + col for col in self._possible_selectors if col != "SENSNAME" + ] + self._dataframe["SENSNAME"].fillna("None") + self._validate_dframe() self._sensrun = self._check_if_sensitivity_run() self._prepare_data(drop_constants, keep_numeric_only, drop_parameters_with_nan) self._parameters = [ - x for x in self._dataframe if x not in self.POSSIBLE_SELECTORS + x for x in self._dataframe if x not in self._possible_selectors ] self._parameters_per_ensemble = self._split_parameters_by_ensemble() @@ -44,7 +52,7 @@ def parameters_per_ensemble(self) -> dict: @property def selectors(self) -> list: - return [col for col in self.POSSIBLE_SELECTORS if col in self.dataframe] + return [col for col in self._possible_selectors if col in self.dataframe] @property def sensitivities(self) -> list: @@ -64,7 +72,7 @@ def mc_ensembles(self) -> list: @property def sens_df(self) -> pd.DataFrame: - return self.dataframe[self.POSSIBLE_SELECTORS] + return self.dataframe[self._possible_selectors] @property def dataframe(self) -> pd.DataFrame: @@ -96,7 +104,7 @@ def _prepare_data( param for param in self._dataframe if self._dataframe[param].dropna().nunique() == 1 - and param not in self.POSSIBLE_SELECTORS + and param not in self._possible_selectors ] self._dataframe = self._dataframe.drop(columns=constant_params) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_utils/_parameters_model.py b/webviz_subsurface/plugins/_parameter_analysis/_utils/_parameters_model.py index 4e6b79685..a65b722b2 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_utils/_parameters_model.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_utils/_parameters_model.py @@ -65,8 +65,14 @@ def ensembles(self) -> List[str]: @staticmethod def _aggregate_ensemble_data(dframe: pd.DataFrame) -> pd.DataFrame: """Compute parameter statistics for the different ensembles""" + drop_columns = [ + col + for col in ["REAL", "SENSNAME", "SENSTYPE", "SENSNAME_CASE", "SENSCASE"] + if col in dframe.columns + ] + return ( - dframe.drop(columns=["REAL"]) + dframe.drop(columns=drop_columns) .groupby(["ENSEMBLE"]) .agg( [ From 2c595c2373e0e994a0021766ae414377dfe6d331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 12:50:50 +0200 Subject: [PATCH 09/16] should have been in the previous commit --- webviz_subsurface/_components/parameter_filter.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/webviz_subsurface/_components/parameter_filter.py b/webviz_subsurface/_components/parameter_filter.py index eab259e9c..65026a2f8 100644 --- a/webviz_subsurface/_components/parameter_filter.py +++ b/webviz_subsurface/_components/parameter_filter.py @@ -43,6 +43,7 @@ def __init__( drop_constants=True, keep_numeric_only=False, drop_parameters_with_nan=True, + include_sens_filter=True, ) self._dframe = self._pmodel.dataframe self._range_parameters = self._get_range_parameters() @@ -361,7 +362,15 @@ def update_filtercomponents_and_apply( ens_df = self._dframe[self._dframe["ENSEMBLE"].isin(ensembles)] children = [] - for col in self._pmodel.get_parameters_for_ensembles(ensembles): + ens_parameters = self._pmodel.get_parameters_for_ensembles(ensembles) + + # if SENSNAME is among the parameters we want to place it first + if "SENSNAME" in ens_parameters: + ens_parameters = ["SENSNAME"] + [ + p for p in ens_parameters if p != "SENSNAME" + ] + + for col in ens_parameters: if col in self._range_parameters: children.append( make_range_slider( From f16f1af71b74dc68de2a0314370d13cc55eca463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 13:34:58 +0200 Subject: [PATCH 10/16] Fixed bug related to vectors not existing in all ensembles --- .../_views/_parameter_response_view/_view.py | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py index ff0d55235..db6855a8d 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_view.py @@ -226,17 +226,27 @@ def _update_graphs( else [] ) - # Get dataframe with vectors and dataframe with parameters and merge - # If the resampling dropdown is disable it means the data is presampled, - # in which case we pass None as resampling frequency - vector_df = self._vectormodel.get_vector_df( - ensemble=ensemble, - realizations=realizations, - vectors=vectors_for_param_corr + [selected_vector], - resampling_frequency=resampling_frequency - if not self._disable_resampling_dropdown - else None, - ) + try: + # Get dataframe with vectors and dataframe with parameters and merge + # If the resampling dropdown is disable it means the data is presampled, + # in which case we pass None as resampling frequency + vector_df = self._vectormodel.get_vector_df( + ensemble=ensemble, + realizations=realizations, + vectors=vectors_for_param_corr + [selected_vector], + resampling_frequency=resampling_frequency + if not self._disable_resampling_dropdown + else None, + ) + except ValueError: + # It could be that the selected vector does not exist in the + # selected ensemble, f.ex if the ensembles have different well names + return [ + empty_figure( + "Selected vector probably does not exist in selected ensemble" + ) + ] * 4 + if date not in vector_df["DATE"].values: return [empty_figure("Selected date does not exist for ensemble")] * 4 if selected_vector not in vector_df: From c80fb4399ca344c534aca6bbdf52b3d19cd00711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 13:47:18 +0200 Subject: [PATCH 11/16] Changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6efb154aa..5bbd79a23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1195](https://github.com/equinor/webviz-subsurface/pull/1195) - `RftPlotter` faultlines argument can now use fault polygons csv file with *X, Y, ID* header (fmu-dataio default) - [#1196](https://github.com/equinor/webviz-subsurface/pull/1196) - `SwatinitQC` faultlines argument can now use fault polygons csv file with *X, Y, ID* header (fmu-dataio default) -- [#1201](https://github.com/equinor/webviz-subsurface/pull/1196) - `ParameterAnalysis` plugin converted to WLF (Webviz Layout Framework). Removed auto-detection of sensitivity ensembles. +- [#1201](https://github.com/equinor/webviz-subsurface/pull/1201) - `ParameterAnalysis` plugin converted to WLF (Webviz Layout Framework). Removed auto-detection of sensitivity ensembles. ### Added - [#1199](https://github.com/equinor/webviz-subsurface/pull/1199) - Added more statistical options to the WellOverview tab in `WellAnalysis`, and the possibility to see injection rates. +- [#1207](https://github.com/equinor/webviz-subsurface/pull/1207) - New functionality in `ParameterAnalysis`: observations, resampling frequency and sensitivity filter. ## [0.2.17] - 2023-01-18 From 3a1b8be0df46da8feea5e7dbf7a7d15bc77fa485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 15:02:23 +0200 Subject: [PATCH 12/16] Fixed problem in RftPlotter plugin related to changes in parameter_model.py --- .../plugins/_rft_plotter/_utils/_rft_plotter_data_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webviz_subsurface/plugins/_rft_plotter/_utils/_rft_plotter_data_model.py b/webviz_subsurface/plugins/_rft_plotter/_utils/_rft_plotter_data_model.py index cbb1ef8aa..5c16b0eb8 100644 --- a/webviz_subsurface/plugins/_rft_plotter/_utils/_rft_plotter_data_model.py +++ b/webviz_subsurface/plugins/_rft_plotter/_utils/_rft_plotter_data_model.py @@ -266,7 +266,7 @@ def create_rft_and_param_pivot_table( ens_params = [ param for param in param_df.columns - if param not in self.param_model.POSSIBLE_SELECTORS + if param not in self.param_model.selectors ] ens_rfts = [rft for rft in pivot_df.columns if rft != "REAL"] From 2a61b53ea6492acfa60b3342f305dfbfbc17fdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 15:28:11 +0200 Subject: [PATCH 13/16] Bug fix related to ensembles without SENSNAME --- webviz_subsurface/_models/parameter_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webviz_subsurface/_models/parameter_model.py b/webviz_subsurface/_models/parameter_model.py index 92bb7cb88..167fa0d0e 100644 --- a/webviz_subsurface/_models/parameter_model.py +++ b/webviz_subsurface/_models/parameter_model.py @@ -24,7 +24,8 @@ def __init__( "SENSNAME_CASE", ] - if include_sens_filter: + if include_sens_filter and "SENSNAME" in self._dataframe.columns: + # Remove SENSNAME from possible selectors self._possible_selectors = [ col for col in self._possible_selectors if col != "SENSNAME" ] From 31bf1cf415bdbac36353f1dfaac5ce4e019c5e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 15:43:23 +0200 Subject: [PATCH 14/16] Bug fix related to the new parameter observations in the time series figure --- webviz_subsurface/_figures/timeseries_figure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webviz_subsurface/_figures/timeseries_figure.py b/webviz_subsurface/_figures/timeseries_figure.py index dc38cd1fe..1950a6df0 100644 --- a/webviz_subsurface/_figures/timeseries_figure.py +++ b/webviz_subsurface/_figures/timeseries_figure.py @@ -30,7 +30,7 @@ def __init__( ensemble: str, color_col: Optional[str], line_shape_fallback: str, - observations: Dict, + observations: Optional[Dict], historical_vector_df: Optional[pd.DataFrame] = None, dateline: Optional[datetime.datetime] = None, ): @@ -41,7 +41,7 @@ def __init__( self.visualization = visualization self.historical_vector_df = historical_vector_df self.date = dateline - self.observations = observations + self.observations = observations if observations is not None else {} self.line_shape = self.get_line_shape(line_shape_fallback) self.create_traces() From 23f8b41d19e8364d205c480534a3808b026b3dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Wed, 12 Apr 2023 15:43:52 +0200 Subject: [PATCH 15/16] More bug fixing related to the same --- webviz_subsurface/_figures/timeseries_figure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webviz_subsurface/_figures/timeseries_figure.py b/webviz_subsurface/_figures/timeseries_figure.py index 1950a6df0..d180dde84 100644 --- a/webviz_subsurface/_figures/timeseries_figure.py +++ b/webviz_subsurface/_figures/timeseries_figure.py @@ -30,7 +30,7 @@ def __init__( ensemble: str, color_col: Optional[str], line_shape_fallback: str, - observations: Optional[Dict], + observations: Optional[Dict] = None, historical_vector_df: Optional[pd.DataFrame] = None, dateline: Optional[datetime.datetime] = None, ): From 2ea4b94f25fe38854e324ff387ccd90d73a95fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Lind-Johansen?= Date: Thu, 13 Apr 2023 08:00:35 +0200 Subject: [PATCH 16/16] Some updates related to failing test --- .../test_parameter_filter.py | 19 ++++++++++++++++--- .../_components/parameter_filter.py | 3 ++- .../_settings/_parameter_filter.py | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/integration_tests/test_parameter_filter.py b/tests/integration_tests/test_parameter_filter.py index c1e97bf46..23de5d818 100644 --- a/tests/integration_tests/test_parameter_filter.py +++ b/tests/integration_tests/test_parameter_filter.py @@ -4,12 +4,25 @@ def test_dataframe(testdata_folder) -> None: + # pylint: disable=protected-access dframe = pd.read_csv( testdata_folder / "reek_test_data" / "aggregated_data" / "parameters.csv" ) - component = ParameterFilter("test", dframe) - # pylint: disable=protected-access + + expected_discrete_parameters = [ + "FWL", + "MULTFLT_F1", + "INTERPOLATE_WO", + "COHIBA_MODEL_MODE", + "RMS_SEED", + ] + + component = ParameterFilter("test", dframe, include_sens_filter=False) + assert set(component._discrete_parameters) == set(expected_discrete_parameters) + + component = ParameterFilter("test", dframe, include_sens_filter=True) assert set(component._discrete_parameters) == set( - ["FWL", "MULTFLT_F1", "INTERPOLATE_WO", "COHIBA_MODEL_MODE", "RMS_SEED"] + expected_discrete_parameters + ["SENSNAME"] ) + assert component.is_sensitivity_run is True diff --git a/webviz_subsurface/_components/parameter_filter.py b/webviz_subsurface/_components/parameter_filter.py index 65026a2f8..b0f9ee96a 100644 --- a/webviz_subsurface/_components/parameter_filter.py +++ b/webviz_subsurface/_components/parameter_filter.py @@ -30,6 +30,7 @@ def __init__( dframe: pd.DataFrame, reset_on_ensemble_update: bool = False, display_header: bool = True, + include_sens_filter: bool = False, ) -> None: """ * **`uuid`:** Unique id (use the plugin id). @@ -43,7 +44,7 @@ def __init__( drop_constants=True, keep_numeric_only=False, drop_parameters_with_nan=True, - include_sens_filter=True, + include_sens_filter=include_sens_filter, ) self._dframe = self._pmodel.dataframe self._range_parameters = self._get_range_parameters() diff --git a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_parameter_filter.py b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_parameter_filter.py index 943edd05e..3f2f6935b 100644 --- a/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_parameter_filter.py +++ b/webviz_subsurface/plugins/_parameter_analysis/_views/_parameter_response_view/_settings/_parameter_filter.py @@ -25,4 +25,5 @@ def layout(self) -> List[Component]: ].copy(), reset_on_ensemble_update=True, display_header=False, + include_sens_filter=True, ).layout