plot-finder 0.3.2__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plot_finder-0.3.2 → plot_finder-0.3.4}/PKG-INFO +1 -1
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/analyzer.py +94 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/plot.py +6 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/report.py +7 -6
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder.egg-info/PKG-INFO +1 -1
- {plot_finder-0.3.2 → plot_finder-0.3.4}/pyproject.toml +1 -1
- {plot_finder-0.3.2 → plot_finder-0.3.4}/LICENSE +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/README.md +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/__init__.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/ai.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/air.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/climate.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/exceptions.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/gugik.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/mpzp.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/noise.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/place.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/risks.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/sun.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder/visualizer.py +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder.egg-info/SOURCES.txt +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder.egg-info/dependency_links.txt +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder.egg-info/requires.txt +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/plot_finder.egg-info/top_level.txt +0 -0
- {plot_finder-0.3.2 → plot_finder-0.3.4}/setup.cfg +0 -0
|
@@ -61,6 +61,43 @@ _VOIVODESHIP_MAP = {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
_PLACE_CATEGORIES: dict[str, str] = {
|
|
65
|
+
# education
|
|
66
|
+
"school": "education", "kindergarten": "education",
|
|
67
|
+
"university": "education", "college": "education",
|
|
68
|
+
# finance
|
|
69
|
+
"atm": "finance", "bank": "finance",
|
|
70
|
+
# transport
|
|
71
|
+
"bus_stop": "transport", "bus_station": "transport",
|
|
72
|
+
"platform": "transport", "stop_position": "transport",
|
|
73
|
+
"tram_stop": "transport", "station": "transport", "halt": "transport",
|
|
74
|
+
"ferry_terminal": "transport", "aerodrome": "transport",
|
|
75
|
+
# infrastructure
|
|
76
|
+
"supermarket": "infrastructure", "convenience": "infrastructure",
|
|
77
|
+
"mall": "infrastructure", "pharmacy": "infrastructure",
|
|
78
|
+
"hospital": "infrastructure", "clinic": "infrastructure",
|
|
79
|
+
"doctors": "infrastructure", "dentist": "infrastructure",
|
|
80
|
+
"post_office": "infrastructure", "fuel": "infrastructure",
|
|
81
|
+
"police": "infrastructure", "fire_station": "infrastructure",
|
|
82
|
+
"place_of_worship": "infrastructure", "restaurant": "infrastructure",
|
|
83
|
+
"cafe": "infrastructure",
|
|
84
|
+
# green_areas
|
|
85
|
+
"park": "green_areas", "garden": "green_areas",
|
|
86
|
+
"nature_reserve": "green_areas", "playground": "green_areas",
|
|
87
|
+
"forest": "green_areas", "wood": "green_areas",
|
|
88
|
+
# water
|
|
89
|
+
"water": "water", "river": "water", "lake": "water",
|
|
90
|
+
"pond": "water", "reservoir": "water",
|
|
91
|
+
"stream": "water", "canal": "water",
|
|
92
|
+
# nuisances
|
|
93
|
+
"line": "nuisances", "transformer": "nuisances",
|
|
94
|
+
"plant": "nuisances", "generator": "nuisances",
|
|
95
|
+
"industrial": "nuisances", "landfill": "nuisances",
|
|
96
|
+
"quarry": "nuisances", "works": "nuisances",
|
|
97
|
+
"wastewater_plant": "nuisances", "sawmill": "nuisances",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
64
101
|
class PlotAnalyzer:
|
|
65
102
|
def __init__(self, plot: Plot, *, radius: int = 1000, openweather_api_key: str | None = None) -> None:
|
|
66
103
|
self.plot = plot
|
|
@@ -87,6 +124,63 @@ class PlotAnalyzer:
|
|
|
87
124
|
lon, lat = _EPSG2180_TO_WGS84.transform(x, y)
|
|
88
125
|
return lat, lon
|
|
89
126
|
|
|
127
|
+
# ------------------------------------------------------------------
|
|
128
|
+
# Bulk fetch — one Overpass request for all categories
|
|
129
|
+
# ------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
def all_places(self, radius: int | None = None) -> dict[str, list[Place]]:
|
|
132
|
+
"""Fetch all POI categories in a single Overpass request.
|
|
133
|
+
|
|
134
|
+
Returns a dict with keys: education, finance, transport,
|
|
135
|
+
infrastructure, green_areas, water, nuisances.
|
|
136
|
+
Also populates the cache so subsequent calls to individual
|
|
137
|
+
methods (e.g. education()) return instantly.
|
|
138
|
+
"""
|
|
139
|
+
r = radius or self.radius
|
|
140
|
+
key = ("all_places", r)
|
|
141
|
+
if key in self._cache:
|
|
142
|
+
return self._cache[key]
|
|
143
|
+
|
|
144
|
+
query = f"""
|
|
145
|
+
[out:json][timeout:60];
|
|
146
|
+
(
|
|
147
|
+
nwr["amenity"~"school|kindergarten|university|college|atm|bank|bus_station|pharmacy|hospital|clinic|doctors|dentist|post_office|fuel|police|fire_station|place_of_worship|restaurant|cafe|ferry_terminal"](around:{r},{self._lat},{self._lon});
|
|
148
|
+
nwr["shop"~"supermarket|convenience|mall"](around:{r},{self._lat},{self._lon});
|
|
149
|
+
nwr["highway"="bus_stop"](around:{r},{self._lat},{self._lon});
|
|
150
|
+
nwr["public_transport"~"platform|stop_position"](around:{r},{self._lat},{self._lon});
|
|
151
|
+
nwr["railway"~"tram_stop|station|halt"](around:{r},{self._lat},{self._lon});
|
|
152
|
+
nwr["aeroway"="aerodrome"](around:{r},{self._lat},{self._lon});
|
|
153
|
+
nwr["leisure"~"park|garden|nature_reserve|playground"](around:{r},{self._lat},{self._lon});
|
|
154
|
+
nwr["landuse"~"forest|industrial|landfill|quarry"](around:{r},{self._lat},{self._lon});
|
|
155
|
+
nwr["natural"~"water|wood"](around:{r},{self._lat},{self._lon});
|
|
156
|
+
nwr["water"~"river|lake|pond|reservoir"](around:{r},{self._lat},{self._lon});
|
|
157
|
+
nwr["waterway"~"river|stream|canal"](around:{r},{self._lat},{self._lon});
|
|
158
|
+
nwr["power"~"line|transformer|plant|generator"](around:{r},{self._lat},{self._lon});
|
|
159
|
+
nwr["man_made"~"works|wastewater_plant"](around:{r},{self._lat},{self._lon});
|
|
160
|
+
nwr["craft"="sawmill"](around:{r},{self._lat},{self._lon});
|
|
161
|
+
);
|
|
162
|
+
out center;
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
all_results = self._run_overpass(query)
|
|
166
|
+
|
|
167
|
+
categories: dict[str, list[Place]] = {
|
|
168
|
+
"education": [], "finance": [], "transport": [],
|
|
169
|
+
"infrastructure": [], "green_areas": [], "water": [],
|
|
170
|
+
"nuisances": [],
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for place in all_results:
|
|
174
|
+
cat = _PLACE_CATEGORIES.get(place.kind)
|
|
175
|
+
if cat:
|
|
176
|
+
categories[cat].append(place)
|
|
177
|
+
|
|
178
|
+
for cat_name, places in categories.items():
|
|
179
|
+
self._cache[(cat_name, r)] = places
|
|
180
|
+
|
|
181
|
+
self._cache[key] = categories
|
|
182
|
+
return categories
|
|
183
|
+
|
|
90
184
|
# ------------------------------------------------------------------
|
|
91
185
|
# Overpass-based place methods (cached)
|
|
92
186
|
# ------------------------------------------------------------------
|
|
@@ -29,9 +29,15 @@ class Plot(BaseModel):
|
|
|
29
29
|
@computed_field # type: ignore[prop-decorator]
|
|
30
30
|
@property
|
|
31
31
|
def area(self) -> float | None:
|
|
32
|
+
"""Area in m². Transforms to EPSG:2180 if needed."""
|
|
32
33
|
if not self.geom_wkt:
|
|
33
34
|
return None
|
|
34
35
|
geom = shapely.wkt.loads(self.geom_wkt)
|
|
36
|
+
if self.srid != 2180:
|
|
37
|
+
from pyproj import Transformer
|
|
38
|
+
from shapely.ops import transform
|
|
39
|
+
t = Transformer.from_crs(f"EPSG:{self.srid}", "EPSG:2180", always_xy=True)
|
|
40
|
+
geom = transform(t.transform, geom)
|
|
35
41
|
return round(geom.area, 2)
|
|
36
42
|
|
|
37
43
|
@computed_field # type: ignore[prop-decorator]
|
|
@@ -8,7 +8,6 @@ from pydantic import BaseModel
|
|
|
8
8
|
from plot_finder.air import AirQuality
|
|
9
9
|
from plot_finder.climate import Climate
|
|
10
10
|
from plot_finder.exceptions import (
|
|
11
|
-
NothingFoundError,
|
|
12
11
|
OpenMeteoError,
|
|
13
12
|
OSRMError,
|
|
14
13
|
OpenWeatherAuthError,
|
|
@@ -64,11 +63,13 @@ class PlotReporter:
|
|
|
64
63
|
if a.plot.geom_wkt:
|
|
65
64
|
data["geometry"] = self._geometry_wgs84(a.plot.geom_wkt)
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
try:
|
|
67
|
+
places = a.all_places()
|
|
68
|
+
for category in ("education", "finance", "transport", "infrastructure", "green_areas", "water", "nuisances"):
|
|
69
|
+
if places.get(category):
|
|
70
|
+
data[category] = places[category]
|
|
71
|
+
except (OverpassError, OSRMError):
|
|
72
|
+
pass
|
|
72
73
|
|
|
73
74
|
try:
|
|
74
75
|
data["air_quality"] = a.air_quality()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|