Files
fn_registry/python/functions/datascience/analyze_geo_extent.md
T
egutierrez cd658cc703 feat(eda): primitivas geoespaciales del grupo eda (detección lat/lon + extensión + scatter)
Tres funciones puras nuevas del dominio datascience (tags eda + geospatial) que
sostienen el capítulo GEOSPATIAL del AutomaticEDA, delegadas a fn-constructor:

- detect_latlon_columns: identifica el par (lat, lon) por nombre de columna +
  rango de valores ([-90,90] / [-180,180]) desde profile['columns']. Devuelve
  {lat_col, lon_col, confidence, reason}. 9 tests.
- analyze_geo_extent: bbox, centroide, span haversine, conteo por zona/país
  (lookup offline con bounding boxes embebidos, KISS sin geopandas) y
  hemisferios. 7 tests.
- build_geo_scatter: prepara los puntos del scatter en orden [lon, lat] con
  downsampling determinista por paso fijo + aspect equirectangular 1/cos(lat)
  clampado. 6 tests.

Registradas en datascience/__init__.py. Todas pure, params_schema completo,
.md autosuficiente (Ejemplo + Cuando usarla + Gotchas).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:29:33 +02:00

5.0 KiB

name, kind, lang, domain, version, purity, signature, description, tags, params, output, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags params output uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path
analyze_geo_extent function py datascience 1.0.0 pure def analyze_geo_extent(lats: list, lons: list) -> dict Calcula la extension geografica de una nube de coordenadas (lat/lon) y asigna cada punto a un pais/region mediante un lookup OFFLINE contra una tabla de bounding boxes embebida como constante. Devuelve bounding box, centroide, span de la diagonal (haversine), conteo por region (top-8 + Otros), reparto por hemisferios y una frase resumen en ES. Lectura defensiva: descarta pares None/NaN/fuera de rango y NUNCA lanza. Solo stdlib (math); sin geopandas/shapely. Las cajas de paises son rectangulos aproximados, no reverse-geocoding exacto.
eda
geospatial
geo
coordinates
bounding-box
haversine
datascience
name desc
lats Lista de latitudes en grados, rango valido [-90, 90]. Se empareja por indice con lons (gana la longitud minima comun si difieren). Cada valor puede ser None/NaN/no-numerico/fuera de rango: se lee defensivo y se descarta el par.
name desc
lons Lista de longitudes en grados, rango valido [-180, 180]. Paralela a lats, emparejada por indice. Valores None/NaN/no-numericos/fuera de rango se descartan junto con su par.
Dict con el resumen geografico: {n_points=pares validos usados, bbox={lat_min,lat_max,lon_min,lon_max} o None, centroid={lat,lon}=media de lat/lon validos o None, span_km=distancia haversine (radio 6371 km) de la diagonal SO->NE del bbox, by_region=[{region,count}] descendente por count limitado a top-8 con el resto agregado en 'Otros', hemisphere={north,south,east,west} (ecuador->norte, meridiano 0->este), note=frase ES resumen}. Si no hay pares validos devuelve la forma cero: n_points 0, bbox None, centroid None, span_km 0.0, by_region [], hemisphere a ceros y note 'sin coordenadas validas'. Puntos que no caen en ninguna caja -> region 'Oceano/Otros'.
false
math
true
test_nube_en_espana
test_dos_paises_distintos
test_listas_vacias
test_pares_invalidos_filtrados
test_longitudes_desbalanceadas
test_span_km_haversine_par_conocido
test_no_lanza_con_entradas_raras
python/functions/datascience/analyze_geo_extent_test.py python/functions/datascience/analyze_geo_extent.py

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from datascience.analyze_geo_extent import analyze_geo_extent

# Nube de puntos alrededor de Madrid + un punto en Paris.
lats = [40.4, 40.0, 41.0, 48.8]
lons = [-3.7, -3.5, -4.0, 2.3]
res = analyze_geo_extent(lats, lons)

print(res["n_points"])          # 4
print(res["by_region"])         # [{'region': 'España', 'count': 3}, {'region': 'Francia', 'count': 1}]
print(round(res["span_km"], 1)) # diagonal SO->NE del bbox en km
print(res["hemisphere"])        # {'north': 4, 'south': 0, 'east': 1, 'west': 3}
print(res["note"])              # los puntos se concentran en España (3 de 4)

Cuando usarla

  • Usala en el perfilado EDA (grupo eda) cuando una tabla tenga columnas de latitud y longitud y quieras un resumen geografico rapido: donde se concentran los puntos, cuanto territorio cubren y a que paises/regiones caen, sin montar geopandas ni un reverse-geocoder.
  • Cuando necesites un capitulo geospatial del AutomaticEDA: alimenta el bbox + centroide para centrar un mapa, el span_km para elegir el zoom, y by_region para una tabla de conteos por pais.
  • Cuando quieras detectar datos sucios de coordenadas (mezcla de hemisferios inesperada, puntos en Oceano/Otros, span enorme) antes de seguir el analisis.

Gotchas

  • Funcion pura, sin I/O ni red y determinista: mismas entradas -> misma salida. Lectura defensiva, NUNCA lanza; pares con None/NaN o fuera de rango ([-90,90] lat, [-180,180] lon) se descartan en silencio.
  • El lookup de region es una aproximacion rectangular: cada pais/region es un bounding box, NO su frontera real. Un punto en el mar cerca de una costa, o en una esquina del rectangulo, puede asignarse a un pais vecino. No es reverse-geocoding exacto — para precision real hace falta un shapefile (fuera de scope por KISS).
  • Cajas solapadas se resuelven por orden: gana la PRIMERA que contiene el punto. Los paises se listan antes que los continentes (fallback), y entre vecinos el mas estrecho/occidental va primero (Portugal antes que España, Chile antes que Argentina, EEUU contiguo antes que Canada). Un punto que no cae en ninguna caja -> Oceano/Otros.
  • La tabla cubre ~24 paises grandes + 6 regiones continentales; paises pequeños o no listados caen a su continente o a Oceano/Otros. No incluye territorios insulares lejanos (Canarias, Hawaii, etc.).
  • span_km es la diagonal del bounding box (esquina SO a NE), no la dispersion real de la nube ni el area; con un solo punto valido el bbox es degenerado y span_km es 0.0.
  • El ecuador (lat == 0) cuenta como hemisferio norte y el meridiano 0 (lon == 0) como este, por convencion >= 0.