Barrido de los 498.528 km² de la península y Baleares sobre malla de 100 m (EPSG:3035) para localizar sitios alejados de todo con acceso rodado. - 12,5 M de edificios y 1,4 M de km de viales de OSM, incluidos los países vecinos para no inflar el aislamiento en la franja fronteriza - Espacios protegidos oficiales (Red Natura 2000 + designación nacional) vía la Agencia Europea de Medio Ambiente: cubren el 29 % del país frente al 15 % que tenía OSM - Modelo acústico con propagación real; es el filtro que de verdad corta, y deja 505 km² en toda España - 355 localizaciones valoradas de 1 a 5 estrellas en seis criterios - Visor autónomo con relieve, ortofoto PNOA por localización, relieve 3D y mapa deslizante con satélite, catastro y espacios protegidos
74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
"""Control de sesgo: ¿está OSM igual de mapeado en toda España?
|
|
|
|
Importa porque el modelo mide aislamiento como "distancia al edificio más
|
|
cercano". Si una comunidad tiene los edificios a medio mapear, sus celdas
|
|
saldrán aisladas por un hueco en los datos y no por estar lejos de nada.
|
|
El import del Catastro cubre casi toda España pero no Navarra ni Euskadi, que
|
|
tienen catastro propio, así que el sesgo es esperable y hay que cuantificarlo.
|
|
|
|
Como no usamos datos externos de población, el contraste es interno: viales por
|
|
km2 (que en España están mapeados de forma homogénea) frente a edificios por
|
|
km2. Si la proporción se desploma en una región, es un agujero de datos.
|
|
"""
|
|
import pickle
|
|
import sys
|
|
|
|
import numpy as np
|
|
import rasterio.features
|
|
from shapely.geometry import mapping
|
|
|
|
sys.path.insert(0, str(__file__.rsplit("/", 1)[0]))
|
|
import config as C
|
|
|
|
STEP_M = 60.0 # espaciado de densificación usado en extract_osm
|
|
|
|
|
|
def main():
|
|
with open(C.INTERIM / "area_admin_region.pkl", "rb") as fh:
|
|
regs = [r for r in pickle.load(fh) if r["geom"].area > 1e6]
|
|
regs.sort(key=lambda r: -r["geom"].area)
|
|
|
|
rid = rasterio.features.rasterize(
|
|
[(mapping(r["geom"]), i + 1) for i, r in enumerate(regs)],
|
|
out_shape=(C.HEIGHT, C.WIDTH), transform=C.TRANSFORM,
|
|
fill=0, dtype=np.uint8, all_touched=False)
|
|
|
|
def counts_for(base):
|
|
a = np.load(C.INTERIM / f"{base}.npy")
|
|
r, c = C.xy_to_rowcol(a[0], a[1])
|
|
ok = C.inside(r, c)
|
|
ids = rid[r[ok], c[ok]]
|
|
return np.bincount(ids, minlength=len(regs) + 1)
|
|
|
|
b = counts_for("buildings")
|
|
v = counts_for("line_minor") + counts_for("line_track")
|
|
cells = np.bincount(rid.ravel(), minlength=len(regs) + 1)
|
|
|
|
print(f"{'comunidad':24s} {'km2':>8s} {'edif':>10s} {'edif/km2':>9s} "
|
|
f"{'vial km':>9s} {'edif/vial-km':>13s}")
|
|
print("-" * 78)
|
|
ratios = []
|
|
for i, r in enumerate(regs, start=1):
|
|
km2 = cells[i] * 0.01
|
|
if km2 < 100:
|
|
continue
|
|
vial_km = v[i] * STEP_M / 1000.0
|
|
ratio = b[i] / vial_km if vial_km else 0
|
|
ratios.append((ratio, r["name"]))
|
|
print(f"{r['name'][:24]:24s} {km2:8,.0f} {b[i]:10,} {b[i]/km2:9.1f} "
|
|
f"{vial_km:9,.0f} {ratio:13.2f}")
|
|
|
|
med = np.median([x for x, _ in ratios])
|
|
print("-" * 78)
|
|
print(f"mediana edif/vial-km: {med:.2f}")
|
|
print("\nregiones con menos de la mitad de la mediana "
|
|
"(sospecha de infra-mapeo de edificios):")
|
|
flagged = [n for x, n in ratios if x < 0.5 * med]
|
|
for n in flagged:
|
|
print(f" - {n}")
|
|
if not flagged:
|
|
print(" ninguna")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|