Skip to content

Commit

Permalink
Add DesignMatrixPanel to show DataFrame parameters in a table
Browse files Browse the repository at this point in the history
- Button to show the parameters is shown when design_matrix is present
- Add test for design matrix show parameters button
  • Loading branch information
xjules committed Oct 11, 2024
1 parent dad96ea commit 391a25f
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 8 deletions.
51 changes: 45 additions & 6 deletions src/ert/gui/simulation/ensemble_experiment_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@

from qtpy import QtCore
from qtpy.QtCore import Slot
from qtpy.QtWidgets import QFormLayout, QLabel
from qtpy.QtWidgets import QFormLayout, QHBoxLayout, QLabel, QPushButton

from ert.config import AnalysisConfig, DesignMatrix
from ert.gui.ertnotifier import ErtNotifier
from ert.gui.ertwidgets import (
ActiveRealizationsModel,
CopyableLabel,
StringBox,
TextModel,
)
from ert.gui.tools.design_matrix.design_matrix_panel import DesignMatrixPanel
from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
from ert.run_models import EnsembleExperiment
from ert.validation import RangeStringArgument
from ert.validation.proper_name_argument import (
ExperimentValidation,
ProperNameArgument,
)
from ert.validation.proper_name_argument import ExperimentValidation, ProperNameArgument

from .experiment_config_panel import ExperimentConfigPanel

Expand All @@ -31,7 +30,13 @@ class Arguments:


class EnsembleExperimentPanel(ExperimentConfigPanel):
def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):
def __init__(
self,
analysis_config: AnalysisConfig,
ensemble_size: int,
run_path: str,
notifier: ErtNotifier,
):
self.notifier = notifier
super().__init__(EnsembleExperiment)
self.setObjectName("Ensemble_experiment_panel")
Expand Down Expand Up @@ -78,6 +83,21 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):
)
layout.addRow("Active realizations", self._active_realizations_field)

design_matrix = analysis_config.design_matrix
if design_matrix is not None:
show_dm_param_button = QPushButton("Show parameters")
show_dm_param_button.setObjectName("show-dm-parameters")
show_dm_param_button.setMinimumWidth(50)

button_layout = QHBoxLayout()
button_layout.addWidget(show_dm_param_button)
button_layout.addStretch() # Add stretch to push the button to the left

layout.addRow("Design Matrix", button_layout)
show_dm_param_button.clicked.connect(
lambda: self.on_show_dm_params_clicked(design_matrix)
)

self.setLayout(layout)

