# PlotXY.py -- Pamhyr # Copyright (C) 2023-2025 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 . # -*- 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 try: import rasterio import rasterio.control import rasterio.crs import rasterio.sample import rasterio.vrt import rasterio._features from rasterio.io import MemoryFile _rasterio_loaded = True except Exception as e: print(f"Module 'rasterio' is not available: {e}") _rasterio_loaded = False _translate = QCoreApplication.translate class PlotXY(PamhyrPlot): def __init__(self, canvas=None, trad=None, data=None, geotiff=None, toolbar=None, table=None, parent=None): super(PlotXY, self).__init__( canvas=canvas, trad=trad, data=data, toolbar=toolbar, table=table, parent=parent ) self._data = data self._geotiff = geotiff self.label_x = self._trad["x"] self.label_y = self._trad["y"] self.parent = parent self._plot_img = {} self._isometric_axis = True self._auto_relim_update = True self._autoscale_update = True @timer def draw(self): self.init_axes() if self._data is None: self.idle() return if len(self._data) < 1: self.idle() return self.line_lr = [] for data in self._data: if data.reach.number_profiles != 0: self.draw_xy(data.reach) self.draw_lr(data.reach) if self._geotiff is not None: self.draw_geotiff(self._geotiff.files) self.idle() return def draw_xy(self, reach): line_xy = [] for xy in zip(reach.get_x(), reach.get_y()): line_xy.append(np.column_stack(xy)) line_xy_collection = collections.LineCollection( line_xy, colors=self.color_plot_river_bottom ) self.canvas.axes.add_collection(line_xy_collection) def draw_lr(self, reach): lx = [] ly = [] rx = [] ry = [] for x, y in zip(reach.get_x(), reach.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_geotiff(self, lst): if not _rasterio_loaded: return for img in self._plot_img: self._plot_img[img].remove() self._plot_img = {} for geotiff in lst: if geotiff.is_deleted(): continue memfile = geotiff.memfile if memfile is None: continue with memfile.open() as gt: img = gt.read() coords = geotiff.coordinates left = coords["left"] right = coords["right"] bottom = coords["bottom"] top = coords["top"] self._plot_img[geotiff] = self.canvas.axes.imshow( img.transpose((1, 2, 0)), extent=(left, right, bottom, top) ) if not geotiff.is_enabled(): self._plot_img[geotiff].set(alpha=0.5) self.idle() @timer def update(self): self.draw() self.update_idle()