Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort the responses and parameter views #233

Merged
merged 1 commit into from
Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions tests/data/snake_oil_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def content(self):
"id": 2,
"time_created": "2020-04-29T09:43:25",
},
{
"children": [],
"name": "nr_42",
"parent": None,
"id": 42,
"time_created": "2021-04-29T09:43:25",
},
],
}
],
Expand Down Expand Up @@ -97,6 +104,10 @@ def content(self):
}
}
},
"http://127.0.0.1:5000/ensembles/2/parameters": [
{"name": "test_parameter_1", "labels": []},
{"name": "test_parameter_11", "labels": []},
],
"http://127.0.0.1:5000/ensembles/2/responses": {
"SNAKE_OIL_GPR_DIFF": {
"name": "SNAKE_OIL_GPR_DIFF",
Expand Down Expand Up @@ -280,29 +291,41 @@ def to_parquet_helper(dataframe: pd.DataFrame) -> bytes:
"timeCreated": "2020-04-29T09:36:26",
"size": 1,
"activeRealizations": [0],
"userdata": '{"name": "default"}',
"userdata": '{"name": "nr_42"}',
}
}
},
"http://127.0.0.1:5000/ensembles/42/parameters": [
{"name": "test_parameter_1", "labels": []},
{"name": "test_parameter_2", "labels": ["a", "b"]},
{"name": "test_parameter_77", "labels": []},
{"name": "test_parameter_11", "labels": []},
],
"http://127.0.0.1:5000/ensembles/42/responses": {
"test_resposne": {
"test_response": {
"name": "name_test_response",
"id": "test_response_id_1",
},
"test_response_99": {
"name": "name_test_response",
"id": "test_response_id_99",
},
"test_response_44": {
"name": "name_test_response",
"id": "test_response_id_44",
},
"test_response_4": {
"name": "name_test_response",
"id": "test_response_id_4",
},
},
"http://127.0.0.1:5000/ensembles/42/records/test_parameter_1/labels": [],
"http://127.0.0.1:5000/ensembles/42/records/test_parameter_2/labels": [
"a",
"b",
],
"http://127.0.0.1:5000/ensembles/42/records/test_parameter_2/labels": [
"a",
"b",
],
"http://127.0.0.1:5000/ensembles/42/records/test_parameter_77/labels": [],
"http://127.0.0.1:5000/ensembles/42/records/test_parameter_11/labels": [],
}
)

Expand Down
8 changes: 4 additions & 4 deletions tests/models/test_ensemble_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ def test_ensemble_model(mock_data):
assert len(ens_model.responses) == 1


