miércoles, 21 de enero de 2026

Análisis geoespacial con Python - Parte 2 - Aprendiendo sobre Datos Geoespaciales

Aprendiendo Datos Geoespaciales con Python
Capítulo 02

Aprendiendo Datos Geoespaciales

Python Geospatial Analysis // Learning Geospatial Data

Uno de los aspectos más desafiantes del análisis geoespacial son los datos. Los datos geoespaciales ya incluyen docenas de formatos de archivo y estructuras de bases de datos, y continúan evolucionando para incluir nuevos tipos de datos y estándares. Además, casi cualquier formato de archivo puede contener técnicamente información geoespacial simplemente agregando una ubicación.

En este capítulo exploraremos los formatos de datos comunes, examinaremos las características compartidas de los datos geoespaciales, comprenderemos la indexación espacial, conoceremos los tipos de datos vectoriales y ráster más utilizados, y obtendremos información sobre tipos más complejos como nubes de puntos, servicios web y bases de datos geoespaciales.

SECTION_01

Formatos de Datos Comunes

Como analista geoespacial, frecuentemente encontrarás los siguientes tipos generales de datos. Cada formato contiene sus propios desafíos para el acceso y procesamiento. Cuando realizas análisis sobre datos, generalmente debes hacer alguna forma de preprocesamiento primero.

CSV / TSV
Hojas de cálculo y valores separados por comas o tabulaciones. Formato simple pero efectivo para datos tabulares con coordenadas.
GEOTAGGED PHOTOS
Fotos con metadatos de ubicación GPS embebidos. Capturan información geográfica en el momento de la toma.
BINARY VECTORS
Puntos, líneas y polígonos en formato binario ligero. Eficientes para almacenamiento y procesamiento.
SATELLITE IMAGES
Imágenes satelitales o aéreas de múltiples gigabytes. Requieren hardware y software especializado.
ELEVATION DATA
Grillas, nubes de puntos o imágenes basadas en enteros representando alturas del terreno.
XML / JSON
Formatos estructurados basados en texto. Muy utilizados para intercambio de datos geoespaciales.
DATABASES
Tanto servidores como bases de datos de archivo. Permiten consultas espaciales complejas.
WEB SERVICES
APIs REST y servicios OGC para distribución y acceso a datos geoespaciales en tiempo real.
SECTION_02

Estructuras de Datos

Los datos geoespaciales generalmente caen en dos categorías fundamentales: datos vectoriales y datos ráster. Entender la diferencia entre estas dos estructuras es fundamental para cualquier analista geoespacial.

Tipos Fundamentales de Datos Geoespaciales
GEOSPATIAL DATA
——→
VECTOR
RASTER
VECTOR
Puntos, líneas y polígonos definidos por coordenadas matemáticas. Escalables sin pérdida de calidad.
RASTER
Matrices de celdas o píxeles donde cada celda representa un valor. Similares a imágenes digitales.
HYBRID
Algunos formatos modernos combinan ambos tipos para aprovechar las ventajas de cada uno.
SECTION_03

Indexación Espacial

La indexación espacial organiza los datos geoespaciales de manera que permite un rápido acceso mediante ubicación geográfica. Los conjuntos de datos geoespaciales pueden contener millones de puntos o polígonos, así como imágenes que contienen billones de píxeles. Sin la indexación espacial, incluso las operaciones más simples serían impracticables.

Algoritmos de Indexación

La mayoría de los algoritmos de indexación espacial mapean coordenadas de punto flotante a una grilla de enteros de tamaño fijo. Las comparaciones con enteros son mucho más eficientes computacionalmente que trabajar con números de punto flotante.

Algoritmos Principales
Quadtree
R-tree
Grid Index

Quadtree Index

El índice Quadtree subdivide recursivamente un espacio bidimensional en cuatro cuadrantes. Es particularmente efectivo para datos con distribución desigual, ya que subdivide más las áreas con mayor densidad de datos.

