Plan para ISC Stations, fallas y cache en kashima.mapper

Este documento resume, de forma concreta y minimal, cómo:

  • Incorporar estaciones ISC en los mapas (vía KMZ externo → CSV o soporte interno de KMZ).
  • Entender qué hay en el cache, cómo llega allí y qué hace (y no hace) el instalador.
  • Explicar por qué no ves ciertas fallas que ya están en cache y qué tienes que hacer para verlas.

1. Estado actual

Actualizado para kashima 1.7.0 (estrella en el sitio + capa ISC Stations global por defecto + fallas GEM/USGS/EFSM20 siempre recortadas al bound, más fallas locales de usuario como ejemplo en Angola).

1.1 Estaciones

  • StationConfig sigue leyendo CSV (o CSV con columnas x,y que se convierten a latitude, longitude).
  • El paquete ahora incluye kashima/mapper/data/isc_stations.csv (~41k estaciones ISC globales).
  • initialize_cache_from_package_data() copia ese CSV a ~/Library/Caches/kashima/isc_stations.csv si aún no existe.
  • buildMap, cuando no se pasa station_csv_path, busca isc_stations.csv en el cache, lo copia a output_dir/data/isc_stations.csv y construye StationConfig por defecto con ese archivo.
  • EventMap._load_stations carga ese CSV y filtra las estaciones al mismo bbox que los eventos (radio × event_radius_multiplier).
  • StationLayer ahora pinta cada estación como un cuadrado DivIcon (no pin), con tooltip del tipo NETWORK STATION – Name y popup con metadatos básicos (network, station, name, lat, lon).
  • Si el usuario pasa explícitamente station_csv_path, se usa su CSV y se ignoran las estaciones ISC por defecto.
  • Sigue sin haber soporte directo para KMZ/KML: el KMZ de ISC se convierte a CSV una vez (con el script de ayuda) y a partir de ahí se trabaja siempre con CSV.

