"""Alaro forecasts companion for WolfMapViewer.
All Alaro-related menu and command logic lives here.
``WolfMapViewer`` holds a single instance as ``self._alaro`` and exposes
one-line delegators so external callers remain unaffected.
"""
from __future__ import annotations
import logging
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING
import wx
from .PyTranslate import _
from .irm_alaro import IRM_Alaro, GribFiles, _convert_col2date_str
if TYPE_CHECKING:
from .PyDraw import WolfMapViewer
__all__ = ['AlaroManager']
[docs]
class AlaroManager:
"""Companion object that owns Alaro menu state and actions."""
def __init__(self, viewer: 'WolfMapViewer') -> None:
[docs]
self.active: IRM_Alaro | None = None
[docs]
def _ensure_active(self) -> None:
if self.active is None:
self.active = IRM_Alaro()
[docs]
def _on_list_ftp(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
runs = self.active.run_dates_str
for run in runs:
logging.info(f'Available Alaro run: {run}')
dlg = wx.MessageDialog(v, _('Available Alaro runs:\n\n') + '\n'.join(runs), _('Alaro runs'), wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
[docs]
def _on_compare_video(self, event: wx.MenuEvent) -> None:
"""Rain intensity [mm/h] - Comparison video."""
from datetime import timezone as tz
v = self._viewer
self._ensure_active()
data_dir = self.active.data_directory
dates = self.active.list_run_dates_cached()
dates_str = [datetime.strptime(date, '%Y%m%d%H').replace(tzinfo=tz.utc) for date in dates]
dates_str = [date.strftime('%Y-%m-%d %H+00') for date in dates_str]
dlg = wx.MultiChoiceDialog(v, _('Choose one or multiple Alaro runs to treat'), _('Choose Alaro runs'), choices=dates_str)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
choices = dlg.GetSelections()
dlg.Destroy()
if len(choices) == 0:
logging.warning(_('No Alaro run selected'))
return
dates = [dates[choice] for choice in choices]
dlg = wx.FileDialog(v, _('Choose output video filename'), wildcard='mp4 (*.mp4)|*.mp4', defaultDir=str(data_dir), defaultFile='Alaro_RainIntensity_Comparison.mp4', style=wx.FD_SAVE)
ret = dlg.ShowModal()
if ret == wx.ID_OK:
output_dir = dlg.GetPath()
dlg.Destroy()
self.active.reset_gdf()
pgbar = wx.ProgressDialog(_('Loading Alaro runs'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Creating video...'))
outfile = self.active.video_gradient_cumulated_rain_compare(Path(output_dir), run_dates=dates)
pgbar.Update(100, _('Video created'))
pgbar.Destroy()
logging.info(f'Videos: {dates}')
dlg = wx.MessageDialog(v, _('Video created: {}\n\nDo you want to launch it ?').format(outfile), _('Video created'), wx.YES_NO | wx.ICON_QUESTION)
ret = dlg.ShowModal()
if ret == wx.ID_YES:
if sys.platform == 'win32':
os.startfile(outfile)
dlg.Destroy()
[docs]
def _on_one_run_video(self, event: wx.MenuEvent) -> None:
"""Total precip. [mm] - One run video."""
from datetime import timezone as tz
v = self._viewer
self._ensure_active()
data_dir = self.active.data_directory
dates = self.active.list_run_dates_cached()
dates_str = [datetime.strptime(date, '%Y%m%d%H').replace(tzinfo=tz.utc) for date in dates]
dates_str = [date.strftime('%Y-%m-%d %H+00') for date in dates_str]
dlg = wx.SingleChoiceDialog(v, _('Choose one Alaro run to treat'), _('Choose Alaro run'), choices=dates_str)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
choice = dlg.GetSelection()
dlg.Destroy()
if choice == wx.NOT_FOUND:
logging.warning(_('No Alaro run selected'))
return
dates = [dates[choice]]
dlg = wx.FileDialog(v, _('Choose output video filename'), wildcard='mp4 (*.mp4)|*.mp4', defaultDir=str(data_dir), defaultFile=f"Alaro_cumulated_rain_{dates[0]}.mp4", style=wx.FD_SAVE)
ret = dlg.ShowModal()
if ret == wx.ID_OK:
output_dir = dlg.GetPath()
dlg.Destroy()
self.active.reset_gdf()
pgbar = wx.ProgressDialog(_('Loading Alaro runs'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Creating video...'))
outfile = self.active.video_cumulated_rain(dates[0], Path(output_dir))
pgbar.Update(100, _('Video created'))
pgbar.Destroy()
dlg = wx.MessageDialog(v, _('Video created: {}\n\nDo you want to launch it ?').format(outfile), _('Video created'), wx.YES_NO | wx.ICON_QUESTION)
ret = dlg.ShowModal()
if ret == wx.ID_YES:
if sys.platform == 'win32':
os.startfile(outfile)
dlg.Destroy()
[docs]
def _on_multi_run_video(self, event: wx.MenuEvent) -> None:
"""Total precip. [mm] - Multiple runs video."""
from datetime import timezone as tz
v = self._viewer
self._ensure_active()
data_dir = self.active.data_directory
dates = self.active.list_run_dates_cached()
dates_str = [datetime.strptime(date, '%Y%m%d%H').replace(tzinfo=tz.utc) for date in dates]
dates_str = [date.strftime('%Y-%m-%d %H+00') for date in dates_str]
dlg = wx.MultiChoiceDialog(v, _('Choose multiple Alaro runs to treat'), _('Choose Alaro runs'), choices=dates_str)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
choices = dlg.GetSelections()
dlg.Destroy()
if len(choices) == 0:
logging.warning(_('No Alaro run selected'))
return
dates = [dates[choice] for choice in choices]
dlg = wx.DirDialog(v, _('Choose output video directory'), defaultPath=str(data_dir), style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
ret = dlg.ShowModal()
if ret == wx.ID_OK:
output_dir = dlg.GetPath()
dlg.Destroy()
self.active.reset_gdf()
pgbar = wx.ProgressDialog(_('Loading Alaro runs'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Creating video...'))
self.active.videos_cumulated_rain_allforecasts(output_dir, run_dates=dates)
pgbar.Update(100, _('Video created'))
pgbar.Destroy()
[docs]
def _on_download(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
pgbar = wx.ProgressDialog(_('Downloading Alaro runs'), _('Downloading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Downloading Alaro runs...'))
ret = self.active.download_all_available_files()
pgbar.Update(100, _('Alaro runs downloaded'))
pgbar.Destroy()
for run_id in ret:
logging.info(f'Downloaded Alaro run: {run_id}')
[docs]
def _on_download_rain_temp(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
pgbar = wx.ProgressDialog(_('Downloading Alaro runs'), _('Downloading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Downloading Alaro runs...'))
ret = self.active.download_TotalPrecipitations_available_files()
pgbar.Update(100, _('Alaro runs downloaded'))
pgbar.Destroy()
for run_id in ret:
logging.info(f'Downloaded Alaro run: {run_id}')
[docs]
def _on_load_run(self, event: wx.MenuEvent) -> None:
from datetime import timezone as tz
v = self._viewer
self._ensure_active()
dates = self.active.list_run_dates_cached()
dates_str = [datetime.strptime(date, '%Y%m%d%H').replace(tzinfo=tz.utc) for date in dates]
dates_str = [date.strftime('%Y-%m-%d %H+00') for date in dates_str]
dlg = wx.MultiChoiceDialog(v, _('Choose one or multiple Alaro runs to load'), _('Choose Alaro runs'), choices=dates_str)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
choices = dlg.GetSelections()
dlg.Destroy()
if len(choices) == 0:
logging.warning(_('No Alaro run selected'))
return
dates = [dates[choice] for choice in choices]
self.active.reset_gdf()
pgbar = wx.ProgressDialog(_('Loading Alaro runs'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Loading Alaro runs...'))
self.active.load_grib_data_to_gdf(GribFiles.FILE_TotPrecip, dates)
pgbar.Update(100, _('Alaro runs loaded'))
pgbar.Destroy()
logging.info(f'Loaded Alaro run: {dates}')
[docs]
def _on_add_forecasts(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
if self.active._gdf is None:
logging.warning(_('No Alaro run loaded -- Please load a run first'))
return
columns = self.active.get_forecast_columns()
columns_str = [_convert_col2date_str(col) for col in columns]
dlg = wx.MultiChoiceDialog(v, _('Choose one or multiple Alaro forecast to show'), _('Choose Alaro forecasts'), choices=columns_str)
ret = dlg.ShowModal()
if ret == wx.ID_CANCEL:
dlg.Destroy()
return
choices = dlg.GetSelections()
dlg.Destroy()
if len(choices) == 0:
logging.warning(_('No Alaro forecast selected'))
return
columns = [columns[choice] for choice in choices]
pgbar = wx.ProgressDialog(_('Loading Alaro forecasts'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Loading Alaro forecasts...'))
arrays = self.active.forecasts_to_arrays(columns)
pgbar.Update(100, _('Alaro forecasts loaded'))
pgbar.Destroy()
if len(arrays) == 0:
logging.warning(_('No Alaro forecast to show'))
return
for array in arrays:
array.array *= 1000.0
v.add_object('array', newobj=array, id=array.idx)
v.Refresh()
logging.info(_('Alaro forecasts added to the viewer'))
[docs]
def _on_show_grid(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
if self.active._zones is None:
self.active._prepare_Zones_from_grib(GribFiles.FILE_TotPrecip, self.active.run_dates[0])
self.active._zones.prep_listogl()
v.add_object('vector', newobj=self.active._zones, id='Alaro_grid')
v.Refresh()
[docs]
def _on_add_all_forecasts(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
if self.active._gdf is None:
logging.warning(_('No Alaro run loaded -- Please load a run first'))
return
pgbar = wx.ProgressDialog(_('Loading Alaro forecasts'), _('Loading data...'), maximum=100, parent=v, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
pgbar.Pulse(_('Loading Alaro forecasts...'))
arrays = self.active.forecasts_to_arrays()
pgbar.Update(100, _('Alaro forecasts loaded'))
pgbar.Destroy()
if len(arrays) == 0:
logging.warning(_('No Alaro forecast to show'))
return
for array in arrays:
array.array *= 1000.0
v.add_object('array', newobj=array, id=array.idx, ToCheck=False)
v.Refresh()
logging.info(_('Alaro forecasts added to the viewer'))
[docs]
def _on_plot_xy(self, event: wx.MenuEvent) -> None:
v = self._viewer
self._ensure_active()
if self.active._gdf is None:
logging.warning(_('No Alaro run loaded -- Please load a run first'))
return
v.start_action('plot alaro xy', _('Plot Alaro forecasts for a specific point -- Right click to select points'))