diff --git a/src/View/Frictions/PlotKPZ.py b/src/View/Frictions/PlotKPZ.py new file mode 100644 index 0000000000000000000000000000000000000000..97a80b5b80ddac41067f1630747aded8fbdda82d --- /dev/null +++ b/src/View/Frictions/PlotKPZ.py @@ -0,0 +1,50 @@ +# PlotKPC.py -- Pamhyr +# Copyright (C) 2023-2024 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +from PyQt5.QtCore import QCoreApplication +from View.HydraulicStructures.PlotKPC import PlotKPC + +_translate = QCoreApplication.translate + + +class PlotKPZ(PlotKPC): + def __init__(self, canvas=None, trad=None, toolbar=None, + river=None, reach=None, profile=None, + parent=None): + super(PlotKPC, self).__init__( + canvas=canvas, + trad=trad, + data=river, + toolbar=toolbar, + parent=parent + ) + + self._current_reach = reach + self._current_profile = profile + + self.label_x = self._trad["unit_kp"] + self.label_y = self._trad["unit_elevation"] + + self._isometric_axis = False + + self._auto_relim_update = True + self._autoscale_update = True + self.parent = parent + + def onpick(self, event): + return diff --git a/src/View/Frictions/Window.py b/src/View/Frictions/Window.py index c0c7d81bd47cfded1d29ab14e529a71caf7bbf55..9776ce56b3ff66503dd6af84626e9564e57b42e1 100644 --- a/src/View/Frictions/Window.py +++ b/src/View/Frictions/Window.py @@ -50,7 +50,7 @@ from View.Frictions.Table import ( ) from View.Tools.Plot.PamhyrCanvas import MplCanvas -from View.Geometry.PlotKPZ import PlotKPZ +from View.Frictions.PlotKPZ import PlotKPZ from View.Frictions.PlotStricklers import PlotStricklers from View.Frictions.translate import FrictionsTranslate @@ -135,10 +135,11 @@ class FrictionsWindow(PamhyrWindow): self.plot = PlotKPZ( canvas=self.canvas, - data=self._reach.reach, - study=self._study, + reach=self._reach, + river=self._study.river, trad=self._trad, toolbar=None, + parent=self ) self.plot.draw() diff --git a/src/View/Geometry/PlotXY.py b/src/View/Geometry/PlotXY.py index e163e53872a74321034855392ea200bd1130bebe..2793e78b92e61c110a1f12f43128d75b5509df85 100644 --- a/src/View/Geometry/PlotXY.py +++ b/src/View/Geometry/PlotXY.py @@ -179,7 +179,6 @@ class PlotXY(PamhyrPlot): self._init = True def draw_xy(self): - self.line_xy = [] for xy in zip(self.data.get_x(), self.data.get_y()): self.line_xy.append(np.column_stack(xy)) diff --git a/src/View/HydraulicStructures/PlotKPC.py b/src/View/HydraulicStructures/PlotKPC.py index 209e68a1a8cc5cb1fcc2dde5ade9c5f0772f7176..2844ab8f8cca81f1469021f5cafd0b2ee4159d46 100644 --- a/src/View/HydraulicStructures/PlotKPC.py +++ b/src/View/HydraulicStructures/PlotKPC.py @@ -186,11 +186,9 @@ class PlotKPC(PamhyrPlot): closest = self._closest_profile(event) index = self.parent.tableView.selectedIndexes() - print(index) if self.parent._table is not None: self.parent._table.setData(index[2], closest) - return def _closest_profile(self, event): diff --git a/src/View/LateralContribution/PlotXY.py b/src/View/LateralContribution/PlotXY.py new file mode 100644 index 0000000000000000000000000000000000000000..91e279ec94a20463cc9f0a3de41f619f3ab0ae49 --- /dev/null +++ b/src/View/LateralContribution/PlotXY.py @@ -0,0 +1,259 @@ +# PlotXY.py -- Pamhyr +# Copyright (C) 2023-2024 INRAE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# -*- coding: utf-8 -*- + +from tools import timer, trace +from View.Tools.PamhyrPlot import PamhyrPlot +from matplotlib import collections +import numpy as np + +from PyQt5.QtCore import ( + QCoreApplication, Qt, QItemSelectionModel, + QItemSelection, QItemSelectionRange, +) +from PyQt5.QtWidgets import QApplication, QTableView + +_translate = QCoreApplication.translate + + +class PlotXY(PamhyrPlot): + def __init__(self, canvas=None, trad=None, data=None, toolbar=None, + table=None, parent=None): + super(PlotXY, self).__init__( + canvas=canvas, + trad=trad, + data=data, + toolbar=toolbar, + table=table, + parent=parent + ) + + self.line_xy = [] + self.line_gl = [] + + self.label_x = self._trad["x"] + self.label_y = self._trad["y"] + + self.before_plot_selected = None + self.plot_selected = None + self.after_plot_selected = None + self.parent=parent + self.line_xy_collection = None + self._table=table + self._colors = [] + self._style = [] + + def onpick(self, event): + if event.mouseevent.inaxes != self.canvas.axes: + return + if event.mouseevent.button.value not in [1,3]: + return + + closest = self._closest_section(event) + t = self.parent.current_tab() + tableView = self.parent.find(QTableView, f"tableView_{t}") + table = self.parent._table[t] + index = tableView.selectedIndexes() + kp = self.data.get_kp() + if self.parent._table is not None: + if event.mouseevent.button.value == 1: + table.setData(index[3], kp[closest[0]]) + if event.mouseevent.button.value == 3: + table.setData(index[4], kp[closest[0]]) + + #self.update() + return + + def _closest_section(self, event): + axes = self.canvas.axes + mx = event.mouseevent.xdata + my = event.mouseevent.ydata + bx, by = axes.get_xlim(), axes.get_ylim() + ratio = (bx[0] - bx[1]) / (by[0] - by[1]) + + segments = event.artist.get_segments() + ind = event.ind + + points = [] + for i in ind: + points = points + [[i, j] for j in segments[i]] + + def dist_mouse(point): + x, y = point[1] + d2 = (((mx - x) / ratio) ** 2) + ((my - y) ** 2) + return d2 + + closest = min( + points, key=dist_mouse + ) + + return closest + + @timer + def draw(self): + self.init_axes() + + if self.data is None: + self.idle() + return + + if self.data.number_profiles == 0: + self._init = False + self.idle() + return + + self.draw_xy() + self.draw_lr() + self.draw_gl() + + self.idle() + self._init = True + + def draw_xy(self): + self.line_xy = [] + for xy in zip(self.data.get_x(), self.data.get_y()): + self.line_xy.append(np.column_stack(xy)) + + self._colors, self._style = self.color_hightlight() + self.line_xy_collection = collections.LineCollection(self.line_xy, + colors = self._colors, + linestyle = self._style, + picker=10) + self.canvas.axes.add_collection(self.line_xy_collection) + + def color_hightlight(self): + kp_min, kp_max = (-1, -1) + if self._highlight_data is not None: + kp_min, kp_max = self._highlight_data + + colors = [self.color_plot for row in range(len(self._data))] + for i, kp in enumerate(self.data.get_kp_complete_profiles()): + if kp_min <= kp <= kp_max: + colors[i] = self.color_plot_current + style = ["-" for row in range(len(self._data))] + + return colors, style + + def draw_lr(self): + lx = [] + ly = [] + rx = [] + ry = [] + + self.line_lr = [] + for x, y in zip(self.data.get_x(), + self.data.get_y()): + lx.append(x[0]) + ly.append(y[0]) + + rx.append(x[-1]) + ry.append(y[-1]) + + line = self.canvas.axes.plot( + lx, ly, + color=self.color_plot_river_bottom, + linestyle="dotted", + lw=1., + ) + self.line_lr.append(line) + + line = self.canvas.axes.plot( + rx, ry, + color=self.color_plot_river_bottom, + linestyle="dotted", + lw=1., + ) + self.line_lr.append(line) + + def draw_gl(self): + x_complete = self.data.get_guidelines_x() + y_complete = self.data.get_guidelines_y() + + ind = 0 + self.line_gl = [] + for x, y in zip(x_complete, y_complete): + line = self.canvas.axes.plot( + x, y, color=self.colors[ind % len(self.colors)], + linestyle=self.linestyle[ind // len(self.colors)] + ) + self.line_gl.append(line) + ind += 1 + + @timer + def update(self): + if not self._init: + self.draw() + return + + if self.data is None: + return + + self.update_lr() + self.update_gl() + self.update_current() + + self.update_idle() + + def update_gl(self): + self.data.compute_guidelines() + x_complete = list(self.data.get_guidelines_x()) + y_complete = list(self.data.get_guidelines_y()) + + # TODO comprendre à quoi sert ce bout de code + # ========> + #for i in range(self.data.number_profiles): + #if i < len(self.line_xy): + #self.line_xy[i][0].set_data( + #self.data.profile(i).x(), + #self.data.profile(i).y() + #) + #else: + #self.line_xy.append( + #self.canvas.axes.plot( + #self.data.profile(i).x(), + #self.data.profile(i).y(), + #color='r', + #**self.plot_default_kargs + #) + #) + # <======== + + for i in range(len(x_complete)): + if i < len(self.line_gl): + self.line_gl[i][0].set_data( + x_complete[i], + y_complete[i] + ) + else: + self.line_gl.append( + self.canvas.axes.plot( + x_complete[i], + y_complete[i] + ) + ) + + def update_current(self): + if self._current_data_update: + self._colors, self._style = self.color_hightlight() + self.line_xy_collection.set_colors(self._colors) + self.line_xy_collection.set_linestyle(self._style) + + def update_lr(self): + for line in self.line_lr: + line[0].remove() + + self.draw_lr() diff --git a/src/View/LateralContribution/Window.py b/src/View/LateralContribution/Window.py index 879955bbb72c7657a903d96c51e5c5ad13dd442c..6a91c1cd597cd188ee221ee3d0a37b1ebbbc359d 100644 --- a/src/View/LateralContribution/Window.py +++ b/src/View/LateralContribution/Window.py @@ -54,7 +54,7 @@ from View.LateralContribution.Table import ( ) from View.Tools.Plot.PamhyrCanvas import MplCanvas -from View.Geometry.PlotXY import PlotXY +from View.LateralContribution.PlotXY import PlotXY from View.LateralContribution.translate import ( LC_types, LCTranslate, ) @@ -83,6 +83,7 @@ class LateralContributionWindow(PamhyrWindow): self.setup_table() self.setup_graph() + self.tabs = self.find(QTabWidget, "tabWidget") self.setup_connections() def setup_table(self): @@ -148,6 +149,7 @@ class LateralContributionWindow(PamhyrWindow): data=None, trad=self._trad, toolbar=None, + parent=self ) def setup_connections(self): @@ -156,6 +158,8 @@ class LateralContributionWindow(PamhyrWindow): self.find(QAction, "action_edit").triggered.connect(self.edit) self.find(QAction, "action_sort").triggered.connect(self.sort) + self.tabs.currentChanged.connect(self._set_current_reach) + for t in ["liquid", "solid", "suspenssion"]: table = self.find(QTableView, f"tableView_{t}") table.selectionModel()\ @@ -216,6 +220,7 @@ class LateralContributionWindow(PamhyrWindow): data=data, trad=self._trad, toolbar=None, + parent=self ) self.plot.highlight = highlight self.plot.update() @@ -292,3 +297,9 @@ class LateralContributionWindow(PamhyrWindow): parent=self ) win.show() + + #@pyqtSlot() + def onChange(self,i): #changed! + QtGui.QMessageBox.information(self, + "Tab Index Changed!", + "Current Tab Index: %d" % i ) #changed!