From 5476c512af66c9c9c53d158ace599f389638f47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Sun, 28 Sep 2025 14:12:00 +0200 Subject: [PATCH] Styles + CODE CLEAN po_modules --- Probleme.txt | 2 - map_tips.py | 4 +- pb_tool.cfg | 2 +- pegelonline_dockwidget_base.ui | 715 +++++++++++++----- {pomodules => po_modules}/__init__.py | 0 .../po_graph_reader.py | 8 +- po_modules/po_station.py | 34 + po_modules/po_stations.py | 28 + po_modules/po_stations_qgs.py | 40 + po_modules/po_waterlevel.py | 39 + po_modules/po_waterlevel_reader.py | 25 + po_modules/po_waterlevels_reader_qgs.py | 41 + {pomodules => po_modules}/urlreader.py | 0 po_runner.py | 164 +++- pomodules/po_stations.py | 40 - pomodules/po_stations_qgs.py | 62 -- pomodules/po_waterlevels.py | 43 -- pomodules/po_waterlevels_qgs.py | 65 -- styles/label_stations.qml | 243 ------ styles/label_waterlevels.qml | 243 ------ styles/stations.qml | 545 +++++++++++++ styles/waterlevels.qml | 575 ++++++++++++++ 22 files changed, 1963 insertions(+), 955 deletions(-) rename {pomodules => po_modules}/__init__.py (100%) rename pomodules/po_history.py => po_modules/po_graph_reader.py (65%) create mode 100644 po_modules/po_station.py create mode 100644 po_modules/po_stations.py create mode 100644 po_modules/po_stations_qgs.py create mode 100644 po_modules/po_waterlevel.py create mode 100644 po_modules/po_waterlevel_reader.py create mode 100644 po_modules/po_waterlevels_reader_qgs.py rename {pomodules => po_modules}/urlreader.py (100%) delete mode 100644 pomodules/po_stations.py delete mode 100644 pomodules/po_stations_qgs.py delete mode 100644 pomodules/po_waterlevels.py delete mode 100644 pomodules/po_waterlevels_qgs.py delete mode 100644 styles/label_stations.qml delete mode 100644 styles/label_waterlevels.qml create mode 100644 styles/stations.qml create mode 100644 styles/waterlevels.qml diff --git a/Probleme.txt b/Probleme.txt index d19eaee..f851a12 100644 --- a/Probleme.txt +++ b/Probleme.txt @@ -2,5 +2,3 @@ Beim Hinzufügen von Features fehlte das layer.updateFields() Beim Hinzufügen von Features fehlte wurde versucht eine viel zu große Pegelonline 'number' in einen Int zu stecken. War schwierig zu entdecken => provider.errors() DockWidget wurde in der Höhe ziemlich voll → Weiteres Widget nur für Grafen - -eigene styles erzeugen! diff --git a/map_tips.py b/map_tips.py index 3a13f8f..e9ca9f5 100644 --- a/map_tips.py +++ b/map_tips.py @@ -46,10 +46,10 @@ WATERLEVELS_MAP_TIPS = "\ \ \ MNW, MHW:\ - [% \"stateMnwMhw\" %]\ + [% \"mean\" %]\ \ \ NSW, HSW:\ - [% \"stateNswHsw\" %]\ + [% \"absolute\" %]\ \ " diff --git a/pb_tool.cfg b/pb_tool.cfg index 7cba20f..bd8bb75 100644 --- a/pb_tool.cfg +++ b/pb_tool.cfg @@ -64,7 +64,7 @@ extras: metadata.txt icon.png pegelonline_dockwidget_graph.ui # Other directories to be deployed with the plugin. # These must be subdirectories under the plugin directory -extra_dirs: pomodules basemap +extra_dirs: po_modules basemap styles # ISO code(s) for any locales (translations), separated by spaces. # Corresponding .ts files must exist in the i18n directory diff --git a/pegelonline_dockwidget_base.ui b/pegelonline_dockwidget_base.ui index b10b29b..6e7b083 100644 --- a/pegelonline_dockwidget_base.ui +++ b/pegelonline_dockwidget_base.ui @@ -6,8 +6,8 @@ 0 0 - 280 - 563 + 292 + 681 @@ -21,131 +21,24 @@ - - - - Pegelstände: - - - - 0 - - - 5 - - - 5 - - - 5 - - - 5 - - - - - Anzeigen (Download von Pegelonline) - - - - - - - Beschriftungen: - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - Nummer - - - - - - - Name - - - - - - - Behörde - - - - - - - Gewässername - - - - - - - - - 0 - - - - - Zeitstempel - - - - - - - Aktueller Wert - - - - - - - MNW, MHW - - - - - - - NSW, HSW - - - - - - - - - - - + + 5 + + + 5 + + + 5 + + + 5 + + + 0 + + + 2 + @@ -153,7 +46,7 @@ - 0 + 2 5 @@ -227,6 +120,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -248,6 +154,91 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Styles: + + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + + Vorgabe + + + true + + + bgStationsStyle + + + + + + + + + + + Behörde + + + false + + + bgStationsStyle + + + + + + + + + + + Gewässer + + + false + + + bgStationsStyle + + + @@ -256,14 +247,17 @@ - - - - Basiskarte: + + + + QFrame::StyledPanel - + + QFrame::Raised + + - 0 + 6 5 @@ -278,19 +272,81 @@ 5 - + - Flüsse + ... - + - Flächen + ... + + + + ... + + + + + + + Qt::Vertical + + + + + + + ... + + + + + + + ... + + + + + + + ... + + + + + + + Qt::Vertical + + + + + + + ... + + + + + + + Qt::Horizontal + + + + 161 + 20 + + + + @@ -301,7 +357,7 @@ - 0 + 2 5 @@ -440,20 +496,30 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + - - - - QFrame::StyledPanel + + + + Pegelstände: - - QFrame::Raised - - + - 6 + 2 5 @@ -468,81 +534,308 @@ 5 - + - ... + Anzeigen (Download von Pegelonline) - + + + Beschriftungen: + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + Nummer + + + + + + + Name + + + + + + + Behörde + + + + + + + Gewässername + + + + + + + + + 0 + + + + + Zeitstempel + + + + + + + Aktueller Wert + + + + + + + MNW, MHW + + + + + + + NSW, HSW + + + + + + + + + + + + Styles: + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Vorgabe + + + true + + + bgWaterlevelsStyle + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Behörde + + + bgWaterlevelsStyle + + + + + + + Gewässer + + + false + + + bgWaterlevelsStyle + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + + + MNW, MHW + + + bgWaterlevelsStyle + + + + + + + NSW, HSW + + + bgWaterlevelsStyle + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + Basiskarte: + + + + 2 + + + 5 + + + 5 + + + 5 + + + 5 + + + - ... + Flüsse - + - ... + Flächen - - - - Qt::Vertical - - - - - - - ... - - - - - - - ... - - - - - - - ... - - - - - - - Qt::Vertical - - - - - - - ... - - - - - - - Qt::Horizontal - - - - 161 - 20 - - - - @@ -551,4 +844,8 @@ + + + + diff --git a/pomodules/__init__.py b/po_modules/__init__.py similarity index 100% rename from pomodules/__init__.py rename to po_modules/__init__.py diff --git a/pomodules/po_history.py b/po_modules/po_graph_reader.py similarity index 65% rename from pomodules/po_history.py rename to po_modules/po_graph_reader.py index 7b6c643..056c205 100644 --- a/pomodules/po_history.py +++ b/po_modules/po_graph_reader.py @@ -4,18 +4,18 @@ from . import poBaseURL from .urlreader import UrlReader -class PoHistory(UrlReader): +class PoGraphReader(UrlReader): def __init__(self, station: str, days: int): super().__init__(poBaseURL + 'stations/%s/W/measurements.png?start=P%dD' % (quote(station), days)) def download(self): - print("download: Lade Bild herunter...") + print("PoGraphReader::download: Lade Bild herunter...") image_data = self.getDataResponse() if image_data is None or len(image_data) == 0: - print("download: Fehler: Keine Daten erhalten") + print("PoGraphReader::download: Fehler: Keine Daten erhalten") return None - print("download: Vollständig") + print("PoGraphReader::download: Vollständig") return image_data diff --git a/po_modules/po_station.py b/po_modules/po_station.py new file mode 100644 index 0000000..561beb8 --- /dev/null +++ b/po_modules/po_station.py @@ -0,0 +1,34 @@ +from qgis._core import QgsFeature, QgsGeometry, QgsPointXY + + +class PoStation(object): + + def __init__(self, json): + self.longitude = json['longitude'] if 'longitude' in json else None + self.latitude = json['latitude'] if 'latitude' in json else None + self.uuid = json['uuid'] + self.number = json['number'] + self.shortname = json['shortname'] + self.longname = json['longname'] + self.km = json['km'] if 'km' in json else None + self.agency = json['agency'] + self.water = json['water']['longname'] + + def new_feature(self, fields) -> None | QgsFeature: + if self.longitude is None or self.latitude is None: + print("PoStation::new_feature: WARN: Station hat fehlende Koordinaten: %s" % (self.shortname,)) + return None + + feature = QgsFeature(fields) + + feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(self.longitude, self.latitude))) + + feature.setAttribute('uuid', self.uuid) + feature.setAttribute('number', self.number) + feature.setAttribute('shortname', self.shortname) + feature.setAttribute('longname', self.longname) + feature.setAttribute('km', self.km) + feature.setAttribute('agency', self.agency) + feature.setAttribute('water', self.water) + + return feature diff --git a/po_modules/po_stations.py b/po_modules/po_stations.py new file mode 100644 index 0000000..397c52e --- /dev/null +++ b/po_modules/po_stations.py @@ -0,0 +1,28 @@ +from . import poBaseURL +from .po_station import PoStation +from .urlreader import UrlReader + + +class PoStationReader(UrlReader): + + def __init__(self): + super().__init__(poBaseURL + 'stations.json') + + def get_stations(self): + print("PoStationReader::get_stations: Lade Stationen herunter...") + + stations_json = self.getJsonResponse() + if stations_json is None or len(stations_json) == 0: + print("PoStationReader::get_stations: Keine Stationen erhalten") + return None + + stations = [] + for station_json in stations_json: + try: + stations.append(PoStation(station_json)) + except Exception as e: + print("PoStationReader::get_stations: Fehler: error=%s, json=%s" % (e, station_json)) + + print("PoStationReader::get_stations: %d Stationen erhalten" % (len(stations),)) + + return stations diff --git a/po_modules/po_stations_qgs.py b/po_modules/po_stations_qgs.py new file mode 100644 index 0000000..135cd75 --- /dev/null +++ b/po_modules/po_stations_qgs.py @@ -0,0 +1,40 @@ +from PyQt5.QtCore import QVariant +from qgis._core import QgsCoordinateReferenceSystem +from qgis.core import QgsFields, QgsField + +from .po_stations import PoStationReader + + +class PoStationReaderQgs(PoStationReader): + + def __init__(self): + super().__init__() + self.fields = None + self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) + + def get_features(self): + print("PoStationReaderQgs::get_features: Erzeuge Features...") + + self.fields = QgsFields() + self.fields.append(QgsField('uuid', QVariant.String)) + self.fields.append(QgsField('number', QVariant.LongLong)) + self.fields.append(QgsField('shortname', QVariant.String)) + self.fields.append(QgsField('longname', QVariant.String)) + self.fields.append(QgsField('km', QVariant.Double)) + self.fields.append(QgsField('agency', QVariant.String)) + self.fields.append(QgsField('water', QVariant.String)) + + features = [] + stations = self.get_stations() + + if stations is None or len(stations) == 0: + print("PoStationReaderQgs::get_features: Fehler: Keine Stationen erhalten") + return None + + for station in stations: + feature = station.new_feature(self.fields) + if feature is not None: + features.append(feature) + + print("PoStationReaderQgs::get_features: %d Features erzeugt" % (len(features),)) + return features diff --git a/po_modules/po_waterlevel.py b/po_modules/po_waterlevel.py new file mode 100644 index 0000000..e04d29c --- /dev/null +++ b/po_modules/po_waterlevel.py @@ -0,0 +1,39 @@ +from qgis._core import QgsFeature, QgsGeometry, QgsPointXY + + +class PoWaterlevel(object): + + def __init__(self, json): + self.longitude = json['longitude'] if 'longitude' in json else None + self.latitude = json['latitude'] if 'latitude' in json else None + self.uuid = json['uuid'] + self.shortname = json['shortname'] + self.number = json['number'] + self.agency = json['agency'] + self.unit = json['timeseries'][0]['unit'] + self.timestamp = json['timeseries'][0]['currentMeasurement']['timestamp'] + self.value = json['timeseries'][0]['currentMeasurement']['value'] + self.mean = json['timeseries'][0]['currentMeasurement']['stateMnwMhw'] + self.absolute = json['timeseries'][0]['currentMeasurement']['stateNswHsw'] + self.water = json['water']['longname'] + + def new_feature(self, fields): + if self.longitude is None or self.latitude is None: + print("PoWaterlevel::new_feature: WARN: Station hat fehlende Koordinaten: %s" % (self.shortname,)) + return None + + feature = QgsFeature(fields) + + feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(self.longitude, self.latitude))) + + feature.setAttribute('shortname', self.shortname) + feature.setAttribute('number', self.number) + feature.setAttribute('agency', self.agency) + feature.setAttribute('timestamp', self.timestamp) + feature.setAttribute('value', self.value) + feature.setAttribute('unit', self.unit) + feature.setAttribute('mean', self.mean) + feature.setAttribute('absolute', self.absolute) + feature.setAttribute('water', self.water) + + return feature diff --git a/po_modules/po_waterlevel_reader.py b/po_modules/po_waterlevel_reader.py new file mode 100644 index 0000000..7fff012 --- /dev/null +++ b/po_modules/po_waterlevel_reader.py @@ -0,0 +1,25 @@ +from . import poBaseURL +from .po_waterlevel import PoWaterlevel +from .urlreader import UrlReader + + +class PoWaterlevelReader(UrlReader): + + def __init__(self): + super().__init__(poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true') + + def get_waterlevels(self): + print("PoWaterlevelReader::get_waterlevels: Lade Pegelstände herunter...") + + stations_json = self.getJsonResponse() + if stations_json is None or len(stations_json) == 0: + print("PoWaterlevelReader::get_waterlevels: FEHLER: Keine Pegelstände erhalten") + return None + + stations = [] + for station_json in stations_json: + stations.append(PoWaterlevel(station_json)) + + print("PoWaterlevelReader::get_waterlevels: %d Pegelstände erhalten" % (len(stations),)) + + return stations diff --git a/po_modules/po_waterlevels_reader_qgs.py b/po_modules/po_waterlevels_reader_qgs.py new file mode 100644 index 0000000..905f8eb --- /dev/null +++ b/po_modules/po_waterlevels_reader_qgs.py @@ -0,0 +1,41 @@ +from PyQt5.QtCore import QVariant +from qgis._core import QgsCoordinateReferenceSystem +from qgis.core import QgsFields, QgsField + +from .po_waterlevel_reader import PoWaterlevelReader + + +class PoWaterlevelReaderQgs(PoWaterlevelReader): + + def __init__(self): + super().__init__() + self.fields = None + self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) + + def get_features(self): + print("PoWaterlevelReaderQgs::get_features: Erzeuge Features...") + + self.fields = QgsFields() + self.fields.append(QgsField('shortname', QVariant.String)) + self.fields.append(QgsField('number', QVariant.LongLong)) + self.fields.append(QgsField('agency', QVariant.String)) + self.fields.append(QgsField('timestamp', QVariant.DateTime)) + self.fields.append(QgsField('value', QVariant.Double)) + self.fields.append(QgsField('unit', QVariant.String)) + self.fields.append(QgsField('mean', QVariant.String)) + self.fields.append(QgsField('absolute', QVariant.String)) + self.fields.append(QgsField('water', QVariant.String)) + + features = [] + waterlevels = self.get_waterlevels() + if waterlevels is None or len(waterlevels) == 0: + print("PoWaterlevelReaderQgs::get_features: Fehler: Keine Pegelstände erhalten") + return None + + for waterlevel in waterlevels: + feature = waterlevel.new_feature(self.fields) + if feature is not None: + features.append(feature) + + print("PoWaterlevelReaderQgs::get_features: %d Features erzeugt" % (len(features),)) + return features diff --git a/pomodules/urlreader.py b/po_modules/urlreader.py similarity index 100% rename from pomodules/urlreader.py rename to po_modules/urlreader.py diff --git a/po_runner.py b/po_runner.py index 3a3d65d..e52e96b 100644 --- a/po_runner.py +++ b/po_runner.py @@ -3,18 +3,17 @@ from typing import Callable from PyQt5 import QtGui from PyQt5.QtWidgets import QAction -from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer, QgsPalLayerSettings, QgsVectorLayerSimpleLabeling +from qgis._core import QgsVectorLayer, QgsProject, QgsLayerTreeLayer, QgsPalLayerSettings, QgsVectorLayerSimpleLabeling, QgsStyle, QgsSymbol, QgsRendererCategory, QgsCategorizedSymbolRenderer from .map_tips import WATERLEVELS_MAP_TIPS, STATIONS_MAP_TIPS, BASEMAP_MAP_TIPS from .pegelonline_dockwidget import PegelonlineDockWidget from .pegelonline_dockwidget_graph import PegelonlineDockWidgetGraph -from .pomodules.po_history import PoHistory -from .pomodules.po_stations import PoStations -from .pomodules.po_stations_qgs import PoStationsQgs -from .pomodules.po_waterlevels_qgs import PoWaterlevelsQgs +from .po_modules.po_graph_reader import PoGraphReader +from .po_modules.po_stations import PoStationReader +from .po_modules.po_stations_qgs import PoStationReaderQgs +from .po_modules.po_waterlevels_reader_qgs import PoWaterlevelReaderQgs -# noinspection PyMethodMayBeStatic class PoRunner(object): def __init__(self, ui: PegelonlineDockWidget, graph: PegelonlineDockWidgetGraph, iface): @@ -43,8 +42,8 @@ class PoRunner(object): self.ui.btnMapTips.setDefaultAction(iface.actionMapTips()) # Signale verbinden - self._connect_basemap_signals() - self._connect_stations_signals() + self._basemap_connect_signals() + self._stations_connect_signals() self._waterlevels_connect_signals() self._history_connect_signals() @@ -60,7 +59,6 @@ class PoRunner(object): return None # disconnect setzen - # noinspection PyUnresolvedReferences basemap.willBeDeleted.connect(disconnect) # map-tips setzen @@ -77,7 +75,7 @@ class PoRunner(object): # basemap signals --------------------------------------------------------- - def _connect_basemap_signals(self): + def _basemap_connect_signals(self): print("_connect_basemap_signals") self.ui.cbBasemapLines.toggled.connect(self._cbBasemapLines_toggled) self.ui.cbBasemapAreas.toggled.connect(self._cbBasemapAreas_toggled) @@ -116,29 +114,57 @@ class PoRunner(object): # stations ---------------------------------------------------------------- - def _connect_stations_signals(self): + def _stations_connect_signals(self): print("_connect_stations_signals") - # noinspection DuplicatedCode self.ui.cbStationsVisible.toggled.connect(self._cbStationsVisible_toggled) self.ui.cbStationsName.toggled.connect(self._cbStationsName_toggled) self.ui.cbStationsNumber.toggled.connect(self._cbStationsNumber_toggled) self.ui.cbStationsAgency.toggled.connect(self._cbStationsAgency_toggled) self.ui.cbStationsKm.toggled.connect(self._cbStationsKm_toggled) self.ui.cbStationsWater.toggled.connect(self._cbStationsWater_toggled) + self.ui.bgStationsStyle.buttonClicked.connect(self._bgStationsStyle_clicked) + + def _stations_apply_style(self): + button = self.ui.bgStationsStyle.checkedButton() + self._bgStationsStyle_clicked(button) + + def _bgStationsStyle_clicked(self, button): + print("_bgStationsStyle_clicked: %s" % (button.objectName(),)) + + if self.stations is None: + return + + file = "styles/stations.qml" + + if self.ui.rbStationsStyleSimple == button: + self._layer_apply_style_from_file(self.stations, file) + return + elif self.ui.rbStationsStyleAgency == button: + field = "agency" + elif self.ui.rbStationsStyleWater == button: + field = "water" + else: + print("_bgStationsStyle_clicked: Style nicht implementiert: %s" % (button.objectName(),)) + self._layer_apply_style_from_file(self.stations, file) + return + + self._stations_update_labels() + self._layer_apply_style_per_category(self.stations, field, file) def _cbStationsVisible_toggled(self): visible = self.ui.cbStationsVisible.isChecked() print("_cbStationsVisible_toggled: %s" % (visible,)) if self.stations is None and visible: - reader = PoStationsQgs() - features = reader.getStationsFeatures() + reader = PoStationReaderQgs() + features = reader.get_features() self.stations = self._layer_create_from_reader(reader.fields, reader.crs, features, "Stationen", STATIONS_MAP_TIPS) - self._layer_add_to_instance(self.stations, "styles/label_stations.qml", self._stations_disconnect) + self._layer_add_to_instance(self.stations, self._stations_disconnect) if self.stations is not None: self._layer_set_visible(self.stations, visible) - self._stations_update_labels() + if visible: + self._stations_apply_style() def _cbStationsName_toggled(self): checked = self.ui.cbStationsName.isChecked() @@ -170,7 +196,6 @@ class PoRunner(object): self.stations = None self.ui.cbStationsVisible.setChecked(False) - # noinspection DuplicatedCode def _stations_update_labels(self): print("_stations_update_labels") if self.stations is None: @@ -194,7 +219,6 @@ class PoRunner(object): def _waterlevels_connect_signals(self): print("_waterlevels_connect_signals") - # noinspection DuplicatedCode self.ui.cbWaterlevelsVisible.toggled.connect(self._cbWaterlevelsVisible_toggled) self.ui.cbWaterlevelsName.toggled.connect(self._cbWaterlevelsName_toggled) self.ui.cbWaterlevelsNumber.toggled.connect(self._cbWaterlevelsNumber_toggled) @@ -204,20 +228,52 @@ class PoRunner(object): self.ui.cbWaterlevelsMean.toggled.connect(self._cbWaterlevelsMean_toggled) self.ui.cbWaterlevelsAbsolute.toggled.connect(self._cbWaterlevelsAbsolute_toggled) self.ui.cbWaterlevelsWater.toggled.connect(self._cbWaterlevelsWater_toggled) + self.ui.bgWaterlevelsStyle.buttonClicked.connect(self._bgWaterlevelsStyle_clicked) + + def _waterlevels_apply_style(self): + button = self.ui.bgWaterlevelsStyle.checkedButton() + self._bgWaterlevelsStyle_clicked(button) + + def _bgWaterlevelsStyle_clicked(self, button): + print("_bgWaterlevelsStyle_clicked: %s" % (button.objectName(),)) + + if self.waterlevels is None: + return + + file = "styles/waterlevels.qml" + if self.ui.rbWaterlevelsStyleSimple == button: + self._layer_apply_style_from_file(self.waterlevels, file) + return + elif self.ui.rbWaterlevelsStyleAgency == button: + field = "agency" + elif self.ui.rbWaterlevelsStyleWater == button: + field = "water" + elif self.ui.rbWaterlevelsStyleMean == button: + field = "mean" + elif self.ui.rbWaterlevelsStyleAbsolute == button: + field = "absolute" + else: + print("_bgWaterlevelsStyle_clicked: Style nicht implementiert: %s" % (button.objectName(),)) + self._layer_apply_style_from_file(self.waterlevels, file) + return + + self._waterlevels_update_labels() + self._layer_apply_style_per_category(self.waterlevels, field, file) def _cbWaterlevelsVisible_toggled(self): visible = self.ui.cbWaterlevelsVisible.isChecked() print("_cbWaterlevelsVisible_toggled: %s" % (visible,)) if self.waterlevels is None and visible: - reader = PoWaterlevelsQgs() - features = reader.getWaterlevelsFeatures() + reader = PoWaterlevelReaderQgs() + features = reader.get_features() self.waterlevels = self._layer_create_from_reader(reader.fields, reader.crs, features, "Pegelstände", WATERLEVELS_MAP_TIPS) - self._layer_add_to_instance(self.waterlevels, "styles/label_waterlevels.qml", self.waterlevels_disconnect) + self._layer_add_to_instance(self.waterlevels, self.waterlevels_disconnect) if self.waterlevels is not None: self._layer_set_visible(self.waterlevels, visible) - self._waterlevels_update_labels() + if visible: + self._waterlevels_apply_style() def _cbWaterlevelsName_toggled(self): checked = self.ui.cbWaterlevelsName.isChecked() @@ -264,7 +320,6 @@ class PoRunner(object): self.waterlevels = None self.ui.cbWaterlevelsVisible.setChecked(False) - # noinspection DuplicatedCode def _waterlevels_update_labels(self): print("_waterlevels_update_labels") if self.waterlevels is None: @@ -284,9 +339,9 @@ class PoRunner(object): if self.ui.cbWaterlevelsValue.isChecked(): fields.append('"value", \' \', "unit"') # 3 Teile anhängen: value, leerzeichen, unit if self.ui.cbWaterlevelsMean.isChecked(): - fields.append('\'MnwMhw=\', "stateMnwMhw"') + fields.append('\'MnwMhw=\', "mean"') if self.ui.cbWaterlevelsAbsolute.isChecked(): - fields.append('\'NswHsw=\', "stateNswHsw"') + fields.append('\'NswHsw=\', "absolute"') self._layer_update_labels(self.waterlevels, fields) # layers ------------------------------------------------------------------ @@ -326,15 +381,12 @@ class PoRunner(object): return None - def _layer_add_to_instance(self, layer: QgsVectorLayer, styles_path: str, disconnect: Callable[[], None]): + def _layer_add_to_instance(self, layer: QgsVectorLayer, disconnect: Callable[[], None]): print("_layer_add_to_instance") if layer is None: print("_layer_add_to_instance: Fehler: Übergebener Layer ist None") return - # Styles laden - layer.loadNamedStyle(os.path.join(self.local_dir, styles_path)) - # disconnect Signal verbinden layer.willBeDeleted.connect(disconnect) layer.selectionChanged.connect(self._layer_selection_changed) @@ -358,7 +410,7 @@ class PoRunner(object): self._history_load_stations() selected_shortname = selected[0].attribute("shortname") - print("_layer_selection_changed: Lade Pegelstandsverlauf zur Auswahl: %s" % (selected_shortname)) + print("_layer_selection_changed: Lade Pegelstandsverlauf zur Auswahl: %s" % (selected_shortname,)) self._historyStation_set_by_shortname(selected_shortname) else: print("_layer_selection_changed: Anzahl ausgewählter Elemente ist NICHT 1, lade Pegelstandsverlauf NICHT!") @@ -386,6 +438,42 @@ class PoRunner(object): else: self.iface.mapCanvas().refresh() + # layers styles ----------------------------------------------------------- + + def _layer_apply_style_per_category(self, layer, attribute_name, file): + print("_layer_apply_style_per_category: Erzeuge kategorisierte Farben...") + ramp = QgsStyle().defaultStyle().colorRamp("Turbo") + if ramp is None: + self._layer_apply_style_from_file(layer, file) + print("_layer_apply_style_per_category: Farbrampe nicht gefunden.") + return + + idx = layer.fields().indexOf(attribute_name) + values = sorted(v for v in layer.uniqueValues(idx) if v is not None) + + cats = [] + for v in values: + sym = QgsSymbol.defaultSymbol(layer.geometryType()) + if len(values) > 1: + t = values.index(v) / (len(values) - 1) + else: + t = 0.0 + sym.setColor(ramp.color(t)) + cats.append(QgsRendererCategory(v, sym, str(v))) + + renderer = QgsCategorizedSymbolRenderer(attribute_name, cats) + layer.setRenderer(renderer) + self._layer_refresh(layer) + + def _layer_apply_style_from_file(self, layer, file): + path = os.path.join(self.local_dir, file) + print("_layer_apply_style_from_file: Lade Style Datei: %s" % (path,)) + + res = layer.loadNamedStyle(path) + print("_layer_apply_style_from_file: result: %s" % (res,)) + + self._layer_refresh(layer) + # history signals --------------------------------------------------------- def _history_connect_signals(self): @@ -433,7 +521,7 @@ class PoRunner(object): self.graph.lbHistory.setText("Bitte Tage [1, 30] wählen...") return - history = PoHistory(station, days) + history = PoGraphReader(station, days) image_data = history.download() if image_data is None or len(image_data) == 0: @@ -455,26 +543,20 @@ class PoRunner(object): # behalte die aktuelle Station, um sie (mit eventuell neuem Index) wiederherzustellen current_station = self.ui.slHistoryStation.currentText() - print("_history_load_stations: bisherige_station=%s" % current_station) + print("_history_load_stations: bisherige_station=%s" % (current_station,)) self.ui.slHistoryStation.clear() - stations = PoStations().getStations() + stations = PoStationReader().get_stations() if stations is None or len(stations) == 0: print("_history_load_stations: Fehler: Keine Stationen erhalten") return - index = 0 - neuer_index = None for station in stations: - shortname = station['attributes']['shortname'] - if shortname == current_station: - neuer_index = index - self.ui.slHistoryStation.addItem(shortname) - index += 1 + self.ui.slHistoryStation.addItem(station.shortname) if self._historyStation_set_by_shortname(current_station): - print("_history_load_stations: Bisherige Station \"%s\" mit neuem index=%d wiederhergestellt" % (current_station, neuer_index)) + print("_history_load_stations: Bisherige Station \"%s\" wiederhergestellt" % (current_station,)) else: self.ui.slHistoryStation.setCurrentIndex(0) station = self.ui.slHistoryStation.currentText() diff --git a/pomodules/po_stations.py b/pomodules/po_stations.py deleted file mode 100644 index 6334e83..0000000 --- a/pomodules/po_stations.py +++ /dev/null @@ -1,40 +0,0 @@ -from . import poBaseURL -from .urlreader import UrlReader - - -class PoStations(UrlReader): - - def __init__(self): - super().__init__(poBaseURL + 'stations.json') - - def getStations(self): - print("getStations: Lade Stationen herunter...") - - stations_json = self.getJsonResponse() - if stations_json is None or len(stations_json) == 0: - print("getStations: Keine Stationen erhalten") - return None - - stations = [] - for station_json in stations_json: - stations.append( - { - 'geometry': { - 'longitude': station_json['longitude'] if 'longitude' in station_json else None, - 'latitude': station_json['latitude'] if 'latitude' in station_json else None, - }, - 'attributes': { - 'uuid': station_json['uuid'], - 'number': station_json['number'], - 'shortname': station_json['shortname'], - 'longname': station_json['longname'], - 'km': station_json['km'] if 'km' in station_json else None, - 'agency': station_json['agency'], - 'water': station_json['water']['longname'], - }, - } - ) - - print("getStations: %d Stationen erhalten" % (len(stations),)) - - return stations diff --git a/pomodules/po_stations_qgs.py b/pomodules/po_stations_qgs.py deleted file mode 100644 index 76619ac..0000000 --- a/pomodules/po_stations_qgs.py +++ /dev/null @@ -1,62 +0,0 @@ -from PyQt5.QtCore import QVariant -from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY -from qgis.core import QgsFields, QgsFeature, QgsField - -from .po_stations import PoStations - - -class PoStationsQgs(PoStations): - - def __init__(self): - super().__init__() - self.fields = None - self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) - - def getStationsFeatures(self): - print("getStationsFeatures: Erzeuge Features...") - - self.fields = QgsFields() - self.fields.append(QgsField('uuid', QVariant.String)) - self.fields.append(QgsField('number', QVariant.LongLong)) - self.fields.append(QgsField('shortname', QVariant.String)) - self.fields.append(QgsField('longname', QVariant.String)) - self.fields.append(QgsField('km', QVariant.Double)) - self.fields.append(QgsField('agency', QVariant.String)) - self.fields.append(QgsField('water', QVariant.String)) - - features = [] - stations = self.getStations() - - if stations is None or len(stations) == 0: - print("getStationsFeatures: Fehler: Keine Stationen erhalten") - return None - - for station in stations: - feature = self._getFeatureForStation(station) - if feature is not None: - features.append(feature) - - print("getStationsFeatures: %d Features erzeugt" % (len(features),)) - return features - - def _getFeatureForStation(self, station) -> None | QgsFeature: - # noinspection DuplicatedCode - if station['geometry']['longitude'] is None or station['geometry']['latitude'] is None: - print("_getFeatureForStation: WARN: Station hat fehlende Koordinaten: %s" % (station['attributes']['shortname'],)) - return None - - feature = QgsFeature(self.fields) - - longitude = station['geometry']['longitude'] - latitude = station['geometry']['latitude'] - feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(longitude, latitude))) - - feature.setAttribute('uuid', station['attributes']['uuid']) - feature.setAttribute('number', station['attributes']['number']) - feature.setAttribute('shortname', station['attributes']['shortname']) - feature.setAttribute('longname', station['attributes']['longname']) - feature.setAttribute('km', station['attributes']['km']) - feature.setAttribute('agency', station['attributes']['agency']) - feature.setAttribute('water', station['attributes']['water']) - - return feature diff --git a/pomodules/po_waterlevels.py b/pomodules/po_waterlevels.py deleted file mode 100644 index 68da9b7..0000000 --- a/pomodules/po_waterlevels.py +++ /dev/null @@ -1,43 +0,0 @@ -from . import poBaseURL -from .urlreader import UrlReader - - -class PoWaterlevels(UrlReader): - - def __init__(self): - super().__init__(poBaseURL + 'stations.json?timeseries=W&includeTimeseries=true&includeCurrentMeasurement=true') - - def getWaterlevels(self): - print("getWaterlevels: Lade Pegelstände herunter...") - - stations_json = self.getJsonResponse() - if stations_json is None or len(stations_json) == 0: - print("getWaterlevels: FEHLER: Keine Pegelstände erhalten") - return None - - stations = [] - for station_json in stations_json: - stations.append( - { - 'geometry': { - 'longitude': station_json['longitude'] if 'longitude' in station_json else None, - 'latitude': station_json['latitude'] if 'latitude' in station_json else None, - }, - 'attributes': { - 'uuid': station_json['uuid'], - 'shortname': station_json['shortname'], - 'number': station_json['number'], - 'agency': station_json['agency'], - 'unit': station_json['timeseries'][0]['unit'], - 'timestamp': station_json['timeseries'][0]['currentMeasurement']['timestamp'], - 'value': station_json['timeseries'][0]['currentMeasurement']['value'], - 'stateMnwMhw': station_json['timeseries'][0]['currentMeasurement']['stateMnwMhw'], - 'stateNswHsw': station_json['timeseries'][0]['currentMeasurement']['stateNswHsw'], - 'water': station_json['water']['longname'], - }, - } - ) - - print("getWaterlevels: %d Pegelstände erhalten" % (len(stations),)) - - return stations diff --git a/pomodules/po_waterlevels_qgs.py b/pomodules/po_waterlevels_qgs.py deleted file mode 100644 index 53da53a..0000000 --- a/pomodules/po_waterlevels_qgs.py +++ /dev/null @@ -1,65 +0,0 @@ -from PyQt5.QtCore import QVariant -from qgis._core import QgsCoordinateReferenceSystem, QgsGeometry, QgsPointXY -from qgis.core import QgsFields, QgsFeature, QgsField - -from .po_waterlevels import PoWaterlevels - - -class PoWaterlevelsQgs(PoWaterlevels): - - def __init__(self): - super().__init__() - self.fields = None - self.crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId) - - def getWaterlevelsFeatures(self): - print("getWaterlevelsFeatures: Erzeuge Features...") - - self.fields = QgsFields() - self.fields.append(QgsField('shortname', QVariant.String)) - self.fields.append(QgsField('number', QVariant.LongLong)) - self.fields.append(QgsField('agency', QVariant.String)) - self.fields.append(QgsField('timestamp', QVariant.DateTime)) - self.fields.append(QgsField('value', QVariant.Double)) - self.fields.append(QgsField('unit', QVariant.String)) - self.fields.append(QgsField('stateMnwMhw', QVariant.String)) - self.fields.append(QgsField('stateNswHsw', QVariant.String)) - self.fields.append(QgsField('water', QVariant.String)) - - features = [] - waterlevels = self.getWaterlevels() - if waterlevels is None or len(waterlevels) == 0: - print("getWaterlevelsFeatures: Fehler: Keine Pegelstände erhalten") - return None - - for station in waterlevels: - feature = self._getFeatureForStation(station) - if feature is not None: - features.append(feature) - - print("getWaterlevelsFeatures: %d Features erzeugt" % (len(features),)) - return features - - def _getFeatureForStation(self, station): - # noinspection DuplicatedCode - if station['geometry']['longitude'] is None or station['geometry']['latitude'] is None: - print("_getFeatureForStation: WARN: Station hat fehlende Koordinaten: %s" % (station['attributes']['shortname'],)) - return None - - feature = QgsFeature(self.fields) - - longitude = station['geometry']['longitude'] - latitude = station['geometry']['latitude'] - feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(longitude, latitude))) - - feature.setAttribute('shortname', station['attributes']['shortname']) - feature.setAttribute('number', station['attributes']['number']) - feature.setAttribute('agency', station['attributes']['agency']) - feature.setAttribute('timestamp', station['attributes']['timestamp']) - feature.setAttribute('value', station['attributes']['value']) - feature.setAttribute('unit', station['attributes']['unit']) - feature.setAttribute('stateMnwMhw', station['attributes']['stateMnwMhw']) - feature.setAttribute('stateNswHsw', station['attributes']['stateNswHsw']) - feature.setAttribute('water', station['attributes']['water']) - - return feature diff --git a/styles/label_stations.qml b/styles/label_stations.qml deleted file mode 100644 index 5383489..0000000 --- a/styles/label_stations.qml +++ /dev/null @@ -1,243 +0,0 @@ - - - - 1 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - generatedlayout - - - - - - - - - - - - - - - - - - - - uuid - - 0 - diff --git a/styles/label_waterlevels.qml b/styles/label_waterlevels.qml deleted file mode 100644 index 2778c13..0000000 --- a/styles/label_waterlevels.qml +++ /dev/null @@ -1,243 +0,0 @@ - - - - 1 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - generatedlayout - - - - - - - - - - - - - - - - - - - - uuid - - 0 - diff --git a/styles/stations.qml b/styles/stations.qml new file mode 100644 index 0000000..266f9fe --- /dev/null +++ b/styles/stations.qml @@ -0,0 +1,545 @@ + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "shortname" + + 0 + diff --git a/styles/waterlevels.qml b/styles/waterlevels.qml new file mode 100644 index 0000000..39fe9e8 --- /dev/null +++ b/styles/waterlevels.qml @@ -0,0 +1,575 @@ + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "shortname" + <h1>[% "shortname" %]</h1> <table> <tr> <th style='text-align: left'>Nummer:</th> <td>#[% "number" %]</td> </tr> <tr> <th style='text-align: left'>Behörde:</th> <td>[% "agency" %]</td> </tr> <tr> <th style='text-align: left'>Gewässer:</th> <td>[% "water" %]</td> </tr> <tr> <th style='text-align: left'>Zeitstempel:</th> <td>[% "timestamp" %]</td> </tr> <tr> <th style='text-align: left'>Aktueller Pegel:</th> <td>[% "value" %] [% "unit" %]</td> </tr> <tr> <th style='text-align: left'>MNW, MHW:</th> <td>[% "mean" %]</td> </tr> <tr> <th style='text-align: left'>NSW, HSW:</th> <td>[% "absolute" %]</td> </tr> </table> + 0 +