quadtree_concept.py
# Representación conceptual de un Quadtree
class QuadTreeNode:
    def __init__(self, bounds, max_objects=10):
        self.bounds = bounds      # (x, y, width, height)
        self.max_objects = max_objects
        self.objects = []
        self.children = []        # [NW, NE, SW, SE]
    
    def subdivide(self):
        """Divide el nodo en 4 cuadrantes"""
        x, y, w, h = self.bounds
        hw, hh = w / 2, h / 2
        
        self.children = [
            QuadTreeNode((x, y + hh, hw, hh)),      # NW
            QuadTreeNode((x + hw, y + hh, hw, hh)),  # NE
            QuadTreeNode((x, y, hw, hh)),           # SW
            QuadTreeNode((x + hw, y, hw, hh))       # SE
        ]
    
    def insert(self, point):
        """Inserta un punto en el quadtree"""
        if not self._contains(point):
            return False
        
        if len(self.objects) < self.max_objects:
            self.objects.append(point)
            return True
        
        if not self.children:
            self.subdivide()
        
        for child in self.children:
            if child.insert(point):
                return True
        return False

R-tree Index

El índice R-tree agrupa objetos cercanos y los representa con su rectángulo delimitador mínimo (MBR). Es el algoritmo de indexación espacial más utilizado en bases de datos geoespaciales debido a su eficiencia con datos dinámicos.

Los tamaños de grilla pueden ser tan pequeños como 256 x 256 para formatos de archivo simples, o tan grandes como 3 millones x 3 millones en bases de datos geoespaciales diseñadas para incorporar cada sistema de coordenadas y resolución posible.

Overviews (Pirámides)

Los datos de overview son versiones remuestreadas y de menor resolución de conjuntos de datos ráster que proporcionan vistas en miniatura o simplemente vistas de carga más rápida a diferentes escalas de mapa. También se conocen como pirámides.

1:1 (Full Resolution)
1:4 (25% Resolution)
1:16 (6.25% Resolution)
1:64 (Thumbnail)
El compromiso de esta conveniencia es que las imágenes adicionales aumentan el tamaño total del archivo del conjunto de datos; sin embargo, aceleran los visores de imágenes significativamente.
SECTION_04

Metadatos Geoespaciales

Los metadatos son cualquier dato que describe el conjunto de datos asociado. Los ejemplos comunes incluyen elementos básicos como la huella del conjunto de datos en la Tierra, así como información más detallada como la proyección espacial e información que describe cómo se creó el conjunto de datos.

FOOTPRINT
Extensión geográfica del dataset en la superficie terrestre
PROJECTION
Sistema de coordenadas y proyección cartográfica utilizada
LINEAGE
Historia de creación, fuentes y transformaciones aplicadas

Estructura de Archivos Típica

📁 geospatial_project/ ├── data.shp ← Geometrías ├── data.shx ← Índice espacial ├── data.dbf ← Atributos (dBASE) ├── data.prj ← Proyección (WKT) ├── data.cpg ← Codificación └── data.xml ← Metadatos ISO
SECTION_05

Tipos de Datos Vectoriales

Los datos vectoriales representan características geográficas usando geometrías definidas matemáticamente: puntos, líneas y polígonos con coordenadas precisas. Esta precisión hace que los datos vectoriales sean ideales para representar límites, carreteras, edificios y otras características discretas.

Shapefiles

El formato shapefile, desarrollado por Esri, es el estándar de facto para datos vectoriales geoespaciales. A pesar de sus limitaciones (nombres de campo de 10 caracteres, tamaño máximo de 2GB), sigue siendo el formato más ampliamente soportado.

read_shapefile.py
import struct

# Leer el bounding box de un shapefile
def read_shapefile_bbox(shp_path):
    """Lee el bounding box desde el header del shapefile"""
    with open(shp_path, 'rb') as f:
        # Saltar al byte 36 donde inicia el bbox
        f.seek(36)
        
        # Leer 8 valores double (64 bytes)
        bbox_data = f.read(64)
        bbox = struct.unpack('<8d', bbox_data)
        
        return {
            'x_min': bbox[0],
            'y_min': bbox[1],
            'x_max': bbox[2],
            'y_max': bbox[3],
            'z_min': bbox[4],
            'z_max': bbox[5],
            'm_min': bbox[6],
            'm_max': bbox[7]
        }

