ert 16.0.9__py3-none-any.whl → 19.0.0rc2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _ert/events.py +19 -2
- _ert/forward_model_runner/client.py +6 -2
- _ert/forward_model_runner/fm_dispatch.py +9 -6
- _ert/forward_model_runner/reporting/event.py +1 -0
- _ert/forward_model_runner/runner.py +1 -2
- _ert/utils.py +12 -0
- ert/__main__.py +58 -38
- ert/analysis/_enif_update.py +8 -4
- ert/analysis/_es_update.py +19 -6
- ert/analysis/_update_commons.py +16 -6
- ert/base_model_context.py +1 -1
- ert/cli/main.py +17 -12
- ert/cli/monitor.py +7 -0
- ert/config/__init__.py +17 -6
- ert/config/_create_observation_dataframes.py +118 -21
- ert/config/_get_num_cpu.py +1 -1
- ert/config/_observations.py +91 -2
- ert/config/_read_summary.py +74 -328
- ert/config/design_matrix.py +62 -23
- ert/config/distribution.py +1 -1
- ert/config/ensemble_config.py +9 -17
- ert/config/ert_config.py +155 -58
- ert/config/everest_control.py +234 -0
- ert/config/{everest_constraints_config.py → everest_response.py} +27 -15
- ert/config/field.py +99 -90
- ert/config/forward_model_step.py +122 -17
- ert/config/gen_data_config.py +5 -10
- ert/config/gen_kw_config.py +11 -41
- ert/config/known_response_types.py +14 -0
- ert/config/parameter_config.py +1 -33
- ert/config/parsing/_option_dict.py +10 -2
- ert/config/parsing/config_errors.py +1 -1
- ert/config/parsing/config_keywords.py +2 -1
- ert/config/parsing/config_schema.py +23 -11
- ert/config/parsing/config_schema_deprecations.py +3 -3
- ert/config/parsing/config_schema_item.py +26 -11
- ert/config/parsing/context_values.py +3 -3
- ert/config/parsing/file_context_token.py +1 -1
- ert/config/parsing/observations_parser.py +6 -2
- ert/config/parsing/queue_system.py +9 -0
- ert/config/parsing/schema_item_type.py +1 -0
- ert/config/queue_config.py +42 -50
- ert/config/response_config.py +0 -8
- ert/config/rft_config.py +275 -0
- ert/config/summary_config.py +3 -8
- ert/config/surface_config.py +73 -26
- ert/config/workflow_fixtures.py +2 -1
- ert/config/workflow_job.py +135 -54
- ert/dark_storage/client/__init__.py +2 -2
- ert/dark_storage/client/_session.py +4 -4
- ert/dark_storage/client/client.py +2 -2
- ert/dark_storage/common.py +12 -3
- ert/dark_storage/compute/misfits.py +11 -7
- ert/dark_storage/endpoints/compute/misfits.py +6 -4
- ert/dark_storage/endpoints/ensembles.py +4 -0
- ert/dark_storage/endpoints/experiment_server.py +30 -24
- ert/dark_storage/endpoints/experiments.py +2 -2
- ert/dark_storage/endpoints/observations.py +8 -6
- ert/dark_storage/endpoints/parameters.py +4 -12
- ert/dark_storage/endpoints/responses.py +24 -5
- ert/dark_storage/json_schema/ensemble.py +3 -0
- ert/dark_storage/json_schema/experiment.py +1 -1
- ert/data/_measured_data.py +6 -5
- ert/ensemble_evaluator/__init__.py +8 -1
- ert/ensemble_evaluator/config.py +2 -1
- ert/ensemble_evaluator/evaluator.py +81 -29
- ert/ensemble_evaluator/event.py +6 -0
- ert/ensemble_evaluator/snapshot.py +3 -1
- ert/ensemble_evaluator/state.py +1 -0
- ert/field_utils/__init__.py +8 -0
- ert/field_utils/field_utils.py +228 -15
- ert/field_utils/grdecl_io.py +1 -1
- ert/field_utils/roff_io.py +1 -1
- ert/gui/__init__.py +5 -2
- ert/gui/ertnotifier.py +1 -1
- ert/gui/ertwidgets/__init__.py +23 -16
- ert/gui/ertwidgets/analysismoduleedit.py +2 -2
- ert/gui/ertwidgets/checklist.py +1 -1
- ert/gui/ertwidgets/closabledialog.py +2 -0
- ert/gui/ertwidgets/copyablelabel.py +2 -0
- ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
- ert/gui/ertwidgets/ensembleselector.py +2 -2
- ert/gui/ertwidgets/listeditbox.py +2 -0
- ert/gui/ertwidgets/models/__init__.py +2 -0
- ert/gui/ertwidgets/models/activerealizationsmodel.py +5 -1
- ert/gui/ertwidgets/models/path_model.py +1 -1
- ert/gui/ertwidgets/models/targetensemblemodel.py +5 -1
- ert/gui/ertwidgets/models/text_model.py +4 -1
- ert/gui/ertwidgets/pathchooser.py +0 -3
- ert/gui/ertwidgets/searchbox.py +17 -4
- ert/gui/ertwidgets/stringbox.py +2 -0
- ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
- ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +63 -30
- ert/gui/main.py +41 -13
- ert/gui/main_window.py +3 -7
- ert/gui/model/fm_step_list.py +3 -0
- ert/gui/model/real_list.py +1 -0
- ert/gui/model/snapshot.py +1 -0
- ert/gui/simulation/combobox_with_description.py +3 -0
- ert/gui/simulation/ensemble_experiment_panel.py +8 -2
- ert/gui/simulation/ensemble_information_filter_panel.py +7 -2
- ert/gui/simulation/ensemble_smoother_panel.py +8 -2
- ert/gui/simulation/evaluate_ensemble_panel.py +17 -7
- ert/gui/simulation/experiment_panel.py +18 -6
- ert/gui/simulation/manual_update_panel.py +35 -10
- ert/gui/simulation/multiple_data_assimilation_panel.py +13 -9
- ert/gui/simulation/run_dialog.py +47 -20
- ert/gui/simulation/single_test_run_panel.py +6 -3
- ert/gui/simulation/view/progress_widget.py +2 -0
- ert/gui/simulation/view/realization.py +5 -1
- ert/gui/simulation/view/update.py +2 -0
- ert/gui/summarypanel.py +20 -1
- ert/gui/tools/event_viewer/panel.py +3 -4
- ert/gui/tools/event_viewer/tool.py +2 -0
- ert/gui/tools/load_results/load_results_panel.py +1 -1
- ert/gui/tools/load_results/load_results_tool.py +2 -0
- ert/gui/tools/manage_experiments/export_dialog.py +136 -0
- ert/gui/tools/manage_experiments/manage_experiments_panel.py +2 -0
- ert/gui/tools/manage_experiments/storage_info_widget.py +121 -16
- ert/gui/tools/manage_experiments/storage_widget.py +4 -3
- ert/gui/tools/plot/customize/color_chooser.py +5 -2
- ert/gui/tools/plot/customize/customize_plot_dialog.py +2 -0
- ert/gui/tools/plot/customize/default_customization_view.py +4 -0
- ert/gui/tools/plot/customize/limits_customization_view.py +3 -0
- ert/gui/tools/plot/customize/statistics_customization_view.py +3 -0
- ert/gui/tools/plot/customize/style_chooser.py +2 -0
- ert/gui/tools/plot/customize/style_customization_view.py +3 -0
- ert/gui/tools/plot/data_type_keys_widget.py +2 -0
- ert/gui/tools/plot/data_type_proxy_model.py +3 -0
- ert/gui/tools/plot/plot_api.py +50 -28
- ert/gui/tools/plot/plot_ensemble_selection_widget.py +17 -10
- ert/gui/tools/plot/plot_widget.py +15 -2
- ert/gui/tools/plot/plot_window.py +41 -19
- ert/gui/tools/plot/plottery/plot_config.py +2 -0
- ert/gui/tools/plot/plottery/plot_context.py +14 -0
- ert/gui/tools/plot/plottery/plots/__init__.py +2 -0
- ert/gui/tools/plot/plottery/plots/cesp.py +3 -1
- ert/gui/tools/plot/plottery/plots/distribution.py +6 -1
- ert/gui/tools/plot/plottery/plots/ensemble.py +13 -5
- ert/gui/tools/plot/plottery/plots/gaussian_kde.py +12 -2
- ert/gui/tools/plot/plottery/plots/histogram.py +3 -1
- ert/gui/tools/plot/plottery/plots/misfits.py +436 -0
- ert/gui/tools/plot/plottery/plots/observations.py +18 -4
- ert/gui/tools/plot/plottery/plots/statistics.py +62 -20
- ert/gui/tools/plot/plottery/plots/std_dev.py +3 -1
- ert/gui/tools/plot/widgets/clearable_line_edit.py +9 -0
- ert/gui/tools/plot/widgets/filter_popup.py +2 -0
- ert/gui/tools/plot/widgets/filterable_kw_list_model.py +3 -0
- ert/gui/tools/plugins/plugin.py +1 -1
- ert/gui/tools/plugins/plugins_tool.py +2 -0
- ert/gui/tools/plugins/process_job_dialog.py +3 -0
- ert/gui/tools/workflows/workflow_dialog.py +2 -0
- ert/gui/tools/workflows/workflows_tool.py +2 -0
- ert/libres_facade.py +5 -7
- ert/logging/__init__.py +4 -1
- ert/mode_definitions.py +2 -0
- ert/plugins/__init__.py +4 -6
- ert/plugins/hook_implementations/workflows/csv_export.py +2 -3
- ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
- ert/plugins/hook_specifications/__init__.py +0 -10
- ert/plugins/hook_specifications/jobs.py +0 -9
- ert/plugins/plugin_manager.py +53 -124
- ert/resources/forward_models/run_reservoirsimulator.py +8 -4
- ert/resources/forward_models/template_render.py +10 -10
- ert/resources/shell_scripts/delete_directory.py +2 -2
- ert/run_models/__init__.py +24 -6
- ert/run_models/_create_run_path.py +133 -38
- ert/run_models/ensemble_experiment.py +10 -4
- ert/run_models/ensemble_information_filter.py +8 -1
- ert/run_models/ensemble_smoother.py +9 -3
- ert/run_models/evaluate_ensemble.py +8 -6
- ert/run_models/event.py +7 -3
- ert/run_models/everest_run_model.py +337 -113
- ert/run_models/initial_ensemble_run_model.py +25 -24
- ert/run_models/manual_update.py +6 -3
- ert/run_models/manual_update_enif.py +37 -0
- ert/run_models/model_factory.py +78 -18
- ert/run_models/multiple_data_assimilation.py +22 -11
- ert/run_models/run_model.py +72 -73
- ert/run_models/single_test_run.py +7 -4
- ert/run_models/update_run_model.py +4 -2
- ert/runpaths.py +5 -6
- ert/sample_prior.py +9 -4
- ert/scheduler/__init__.py +10 -5
- ert/scheduler/driver.py +40 -0
- ert/scheduler/event.py +3 -1
- ert/scheduler/job.py +23 -13
- ert/scheduler/lsf_driver.py +15 -5
- ert/scheduler/openpbs_driver.py +10 -4
- ert/scheduler/scheduler.py +5 -0
- ert/scheduler/slurm_driver.py +20 -5
- ert/services/__init__.py +2 -2
- ert/services/_base_service.py +37 -20
- ert/services/_storage_main.py +20 -18
- ert/services/ert_server.py +317 -0
- ert/shared/_doc_utils/__init__.py +4 -2
- ert/shared/_doc_utils/ert_jobs.py +1 -4
- ert/shared/net_utils.py +43 -18
- ert/shared/storage/connection.py +3 -3
- ert/shared/version.py +3 -3
- ert/storage/__init__.py +14 -1
- ert/storage/local_ensemble.py +44 -13
- ert/storage/local_experiment.py +54 -34
- ert/storage/local_storage.py +90 -58
- ert/storage/migration/to10.py +3 -2
- ert/storage/migration/to11.py +9 -10
- ert/storage/migration/to12.py +19 -20
- ert/storage/migration/to13.py +28 -27
- ert/storage/migration/to14.py +3 -3
- ert/storage/migration/to15.py +25 -0
- ert/storage/migration/to16.py +38 -0
- ert/storage/migration/to17.py +42 -0
- ert/storage/migration/to18.py +11 -0
- ert/storage/migration/to19.py +34 -0
- ert/storage/migration/to20.py +23 -0
- ert/storage/migration/to21.py +25 -0
- ert/storage/migration/to6.py +3 -2
- ert/storage/migration/to7.py +12 -13
- ert/storage/migration/to8.py +9 -11
- ert/storage/migration/to9.py +5 -4
- ert/storage/realization_storage_state.py +7 -7
- ert/substitutions.py +12 -28
- ert/validation/active_range.py +7 -7
- ert/validation/ensemble_realizations_argument.py +4 -2
- ert/validation/rangestring.py +16 -16
- ert/workflow_runner.py +6 -3
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/METADATA +21 -15
- ert-19.0.0rc2.dist-info/RECORD +524 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/WHEEL +1 -1
- everest/api/everest_data_api.py +14 -1
- everest/assets/everest_logo.svg +406 -0
- everest/bin/config_branch_script.py +30 -14
- everest/bin/everconfigdump_script.py +2 -10
- everest/bin/everest_script.py +53 -33
- everest/bin/everlint_script.py +3 -5
- everest/bin/kill_script.py +7 -5
- everest/bin/main.py +11 -24
- everest/bin/monitor_script.py +64 -35
- everest/bin/utils.py +58 -43
- everest/bin/visualization_script.py +23 -13
- everest/config/__init__.py +4 -1
- everest/config/control_config.py +81 -6
- everest/config/control_variable_config.py +4 -3
- everest/config/everest_config.py +102 -79
- everest/config/forward_model_config.py +5 -3
- everest/config/install_data_config.py +7 -5
- everest/config/install_job_config.py +45 -3
- everest/config/install_template_config.py +3 -3
- everest/config/optimization_config.py +19 -6
- everest/config/output_constraint_config.py +8 -2
- everest/config/server_config.py +6 -55
- everest/config/simulator_config.py +62 -17
- everest/config/utils.py +25 -105
- everest/config/validation_utils.py +34 -15
- everest/config_file_loader.py +30 -21
- everest/detached/__init__.py +0 -6
- everest/detached/client.py +7 -52
- everest/detached/everserver.py +19 -45
- everest/everest_storage.py +24 -40
- everest/gui/everest_client.py +2 -3
- everest/gui/main_window.py +2 -2
- everest/optimizer/everest2ropt.py +68 -42
- everest/optimizer/opt_model_transforms.py +15 -20
- everest/optimizer/utils.py +0 -29
- everest/plugins/hook_specs.py +0 -24
- everest/strings.py +1 -6
- everest/util/__init__.py +3 -1
- ert/config/everest_objective_config.py +0 -95
- ert/config/ext_param_config.py +0 -107
- ert/gui/tools/export/__init__.py +0 -3
- ert/gui/tools/export/export_panel.py +0 -83
- ert/gui/tools/export/export_tool.py +0 -67
- ert/gui/tools/export/exporter.py +0 -36
- ert/plugins/hook_specifications/ecl_config.py +0 -29
- ert/services/storage_service.py +0 -127
- ert/summary_key_type.py +0 -234
- ert-16.0.9.dist-info/RECORD +0 -521
- everest/bin/everexport_script.py +0 -53
- everest/config/sampler_config.py +0 -103
- everest/simulator/__init__.py +0 -88
- everest/simulator/everest_to_ert.py +0 -252
- /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
- /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/entry_points.txt +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/licenses/COPYING +0 -0
- {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/top_level.txt +0 -0
ert/gui/tools/plot/plot_api.py
CHANGED
|
@@ -16,10 +16,12 @@ import numpy.typing as npt
|
|
|
16
16
|
import pandas as pd
|
|
17
17
|
from pandas.api.types import is_numeric_dtype
|
|
18
18
|
from pandas.errors import ParserError
|
|
19
|
+
from resfo_utilities import history_key
|
|
19
20
|
|
|
20
|
-
from ert.config import
|
|
21
|
-
from ert.services import
|
|
22
|
-
from ert.
|
|
21
|
+
from ert.config import ParameterConfig, ResponseMetadata
|
|
22
|
+
from ert.services import ErtServer
|
|
23
|
+
from ert.storage.local_experiment import _parameters_adapter as parameter_config_adapter
|
|
24
|
+
from ert.storage.realization_storage_state import RealizationStorageState
|
|
23
25
|
|
|
24
26
|
logger = logging.getLogger(__name__)
|
|
25
27
|
|
|
@@ -43,7 +45,7 @@ class PlotApiKeyDefinition(NamedTuple):
|
|
|
43
45
|
dimensionality: int
|
|
44
46
|
metadata: dict[Any, Any]
|
|
45
47
|
filter_on: dict[Any, Any] | None = None
|
|
46
|
-
|
|
48
|
+
parameter: ParameterConfig | None = None
|
|
47
49
|
response_metadata: ResponseMetadata | None = None
|
|
48
50
|
|
|
49
51
|
|
|
@@ -55,7 +57,7 @@ class PlotApi:
|
|
|
55
57
|
|
|
56
58
|
@property
|
|
57
59
|
def api_version(self) -> str:
|
|
58
|
-
with
|
|
60
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
59
61
|
try:
|
|
60
62
|
response = client.get("/version", timeout=self._timeout)
|
|
61
63
|
self._check_response(response)
|
|
@@ -81,7 +83,7 @@ class PlotApi:
|
|
|
81
83
|
return self._all_ensembles
|
|
82
84
|
|
|
83
85
|
self._all_ensembles = []
|
|
84
|
-
with
|
|
86
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
85
87
|
try:
|
|
86
88
|
response = client.get("/experiments", timeout=self._timeout)
|
|
87
89
|
self._check_response(response)
|
|
@@ -92,18 +94,27 @@ class PlotApi:
|
|
|
92
94
|
f"/ensembles/{ensemble_id}", timeout=self._timeout
|
|
93
95
|
)
|
|
94
96
|
self._check_response(response)
|
|
95
|
-
response_json = response.json()
|
|
97
|
+
response_json: dict[str, Any] = response.json()
|
|
96
98
|
ensemble_name: str = response_json["userdata"]["name"]
|
|
97
99
|
experiment_name: str = response_json["userdata"][
|
|
98
100
|
"experiment_name"
|
|
99
101
|
]
|
|
100
102
|
ensemble_started_at = response_json["userdata"]["started_at"]
|
|
103
|
+
ensemble_undefined = False
|
|
104
|
+
if realization_storage_states := response_json.get(
|
|
105
|
+
"realization_storage_states"
|
|
106
|
+
):
|
|
107
|
+
ensemble_undefined = (
|
|
108
|
+
RealizationStorageState.PARAMETERS_LOADED
|
|
109
|
+
not in set(realization_storage_states)
|
|
110
|
+
)
|
|
101
111
|
self._all_ensembles.append(
|
|
102
112
|
EnsembleObject(
|
|
103
113
|
name=ensemble_name,
|
|
104
114
|
id=ensemble_id,
|
|
105
115
|
experiment_name=experiment_name,
|
|
106
|
-
hidden=ensemble_name.startswith(".")
|
|
116
|
+
hidden=ensemble_name.startswith(".")
|
|
117
|
+
or ensemble_undefined,
|
|
107
118
|
started_at=ensemble_started_at,
|
|
108
119
|
)
|
|
109
120
|
)
|
|
@@ -128,23 +139,26 @@ class PlotApi:
|
|
|
128
139
|
all_keys: dict[str, PlotApiKeyDefinition] = {}
|
|
129
140
|
all_params = {}
|
|
130
141
|
|
|
131
|
-
with
|
|
142
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
132
143
|
response = client.get("/experiments", timeout=self._timeout)
|
|
133
144
|
self._check_response(response)
|
|
134
145
|
|
|
135
146
|
for experiment in response.json():
|
|
136
|
-
for
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
for metadata in experiment["parameters"].values():
|
|
148
|
+
param_cfg = parameter_config_adapter.validate_python(metadata)
|
|
149
|
+
if group := metadata.get("group"):
|
|
150
|
+
param_key = f"{group}:{metadata['name']}"
|
|
151
|
+
else:
|
|
152
|
+
param_key = metadata["name"]
|
|
153
|
+
all_keys[param_key] = PlotApiKeyDefinition(
|
|
154
|
+
key=param_key,
|
|
155
|
+
index_type=None,
|
|
156
|
+
observations=False,
|
|
157
|
+
dimensionality=metadata["dimensionality"],
|
|
158
|
+
metadata={"data_origin": metadata["type"]},
|
|
159
|
+
parameter=param_cfg,
|
|
160
|
+
)
|
|
161
|
+
all_params[param_key] = all_keys[param_key]
|
|
148
162
|
|
|
149
163
|
return list(all_keys.values())
|
|
150
164
|
|
|
@@ -152,7 +166,7 @@ class PlotApi:
|
|
|
152
166
|
def responses_api_key_defs(self) -> list[PlotApiKeyDefinition]:
|
|
153
167
|
key_defs: dict[str, PlotApiKeyDefinition] = {}
|
|
154
168
|
|
|
155
|
-
with
|
|
169
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
156
170
|
response = client.get("/experiments", timeout=self._timeout)
|
|
157
171
|
self._check_response(response)
|
|
158
172
|
|
|
@@ -214,7 +228,7 @@ class PlotApi:
|
|
|
214
228
|
response_key: str,
|
|
215
229
|
filter_on: dict[str, Any] | None = None,
|
|
216
230
|
) -> pd.DataFrame:
|
|
217
|
-
with
|
|
231
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
218
232
|
response = client.get(
|
|
219
233
|
f"/ensembles/{ensemble_id}/responses/{PlotApi.escape(response_key)}",
|
|
220
234
|
headers={"accept": "application/x-parquet"},
|
|
@@ -231,7 +245,10 @@ class PlotApi:
|
|
|
231
245
|
try:
|
|
232
246
|
df.columns = pd.to_datetime(df.columns, format="%Y-%m-%d %H:%M:%S")
|
|
233
247
|
except (ParserError, ValueError):
|
|
234
|
-
|
|
248
|
+
try:
|
|
249
|
+
df.columns = [int(s) for s in df.columns]
|
|
250
|
+
except ValueError:
|
|
251
|
+
df.columns = [float(s) for s in df.columns]
|
|
235
252
|
|
|
236
253
|
try:
|
|
237
254
|
return df.astype(float)
|
|
@@ -239,7 +256,7 @@ class PlotApi:
|
|
|
239
256
|
return df
|
|
240
257
|
|
|
241
258
|
def data_for_parameter(self, ensemble_id: str, parameter_key: str) -> pd.DataFrame:
|
|
242
|
-
with
|
|
259
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
243
260
|
parameter = client.get(
|
|
244
261
|
f"/ensembles/{ensemble_id}/parameters/{PlotApi.escape(parameter_key)}",
|
|
245
262
|
headers={"accept": "application/x-parquet"},
|
|
@@ -281,7 +298,7 @@ class PlotApi:
|
|
|
281
298
|
assert key_def.response_metadata is not None
|
|
282
299
|
actual_response_key = key_def.response_metadata.response_key
|
|
283
300
|
filter_on = key_def.filter_on
|
|
284
|
-
with
|
|
301
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
285
302
|
response = client.get(
|
|
286
303
|
f"/ensembles/{ensemble.id}/responses/{PlotApi.escape(actual_response_key)}/observations",
|
|
287
304
|
timeout=self._timeout,
|
|
@@ -305,12 +322,17 @@ class PlotApi:
|
|
|
305
322
|
f"ensemble_name={ensemble.name}, e={e}"
|
|
306
323
|
) from e
|
|
307
324
|
|
|
325
|
+
key_index: list[int | float | pd.Timestamp]
|
|
308
326
|
for obs in observations:
|
|
309
327
|
try:
|
|
310
328
|
int(obs["x_axis"][0])
|
|
311
329
|
key_index = [int(v) for v in obs["x_axis"]]
|
|
312
330
|
except ValueError:
|
|
313
|
-
|
|
331
|
+
try:
|
|
332
|
+
float(obs["x_axis"][0])
|
|
333
|
+
key_index = [float(v) for v in obs["x_axis"]]
|
|
334
|
+
except ValueError:
|
|
335
|
+
key_index = [pd.Timestamp(v) for v in obs["x_axis"]]
|
|
314
336
|
|
|
315
337
|
observations_dfs.append(
|
|
316
338
|
pd.DataFrame(
|
|
@@ -364,7 +386,7 @@ class PlotApi:
|
|
|
364
386
|
if not ensemble:
|
|
365
387
|
return np.array([])
|
|
366
388
|
|
|
367
|
-
with
|
|
389
|
+
with ErtServer.session(project=self.ens_path) as client:
|
|
368
390
|
response = client.get(
|
|
369
391
|
f"/ensembles/{ensemble.id}/parameters/{PlotApi.escape(key)}/std_dev",
|
|
370
392
|
params={"z": z},
|
|
@@ -28,6 +28,7 @@ from PyQt6.QtWidgets import (
|
|
|
28
28
|
QVBoxLayout,
|
|
29
29
|
QWidget,
|
|
30
30
|
)
|
|
31
|
+
from typing_extensions import override
|
|
31
32
|
|
|
32
33
|
from .plot_api import EnsembleObject
|
|
33
34
|
|
|
@@ -39,22 +40,24 @@ class EnsembleSelectionWidget(QWidget):
|
|
|
39
40
|
self, ensembles: list[EnsembleObject], number_of_plot_colors: int
|
|
40
41
|
) -> None:
|
|
41
42
|
QWidget.__init__(self)
|
|
42
|
-
self.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
43
|
+
self._selected_ensembles = EnsembleSelectListWidget(
|
|
44
|
+
ensembles, number_of_plot_colors
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
self._ensemble_layout = QVBoxLayout()
|
|
48
|
+
self._ensemble_layout.setSpacing(0)
|
|
49
|
+
self._ensemble_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
|
50
|
+
self._ensemble_layout.addWidget(self._selected_ensembles)
|
|
51
|
+
self.setLayout(self._ensemble_layout)
|
|
52
|
+
self._selected_ensembles.ensembleSelectionListChanged.connect(
|
|
50
53
|
self.ensembleSelectionChanged.emit
|
|
51
54
|
)
|
|
52
55
|
|
|
53
56
|
def get_selected_ensembles(self) -> list[EnsembleObject]:
|
|
54
|
-
return self.
|
|
57
|
+
return self._selected_ensembles.get_checked_ensembles()
|
|
55
58
|
|
|
56
59
|
def get_selected_ensembles_color_indexes(self) -> list[int]:
|
|
57
|
-
return self.
|
|
60
|
+
return self._selected_ensembles.get_checked_color_indexes()
|
|
58
61
|
|
|
59
62
|
|
|
60
63
|
class EnsembleSelectListWidgetItemDataRole(IntEnum):
|
|
@@ -121,6 +124,7 @@ class EnsembleSelectListWidget(QListWidget):
|
|
|
121
124
|
|
|
122
125
|
return list(_iter())
|
|
123
126
|
|
|
127
|
+
@override
|
|
124
128
|
def mouseMoveEvent(self, e: QMouseEvent | None) -> None:
|
|
125
129
|
super().mouseMoveEvent(e)
|
|
126
130
|
if e is not None and self.itemAt(e.pos()):
|
|
@@ -128,6 +132,7 @@ class EnsembleSelectListWidget(QListWidget):
|
|
|
128
132
|
else:
|
|
129
133
|
self.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
|
|
130
134
|
|
|
135
|
+
@override
|
|
131
136
|
def dropEvent(self, event: QDropEvent | None) -> None:
|
|
132
137
|
super().dropEvent(event)
|
|
133
138
|
self.ensembleSelectionListChanged.emit()
|
|
@@ -171,9 +176,11 @@ class CustomItemDelegate(QStyledItemDelegate):
|
|
|
171
176
|
super().__init__()
|
|
172
177
|
self.swap_pixmap = QIcon("img:reorder.svg").pixmap(QSize(20, 20))
|
|
173
178
|
|
|
179
|
+
@override
|
|
174
180
|
def sizeHint(self, option: Any, index: Any) -> QSize:
|
|
175
181
|
return QSize(-1, 30)
|
|
176
182
|
|
|
183
|
+
@override
|
|
177
184
|
def paint(
|
|
178
185
|
self, painter: QPainter | None, option: QStyleOptionViewItem, index: QModelIndex
|
|
179
186
|
) -> None:
|
|
@@ -23,8 +23,9 @@ from PyQt6.QtWidgets import (
|
|
|
23
23
|
QWidget,
|
|
24
24
|
QWidgetAction,
|
|
25
25
|
)
|
|
26
|
+
from typing_extensions import override
|
|
26
27
|
|
|
27
|
-
from .plot_api import EnsembleObject
|
|
28
|
+
from .plot_api import EnsembleObject, PlotApiKeyDefinition
|
|
28
29
|
|
|
29
30
|
if TYPE_CHECKING:
|
|
30
31
|
from .plottery import PlotContext
|
|
@@ -33,6 +34,7 @@ if TYPE_CHECKING:
|
|
|
33
34
|
from .plottery.plots.ensemble import EnsemblePlot
|
|
34
35
|
from .plottery.plots.gaussian_kde import GaussianKDEPlot
|
|
35
36
|
from .plottery.plots.histogram import HistogramPlot
|
|
37
|
+
from .plottery.plots.misfits import MisfitsPlot
|
|
36
38
|
from .plottery.plots.statistics import StatisticsPlot
|
|
37
39
|
from .plottery.plots.std_dev import StdDevPlot
|
|
38
40
|
|
|
@@ -79,19 +81,23 @@ class CustomNavigationToolbar(NavigationToolbar2QT):
|
|
|
79
81
|
|
|
80
82
|
action.triggered.connect(lambda _, a=action: self.logToolbarUsage(a.text()))
|
|
81
83
|
|
|
84
|
+
@override
|
|
82
85
|
def logToolbarUsage(self, action_name: str) -> None:
|
|
83
86
|
logger.info(f"Plotwindow toolbar used: {action_name}")
|
|
84
87
|
|
|
88
|
+
@override
|
|
85
89
|
@Slot(bool)
|
|
86
90
|
def showLayerWidget(self, show: bool) -> None:
|
|
87
91
|
self._layer_action.setVisible(show)
|
|
88
92
|
|
|
93
|
+
@override
|
|
89
94
|
@Slot()
|
|
90
95
|
def resetLayerWidget(
|
|
91
96
|
self,
|
|
92
97
|
) -> None:
|
|
93
98
|
self._layer_action.defaultWidget().setCurrentIndex(0)
|
|
94
99
|
|
|
100
|
+
@override
|
|
95
101
|
@Slot(int)
|
|
96
102
|
def updateLayerWidget(self, layers: int) -> None:
|
|
97
103
|
if layers != len(self._model.stringList()):
|
|
@@ -117,6 +123,7 @@ class PlotWidget(QWidget):
|
|
|
117
123
|
"DistributionPlot",
|
|
118
124
|
"CrossEnsembleStatisticsPlot",
|
|
119
125
|
"StdDevPlot",
|
|
126
|
+
"MisfitsPlot",
|
|
120
127
|
],
|
|
121
128
|
parent: QWidget | None = None,
|
|
122
129
|
) -> None:
|
|
@@ -168,7 +175,11 @@ class PlotWidget(QWidget):
|
|
|
168
175
|
self._figure.clear()
|
|
169
176
|
|
|
170
177
|
def _sync_log_checkbox(self) -> None:
|
|
171
|
-
if type(self._plotter).__name__
|
|
178
|
+
if type(self._plotter).__name__ in {
|
|
179
|
+
"HistogramPlot",
|
|
180
|
+
"DistributionPlot",
|
|
181
|
+
"GaussianKDEPlot",
|
|
182
|
+
}:
|
|
172
183
|
self._log_checkbox.setVisible(True)
|
|
173
184
|
else:
|
|
174
185
|
self._log_checkbox.setVisible(False)
|
|
@@ -183,6 +194,7 @@ class PlotWidget(QWidget):
|
|
|
183
194
|
ensemble_to_data_map: dict[EnsembleObject, pd.DataFrame],
|
|
184
195
|
observations: pd.DataFrame,
|
|
185
196
|
std_dev_images: dict[str, npt.NDArray[np.float32]],
|
|
197
|
+
key_def: PlotApiKeyDefinition | None = None,
|
|
186
198
|
) -> None:
|
|
187
199
|
self.resetPlot()
|
|
188
200
|
try:
|
|
@@ -195,6 +207,7 @@ class PlotWidget(QWidget):
|
|
|
195
207
|
ensemble_to_data_map,
|
|
196
208
|
observations,
|
|
197
209
|
std_dev_images,
|
|
210
|
+
key_def,
|
|
198
211
|
)
|
|
199
212
|
self._canvas.draw()
|
|
200
213
|
self._sync_log_checkbox()
|
|
@@ -22,6 +22,7 @@ from PyQt6.QtWidgets import (
|
|
|
22
22
|
QWidget,
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
+
from ert.config.field import Field
|
|
25
26
|
from ert.dark_storage.common import get_storage_api_version
|
|
26
27
|
from ert.gui.ertwidgets import CopyButton, showWaitCursorWhileWaiting
|
|
27
28
|
from ert.services._base_service import ServerBootFail
|
|
@@ -39,6 +40,7 @@ from .plottery.plots import (
|
|
|
39
40
|
EnsemblePlot,
|
|
40
41
|
GaussianKDEPlot,
|
|
41
42
|
HistogramPlot,
|
|
43
|
+
MisfitsPlot,
|
|
42
44
|
StatisticsPlot,
|
|
43
45
|
StdDevPlot,
|
|
44
46
|
)
|
|
@@ -50,10 +52,11 @@ ENSEMBLE = "Ensemble"
|
|
|
50
52
|
HISTOGRAM = "Histogram"
|
|
51
53
|
STATISTICS = "Statistics"
|
|
52
54
|
STD_DEV = "Std Dev"
|
|
55
|
+
MISFITS = "Misfits"
|
|
53
56
|
|
|
54
57
|
RESPONSE_DEFAULT = 0
|
|
55
|
-
GEN_KW_DEFAULT =
|
|
56
|
-
STD_DEV_DEFAULT =
|
|
58
|
+
GEN_KW_DEFAULT = 3
|
|
59
|
+
STD_DEV_DEFAULT = 7
|
|
57
60
|
|
|
58
61
|
|
|
59
62
|
logger = logging.getLogger(__name__)
|
|
@@ -188,6 +191,7 @@ class PlotWindow(QMainWindow):
|
|
|
188
191
|
|
|
189
192
|
self.addPlotWidget(ENSEMBLE, EnsemblePlot())
|
|
190
193
|
self.addPlotWidget(STATISTICS, StatisticsPlot())
|
|
194
|
+
self.addPlotWidget(MISFITS, MisfitsPlot())
|
|
191
195
|
self.addPlotWidget(HISTOGRAM, HistogramPlot())
|
|
192
196
|
self.addPlotWidget(GAUSSIAN_KDE, GaussianKDEPlot())
|
|
193
197
|
self.addPlotWidget(DISTRIBUTION, DistributionPlot())
|
|
@@ -269,10 +273,13 @@ class PlotWindow(QMainWindow):
|
|
|
269
273
|
response_key=key_def.response_metadata.response_key,
|
|
270
274
|
filter_on=key_def.filter_on,
|
|
271
275
|
)
|
|
272
|
-
elif
|
|
276
|
+
elif (
|
|
277
|
+
key_def.parameter is not None
|
|
278
|
+
and key_def.parameter.type == "gen_kw"
|
|
279
|
+
):
|
|
273
280
|
ensemble_to_data_map[ensemble] = self._api.data_for_parameter(
|
|
274
281
|
ensemble_id=ensemble.id,
|
|
275
|
-
parameter_key=key_def.
|
|
282
|
+
parameter_key=key_def.parameter.name,
|
|
276
283
|
)
|
|
277
284
|
except BaseException as e:
|
|
278
285
|
handle_exception(e)
|
|
@@ -287,10 +294,10 @@ class PlotWindow(QMainWindow):
|
|
|
287
294
|
handle_exception(e)
|
|
288
295
|
|
|
289
296
|
std_dev_images: dict[str, npt.NDArray[np.float32]] = {}
|
|
290
|
-
if "FIELD" in key_def.metadata["data_origin"]:
|
|
291
|
-
plot_widget.showLayerWidget.emit(True)
|
|
292
297
|
|
|
293
|
-
|
|
298
|
+
if isinstance(key_def.parameter, Field):
|
|
299
|
+
plot_widget.showLayerWidget.emit(True)
|
|
300
|
+
layers = key_def.parameter.ertbox_params.nz
|
|
294
301
|
plot_widget.updateLayerWidget.emit(layers)
|
|
295
302
|
|
|
296
303
|
if layer is None:
|
|
@@ -332,6 +339,18 @@ class PlotWindow(QMainWindow):
|
|
|
332
339
|
handle_exception(e)
|
|
333
340
|
plot_context.history_data = None
|
|
334
341
|
|
|
342
|
+
if (
|
|
343
|
+
key_def.response_metadata is not None
|
|
344
|
+
and key_def.response_metadata.response_type == "rft"
|
|
345
|
+
):
|
|
346
|
+
plot_context.setXLabel(key.split(":")[-1])
|
|
347
|
+
plot_context.setYLabel("TVD")
|
|
348
|
+
plot_context.depth_y_axis = True
|
|
349
|
+
for ekey, data in list(ensemble_to_data_map.items()):
|
|
350
|
+
ensemble_to_data_map[ekey] = data.interpolate(
|
|
351
|
+
method="linear", axis="columns"
|
|
352
|
+
)
|
|
353
|
+
|
|
335
354
|
for data in ensemble_to_data_map.values():
|
|
336
355
|
data = data.T
|
|
337
356
|
|
|
@@ -342,7 +361,11 @@ class PlotWindow(QMainWindow):
|
|
|
342
361
|
self._updateCustomizer(plot_widget, self._preferred_ensemble_x_axis_format)
|
|
343
362
|
|
|
344
363
|
plot_widget.updatePlot(
|
|
345
|
-
plot_context,
|
|
364
|
+
plot_context,
|
|
365
|
+
ensemble_to_data_map,
|
|
366
|
+
observations,
|
|
367
|
+
std_dev_images,
|
|
368
|
+
key_def,
|
|
346
369
|
)
|
|
347
370
|
|
|
348
371
|
def _updateCustomizer(
|
|
@@ -371,15 +394,14 @@ class PlotWindow(QMainWindow):
|
|
|
371
394
|
def addPlotWidget(
|
|
372
395
|
self,
|
|
373
396
|
name: str,
|
|
374
|
-
plotter:
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
),
|
|
397
|
+
plotter: EnsemblePlot
|
|
398
|
+
| StatisticsPlot
|
|
399
|
+
| HistogramPlot
|
|
400
|
+
| GaussianKDEPlot
|
|
401
|
+
| DistributionPlot
|
|
402
|
+
| CrossEnsembleStatisticsPlot
|
|
403
|
+
| StdDevPlot
|
|
404
|
+
| MisfitsPlot,
|
|
383
405
|
enabled: bool = True,
|
|
384
406
|
) -> None:
|
|
385
407
|
plot_widget = PlotWidget(name, plotter)
|
|
@@ -418,6 +440,7 @@ class PlotWindow(QMainWindow):
|
|
|
418
440
|
widget
|
|
419
441
|
for widget in self._plot_widgets
|
|
420
442
|
if widget._plotter.dimensionality == key_def.dimensionality
|
|
443
|
+
and (key_def.observations or not widget._plotter.requires_observations)
|
|
421
444
|
]
|
|
422
445
|
|
|
423
446
|
# Enabling/disabling tab triggers the
|
|
@@ -431,8 +454,6 @@ class PlotWindow(QMainWindow):
|
|
|
431
454
|
self._central_tab.setTabEnabled(
|
|
432
455
|
self._central_tab.indexOf(plot_widget), plot_widget in available_widgets
|
|
433
456
|
)
|
|
434
|
-
self._central_tab.currentChanged.connect(self.currentTabChanged)
|
|
435
|
-
|
|
436
457
|
current_widget = self._central_tab.currentWidget()
|
|
437
458
|
|
|
438
459
|
if 0 < self._prev_key_dimensionality != key_def.dimensionality:
|
|
@@ -447,6 +468,7 @@ class PlotWindow(QMainWindow):
|
|
|
447
468
|
self._current_tab_index = -1
|
|
448
469
|
|
|
449
470
|
self._central_tab.setCurrentWidget(current_widget)
|
|
471
|
+
self._central_tab.currentChanged.connect(self.currentTabChanged)
|
|
450
472
|
self._prev_tab_widget_index = self._central_tab.currentIndex()
|
|
451
473
|
self._prev_key_dimensionality = key_def.dimensionality
|
|
452
474
|
self.updatePlot()
|
|
@@ -47,6 +47,14 @@ class PlotContext:
|
|
|
47
47
|
self._y_axis: str | None = None
|
|
48
48
|
self._log_scale = False
|
|
49
49
|
|
|
50
|
+
@property
|
|
51
|
+
def depth_y_axis(self) -> bool:
|
|
52
|
+
return self._plot_config.depth_y_axis
|
|
53
|
+
|
|
54
|
+
@depth_y_axis.setter
|
|
55
|
+
def depth_y_axis(self, value: bool) -> None:
|
|
56
|
+
self._plot_config.depth_y_axis = value
|
|
57
|
+
|
|
50
58
|
def plotConfig(self) -> PlotConfig:
|
|
51
59
|
return self._plot_config
|
|
52
60
|
|
|
@@ -93,6 +101,12 @@ class PlotContext:
|
|
|
93
101
|
)
|
|
94
102
|
self._y_axis = value
|
|
95
103
|
|
|
104
|
+
def setXLabel(self, value: str) -> None:
|
|
105
|
+
self._plot_config.setXLabel(value)
|
|
106
|
+
|
|
107
|
+
def setYLabel(self, value: str) -> None:
|
|
108
|
+
self._plot_config.setYLabel(value)
|
|
109
|
+
|
|
96
110
|
@property
|
|
97
111
|
def log_scale(self) -> bool:
|
|
98
112
|
return self._log_scale
|
|
@@ -3,6 +3,7 @@ from .distribution import DistributionPlot
|
|
|
3
3
|
from .ensemble import EnsemblePlot
|
|
4
4
|
from .gaussian_kde import GaussianKDEPlot
|
|
5
5
|
from .histogram import HistogramPlot
|
|
6
|
+
from .misfits import MisfitsPlot
|
|
6
7
|
from .statistics import StatisticsPlot
|
|
7
8
|
from .std_dev import StdDevPlot
|
|
8
9
|
|
|
@@ -12,6 +13,7 @@ __all__ = [
|
|
|
12
13
|
"EnsemblePlot",
|
|
13
14
|
"GaussianKDEPlot",
|
|
14
15
|
"HistogramPlot",
|
|
16
|
+
"MisfitsPlot",
|
|
15
17
|
"StatisticsPlot",
|
|
16
18
|
"StdDevPlot",
|
|
17
19
|
]
|
|
@@ -8,7 +8,7 @@ from matplotlib.lines import Line2D
|
|
|
8
8
|
from matplotlib.patches import Rectangle
|
|
9
9
|
from typing_extensions import TypedDict
|
|
10
10
|
|
|
11
|
-
from ert.gui.tools.plot.plot_api import EnsembleObject
|
|
11
|
+
from ert.gui.tools.plot.plot_api import EnsembleObject, PlotApiKeyDefinition
|
|
12
12
|
|
|
13
13
|
from .plot_tools import ConditionalAxisFormatter, PlotTools
|
|
14
14
|
|
|
@@ -37,6 +37,7 @@ class CcsData(TypedDict):
|
|
|
37
37
|
class CrossEnsembleStatisticsPlot:
|
|
38
38
|
def __init__(self) -> None:
|
|
39
39
|
self.dimensionality = 1
|
|
40
|
+
self.requires_observations = False
|
|
40
41
|
|
|
41
42
|
@staticmethod
|
|
42
43
|
def plot(
|
|
@@ -45,6 +46,7 @@ class CrossEnsembleStatisticsPlot:
|
|
|
45
46
|
ensemble_to_data_map: dict[EnsembleObject, pd.DataFrame],
|
|
46
47
|
observation_data: pd.DataFrame,
|
|
47
48
|
std_dev_images: dict[str, npt.NDArray[np.float32]],
|
|
49
|
+
key_def: PlotApiKeyDefinition | None = None,
|
|
48
50
|
) -> None:
|
|
49
51
|
plotCrossEnsembleStatistics(
|
|
50
52
|
figure, plot_context, ensemble_to_data_map, observation_data
|
|
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
7
|
|
|
8
|
-
from ert.gui.tools.plot.plot_api import EnsembleObject
|
|
8
|
+
from ert.gui.tools.plot.plot_api import EnsembleObject, PlotApiKeyDefinition
|
|
9
9
|
|
|
10
10
|
from .plot_tools import ConditionalAxisFormatter, PlotTools
|
|
11
11
|
|
|
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
|
|
|
20
20
|
class DistributionPlot:
|
|
21
21
|
def __init__(self) -> None:
|
|
22
22
|
self.dimensionality = 1
|
|
23
|
+
self.requires_observations = False
|
|
23
24
|
|
|
24
25
|
@staticmethod
|
|
25
26
|
def plot(
|
|
@@ -28,6 +29,7 @@ class DistributionPlot:
|
|
|
28
29
|
ensemble_to_data_map: dict[EnsembleObject, pd.DataFrame],
|
|
29
30
|
observation_data: pd.DataFrame,
|
|
30
31
|
std_dev_images: dict[str, npt.NDArray[np.float32]],
|
|
32
|
+
key_def: PlotApiKeyDefinition | None = None,
|
|
31
33
|
) -> None:
|
|
32
34
|
plotDistribution(figure, plot_context, ensemble_to_data_map, observation_data)
|
|
33
35
|
|
|
@@ -80,6 +82,9 @@ def plotDistribution(
|
|
|
80
82
|
)
|
|
81
83
|
config.setLegendEnabled(False)
|
|
82
84
|
|
|
85
|
+
if plot_context.log_scale:
|
|
86
|
+
axes.set_yscale("log")
|
|
87
|
+
|
|
83
88
|
PlotTools.finalizePlot(
|
|
84
89
|
plot_context, figure, axes, default_x_label="Ensemble", default_y_label="Value"
|
|
85
90
|
)
|
|
@@ -4,8 +4,7 @@ from typing import TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
|
-
|
|
8
|
-
from ert.summary_key_type import is_rate
|
|
7
|
+
from resfo_utilities import is_rate
|
|
9
8
|
|
|
10
9
|
from .history import plotHistory
|
|
11
10
|
from .observations import plotObservations
|
|
@@ -16,13 +15,14 @@ if TYPE_CHECKING:
|
|
|
16
15
|
from matplotlib.axes import Axes
|
|
17
16
|
from matplotlib.figure import Figure
|
|
18
17
|
|
|
19
|
-
from ert.gui.tools.plot.plot_api import EnsembleObject
|
|
18
|
+
from ert.gui.tools.plot.plot_api import EnsembleObject, PlotApiKeyDefinition
|
|
20
19
|
from ert.gui.tools.plot.plottery import PlotConfig, PlotContext
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class EnsemblePlot:
|
|
24
23
|
def __init__(self) -> None:
|
|
25
24
|
self.dimensionality = 2
|
|
25
|
+
self.requires_observations = False
|
|
26
26
|
|
|
27
27
|
def plot(
|
|
28
28
|
self,
|
|
@@ -31,6 +31,7 @@ class EnsemblePlot:
|
|
|
31
31
|
ensemble_to_data_map: dict[EnsembleObject, pd.DataFrame],
|
|
32
32
|
observation_data: pd.DataFrame,
|
|
33
33
|
std_dev_images: dict[str, npt.NDArray[np.float32]],
|
|
34
|
+
key_def: PlotApiKeyDefinition | None = None,
|
|
34
35
|
) -> None:
|
|
35
36
|
config = plot_context.plotConfig()
|
|
36
37
|
axes = figure.add_subplot(111)
|
|
@@ -87,9 +88,16 @@ class EnsemblePlot:
|
|
|
87
88
|
if len(data) == 1 and not style.marker:
|
|
88
89
|
style.marker = "."
|
|
89
90
|
|
|
91
|
+
if plot_config.depth_y_axis:
|
|
92
|
+
x = data.to_numpy()
|
|
93
|
+
y = data.index.to_numpy()
|
|
94
|
+
axes.yaxis.set_inverted(True)
|
|
95
|
+
else:
|
|
96
|
+
y = data.to_numpy()
|
|
97
|
+
x = data.index.to_numpy()
|
|
90
98
|
lines = axes.plot(
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
x,
|
|
100
|
+
y,
|
|
93
101
|
color=style.color,
|
|
94
102
|
alpha=style.alpha,
|
|
95
103
|
marker=style.marker,
|