From b21846a5137a2903d89be0bf71d5054e3a0178f7 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Thu, 3 Sep 2026 16:17:49 +0200 Subject: [PATCH] Ensemble: Results: Add base of 'ResultsEnsembleWindow' obj. --- src/View/MainWindow.py | 2 +- src/View/Results/Table.py | 5 + src/View/Results/Window.py | 210 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index f40c6934..61ef6729 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -90,7 +90,7 @@ from View.RunSolver.Window import ( ) -from View.Results.Window import ResultsWindow +from View.Results.Window import ResultsWindow, ResultsEnsembleWindow from View.Results.CompareDialog import ( CompareScenariosWindow ) diff --git a/src/View/Results/Table.py b/src/View/Results/Table.py index b730ce12..d4f5b320 100644 --- a/src/View/Results/Table.py +++ b/src/View/Results/Table.py @@ -61,6 +61,8 @@ class TableModel(PamhyrTableModel): # _river.reach(0).profiles)) elif self._opt_data == "solver": self._lst = self._parent._solvers + elif self._opt_data == "runs": + self._lst = self._data[0].get("table")["sample"] def __init__(self, **kwargs): self._timestamp = max(kwargs["parent"]._timestamps) @@ -93,6 +95,9 @@ class TableModel(PamhyrTableModel): if v is None: v = self._data[0].solver_name return str(v) + elif self._opt_data == "runs": + if self._headers[column] == "runs": + return f"{row}: {p}" elif self._opt_data == "raw_data": table = self._data[0].get("table") ts = self._data[0].get_timestamp_id(self._timestamp) diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py index 9dcc0bec..2362b984 100644 --- a/src/View/Results/Window.py +++ b/src/View/Results/Window.py @@ -1437,3 +1437,213 @@ class ResultsWindow(PamhyrWindow): for data in results.get("additional_data"): for p in self._additional_plot: self._additional_plot[p].add_imported_plot(data) + + +class ResultsEnsembleWindow(ResultsWindow): + _pamhyr_ui = "ResultsEnsemble" + _pamhyr_name = "Results" + + def setup_table(self): + self._table = {} + + for t in ["reach", "profile", "runs"]: + table = self.find(QTableView, f"tableView_{t}") + + self._table[t] = TableModel( + table_view=table, + table_headers=self._trad.get_dict(f"table_headers_{t}"), + data=self._results, + undo=self._undo_stack, + opt_data=t, + parent=self + ) + + self._table[t]._timestamp = self._timestamps[ + self._slider_time.value() + ] + + if len(self._results) <= 1: + table = self.find(QTableView, f"tableView_solver") + table.hide() + + def setup_plots(self): + self.canvas = MplCanvas(width=5, height=4, dpi=100) + + tab_widget = self.find(QTabWidget, f"tabWidget") + + tab_widget.setTabsClosable(True) + tab_widget.tabCloseRequested.connect(self.delete_tab) + tab_widget.tabBar().setTabButton(0, QTabBar.RightSide, None) + tab_widget.tabBar().setTabButton(1, QTabBar.RightSide, None) + + self.canvas_1 = MplCanvas(width=5, height=4, dpi=100) + self.canvas_1.setObjectName("canvas_1") + self.toolbar_1 = PamhyrPlotToolbar( + self.canvas_1, self, items=[ + "home", "move", "zoom", "save", + "iso", "back/forward" + ] + ) + self.plot_layout_1 = self.find(QVBoxLayout, + "verticalLayout_elevation") + self.plot_layout_1.addWidget(self.toolbar_1) + self.plot_layout_1.addWidget(self.canvas_1) + + self.plot_rkc = PlotRKC( + canvas=self.canvas_1, + results=self._results, + reach_id=0, + profile_id=0, + res_id=self._current_results, + trad=self._trad, + toolbar=self.toolbar_1, + parent=self + ) + self.plot_rkc.draw() + + self.canvas_2 = MplCanvas(width=5, height=4, dpi=100) + self.canvas_2.setObjectName("canvas_2") + self.toolbar_2 = PamhyrPlotToolbar( + self.canvas_2, self, items=[ + "home", "move", "zoom", "save", + "iso", "back/forward" + ] + ) + self.plot_layout_2 = self.find( + QVBoxLayout, "verticalLayout_hydrograph") + self.plot_layout_2.addWidget(self.toolbar_2) + self.plot_layout_2.addWidget(self.canvas_2) + + self.plot_h = PlotH( + canvas=self.canvas_2, + results=self._results, + reach_id=0, + profile_id=[0], + res_id=self._current_results, + trad=self._trad, + toolbar=self.toolbar_2, + parent=self + ) + self.plot_h.draw() + + def setup_connections(self): + # Action + actions = { + "action_add": self._add_custom_plot, + "action_export": self._export, + # "action_export": self.export_current, + "action_import_data": self.import_data + } + + if len(self._results) > 1: + self.find(QAction, "action_reload").setEnabled(False) + + for action in actions: + self.find(QAction, action).triggered.connect( + actions[action] + ) + + # Table and Plot + fun = { + "reach": self._set_current_reach, + "profile": self._set_current_profile, + "runs": self._set_current_results, + } + + for t in ["reach", "profile", "runs"]: + table = self.find(QTableView, f"tableView_{t}") + + table.selectionModel()\ + .selectionChanged\ + .connect(fun[t]) + + self._table[t].dataChanged.connect(fun[t]) + + self._slider_time.valueChanged.connect(self._set_current_timestamp) + self._button_play.setChecked(False) + self._button_play.clicked.connect(self._pause) + self._button_back.clicked.connect(self._back) + self._button_next.clicked.connect(self._next) + self._button_first.clicked.connect(self._first) + self._button_last.clicked.connect(self._last) + self._timer.timeout.connect(self._update_slider) + + # tabs + tab_widget = self.find(QTabWidget, f"tabWidget") + tab_widget.currentChanged.connect(self.tab_changed) + + def _set_current_results(self): + table = self.find(QTableView, f"tableView_runs") + indexes = table.selectedIndexes() + if len(indexes) == 0: + return + + self.update(runs_id=[i.row() for i in indexes]) + + def update(self, + reach_id=None, + profile_id=None, + runs_id=None, + timestamp=None): + + tab_widget = self.find(QTabWidget, f"tabWidget") + tab_index = tab_widget.currentIndex() + name = tab_widget.tabText(tab_index) + + if reach_id is not None: + if tab_index == 1: + self.plot_rkc.set_reach(reach_id) + elif tab_index == 2: + self.plot_h.set_reach(reach_id) + elif tab_index > 2: + self._additional_plot[name].set_reach(reach_id) + + self.update_table_selection_reach(reach_id) + self.update_table_selection_profile(0) + + if profile_id is not None: + if tab_index == 1: + self.plot_rkc.set_profile(profile_id[0]) + elif tab_index == 2: + self.plot_h.set_profile(profile_id) + elif tab_widget.currentIndex() > 2: + self._additional_plot[name].set_profile(profile_id[0]) + + tab_widget = self.find(QTabWidget, f"tabWidget") + if tab_widget.currentIndex() != 2: + self.update_table_selection_profile(profile_id[0]) + + if runs_id is not None: + if tab_index == 1: + self._current_results = runs_id + self.plot_rkc.set_result(runs_id) + elif tab_index == 2: + self.plot_h.set_result(runs_id) + elif tab_widget.currentIndex() > 2: + self._additional_plot[name].set_result(runs_id) + + if timestamp is not None: + self.plot_rkc.set_timestamp(timestamp) + if tab_index == 2: + self.plot_h.set_timestamp(timestamp) + + if tab_widget.currentIndex() > 2: + self._additional_plot[name].set_timestamp(timestamp) + + self.update_statusbar() + + def tab_changed(self, i): + if i != 2: + if len(self._get_current_profiles_list()) > 1: + # unselect all profiles but the first one + profile_id = self._get_current_profile() + self.update_table_selection_profile(profile_id) + tab_widget = self.find(QTabWidget, f"tabWidget") + tab_index = tab_widget.currentIndex() + name = tab_widget.tabText(tab_index) + if tab_index == 1: + self.plot_rkc.update_all() + elif tab_index == 2: + self.plot_h.update_all() + elif tab_index > 2: + self._additional_plot[name].update_all()