Source code for wolfhece._lulc_manager

"""LU/LC companion for WolfMapViewer.

This companion owns the Landuse/Landcover menu construction, including
Walous submenus. Handlers are routed through this companion to private
viewer helpers to keep behavior identical while completing migration in
small safe steps.
"""
from __future__ import annotations

import logging
from pathlib import Path
from typing import TYPE_CHECKING

import geopandas as gpd
import numpy as np
import wx

from .PyTranslate import _
from .wolf_array import WolfArray, header_wolf, WOLF_ARRAY_FULL_SINGLE
from .pydownloader import toys_dataset

if TYPE_CHECKING:
    from .PyDraw import WolfMapViewer

__all__ = ['LulcManager']


[docs] class LulcManager: """Companion object that owns LU/LC menu state and handler routing.""" def __init__(self, viewer: 'WolfMapViewer') -> None:
[docs] self._viewer = viewer
[docs] self._menu: wx.Menu | None = None
[docs] def menu_build(self) -> None: v = self._viewer if self._menu is not None: return self._menu = wx.Menu() self._importFromFile_menu = wx.Menu() self._vectorImport = self._importFromFile_menu.Append(wx.ID_ANY, _("Import vector LU-LC data"), _("Import vector landuse/landcover data and map to Manning's n for active array")) self._rasterImport = self._importFromFile_menu.Append(wx.ID_ANY, _("Import raster LU-LC data"), _("Import raster landuse/landcover data and map to Manning's n for active array")) self._menuwalous = wx.Menu() self._uts_menu = wx.Menu() self._ocs_menu = wx.Menu() self._uts_crop = self._uts_menu.Append(wx.ID_ANY, _("Crop on active array"), _("Crop UTS data (vectorized - shp, gpkg) on the active array extent")) self._uts_cropscreen = self._uts_menu.Append(wx.ID_ANY, _("Crop on screen"), _("Crop UTS data (vectorized - shp, gpkg) on the current screen extent")) self._uts_map = self._uts_menu.Append(wx.ID_ANY, _("Map active array (WAL_UTS -> Manning)"), _("Map Walous UTS active array to Manning's n")) self._uts_legend = self._uts_menu.Append(wx.ID_ANY, _("Legend"), _("Legend")) self._ocs_crop_10m_2023 = self._ocs_menu.Append(wx.ID_ANY, _("Crop on active array (prepared data 10 m - 2023)"), _("Crop OCS data (matrix - geotif) on the active array extent using prepared 10m data")) self._ocs_cropscreen_10m_2023 = self._ocs_menu.Append(wx.ID_ANY, _("Crop on screen (prepared data 10 m - 2023)"), _("Crop OCS data (matrix - geotif) on the current screen extent using prepared 10m data")) self._ocs_menu.AppendSeparator() self._ocs_crop_10m_2020 = self._ocs_menu.Append(wx.ID_ANY, _("Crop on active array (prepared data 10 m - 2020)"), _("Crop OCS data (matrix - geotif) on the active array extent using prepared 10m data")) self._ocs_cropscreen_10m_2020 = self._ocs_menu.Append(wx.ID_ANY, _("Crop on screen (prepared data 10 m - 2020)"), _("Crop OCS data (matrix - geotif) on the current screen extent using prepared 10m data")) self._ocs_menu.AppendSeparator() self._ocs_crop = self._ocs_menu.Append(wx.ID_ANY, _("Crop on active array"), _("Crop OCS data (matrix - geotif) on the active array extent")) self._ocs_cropscreen = self._ocs_menu.Append(wx.ID_ANY, _("Crop on screen"), _("Crop OCS data (matrix - geotif) on the current screen extent")) self._ocs_menu.AppendSeparator() self._ocs_map_hydrology = self._ocs_menu.Append(wx.ID_ANY, _("Map active array (WAL_OCS -> Hydrology)"), _("Map Walous OCS active array to Hydrology's landuse classification")) self._ocs_map = self._ocs_menu.Append(wx.ID_ANY, _("Map active array (WAL_OCS -> Manning)"), _("Map Walous OCS active array to Manning's n")) self._ocs_legend = self._ocs_menu.Append(wx.ID_ANY, _("Legend"), _("Legend")) v._walous_UTS_filepath = None v._walous_OCS_filepath = None v._walous_layer = None v._walous_map = None self._menuwalous.AppendSubMenu(self._uts_menu, _('UTS')) self._menuwalous.AppendSubMenu(self._ocs_menu, _('OCS')) self._menu.AppendSubMenu(self._importFromFile_menu, _('Map imported data to Manning')) self._menu.AppendSubMenu(self._menuwalous, _('Walous')) v.menubar.Append(self._menu, _('Landuse/Landcover')) self._importFromFile_menu.Bind(wx.EVT_MENU, self._handle_importfromfile, self._vectorImport) self._importFromFile_menu.Bind(wx.EVT_MENU, self._handle_importfromfile, self._rasterImport) self._uts_menu.Bind(wx.EVT_MENU, self._handle_walous_uts, self._uts_crop) self._uts_menu.Bind(wx.EVT_MENU, self._handle_walous_uts, self._uts_cropscreen) self._uts_menu.Bind(wx.EVT_MENU, self._handle_walous_uts, self._uts_map) self._uts_menu.Bind(wx.EVT_MENU, self._handle_walous_uts, self._uts_legend) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_crop_10m_2023) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_cropscreen_10m_2023) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_crop_10m_2020) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_cropscreen_10m_2020) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_crop) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_cropscreen) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_map_hydrology) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_map) self._ocs_menu.Bind(wx.EVT_MENU, self._handle_walous_ocs, self._ocs_legend)
[docs] def _handle_importfromfile(self, event: wx.MenuEvent) -> None: # Keep original handler logic unchanged by aliasing to the viewer instance. self = self._viewer """ Handle the Landuse/Landcover import from file menu events """ id = event.GetId() item = self.menubar.FindItemById(event.GetId()) if item is None: return itemlabel = item.ItemLabel if itemlabel == _("Import vector LU-LC data"): logging.info("Import vector LU-LC data selected") dlg = wx.FileDialog(self, _("Choose the vector LU-LC file"), wildcard="Shapefile (*.shp)|*.shp", style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return self._vectorLU_LC_filepath = Path(dlg.GetPath()) dlg.Destroy() # Import vector LU-LC data try: self._vectorLU_LC_data = gpd.read_file(self._vectorLU_LC_filepath) except Exception as e: logging.error(f"Error reading shapefile: {e}") wx.MessageBox( _("Failed to read the shapefile.\nPlease ensure it is valid."), _("Error"), wx.OK | wx.ICON_ERROR ) return if self._vectorLU_LC_data.empty: logging.error(f"Failed to read vector LU-LC data from {self._vectorLU_LC_filepath}") wx.MessageBox( _("The shapefile appears to be empty."), _("Error"), wx.OK | wx.ICON_ERROR ) return else: logging.info(f"Vector LU-LC data imported from {self._vectorLU_LC_filepath}") headers = list(self._vectorLU_LC_data.columns) dlg_attr = wx.SingleChoiceDialog( self, message=_("Select the attribute column to use for Manning's mapping:"), caption=_("Select LU-LC Attribute"), choices=headers, style=wx.CHOICEDLG_STYLE ) if dlg_attr.ShowModal() == wx.ID_OK: self._selected_LULC_column = dlg_attr.GetStringSelection() logging.info(f"Selected LU-LC attribute column: {self._selected_LULC_column}") else: logging.info("User cancelled attribute column selection.") dlg_attr.Destroy() return dlg_attr.Destroy() unique_values = sorted(self._vectorLU_LC_data[self._selected_LULC_column].dropna().unique().tolist()) if not unique_values: wx.MessageBox( _("No valid attribute values found in the selected column."), _("Error"), wx.OK | wx.ICON_ERROR ) return dlg_map = wx.Dialog(self, title=_("Map LU-LC Classes to Manning's Coefficients"), size=(500, 400)) panel = wx.Panel(dlg_map) vbox = wx.BoxSizer(wx.VERTICAL) info_text = wx.StaticText( panel, label=_("Enter Manning's n value for each LU/LC class:") ) vbox.Add(info_text, 0, wx.ALL, 10) # Create table for mapping grid = wx.grid.Grid(panel) grid.CreateGrid(len(unique_values), 2) grid.SetColLabelValue(0, _("LU/LC Class")) grid.SetColLabelValue(1, _("Manning's n")) grid.EnableEditing(True) grid.SetColSize(0, 250) grid.SetColSize(1, 150) for i, val in enumerate(unique_values): grid.SetCellValue(i, 0, str(val)) grid.SetReadOnly(i, 0, True) # LU/LC column is not editable vbox.Add(grid, 1, wx.EXPAND | wx.ALL, 10) hbox = wx.BoxSizer(wx.HORIZONTAL) btn_ok = wx.Button(panel, wx.ID_OK, _("OK")) btn_cancel = wx.Button(panel, wx.ID_CANCEL, _("Cancel")) hbox.Add(btn_ok, 0, wx.ALL, 5) hbox.Add(btn_cancel, 0, wx.ALL, 5) vbox.Add(hbox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10) panel.SetSizer(vbox) dlg_map.Layout() while True: if dlg_map.ShowModal() != wx.ID_OK: logging.info("User cancelled LU-LC to Manning's mapping.") return mapping = {} validation_failed = False for i, val in enumerate(unique_values): n_str = grid.GetCellValue(i, 1).strip() if not n_str: wx.MessageBox( _(f"Missing Manning's n value for class '{val}'."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break try: n_value = float(n_str) if n_value <= 0: wx.MessageBox( _(f"Invalid Manning's n value for class '{val}'. Must be positive."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break except ValueError: wx.MessageBox( _(f"Invalid Manning's n value for class '{val}'. Must be numeric."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break mapping[val] = n_value if validation_failed: continue self._lulc_manning_mapping = mapping logging.info("LU-LC to Manning's mapping completed:") for k, v in mapping.items(): logging.info(f" {k}: {v}") break dlg_map.Destroy() if hasattr(self, "_lulc_manning_mapping") and self._lulc_manning_mapping: manning_col_name = "MANNING_N" self._vectorLU_LC_data[manning_col_name] = self._vectorLU_LC_data[self._selected_LULC_column].map(self._lulc_manning_mapping) mapped_count = self._vectorLU_LC_data[manning_col_name].notna().sum() total_count = len(self._vectorLU_LC_data) logging.info( f"Applied Manning's coefficients to {mapped_count}/{total_count} features " f"using attribute '{self._selected_LULC_column}'." ) wx.MessageBox( _( f"Manning's n values assigned to {mapped_count} out of {total_count} features.\n" f"A new column '{manning_col_name}' has been added." ), _("Mapping Complete"), wx.OK | wx.ICON_INFORMATION ) else: logging.warning("No Manning's mapping found or user cancelled mapping process.") export_prompt = wx.MessageDialog( self, _( "Do you want to export the updated LU/LC data (with Manning's n values) " "to a new file?" ), _("Export Updated Layer"), style=wx.YES_NO | wx.ICON_QUESTION ) if export_prompt.ShowModal() == wx.ID_YES: export_prompt.Destroy() save_dlg = wx.FileDialog(self,_("Save updated LU/LC file as"),wildcard="Shapefile (*.shp)|*.shp",style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if save_dlg.ShowModal() == wx.ID_CANCEL: save_dlg.Destroy() logging.info("User cancelled export.") return export_path = Path(save_dlg.GetPath()) save_dlg.Destroy() try: driver = "ESRI Shapefile" self._vectorLU_LC_data.to_file(export_path, driver=driver) logging.info(f"Exported updated LU/LC data to {export_path}") wx.MessageBox(_(f"Successfully exported updated LU/LC data to:\n{export_path}"),_("Export Successful"),wx.OK | wx.ICON_INFORMATION) except Exception as e: logging.error(f"Failed to export LU/LC data: {e}") wx.MessageBox(_(f"Error while exporting:\n{e}"), _("Export Error"), wx.OK | wx.ICON_ERROR) else: export_prompt.Destroy() logging.info("User chose not to export updated LU/LC data.") raster_prompt = wx.MessageDialog(self, _("Do you want to create a raster file from the Manning's n data?"), _("Create Raster"), style=wx.YES_NO | wx.ICON_QUESTION) if raster_prompt.ShowModal() == wx.ID_YES: raster_prompt.Destroy() choices = [_("Use vector bounds"), _("Crop to active array")] bounds_dlg = wx.SingleChoiceDialog(self, _("Select bounding extent:"), _("Raster Bounds"), choices) if bounds_dlg.ShowModal() == wx.ID_CANCEL: bounds_dlg.Destroy() return bounds_choice = bounds_dlg.GetStringSelection() bounds_dlg.Destroy() if bounds_choice == _("Crop to active array"): if self.active_array is None: logging.warning(_("No active array -- Please activate data first")) wx.MessageBox(_("No active array available.\nCannot crop raster."), _("Error"), wx.OK | wx.ICON_ERROR) return bounds_x, bounds_y = self.active_array.get_bounds() xmin, xmax = bounds_x ymin, ymax = bounds_y spatial_res = self.active_array.dx def_outdir = Path(self.active_array.filename).parent else: xmin, ymin, xmax, ymax = self._vectorLU_LC_data.total_bounds def_outdir = Path(self._vectorLU_LC_filepath).parent res_dlg = wx.TextEntryDialog(self, _("Enter spatial resolution (m):"), _("Spatial Resolution"), value="10.0") if res_dlg.ShowModal() == wx.ID_OK: try: spatial_res = float(res_dlg.GetValue()) except ValueError: wx.MessageBox(_("Invalid resolution entered. Must be numeric."), _("Error"), wx.OK | wx.ICON_ERROR) res_dlg.Destroy() return else: res_dlg.Destroy() return res_dlg.Destroy() save_dlg = wx.FileDialog( self, _("Save raster file as"), defaultDir=str(def_outdir), wildcard="GeoTIFF (*.tif)|*.tif", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT ) if save_dlg.ShowModal() == wx.ID_CANCEL: save_dlg.Destroy() return raster_path = Path(save_dlg.GetPath()) save_dlg.Destroy() # Rasterization import rasterio from rasterio import features try: logging.info("Starting rasterization of Manning's n data...") width = int((xmax - xmin) / spatial_res) height = int((ymax - ymin) / spatial_res) transform = rasterio.transform.from_origin(xmin, ymax, spatial_res, spatial_res) shapes = zip( self._vectorLU_LC_data.geometry, self._vectorLU_LC_data["MANNING_N"] ) raster_data = features.rasterize( shapes=shapes, out_shape=(height, width), transform=transform, fill=np.nan, dtype="float32" ) new_dataset = rasterio.open( raster_path, "w", driver="GTiff", height=height, width=width, count=1, dtype="float32", crs=self._vectorLU_LC_data.crs, transform=transform, nodata=np.nan ) new_dataset.write(raster_data, 1) new_dataset.close() logging.info(f"Raster created successfully: {raster_path}") wx.MessageBox(_(f"Raster file created successfully:\n{raster_path}"), _("Rasterization Complete"), wx.OK | wx.ICON_INFORMATION) dlg = wx.MessageDialog(self, _('Do you want to load the created file ?'), _('Load file'), wx.YES_NO | wx.ICON_QUESTION) ret = dlg.ShowModal() dlg.Destroy() if ret == wx.ID_CANCEL: return if ret == wx.ID_YES: manning_array = WolfArray(fname=raster_path) self.add_object('array', newobj=manning_array, id='manning_array') except Exception as e: logging.error(f"Error creating raster: {e}") wx.MessageBox(_(f"Error creating raster:\n{e}"),_("Rasterization Error"),wx.OK | wx.ICON_ERROR) else: raster_prompt.Destroy() logging.info("User skipped raster creation.") self.Autoscale() elif itemlabel == _("Import raster LU-LC data"): logging.info("Import raster LU-LC data selected") dlg = wx.FileDialog(self, _("Choose the raster LU-LC file"), wildcard="GeoTIFF (*.tif)|*.tif|all (*.*)|*.*", style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return raster_path = Path(dlg.GetPath()) dlg.Destroy() try: lu_lc_array = WolfArray(fname=raster_path) unique_values = sorted(lu_lc_array.get_unique_values()) if not unique_values: wx.MessageBox( _("Something went wrong reading unique values from the raster. Please check the file."), _("Error"), wx.OK | wx.ICON_ERROR ) return dlg_map = wx.Dialog(self, title=_("Map LU-LC Classes to Manning's Coefficients"), size=(500, 400)) panel = wx.Panel(dlg_map) vbox = wx.BoxSizer(wx.VERTICAL) info_text = wx.StaticText( panel, label=_("Enter Manning's n value for each LU/LC class. \nCheck the file's documentation for class meanings:") ) vbox.Add(info_text, 0, wx.ALL, 10) # Create table for mapping grid = wx.grid.Grid(panel) grid.CreateGrid(len(unique_values), 2) grid.SetColLabelValue(0, _("LU/LC Class")) grid.SetColLabelValue(1, _("Manning's n")) grid.EnableEditing(True) grid.SetColSize(0, 150) grid.SetColSize(1, 150) for i, val in enumerate(unique_values): grid.SetCellValue(i, 0, str(val)) grid.SetReadOnly(i, 0, True) # LU/LC column is not editable vbox.Add(grid, 1, wx.EXPAND | wx.ALL, 10) hbox = wx.BoxSizer(wx.HORIZONTAL) btn_ok = wx.Button(panel, wx.ID_OK, _("OK")) btn_cancel = wx.Button(panel, wx.ID_CANCEL, _("Cancel")) hbox.Add(btn_ok, 0, wx.ALL, 5) hbox.Add(btn_cancel, 0, wx.ALL, 5) vbox.Add(hbox, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10) panel.SetSizer(vbox) dlg_map.Layout() while True: if dlg_map.ShowModal() != wx.ID_OK: logging.info("User cancelled LU-LC to Manning's mapping.") return mapping = {} validation_failed = False for i, val in enumerate(unique_values): n_str = grid.GetCellValue(i, 1).strip() if not n_str: wx.MessageBox( _(f"Missing Manning's n value for class '{val}'."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break try: n_value = float(n_str) if n_value <= 0: wx.MessageBox( _(f"Invalid Manning's n value for class '{val}'. Must be positive."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break except ValueError: wx.MessageBox( _(f"Invalid Manning's n value for class '{val}'. Must be numeric."), _("Error"), wx.OK | wx.ICON_ERROR ) validation_failed = True break mapping[val] = n_value if validation_failed: continue self._lulc_manning_mapping = mapping logging.info("LU-LC to Manning's mapping completed:") for k, v in self._lulc_manning_mapping.items(): logging.info(f" {k}: {v}") break dlg_map.Destroy() if hasattr(self, "_lulc_manning_mapping") and self._lulc_manning_mapping: lu_lc_array_copy = lu_lc_array.array.data.copy() for lu_lc_value, manning_n in self._lulc_manning_mapping.items(): lu_lc_array.array.data[lu_lc_array_copy == lu_lc_value] = manning_n if self.active_array is not None: dlg_crop = wx.MessageDialog( self, _("Do you want to crop the raster to the active array extent?"), _('Crop Raster'), wx.YES_NO | wx.ICON_QUESTION ) if dlg_crop.ShowModal() == wx.ID_YES: try: lu_lc_array = WolfArray(mold=lu_lc_array, crop=self.active_array.get_bounds()) logging.info("Raster cropped to active array extent.") except Exception as e: logging.error(f"Error cropping raster: {e}") dlg_crop.Destroy() dlg_resample = wx.TextEntryDialog( self, _(f"Resample the raster to active array resolution ({self.active_array.dx} m) \n or enter desired resolution"), _("Resample Raster"), value=str(self.active_array.dx) ) try: if dlg_resample.ShowModal() == wx.ID_OK: try: new_resolution = float(dlg_resample.GetValue()) if new_resolution <= 0: raise ValueError("Resolution must be positive.") lu_lc_array.rebin(new_resolution / lu_lc_array.dx, operation='min') logging.info(f"Raster resampled to {new_resolution} m.") save_dlg = wx.FileDialog( self, _("Save raster file as"), defaultDir=str(raster_path), wildcard="GeoTIFF (*.tif)|*.tif", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT ) if save_dlg.ShowModal() == wx.ID_CANCEL: save_dlg.Destroy() return raster_path = Path(save_dlg.GetPath()) save_dlg.Destroy() lu_lc_array.write_all(raster_path) logging.info(f"Raster file saved: {raster_path}") dlg = wx.MessageDialog(self, _('Do you want to load the created array ?'), _('Load file'), wx.YES_NO | wx.ICON_QUESTION) ret = dlg.ShowModal() dlg.Destroy() if ret == wx.ID_CANCEL: return if ret == wx.ID_YES: manning_array = WolfArray(fname=raster_path) self.add_object('array', newobj=manning_array, id=f'{raster_path.stem}') except ValueError as e: wx.MessageBox( _(f"Invalid resolution value: {e}"), _("Error"), wx.OK | wx.ICON_ERROR ) return finally: dlg_resample.Destroy() else: logging.info("No active array to resample raster to.") dlg_resample = wx.TextEntryDialog( self, _(f"Enter desired spatial resolution (m) for the raster \n Current: {lu_lc_array.dx}"), _("Resample Raster"), value="" ) try: if dlg_resample.ShowModal() == wx.ID_OK: try: new_resolution = float(dlg_resample.GetValue()) if new_resolution <= 0: raise ValueError("Resolution must be positive.") lu_lc_array.rebin(new_resolution / lu_lc_array.dx, operation='min') logging.info(f"Raster resampled to {new_resolution} m.") save_dlg = wx.FileDialog( self, _("Save raster file as"), defaultDir=str(raster_path), wildcard="GeoTIFF (*.tif)|*.tif", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT ) if save_dlg.ShowModal() == wx.ID_CANCEL: save_dlg.Destroy() return raster_path = Path(save_dlg.GetPath()) save_dlg.Destroy() lu_lc_array.write_all(raster_path) logging.info(f"Raster file saved: {raster_path}") dlg = wx.MessageDialog(self, _('Do you want to load the created array ?'), _('Load file'), wx.YES_NO | wx.ICON_QUESTION) ret = dlg.ShowModal() dlg.Destroy() if ret == wx.ID_CANCEL: return if ret == wx.ID_YES: manning_array = WolfArray(fname=raster_path) self.add_object('array', newobj=manning_array, id=f'{raster_path.stem}') except ValueError as e: wx.MessageBox( _(f"Invalid resolution value: {e}"), _("Error"), wx.OK | wx.ICON_ERROR ) return finally: dlg_resample.Destroy() else: logging.info("No LU-LC to Manning's mapping available.") except Exception as e: logging.error(f"Error: {e}") self.Autoscale()
[docs] def _handle_walous_ocs(self, event: wx.MenuEvent) -> None: """Handle Walous OCS menu events.""" v = self._viewer item = v.menubar.FindItemById(event.GetId()) if item is None: return itemlabel = item.ItemLabel if _("Crop on active array") in itemlabel or _("Crop on screen") in itemlabel: if _("Crop on screen") in itemlabel: bounds = v.get_canvas_bounds(gridsize=1.0) def_outdrir = '' spatial_res = 1.0 if v.active_array is not None: spatial_res = v.active_array.dx dlg = wx.TextEntryDialog(None, _("Spatial resolution [m] ?"), value=str(spatial_res)) dlg.ShowModal() try: spatial_res = float(dlg.GetValue()) dlg.Destroy() except Exception: dlg.Destroy() logging.warning(_("Bad value -- Rety")) return else: if v.active_array is None: logging.warning(_('No active array -- Please activate data first')) return bounds = v.active_array.get_bounds() def_outdrir = Path(v.active_array.filename).parent spatial_res = v.active_array.dx from .pywalous import update_palette_walous_ocs if v._walous_OCS_filepath is None: if itemlabel in [_("Crop on active array (prepared data 10 m - 2023)"), _("Crop on screen (prepared data 10 m - 2023)")]: v._walous_OCS_filepath = toys_dataset('Walous_OCS', 'WALOUS_2023_lbt72_10m.tif') elif itemlabel in [_("Crop on active array (prepared data 10 m - 2020)"), _("Crop on screen (prepared data 10 m - 2020)")]: v._walous_OCS_filepath = toys_dataset('Walous_OCS', 'WALOUS_2020_lbt72_10m.tif') else: dlg = wx.FileDialog(v, _("Choose the Walous OCS Tif file"), wildcard="Tif file (*.tif)|*.tif|all (*.*)|*.*", style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return v._walous_OCS_filepath = Path(dlg.GetPath()) dlg.Destroy() if v._walous_OCS_filepath is None or not Path(v._walous_OCS_filepath).exists(): logging.error(_('No Walous OCS file -- Please set it')) return dlg = wx.FileDialog(v, _("Choose the output file"), wildcard="Geotif (*.tif)|*.tif|all (*.*)|*.*", style=wx.FD_SAVE, defaultDir=str(def_outdrir)) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return output = Path(dlg.GetPath()) dlg.Destroy() header_OCS = header_wolf.read_header(v._walous_OCS_filepath) if header_OCS.dx != spatial_res: bounds = [list(bounds[0]), list(bounds[1])] if (bounds[0][0] - header_OCS.origx) % header_OCS.dx != 0: bounds[0][0] = header_OCS.origx + ((bounds[0][0] - header_OCS.origx) // header_OCS.dx) * header_OCS.dx if (bounds[0][1] - bounds[0][0]) % header_OCS.dx != 0: bounds[0][1] = bounds[0][0] + ((bounds[0][1] - bounds[0][0]) // header_OCS.dx + 1) * header_OCS.dx if (bounds[1][0] - header_OCS.origy) % header_OCS.dy != 0: bounds[1][0] = header_OCS.origy + ((bounds[1][0] - header_OCS.origy) // header_OCS.dy) * header_OCS.dy if (bounds[1][1] - bounds[1][0]) % header_OCS.dy != 0: bounds[1][1] = bounds[1][0] + ((bounds[1][1] - bounds[1][0]) // header_OCS.dy + 1) * header_OCS.dy locwalous = WolfArray(fname=v._walous_OCS_filepath, crop=[bounds[0][0], bounds[0][1], bounds[1][0], bounds[1][1]]) if locwalous.dx != spatial_res: locwalous.rebin(spatial_res / locwalous.dx, operation='min') logging.info(_('Rebin to {} m because original data are {} m').format(spatial_res, locwalous.dx)) locwalous = WolfArray(mold=locwalous, crop=v.active_array.get_bounds()) locwalous.write_all(output) if Path(output).exists(): logging.info(_('File {} created').format(output)) else: logging.error(_('File {} not created').format(output)) return dlg = wx.MessageDialog(v, _('Do you want to load the created file ?'), _('Load file'), wx.YES_NO | wx.ICON_QUESTION) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return elif ret == wx.ID_YES: walousarray = WolfArray(fname=output) update_palette_walous_ocs(walousarray.mypal) walousarray.reset_plot() v.add_object('array', newobj=walousarray, id='walous_ocs_crop') dlg.Destroy() elif itemlabel == _("Legend"): from .pywalous import Walous_OCS_Legend newlegend = Walous_OCS_Legend(v) newlegend.Show() elif itemlabel == _("Map active array (WAL_OCS -> Hydrology)"): from .pywalous import DlgMapWalous2Hydrology if v.active_array is None: logging.warning(_('No active array -- Please activate data first')) return if v.active_array.wolftype != WOLF_ARRAY_FULL_SINGLE: logging.error(_('Active array is not a Float32 array -- Please change it to Float32 before mapping')) return vals = v.active_array.get_unique_values() if v._walous_layer is None: if vals[0] > 11: logging.error(_('You have values greater than 11 -- Please check your data')) return dlg = DlgMapWalous2Hydrology(v) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return mapvals = dlg.get_mapping() dlg.Destroy() if mapvals == -1: logging.error(_('Bad values -- retry')) return v.active_array.map_values(mapvals) v.active_array.reset_plot() elif itemlabel == _("Map active array (WAL_OCS -> Manning)"): from .pywalous import DlgMapWalousOCS2Manning if v.active_array is None: logging.warning(_('No active array -- Please activate data first')) return if v.active_array.wolftype != WOLF_ARRAY_FULL_SINGLE: logging.error(_('Active array is not a Float32 array -- Please change it to Float32 before mapping')) return vals = v.active_array.get_unique_values() if v._walous_layer is None: if vals[0] > 11: logging.error(_('You have values greater than 11 -- Please check your data')) return dlg = DlgMapWalousOCS2Manning(v) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return mapvals = dlg.get_mapping() dlg.Destroy() if mapvals == -1: logging.error(_('Bad values -- retry')) return v.active_array.map_values(mapvals) v.active_array.reset_plot()
[docs] def _handle_walous_uts(self, event: wx.MenuEvent) -> None: """Handle Walous UTS menu events.""" v = self._viewer item = v.menubar.FindItemById(event.GetId()) if item is None: return itemlabel = item.ItemLabel if itemlabel in [_("Crop on active array"), _("Crop on screen")]: if itemlabel == _("Crop on screen"): bounds = v.get_canvas_bounds(gridsize=1.) def_outdrir = '' spatial_res = 1. if v.active_array is not None: spatial_res = v.active_array.dx dlg = wx.TextEntryDialog(None,_("Spatial resolution [m] ?"), value = str(spatial_res)) dlg.ShowModal() try: spatial_res = float(dlg.GetValue()) dlg.Destroy() except: dlg.Destroy() logging.warning(_("Bad value -- Rety")) return else: if v.active_array is None: logging.warning(_('No active array -- Please activate data first')) return bounds = v.active_array.get_bounds() def_outdrir = Path(v.active_array.filename).parent spatial_res = v.active_array.dx from .pywalous import Walous_data, WALOUS_UTS2MANNING_MAJ_NIV1, WALOUS_UTS2MANNING_MAJ_NIV2, update_palette_walous_uts if v._walous_UTS_filepath is None: dlg = wx.FileDialog(v, _("Choose the Walous shape file"), wildcard="Geopackage (*.gpkg)|*.gpkg|Shapefile (*.shp)|*.shp|all (*.*)|*.*", style=wx.FD_OPEN) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return v._walous_UTS_filepath = Path(dlg.GetPath()) dlg.Destroy() dlg = wx.FileDialog(v, _("Choose the output file"), wildcard="Geotif (*.tif)|*.tif|all (*.*)|*.*", style=wx.FD_SAVE, defaultDir=str(def_outdrir)) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() return output = Path(dlg.GetPath()) dlg.Destroy() # choix de la couche entre MAJ_NIV1 et MAJ_NIV2 dlg = wx.SingleChoiceDialog(None, _("Choose a layer"), "Choices", ['MAJ_NIV1', 'MAJ_NIV2']) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return v._walous_layer = 'UTS_' + dlg.GetStringSelection() locwalous = Walous_data(v._walous_UTS_filepath.parent, v._walous_UTS_filepath.name) ret = locwalous.rasterize(bounds=bounds, layer=v._walous_layer, fn_out=output, pixel_size=spatial_res) if isinstance(ret, int): logging.error(_('Error {}').format(ret)) return if Path(output).exists(): logging.info(_('File {} created').format(output)) else: logging.error(_('File {} not created').format(output)) return dlg = wx.MessageDialog(v, _('Do you want to load the created file ?'), _('Load file'), wx.YES_NO | wx.ICON_QUESTION) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return elif ret == wx.ID_YES: walousarray = WolfArray(fname=output) update_palette_walous_uts(v._walous_layer, walousarray.mypal) v.add_object('array', newobj=walousarray, id='walous_uts_crop') dlg.Destroy() elif itemlabel == _("Legend"): from .pywalous import Walous_UTS_Legend newlegend = Walous_UTS_Legend(v) newlegend.Show() elif itemlabel == _("Map active array (WAL_UTS -> Manning)"): from .pywalous import DlgMapWalous2Manning if v.active_array is None: logging.warning(_('No active array -- Please activate data first')) return if v.active_array.wolftype != WOLF_ARRAY_FULL_SINGLE: logging.error(_('Active array is not a Float32 array -- Please change it to Float32 before mapping')) return vals = v.active_array.get_unique_values() if v._walous_layer is None: if vals[0] > 10: v._walous_layer = 'UTS_MAJ_NIV2' else: v._walous_layer = 'UTS_MAJ_NIV1' dlg = DlgMapWalous2Manning(v, which=v._walous_layer) ret = dlg.ShowModal() if ret == wx.ID_CANCEL: dlg.Destroy() return mapvals = dlg.get_mapping() dlg.Destroy() if mapvals == -1: logging.error(_('Bad values -- retry')) return v.active_array.map_values(mapvals) v.active_array.reset_plot()