From 1a31c9122ecfa654fb45332ab35bfa9ebb5a1d03 Mon Sep 17 00:00:00 2001 From: Youcef AOUAD <youcef.aouad@inrae.fr> Date: Thu, 5 Sep 2024 12:35:16 +0200 Subject: [PATCH] first plot complete --- src/Model/Results/ResultsAdisTS.py | 2 +- src/Model/Results/River/RiverAdisTS.py | 136 +++++++++++++++++ src/Solver/AdisTS.py | 11 +- src/View/Results/PlotHAdisTS.py | 196 +++++++++++++++++++++++++ src/View/Results/WindowAdisTS.py | 71 +-------- 5 files changed, 345 insertions(+), 71 deletions(-) create mode 100644 src/Model/Results/River/RiverAdisTS.py create mode 100644 src/View/Results/PlotHAdisTS.py diff --git a/src/Model/Results/ResultsAdisTS.py b/src/Model/Results/ResultsAdisTS.py index 79b1b4e0..adf27310 100644 --- a/src/Model/Results/ResultsAdisTS.py +++ b/src/Model/Results/ResultsAdisTS.py @@ -21,7 +21,7 @@ import os, glob from copy import deepcopy from datetime import datetime -from Model.Results.River.River import River +from Model.Results.River.RiverAdisTS import River logger = logging.getLogger() diff --git a/src/Model/Results/River/RiverAdisTS.py b/src/Model/Results/River/RiverAdisTS.py new file mode 100644 index 00000000..4505b145 --- /dev/null +++ b/src/Model/Results/River/RiverAdisTS.py @@ -0,0 +1,136 @@ +# River.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/>. + +import logging + +from datetime import datetime + +logger = logging.getLogger() + + +class Profile(object): + def __init__(self, profile, study): + self._study = study + self._profile = profile # Source profile in the study + self._data = {} # Dict of dict {<ts>: {<key>: <value>, ...}, ...} + + def __len__(self): + return len(self._data) + + @property + def name(self): + return self._profile.name + + @property + def kp(self): + return self._profile.kp + + @property + def geometry(self): + return self._profile + + def set(self, timestamp, key, data): + if timestamp not in self._data: + self._data[timestamp] = {} + + self._data[timestamp][key] = data + + def get_ts(self, timestamp): + return self._data[timestamp] + + def get_key(self, key): + return list( + map(lambda ts: self._data[ts][key], self._data) + ) + + def get_ts_key(self, timestamp, key): + return self._data[timestamp][key] + + def has_sediment(self): + return any(map(lambda ts: "sl" in self._data[ts], self._data)) + + +class Reach(object): + def __init__(self, reach, study): + self._study = study + self._reach = reach # Source reach in the study + self._profiles = list( + map( + lambda p: Profile(p, self._study), + reach.profiles + ) + ) + + def __len__(self): + return len(self._profiles) + + @property + def name(self): + return self._reach.name + + @property + def geometry(self): + return self._reach + + @property + def profiles(self): + return self._profiles.copy() + + def profile(self, id): + return self._profiles[id] + + def set(self, profile_id, timestamp, key, data): + self._profiles[profile_id].set(timestamp, key, data) + + def has_sediment(self): + return any(map(lambda profile: profile.has_sediment(), self._profiles)) + + +class River(object): + def __init__(self, study): + self._study = study + + # Dict with timestamps as key + self._reachs = [] + + def __len__(self): + return len(self._reachs) + + @property + def reachs(self): + return self._reachs.copy() + + def reach(self, id): + return self._reachs[id] + + def has_reach(self, id): + return 0 <= id < len(self._reachs) + + def add(self, reach_id): + reachs = self._study.river.enable_edges() + + new = Reach(reachs[reach_id].reach, self._study) + + self._reachs.append(new) + return new + + def get_reach_by_geometry(self, geometry_reach): + return next( + filter( + lambda r: r.geometry is geometry_reach, + self._reachs + ) + ) diff --git a/src/Solver/AdisTS.py b/src/Solver/AdisTS.py index e1beef6a..9fa56f9d 100644 --- a/src/Solver/AdisTS.py +++ b/src/Solver/AdisTS.py @@ -634,6 +634,8 @@ class AdisTSlc(AdisTS): data = np.fromfile(f, dtype=np.int32, count=1) # line length (bytes) (start) # end data + print("dta tmp AAA") + print("-----------") print(data_tmp["AAA-silt"]) pollutants_keys = list(data_tmp.keys()) @@ -663,7 +665,7 @@ class AdisTSlc(AdisTS): pol_view = [] for pol in pollutants_keys: #print("pol results: ", type(list(data_tmp[pol][t_data].values()))) - pol_view.append(tuple(list(data_tmp[pol][t_data].values()))) + pol_view.append(tuple( list(map(lambda data_el: data_el[p_i], list(data_tmp[pol][t_data].values()))) )) reach.set(p_i, t_data, "pols", pol_view) @@ -675,6 +677,13 @@ class AdisTSlc(AdisTS): results.set("timestamps", set(timestamps_keys)) #print("------------------------set timestamps results meta data: ", set(timestamps_keys)) + print("debug profiles for draw:") + print("------------------------") + print(data_tmp["AAA-silt"][0.0]["C"][0]) + print(data_tmp["AAA-silt"][600.0]["C"][0]) + print(data_tmp["AAA-silt"][1205.7208829578194]["C"][0]) + print("========================") + @timer def results(self, study, repertory, qlog=None, name=None): self._study = study diff --git a/src/View/Results/PlotHAdisTS.py b/src/View/Results/PlotHAdisTS.py new file mode 100644 index 00000000..418acdf7 --- /dev/null +++ b/src/View/Results/PlotHAdisTS.py @@ -0,0 +1,196 @@ +# PlotH.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 -*- + +import logging + +from functools import reduce +from datetime import datetime + +from tools import timer, trace +from View.Tools.PamhyrPlot import PamhyrPlot + +from PyQt5.QtCore import ( + QCoreApplication +) + +_translate = QCoreApplication.translate + +logger = logging.getLogger() + + +class PlotH(PamhyrPlot): + def __init__(self, canvas=None, trad=None, toolbar=None, + results=None, reach_id=0, profile_id=0, + parent=None): + super(PlotH, self).__init__( + canvas=canvas, + trad=trad, + data=results, + toolbar=toolbar, + parent=parent + ) + + self._mode = "time" + + self._current_timestamp = max(results.get("timestamps")) + self._current_reach_id = reach_id + self._current_profile_id = profile_id + + self.label_x = _translate("Results", "Time (s)") + self.label_y = _translate("Results", "Discharge (m³/s)") + + self.label_discharge = _translate("Results", "Cross-section discharge") + self.label_discharge_max = _translate("Results", "Max discharge") + self.label_timestamp = _translate("Results", "Current timestamp") + + self._isometric_axis = False + + self._auto_relim_update = False + self._autoscale_update = False + + @property + def results(self): + return self.data + + @results.setter + def results(self, results): + self.data = results + self._current_timestamp = max(results.get("timestamps")) + + @timer + def draw(self, highlight=None): + self.init_axes() + + if self.results is None: + return + + reach = self.results.river.reach(self._current_reach_id) + profile = reach.profile(self._current_profile_id) + + if reach.geometry.number_profiles == 0: + self._init = False + return + + #self.draw_max(reach) + self.draw_data(reach, profile) + #self.draw_current(reach, profile) + + self.set_ticks_time_formater() + + self.enable_legend() + + self.idle() + self._init = True + + def draw_data(self, reach, profile): + self.ts = list(self.results.get("timestamps")) + self.ts.sort() + + x = self.ts + #y = profile.get_key("Q") + #First 0 for pol and second 0 for phys var + y = list(map(lambda data_el: data_el[0][0], profile.get_key("pols"))) + + print("*****************draw data: ", len(x),len(y)) + print("x: ", x) + print("y: ", y) + print("reach: ", reach) + print("profile: ", profile) + + self._line, = self.canvas.axes.plot( + x, y, + label=self.label_discharge, + color=self.color_plot, + **self.plot_default_kargs + ) + + def draw_current(self, reach, profile): + min_y, max_y = reduce( + lambda acc, p: ( + acc[0] + [min(p.get_key("Q"))], + acc[1] + [max(p.get_key("Q"))] + ), + reach.profiles, + ([], []) + ) + + self._current, = self.canvas.axes.plot( + [self._current_timestamp, self._current_timestamp], + [min(min_y), max(max_y)], + # label=self.label_timestamp, + color=self.color_plot_river_bottom, + linestyle="dashed", + lw=1., + ) + + def draw_max(self, reach): + self.ts = list(self.results.get("timestamps")) + self.ts.sort() + + x = self.ts + y = [] + for ts in x: + ts_y = -9999 + for profile in reach.profiles: + q = profile.get_ts_key(ts, "Q") + ts_y = max(ts_y, q) + y.append(ts_y) + + self._line_max, = self.canvas.axes.plot( + x, y, + label=self.label_discharge_max, + color=self.color_plot_highlight, + linestyle='dotted', + **self.plot_default_kargs + ) + + def set_reach(self, reach_id): + self._current_reach_id = reach_id + self._current_profile_id = 0 + self.draw() + + def set_profile(self, profile_id): + self._current_profile_id = profile_id + self.update() + + def set_timestamp(self, timestamp): + self._current_timestamp = timestamp + self.update() + + def update(self): + if not self._init: + self.draw() + + self.update_data() + + self.update_idle() + + def update_data(self): + reach = self.results.river.reach(self._current_reach_id) + profile = reach.profile(self._current_profile_id) + + x = self.ts + y = profile.get_key("Q") + + self._line.set_data(x, y) + + _, min_max = self._current.get_data() + self._current.set_data( + self._current_timestamp, + min_max + ) diff --git a/src/View/Results/WindowAdisTS.py b/src/View/Results/WindowAdisTS.py index ef1828a8..2de25ae2 100644 --- a/src/View/Results/WindowAdisTS.py +++ b/src/View/Results/WindowAdisTS.py @@ -49,7 +49,7 @@ from View.Tools.Plot.PamhyrToolbar import PamhyrPlotToolbar from View.Results.PlotXY import PlotXY from View.Results.PlotAC import PlotAC from View.Results.PlotKPC import PlotKPC -from View.Results.PlotH import PlotH +from View.Results.PlotHAdisTS import PlotH from View.Results.PlotSedReach import PlotSedReach from View.Results.PlotSedProfile import PlotSedProfile @@ -112,7 +112,7 @@ class ResultsWindowAdisTS(PamhyrWindow): print("setup table adists results") self.setup_table() - #self.setup_plots() + self.setup_plots() #self.setup_slider() #self.setup_statusbar() #self.setup_connections() @@ -165,73 +165,6 @@ class ResultsWindowAdisTS(PamhyrWindow): self._timer = QTimer(self) def setup_plots(self): - self.canvas = MplCanvas(width=5, height=4, dpi=100) - self.canvas.setObjectName("canvas") - self.toolbar = PamhyrPlotToolbar( - self.canvas, self, items=[ - "home", "move", "zoom", "save", - "iso", "back/forward" - ] - ) - self.plot_layout = self.find(QVBoxLayout, "verticalLayout") - self.plot_layout.addWidget(self.toolbar) - self.plot_layout.addWidget(self.canvas) - - self.plot_xy = PlotXY( - canvas=self.canvas, - results=self._results, - reach_id=0, - profile_id=0, - trad=self._trad, - toolbar=self.toolbar, - display_current=True - ) - self.plot_xy.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_2") - self.plot_layout_2.addWidget(self.toolbar_2) - self.plot_layout_2.addWidget(self.canvas_2) - - self.plot_kpc = PlotKPC( - canvas=self.canvas_2, - results=self._results, - reach_id=0, - profile_id=0, - trad=self._trad, - toolbar=self.toolbar_2 - ) - self.plot_kpc.draw() - - self.canvas_3 = MplCanvas(width=5, height=4, dpi=100) - self.canvas_3.setObjectName("canvas_3") - self.toolbar_3 = PamhyrPlotToolbar( - self.canvas_3, self, items=[ - "home", "move", "zoom", "save", - "iso", "back/forward" - ] - ) - self.plot_layout_3 = self.find(QVBoxLayout, "verticalLayout_3") - self.plot_layout_3.addWidget(self.toolbar_3) - self.plot_layout_3.addWidget(self.canvas_3) - - self.plot_ac = PlotAC( - canvas=self.canvas_3, - results=self._results, - reach_id=0, - profile_id=0, - trad=self._trad, - toolbar=self.toolbar_3 - ) - self.plot_ac.draw() - self.canvas_4 = MplCanvas(width=5, height=4, dpi=100) self.canvas_4.setObjectName("canvas_4") self.toolbar_4 = PamhyrPlotToolbar( -- GitLab