def test_ensemble_model_labled_parameters(mock_data):
def test_ensemble_model_labeled_parameters(mock_data):
ens_id = 42
ens_model = EnsembleModel(ensemble_id=ens_id, project_id=None)
assert ens_model.name == "default"
assert len(ens_model.parameters) == 3
assert ens_model.name == "nr_42"
assert len(ens_model.parameters) == 5
for param_name, parameter in ens_model.parameters.items():
name, label = (
param_name.split("::", maxsplit=1)
Expand All @@ -33,7 +33,7 @@ def test_ensemble_model_parameter_data(mock_data):
ens_id = 42
ens_model = EnsembleModel(ensemble_id=ens_id, project_id=None)
parameters = ens_model.parameters
assert len(parameters) == 3
assert len(parameters) == 5

# Parameter no labels:
expected_labels = ens_model._data_loader.get_record_labels(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_data_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

def test_get_ensembles(mock_data):
ens = get_ensembles()
assert len(ens) == 2
assert len(ens) == 3
35 changes: 35 additions & 0 deletions tests/views/test_parameter_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,38 @@ def test_search_input_return_functionality(
)

assert dash_duo.get_logs() == []


def test_parameter_selector_sorting(
mock_data,
dash_duo,
):
app = dash.Dash(__name__)
plugin = ParameterComparison(app, project_identifier=None)
layout = plugin.layout
app.layout = layout
dash_duo.start_server(app)
windowsize = (630, 1200)
dash_duo.driver.set_window_size(*windowsize)

ensemble_selector = dash_duo.find_element(
"#" + plugin.uuid("ensemble-multi-selector")
)

dash_duo.click_at_coord_fractions(ensemble_selector, 0.1, 0.25)
dash_duo.wait_for_contains_text(
"#" + plugin.uuid("selected-ensemble-dropdown"),
"nr_42",
timeout=4,
)

parameter_selector_container = dash_duo.find_element(
"#" + plugin.uuid("container-parameter-selector-multi-params")
)
parameter_list = parameter_selector_container.text.split("\n")

assert parameter_list[0] == "test_parameter_1"
assert parameter_list[1] == "test_parameter_11"
assert parameter_list[2] == "test_parameter_2::a"
assert parameter_list[3] == "test_parameter_2::b"
assert parameter_list[4] == "test_parameter_77"
31 changes: 31 additions & 0 deletions tests/views/test_response_correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,34 @@ def test_response_correlation_view(
assert len(response_views) == 4

assert dash_duo.get_logs() == [], "browser console should contain no error"


def test_response_selector_sorting(mock_data, dash_duo):

app = dash.Dash(__name__)
plugin = ResponseCorrelation(app, project_identifier=None)
layout = plugin.layout
app.layout = layout
dash_duo.start_server(app)
windowsize = (630, 1200)
dash_duo.driver.set_window_size(*windowsize)

ensemble_selector = dash_duo.find_element(
"#" + plugin.uuid("ensemble-multi-selector")
)
dash_duo.click_at_coord_fractions(ensemble_selector, 0.1, 0.25)
dash_duo.wait_for_contains_text(
"#" + plugin.uuid("selected-ensemble-dropdown"),
"nr_42",
timeout=4,
)

response_selector_container = dash_duo.find_element(
"#" + plugin.uuid("container-parameter-selector-multi-resp")
)
response_list = response_selector_container.text.split("\n")

assert response_list[0] == "test_response"
assert response_list[1] == "test_response_4"
assert response_list[2] == "test_response_44"
assert response_list[3] == "test_response_99"
4 changes: 3 additions & 1 deletion webviz_ert/controllers/controller_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def parameter_options(
else:
params_included = params_included.intersection(parameters)
if params_included:
return [
parameter_list = [
{"label": parameter, "value": parameter} for parameter in params_included
]
parameter_list.sort(key=lambda x: str(x.get("label")))
return parameter_list
return []
3 changes: 2 additions & 1 deletion webviz_ert/controllers/observation_response_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ def update_graph(

def _generate_plot(ensemble_id: str, color: str) -> ResponsePlotModel:
ensemble = load_ensemble(parent, ensemble_id)
plot = _create_misfits_plot(ensemble.responses[response], [], color)
resp = ensemble.responses[str(response)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this refactoring really needed? Also, why is the string conversion required ? str(response)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I did not explicitly cast to string the type-check would complain about the Optional[str] type

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, something is fishy here that you had to explicitly cast to string... Any way this function is a bit messy I think it should be refactored in the future such that it does not take response from the outer scope but it should expect a response name as part of the function arguments.

plot = _create_misfits_plot(resp, [], color)
return plot

response_plots = [
Expand Down
1 change: 1 addition & 0 deletions webviz_ert/controllers/parameter_selector_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def update_parameters_options(
raise ValueError(f"Undefined parameter type {store_type}")

options = [option for option in options if option["value"] not in selected]

if bool(filter_search):
options = [
option
Expand Down
36 changes: 21 additions & 15 deletions webviz_ert/models/ensemble_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import pandas as pd
from typing import Mapping, List, Dict, Union, Any, Optional
from webviz_ert.data_loader import get_data_loader, DataLoaderException

from webviz_ert.models import Response, PriorModel, ParametersModel


Expand Down Expand Up @@ -36,7 +35,7 @@ def _create_parameter_models(


class EnsembleModel:
def __init__(self, ensemble_id: str, project_id: str):
def __init__(self, ensemble_id: str, project_id: str) -> None:
self._data_loader = get_data_loader(project_id)
self._schema = self._data_loader.get_ensemble(ensemble_id)
self._experiment_id = self._schema["experiment"]["id"]
Expand All @@ -54,23 +53,30 @@ def __init__(self, ensemble_id: str, project_id: str):
self._size = self._schema["size"]
self._active_realizations = self._schema["activeRealizations"]
self._time_created = self._schema["timeCreated"]
self.responses = {
resp_name: Response(
name=resp_name,
ensemble_id=ensemble_id,
project_id=project_id,
ensemble_size=self._size,
active_realizations=self._active_realizations,
resp_schema=resp_schema,
)
for resp_name, resp_schema in self._data_loader.get_ensemble_responses(
ensemble_id
).items()
}
self._responses: Dict[str, Response] = {}
self._parameters: Optional[Mapping[str, ParametersModel]] = None
self._cached_children: Optional[List["EnsembleModel"]] = None
self._cached_parent: Optional["EnsembleModel"] = None

@property
def responses(self) -> Dict[str, Response]:
if not self._responses:
self._responses = {}
responses_dict = self._data_loader.get_ensemble_responses(self._id)
response_names = list(responses_dict.keys())
response_names.sort()

for name in response_names:
self._responses[name] = Response(
name=name,
ensemble_id=self._id,
project_id=self._project_id,
ensemble_size=self._size,
active_realizations=self._active_realizations,
resp_schema=responses_dict[name],
)
return self._responses

@property
def children(self) -> Optional[List["EnsembleModel"]]:
if not self._cached_children:
Expand Down