self._active_realizations_field.getValidationSupport().validationChanged.connect(
Expand All @@ -92,6 +112,25 @@ def __init__(self, ensemble_size: int, run_path: str, notifier: ErtNotifier):

self.notifier.ertChanged.connect(self._update_experiment_name_placeholder)

def on_show_dm_params_clicked(self, design_matrix: DesignMatrix) -> None:
assert design_matrix is not None

if design_matrix.design_matrix_df is None:
design_matrix.read_design_matrix()

if (
design_matrix.design_matrix_df is not None
and not design_matrix.design_matrix_df.empty
):
viewer = DesignMatrixPanel(
design_matrix.design_matrix_df,
design_matrix.xls_filename.name,
)
viewer.setMinimumHeight(500)
viewer.setMinimumWidth(1000)
viewer.adjustSize()
viewer.exec_()

@Slot(ExperimentConfigPanel)
def experimentTypeChanged(self, w: ExperimentConfigPanel) -> None:
if isinstance(w, EnsembleExperimentPanel):
Expand Down
5 changes: 3 additions & 2 deletions src/ert/gui/simulation/experiment_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ def __init__(
SingleTestRunPanel(run_path, notifier),
True,
)
analysis_config = config.analysis_config
self.addExperimentConfigPanel(
EnsembleExperimentPanel(ensemble_size, run_path, notifier),
EnsembleExperimentPanel(analysis_config, ensemble_size, run_path, notifier),
True,
)
self.addExperimentConfigPanel(
Expand All @@ -154,7 +155,7 @@ def __init__(
experiment_type_valid = bool(
config.ensemble_config.parameter_configs and config.observations
)
analysis_config = config.analysis_config

self.addExperimentConfigPanel(
MultipleDataAssimilationPanel(
analysis_config, run_path, notifier, ensemble_size
Expand Down
50 changes: 50 additions & 0 deletions src/ert/gui/tools/design_matrix/design_matrix_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from typing import Optional

import pandas as pd
from qtpy.QtGui import QStandardItem, QStandardItemModel
from qtpy.QtWidgets import QDialog, QTableView, QVBoxLayout, QWidget


class DesignMatrixPanel(QDialog):
def __init__(
self,
design_matrix_df: pd.DataFrame,
filename: str,
parent: Optional[QWidget] = None,
) -> None:
super().__init__(parent)

self.setWindowTitle(f"Design matrix parameters from {filename}")

table_view = QTableView(self)
table_view.setEditTriggers(QTableView.NoEditTriggers)

self.model = self.create_model(design_matrix_df)
table_view.setModel(self.model)

table_view.resizeColumnsToContents()
table_view.resizeRowsToContents()

layout = QVBoxLayout()
layout.addWidget(table_view)
self.setLayout(layout)
self.adjustSize()

@staticmethod
def create_model(design_matrix_df: pd.DataFrame) -> QStandardItemModel:
model = QStandardItemModel()

if isinstance(design_matrix_df.columns, pd.MultiIndex):
header_labels = [str(col[-1]) for col in design_matrix_df.columns]
else:
header_labels = design_matrix_df.columns.astype(str).tolist()

model.setHorizontalHeaderLabels(header_labels)

for index, _ in design_matrix_df.iterrows():
items = [
QStandardItem(str(design_matrix_df.at[index, col]))
for col in design_matrix_df.columns
]
model.appendRow(items)
return model
45 changes: 45 additions & 0 deletions tests/ert/unit_tests/gui/simulation/test_run_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,48 @@ def test_that_stdout_and_stderr_buttons_react_to_file_content(

with qtbot.waitSignal(run_dialog.accepted, timeout=30000):
run_dialog.close()


@pytest.mark.integration_test
@pytest.mark.usefixtures("use_tmpdir")
@pytest.mark.parametrize(
"design_matrix_entry",
(True, False),
)
def test_that_design_matrix_show_parameters_button_is_visible(
design_matrix_entry, qtbot: QtBot, storage
):
xls_filename = "design_matrix.xls"
with open(f"{xls_filename}", "w", encoding="utf-8"):
pass
config_file = "minimal_config.ert"
with open(config_file, "w", encoding="utf-8") as f:
f.write("NUM_REALIZATIONS 1")
if design_matrix_entry:
f.write(
f"\nDESIGN_MATRIX {xls_filename} DESIGN_SHEET:DesignSheet01 DEFAULT_SHEET:DefaultValues"
)

args_mock = Mock()
args_mock.config = config_file

ert_config = ErtConfig.from_file(config_file)
with StorageService.init_service(
project=os.path.abspath(ert_config.ens_path),
):
gui = _setup_main_window(ert_config, args_mock, GUILogHandler(), storage)
experiment_panel = gui.findChild(ExperimentPanel)
assert isinstance(experiment_panel, ExperimentPanel)

simulation_mode_combo = experiment_panel.findChild(QComboBox)
assert isinstance(simulation_mode_combo, QComboBox)

simulation_mode_combo.setCurrentText(EnsembleExperiment.name())
simulation_settings = gui.findChild(EnsembleExperimentPanel)
show_dm_parameters = simulation_settings.findChild(
QPushButton, "show-dm-parameters"
)
if design_matrix_entry:
assert isinstance(show_dm_parameters, QPushButton)
else:
assert show_dm_parameters is None

0 comments on commit 391a25f

Please sign in to comment.