# Uso
bbox = read_shapefile_bbox('mi_archivo.shp')
print(f"Extensión: {bbox['x_min']:.4f}, {bbox['y_min']:.4f}")
print(f"         a {bbox['x_max']:.4f}, {bbox['y_max']:.4f}")
python read_shapefile.py
Extensión: -89.6700, 30.1730
a -89.0200, 30.6470

GeoJSON

GeoJSON es un formato basado en JSON para codificar estructuras de datos geográficos. Su sintaxis amigable con JavaScript lo convierte en el formato preferido para aplicaciones web y APIs REST geoespaciales.

geojson_example.py
# GeoJSON es válido tanto como JSON como Python dict
geometry_collection = {
    "type": "GeometryCollection",
    "geometries": [
        {
            "type": "Point",
            "coordinates": [-89.33, 30.0]
        },
        {
            "type": "LineString",
            "coordinates": [
                [-89.33, 30.30],
                [-89.36, 30.28]
            ]
        },
        {
            "type": "Polygon",
            "coordinates": [[
                [-104.05, 48.99],
                [-97.22, 48.98],
                [-96.58, 45.94],
                [-104.03, 45.94],
                [-104.05, 48.99]
            ]]
        }
    ]
}

# Acceder a los datos directamente
print(geometry_collection['geometries'][0])
# {'type': 'Point', 'coordinates': [-89.33, 30.0]}
Debido a su tamaño compacto, sintaxis amigable con internet y soporte de los principales lenguajes de programación, GeoJSON es un componente clave de las principales APIs web geoespaciales REST.

GeoPackage

GeoPackage es un estándar abierto de OGC basado en SQLite. Es un contenedor de base de datos basado en archivos que es independiente de plataforma, proveedor y software. Representa un intento de alejarse de los problemas generados por formatos de datos propietarios o limitados.

.shp
Shapefile
.geojson
GeoJSON
.gpkg
GeoPackage
.kml
Keyhole ML
.gml
Geography ML
.dxf
AutoCAD
.wkt
Well-Known Text
.csv
Con coordenadas
SECTION_06

Tipos de Datos Ráster

Los datos ráster consisten en filas y columnas de celdas o píxeles, donde cada celda representa un único valor. La forma más fácil de pensar en los datos ráster es como imágenes. Sin embargo, los conjuntos de datos ráster no necesariamente se almacenan como imágenes; también pueden ser archivos de texto ASCII o BLOBs en bases de datos.

Resolución Geoespacial

Una diferencia clave entre los datos ráster geoespaciales y las imágenes digitales regulares es cómo expresan la resolución. Las imágenes digitales expresan la resolución como puntos por pulgada (DPI) o megapíxeles totales. Los datos ráster geoespaciales usan la distancia en el terreno que cada celda representa.

FORMATO TIPO CARACTERÍSTICAS
TIFF/GeoTIFF Imagen Metadatos geoespaciales embebidos, múltiples bandas
JPEG Comprimido Con pérdida, pequeño tamaño, requiere world file
PNG Comprimido Sin pérdida, transparencia, ideal para web
ASCII Grid Texto Legible por humanos, portable pero grande
MrSID/ECW Wavelet Alta compresión, acceso aleatorio eficiente
NetCDF/HDF Científico Multidimensional, metadatos extensivos

ASCII Grid Format

Los ASCII Grids son archivos de texto plano que representan datos ráster. Aunque no son eficientes en espacio, son fáciles de leer, crear y depurar, haciéndolos ideales para intercambio de datos y aprendizaje.