1.2 Fallas

  • downloadAllCatalogs(include_faults=True) y las funciones buildGEMActiveFaults, buildUSGSQuaternaryFaults, buildEFSM20Faults escriben en el cache global:
    • gem_active_faults.geojson
    • usgs_quaternary_faults.geojson
    • efsm20_faults.geojson
  • buildMap ahora usa por defecto todas las bases de fallas globales disponibles en cache:
    • Copia cada GeoJSON (gem_active_faults, usgs_quaternary_faults, efsm20_faults) desde el cache global a output_dir/data/*.geojson.
    • Crea FaultConfig(include_faults=True, faults_files=[...]) con la lista completa de ficheros locales.
    • EventMap._load_faults lee todos esos ficheros, añade una columna interna __fault_source (“gem”, “usgs”, “efsm20” o “local”), los mergea en un solo GeoDataFrame y recorta los segmentos al mismo bbox que los eventos.
    • FaultLayer dibuja una única capa de fallas pero coloreada por __fault_source.
  • Opcionalmente, el usuario puede controlar qué conjuntos globales se cargan vía fault_sets (por ejemplo fault_sets=["gem", "usgs"]) y añadir fallas locales adicionales vía faults_files (GeoJSONs de usuario, por ejemplo en examples/mapper/faults/).

1.3 Cache e instalador

  • En macOS, el cache real se está usando en ~/Library/Caches/kashima.
  • Ahí, en tu entorno, tienes:
    • usgs_catalog.csv, gcmt_catalog.csv, isc_catalog.csv (+ .bak, .parquet).
    • gem_active_faults.geojson, usgs_quaternary_faults.geojson, efsm20_faults.geojson.
  • Cómo llegan esos archivos al cache:
    • Catálogos (USGS, GCMT, ISC):
      • downloadAllCatalogs() → si el archivo no existe, llama internamente a buildUSGSCatalog, buildGCMTCatalog, buildISCCatalog y guarda los CSV en el cache.
      • También puedes llamarlos tú directamente; con output_path=None escriben en el cache por defecto.
    • Fallas (GEM, USGS, EFSM20):
      • downloadAllCatalogs(include_faults=True) llama a buildGEMActiveFaults, buildUSGSQuaternaryFaults, buildEFSM20Faults si los .geojson no existen aún.
      • También puedes invocar esas funciones individualmente; con output_path=None escriben en el cache.
  • Qué hace el instalador (pip install kashima):
    • Instala el paquete Python y, opcionalmente, incluye archivos en kashima/mapper/data/ (catálogos pre-descargados, fallas, etc.), dentro del paquete.
    • No escribe nada en ~/Library/Caches/kashima.
    • La primera vez que llamas a downloadAllCatalogs(), initialize_cache_from_package_data() copia esos datos embebidos (si existen) desde kashima/mapper/data/ al cache del usuario; si no existen, descarga desde Internet.
  • buildMap no rellena el cache completo:
    • Da por hecho que usgs_catalog.csv, gcmt_catalog.csv, isc_catalog.csv ya están en cache (o fallará indicando que ejecutes los builders).
    • La única excepción es GEM: si gem_active_faults.geojson no existe aún cuando pides fallas, puede llamar a buildGEMActiveFaults() para crear ese archivo en cache.

En resumen: el cache lo llenan tus llamadas a downloadAllCatalogs / build*Catalog / build*Faults, no el instalador.

2. Plan para ISC Stations (dos caminos)

Queremos un layer “ISC Stations” visible como el de fallas, sabiendo que las estaciones llegan en un KMZ de ISC.

2.1 Opción 1 – Procesar el KMZ por fuera y usar StationConfig con CSV

Flujo propuesto:

  1. Inspeccionar el KMZ (fuera de kashima):
    • Instalar GDAL: brew install gdal.
    • Ver contenido: ogrinfo isc_stations.kmz -so -al (muestra capas y campos).
  2. Convertir a CSV con lat/lon e ID de estación:
    • ogr2ogr -f CSV isc_stations.csv isc_stations.kmz.
    • Asegurarte de que el CSV resultante tiene columnas:
      • latitude, longitude (o Y, X que puedas renombrar).
      • Algún identificador de estación, p.ej. ID o station_code.
  3. Usar el CSV en el mapa, sin tocar kashima por dentro:
    • Llamar a buildMap con:
      • station_csv_path="/ruta/a/isc_stations.csv".
      • station_coordinate_system="EPSG:4326" (si las coords del CSV ya están en WGS84).
    • EventMapload_stations_csvStationLayer te generan un layer “Stations” con on/off en el LayerControl.

Pros de esta opción:

  • Cero cambios internos de kashima: se apoya en StationConfig/StationLayer tal como están.
  • Trazabilidad clara del pipeline (KMZ → CSV versionado en tu repo/proyecto).
  • Herramientas estándar (gdal, QGIS) para inspeccionar y depurar el KMZ.

Contras:

  • Requiere que mantengas un pequeño flujo externo (scripts o comandos manuales) para regenerar isc_stations.csv cuando cambie el KMZ.
  • La lógica de mapeo de campos (qué campo del KMZ es el ID de estación, etc.) vive fuera de kashima.

2.2 Opción 2 – Soporte interno de KMZ dentro de kashima

Flujo conceptual:

  1. Reutilizar el patrón ya existente en buildUSGSQuaternaryFaults:
    • Abrir el KMZ como ZIP.
    • Encontrar el .kml interno.
    • Parsear Placemark de estaciones (coordenadas + metadatos) con xml.etree.ElementTree.
  2. Implementar un helper interno (a nivel concepto):
    • Algo tipo load_isc_kmz_as_stations(path) -> pd.DataFrame.
    • Ese DataFrame tendría columnas latitude, longitude, ID, etc., de la misma forma que espera StationLayer.
  3. Integración ligera con buildMap (si se decide dar este paso):
    • Permitir que un parámetro opcional (p.ej. isc_stations_kmz_path) dispare esa conversión internamente y genere un CSV en data/ o pase el DataFrame directamente a StationLayer.

Pros:

  • Todo el flujo está dentro de kashima, sin depender de herramientas externas.
  • Puedes encapsular el conocimiento de qué campos del KMZ corresponden a ID, etc.

Contras:

  • Más código propio que mantener (parseo de KMLs, edge cases, versiones futuras de los KMZ de ISC).
  • Aumenta el acoplamiento: problemas en el servicio de ISC o cambios en el formato del KMZ impactan directamente en buildMap.
  • A corto plazo es más trabajo que la opción 1, que ya se puede usar hoy.

2.3 Recomendación inicial

A corto plazo, para avanzar rápido y ver resultados:

  • Usar Opción 1 (KMZ → CSV con ogr2ogr) y alimentar buildMap con station_csv_path.
  • Dejar la Opción 2 como una posible mejora si decides que quieres que kashima absorba esa responsabilidad.

3. Por qué no ves todas las fallas que hay en cache y qué debes hacer

3.1 Motivo (histórico y bug original)

Nota rápida (estado actual): a partir de kashima 1.3.6 buildMap ya no usa sólo GEM, sino que mergea GEM/USGS/EFSM20 y permite fallas locales vía fault_sets y faults_files (ver §1.2 y §5.3).

Lo que sigue documenta el comportamiento anterior y el bug que motivó el rediseño (se conserva como referencia histórica).

Aunque en tu cache existan:

  • gem_active_faults.geojson
  • usgs_quaternary_faults.geojson
  • efsm20_faults.geojson

el flujo actual de buildMap sólo usa GEM:

  • Siempre construye FaultConfig apuntando a gem_active_faults.geojson.
  • EventMap._load_faults sólo carga ese fichero.
  • FaultLayer sólo dibuja ese GeoDataFrame.

Por eso, aunque hayas descargado o generado grandes GeoJSON nuevos, sigues viendo “lo mismo de siempre”: el mapa no los toca salvo que sustituyan físicamente a gem_active_faults.geojson.

3.2 Qué debes activar o cambiar para ver otras fallas

Tienes dos caminos inmediatos, sin rediseñar la API:

Opción rápida (sin tocar código de Python)

  1. Hacer copia de seguridad del GEM actual:
    • cp ~/Library/Caches/kashima/gem_active_faults.geojson ~/Library/Caches/kashima/gem_active_faults.geojson.bak_manual
  2. Sustituirlo por el fichero que quieras ver en tus mapas, por ejemplo las fallas cuaternarias USGS:
    • cp ~/Library/Caches/kashima/usgs_quaternary_faults.geojson ~/Library/Caches/kashima/gem_active_faults.geojson
  3. Volver a generar el mapa con buildMap sin cambiar nada de código.
    • Desde el punto de vista de kashima, sigue creyendo que usa “GEM”, pero en la práctica estará dibujando el contenido de USGS Quaternary.

Puedes hacer algo análogo con efsm20_faults.geojson o con cualquier otro .geojson propio que copies sobre ese nombre.

Opción más limpia (ya implementada en 1.3.6)

En lugar de sobreescribir archivos en el cache, ahora se recomienda usar los parámetros fault_sets y faults_files de buildMap:

  • fault_sets: lista de identificadores de bases de fallas globales en cache (“gem”, “usgs”, “efsm20”). Permite activar/desactivar conjuntos globales.
  • faults_files: lista de rutas a GeoJSON de fallas locales (por ejemplo, en examples/mapper/faults/), que se añaden y recortan igual que las globales.

Ejemplo equivalente al caso de USGS Quaternary solo:

result = buildMap(
    latitude=..., longitude=...,
    radius_km=..., output_dir=".",
    show_faults_default=True,
    fault_sets=["usgs"],   # sólo fallas cuaternarias USGS desde el cache
)

4. Parámetros disponibles en las fallas (GeoJSON GEM)

Los GeoJSON de fallas (ejemplo: gem_active_faults.geojson) tienen esta estructura genérica por Feature:

  • geometry:
    • type: normalmente "LineString" o "MultiLineString".
    • coordinates: lista de pares [lon, lat] que definen el trazo de la falla.
  • properties (campos típicos observados):
    • name: nombre de la falla (por ejemplo “Mount Diablo Thrust”).
    • slip_type: tipo cinemático (“Reverse”, “Dextral”, “Normal”, “Sinistral”, etc.).
    • catalog_id, catalog_name: identificador y nombre del catálogo de origen (por ejemplo "UCF_2", "UCERF3").
    • average_dip, average_rake: información angular empaquetada como strings.
    • net_slip_rate: string con valor nominal y límites.
    • upper_seis_depth, lower_seis_depth: profundidades sísmicas (strings con valores y límites).

Para filtrar espacialmente (como hacemos con los eventos) lo único indispensable es la geometry:

  • Podemos usar los coordinates para calcular un bounding box por segmento (minx, maxx, miny, maxy) y quedarnos sólo con las fallas cuyo trazo intersecta el bounding box definido por el radio alrededor del sitio.
  • Los campos properties sirven para filtros temáticos (por ejemplo, quedarnos sólo con fallas de tipo slip_type="Reverse"), pero no son necesarios para el filtro principal por radio.

En el plan de modificaciones asumimos:

  • Filtro obligatorio por ventana espacial (bbox del radio) para fallas, igual que para eventos.
  • Opcionalmente, más adelante, filtros por slip_type o catalog_name si quieres vistas más específicas.

5. Plan de modificaciones en rama dev

Este es el plan concreto de trabajo sobre la rama dev (no main) para los próximos cambios:

5.1 Sitio con forma de estrella (sin pin)

Estado: implementado en rama dev y liberado en 1.3.5.

Objetivo: que el sitio se vea como una estrella pura, no como un pin con estrella dentro.

Implementación realizada:

  1. SiteMarkerLayer en kashima/mapper/layers/site_marker.py ahora usa folium.features.DivIcon en lugar de folium.Icon:
    • HTML simple con el carácter , tamaño ~24 px, color gold y text-shadow negro para resaltar.
    • icon_anchor centrado (mitad del ancho y alto) para que la estrella se ubique en el punto exacto.
  2. EventMap.getMap sólo usa SiteMarkerLayer; el antiguo BaseMap ya no forma parte de la superficie activa de kashima.mapper.
  3. Los mapas de prueba (por ejemplo examples/mapper/longonjo.py) muestran ahora el sitio como una estrella sola, claramente distinta de los eventos y de las estaciones.

5.2 Estaciones ISC limitadas al boundary (como los eventos)

Estado: implementados los pasos 1–5; pendiente sólo la lógica futura de actualización automática desde repositorios ISC.

Objetivo: representar todas las estaciones ISC disponibles, pero sólo dibujar las que caen dentro del radio del sitio, igual que se hace con los eventos.

Implementación realizada:

  1. isc_stations.csv se genera a partir del KMZ kmz/station.kmz mediante el script de ayuda scripts/isc_stations.py, que produce kashima/mapper/data/isc_stations.csv con columnas network, station, name, latitude, longitude.
  2. initialize_cache_from_package_data() en kashima/mapper/cache.py copia isc_stations.csv desde kashima/mapper/data/ a get_cache_dir()/isc_stations.csv si aún no existe.
  3. buildMap usa estaciones ISC por defecto:
    • Si el usuario no pasa station_csv_path, busca isc_stations.csv en cache, lo copia a output_dir/data/isc_stations.csv y construye StationConfig con ese path.
    • Si el usuario pasa station_csv_path, se prioriza siempre el CSV del usuario (comportamiento actual conservado).
  4. EventMap._load_stations aplica el mismo bbox que los eventos (radio × event_radius_multiplier) para filtrar el CSV global; el layer “Stations” sólo muestra estaciones dentro del radio.
  5. StationLayer en kashima/mapper/layers/stations.py usa ahora DivIcon con un div cuadrado (no pin) por estación, de color configurable, con tooltip y popup más ricos.

TODO futuro (no implementado aún): investigar repositorios ISC y añadir un pequeño flujo de actualización de isc_stations.csv desde URLs oficiales, posiblemente agregando un campo isc_url en el CSV.

5.3 Todas las bases de datos de fallas limitadas al bound

Estado: implementado para GEM, USGS Quaternary, EFSM20 y fallas locales de usuario (ejemplo: Angola).

  • EventMap._load_faults carga ahora todos los GeoJSON de fallas indicados en FaultConfig.faults_files (construido por buildMap). Por defecto, buildMap copia desde el cache global los tres conjuntos (gem_active_faults.geojson, usgs_quaternary_faults.geojson, efsm20_faults.geojson) a output_dir/data/ y añade esos paths a faults_files.
  • A cada GeoDataFrame se le añade una columna interna __fault_source con valores “gem”, “usgs”, “efsm20” o “local” según el fichero de origen; luego se mergean todos en un único GeoDataFrame y se recortan al bbox definido por el radio del mapa (incluido el caso de cruce del antimeridiano).
  • FaultLayer dibuja una única capa de fallas, pero coloreada por __fault_source (gem/usgs/efsm20/local).
  • El usuario puede controlar qué bases globales se usan mediante el parámetro fault_sets de buildMap (por ejemplo fault_sets=["gem", "usgs"] o fault_sets=[] para desactivar todas las bases globales) y añadir rutas adicionales de fallas locales mediante faults_files.
  • Las fallas de Angola ya no se toman del cache ni van empaquetadas en kashima/mapper/data/. En su lugar, los GeoJSON convertidos (Angola1982.geojson, Escosa2024.geojson, etc.) viven bajo examples/mapper/faults/ como datos de usuario y se pasan explícitamente en faults_files.
  • Bug original (documentado): se intentó empaquetar Angola_faults.geojson dentro de kashima/mapper/data/ y copiarlo al cache como si fuera otra base global. En instalaciones reales, ese archivo no siempre quedaba disponible en el paquete, por lo que nunca entraba en la lista de fallas cargadas y el mapa sólo mostraba GEM. Ese camino se eliminó en favor del modelo “user faults” descrito arriba.

Objetivo (futuro): añadir, a nivel de API de alto nivel o interfaz de usuario, controles más finos para activar/desactivar fuentes individuales sin tener que manipular fault_sets directamente.

5.4 Flujo de trabajo en rama dev

  1. Confirmar rama actual y cambiar a dev si es necesario:
    • git branch --show-current
    • git checkout dev (si no estás ya en dev).
  2. Actualizar este documento (docs/mapper_layers_plan.md) – ya hecho – describiendo:
    • Estado actual.
    • Plan de cambios para sitio, estaciones y fallas.
  3. Commit del plan en rama dev (cuando lo apruebes):
    • git add docs/mapper_layers_plan.md
    • git commit -m "docs: plan ISC stations and fault handling"
    • git push origin dev
  4. Implementación de código:
    • Ejecutar los pasos 5.1, 5.2 y 5.3 en ese orden, con commits pequeños y bien descriptivos.
  5. Verificación:
    • Regenerar mapas de prueba (longonjo y otros ejemplos) para validar:
      • Estrella en el sitio.
      • Estaciones ISC recortadas por radio.
      • Falla(s) visibles sólo dentro del bound.

Este documento ahora refleja:

  • Las dos rutas posibles para incorporar estaciones ISC (KMZ externo → CSV vs soporte interno de KMZ) y sus pros/contras.
  • Cómo llegan los catálogos y fallas al cache y qué papel tiene (y no tiene) el instalador.
  • Por qué no ves ciertas fallas aunque estén en cache y qué pasos concretos debes seguir para verlas en tus mapas.
  • El plan concreto de modificaciones a aplicar sobre la rama dev para sitio, estaciones ISC y fallas siempre filtradas por el bound del radio.

6. Trabajo futuro (refactor de estilo y nombres)

En una fase posterior (no incluida en 1.3.5) se propone un refactor de estilo para kashima.mapper:

  • Homogeneizar nombres de variables y funciones a un estilo claro y consistente (snake_case en inglés, nombres cortos pero expresivos).
  • Reducir abreviaturas ambiguas y mezclar castellano/inglés en identificadores internos.
  • Revisar parámetros de alto nivel en buildMap/buildCatalog para que sigan las mismas convenciones de nombres que el resto del paquete.
  • Actualizar ejemplos y documentación para reflejar los nuevos nombres, manteniendo alias de compatibilidad donde sea necesario.