From 3f171dbf79282821faadee263ebe8abe166009a3 Mon Sep 17 00:00:00 2001 From: David Huggins-Daines Date: Wed, 10 Jul 2024 09:17:22 -0400 Subject: [PATCH] fix: make zone lookup reliable --- zonalda/__init__.py | 25 +++++++++++++++++++++---- zonalda/api.py | 33 ++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/zonalda/__init__.py b/zonalda/__init__.py index 47bfd42..ed4d2f9 100644 --- a/zonalda/__init__.py +++ b/zonalda/__init__.py @@ -31,13 +31,30 @@ def __init__(self): self.zonage = zonage.assign(ZONE=zonage["ZONE"].str.replace(" ", "")) self.collectes = geopandas.read_file(THISDIR / "collectes.geojson") - def __getitem__(self, name: str) -> tuple[float, float]: - """Trouver le centroïde d'une zone par son nom.""" + def __getitem__(self, name: str) -> tuple[ + Series | None, + Series | None, + Series | None, + ]: + """Trouver les informations pour une zone.""" zones = self.zonage.loc[self.zonage["ZONE"] == name] if zones.empty: raise KeyError("Zone not found: %s" % name) - c = zones.iloc[0].geometry.centroid - return c.y, c.x + zone = zones.iloc[0] + district, collecte = None, None + districts = self.districts.loc[self.districts.contains(zone.geometry)] + if len(districts) > 1: + LOGGER.warning("Plusieurs districts trouvé pour %s: %s", name, districts) + if len(districts): + district = districts.iloc[0] + collectes = self.collectes.loc[self.collectes.contains(zone.geometry)] + if len(collectes) > 1: + LOGGER.warning( + "Plusieurs zones de collectes trouvé pour %s: %s", name, collectes + ) + if len(collectes): + collecte = collectes.iloc[0] + return district, zone, collecte def __call__(self, latitude: float, longitude: float) -> tuple[ Series | None, diff --git a/zonalda/api.py b/zonalda/api.py index f6785ee..9f4fea0 100644 --- a/zonalda/api.py +++ b/zonalda/api.py @@ -51,12 +51,12 @@ class Emplacement(BaseModel): point: tuple[float, float] @classmethod - def from_wgs84(self, latitude: float, longitude: float) -> "Emplacement": + def from_wgs84(cls, latitude: float, longitude: float) -> "Emplacement": """ Chercher les informations géomatiques pour un emplacement GPS. """ district, zone, collecte = zonalda(latitude, longitude) - return self( + return cls( district=District(numero=district["id"], conseiller=district["Conseiller"]) if district is not None else None, @@ -76,12 +76,31 @@ def from_wgs84(self, latitude: float, longitude: float) -> "Emplacement": ) @classmethod - def from_zone(self, zone: str) -> "Emplacement": - """ - Localiser le centroïde d'une zone et retourner les autres informations. + def from_zone(cls, zone: str) -> "Emplacement": + """Localiser le centroïde d'une zone et retourner les autres informations. + + Notez que le centroïde d'une zone peut très bien ne pas se + trouver dans la zone elle-même! """ - latitude, longitude = zonalda[zone] - return self.from_wgs84(latitude, longitude) + district, zone, collecte = zonalda[zone] + return cls( + district=District(numero=district["id"], conseiller=district["Conseiller"]) + if district is not None + else None, + collecte=Collecte(jour=collecte["jour"], couleur=collecte["couleur"]) + if collecte is not None + else None, + zone=Zone( + zone=zone["ZONE"], + milieu=zone["Types"], + description=zone["Descr_Type"], + # FIXME: thoroughly unnecessary JSON parsing + geometry=json.loads(shapely.to_geojson(zone["geometry"])), + ) + if zone is not None + else None, + point=(zone.geometry.centroid.x, zone.geometry.centroid.y), + ) @api.exception_handler(MunicipalityError)