ascii_grid_example.asc
ncols         5
nrows         4
xllcorner     -89.5
yllcorner     30.0
cellsize      0.1
NODATA_value  -9999
100 110 120 115 105
105 115 125 120 110
110 120 130 125 115
115 125 135 130 120
read_ascii_grid.py
def read_ascii_grid(filepath):
    """Lee un archivo ASCII Grid y retorna header + datos"""
    with open(filepath, 'r') as f:
        # Leer header (6 líneas)
        header = {}
        for _ in range(6):
            line = f.readline().split()
            header[line[0].lower()] = float(line[1])
        
        # Leer datos como matriz
        data = []
        for line in f:
            row = [float(val) for val in line.split()]
            data.append(row)
    
    return header, data

# Uso
header, elevation = read_ascii_grid('terrain.asc')
print(f"Grid: {int(header['ncols'])}x{int(header['nrows'])}")
print(f"Cell size: {header['cellsize']} degrees")
print(f"Max elevation: {max(max(row) for row in elevation)}")
python read_ascii_grid.py
Grid: 5x4
Cell size: 0.1 degrees
Max elevation: 135.0

World Files

Los world files son archivos sidecar que proporcionan información de georreferenciación para imágenes que no tienen metadatos espaciales embebidos. La extensión sigue un patrón: primera letra, última letra, 'w' (ej: .jgw para .jpg, .pgw para .png).

image.jgw
0.000278    # Tamaño de pixel en X (grados)
0.000000    # Rotación sobre eje Y
0.000000    # Rotación sobre eje X
-0.000278   # Tamaño de pixel en Y (negativo = norte arriba)
-89.500000  # Coordenada X del centro del pixel superior izq
30.500000   # Coordenada Y del centro del pixel superior izq
SECTION_07

Datos de Nubes de Puntos

Las nubes de puntos representan datos 3D como colecciones de puntos individuales, cada uno con coordenadas X, Y, Z y opcionalmente atributos adicionales como intensidad o color. Son producidas principalmente por sensores LIDAR (Light Detection and Ranging).

🛰️
AIRBORNE
🚗
MOBILE
📷
TERRESTRIAL
🤖
ROBOTIC
📱
HANDHELD

LIDAR

LIDAR usa pulsos láser para medir distancias con precisión milimétrica. Un sensor LIDAR aerotransportado puede capturar millones de puntos por segundo, creando representaciones 3D detalladas del terreno y las estructuras sobre él.

lidar_point_structure.py
import struct

# Estructura básica de un punto LAS
class LidarPoint:
    """Representa un punto LIDAR en formato LAS"""
    
    def __init__(self, x, y, z, intensity=0, classification=0):
        self.x = x                    # Coordenada Este
        self.y = y                    # Coordenada Norte
        self.z = z                    # Elevación
        self.intensity = intensity    # Intensidad del retorno
        self.classification = classification
        
    @property
    def class_name(self):
        """Clasificación ASPRS estándar"""
        classes = {
            0: 'Never Classified',
            1: 'Unassigned',
            2: 'Ground',
            3: 'Low Vegetation',
            4: 'Medium Vegetation',
            5: 'High Vegetation',
            6: 'Building',
            7: 'Low Point (Noise)',
            9: 'Water',
        }
        return classes.get(self.classification, 'Other')

# Ejemplo de uso
point = LidarPoint(500000.5, 4500000.3, 125.7, 45, 6)
print(f"Punto: ({point.x}, {point.y}, {point.z})")
print(f"Clasificación: {point.class_name}")
python lidar_point_structure.py
Punto: (500000.5, 4500000.3, 125.7)
Clasificación: Building
SECTION_08

Servicios Web Geoespaciales

Los servicios web permiten el acceso a datos geoespaciales a través de internet usando protocolos estándar. El Open Geospatial Consortium (OGC) ha definido especificaciones estándar que aseguran la interoperabilidad entre diferentes sistemas.

Servicios OGC Principales
WFS
WMS
WCS
WMTS
WMS
Web Map Service - Retorna imágenes renderizadas de mapas. El servidor realiza la simbolización.
WFS
Web Feature Service - Retorna datos vectoriales en bruto (GML/GeoJSON) para procesamiento cliente.
WCS
Web Coverage Service - Retorna datos ráster en bruto para análisis, no solo visualización.
WMTS
Web Map Tile Service - Retorna tiles pre-renderizados para visualización rápida.

Ejemplo: Consulta WFS

wfs_request.py
import requests

def get_features_wfs(base_url, typename, bbox=None):
    """Consulta un servicio WFS y retorna GeoJSON"""
    
    params = {
        'service': 'WFS',
        'version': '2.0.0',
        'request': 'GetFeature',
        'typeName': typename,
        'outputFormat': 'application/json',
        'srsName': 'EPSG:4326'
    }
    
    if bbox:
        params['bbox'] = ','.join(map(str, bbox))
    
    response = requests.get(base_url, params=params)
    response.raise_for_status()
    
    return response.json()

# Uso
try:
    features = get_features_wfs(
        'https://example.com/geoserver/wfs',
        'namespace:layer_name',
        bbox=[-90, 30, -89, 31]
    )
    print(f"Features encontrados: {len(features['features'])}")
except Exception as e:
    print(f"Error: {e}")
SECTION_09

Bases de Datos Geoespaciales

Las geodatabases son bases de datos convencionales con extensiones espaciales que permiten almacenar, consultar y analizar datos geométricos. La geometría se almacena típicamente en una columna de tipo espacial junto con las columnas de atributos tradicionales.

Arquitectura de Geodatabase
GEODATABASE
Geometry Column
Attribute Columns
Spatial Index

PostgreSQL/PostGIS

PostGIS es la extensión espacial más popular para PostgreSQL. Proporciona soporte para objetos geográficos, permitiendo consultas SQL espaciales avanzadas.

postgis_query.sql
-- Crear tabla con geometría
CREATE TABLE cities (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    population INTEGER,
    geom GEOMETRY(Point, 4326)
);

-- Insertar punto
INSERT INTO cities (name, population, geom)
VALUES (
    'New Orleans', 
    390144,
    ST_SetSRID(ST_MakePoint(-90.0715, 29.9511), 4326)
);

-- Consulta espacial: ciudades dentro de 100km
SELECT name, population,
       ST_Distance(
           geom::geography,
           ST_SetSRID(ST_MakePoint(-90.0, 30.0), 4326)::geography
       ) / 1000 AS distance_km
FROM cities
WHERE ST_DWithin(
    geom::geography,
    ST_SetSRID(ST_MakePoint(-90.0, 30.0), 4326)::geography,
    100000  -- 100 km en metros
);
Los grandes conjuntos de datos ráster geoespaciales raramente se almacenan directamente en la base de datos. Típicamente, los datos ráster se almacenan en disco y solo una referencia al archivo se guarda en la base de datos junto con el footprint geométrico.

Resumen del Capítulo

01 // Formatos de Datos

Los datos geoespaciales vienen en docenas de formatos: CSV, imágenes, XML, JSON, bases de datos y servicios web. Cada uno tiene sus desafíos únicos.

02 // Vector vs Ráster

Vectoriales para características discretas (puntos, líneas, polígonos). Ráster para datos continuos (imágenes, elevación, temperatura).

03 // Indexación Espacial

Quadtree, R-tree y grillas permiten búsquedas espaciales eficientes en millones de registros o billones de píxeles.

04 // Shapefiles & GeoJSON

Shapefile sigue siendo el estándar de facto. GeoJSON domina las APIs web por su simplicidad y compatibilidad con JavaScript.

05 // Nubes de Puntos

LIDAR genera millones de puntos 3D por segundo. Cada punto tiene coordenadas XYZ, intensidad y clasificación.

06 // Servicios OGC

WMS para mapas renderizados, WFS para vectores, WCS para ráster, WMTS para tiles. Estándares que garantizan interoperabilidad.

Basado en "Learning Geospatial Analysis with Python" // Joel Lawhead

Chapter 2: Learning Geospatial Data

Publisher: Packt Publishing // Third Edition 2019