Una red es un sistema de elementos interconectados entre sí con una lógica y topología interna, como bordes (líneas) y cruces de conexión (puntos), que representan las posibles rutas desde una ubicación origen a una ubicación de destino. En este artículo aprenderemos cómo obtener redes de viarias de OpenStreetMap usando la librería Python OSMnx y realizar ciertos análisis con NetworkX.
Dentro de los Sistemas de Información Geográfica, el uso más extendido de los datos en un modelo de red es el del análisis de costes movimiento sobre una infraestructura viaria. Los trabajos con bases vectoriales en este formato se amplían a estudios de conectividad entre nodos (árbol de recubrimiento mínimo), análisis de centralidad, cálculo de áreas de servicio, obtención de isócronas…
Gracias a la potencia de estos cálculos basados en la teoría de grafos, la aplicación de los trabajos con redes no se limita exclusivamente a estudios sobre redes de transporte. La existencia datos topológicamente correctos van a permitir modelar otras entidades del mundo real como infraestructuras de saneamiento y abastecimiento de agua, redes de Fibra (FTTH) o eléctricas. Como ejemplo de aplicaciones específicas de datos en red con software open source podemos citar GISWater para infraestructuras hidráulicas o QElectricGIS para redes eléctricas.
Si bien, el trabajo creación, edición y análisis de la red suele hacerse en la mayoría de los casos con un Sistema de Información Geográfica como QGIS existe también la posibilidad de trabajar con realizar estos ciertos trabajos directamente con Python apoyándonos en librerías específicas.
Librerías Python de redes
OSMnx
La librería OSMnx desarrollada por Geoff Boeing nos va a dar la posibilidad de descargar la información de redes transporte de la gran base de datos geográfica abierta del proyecto OpenStreetMap (OSM).
El modelo de datos OSM para calles y carreteras es muy completo. Los datos recopilados incluyen distintas tipologías de viarios (autovías, carreteras principales y secundarias, senderos, caminos peatonales…) y atributos vinculados con la circulación como son la velocidad, giro, sentido o restricciones.

Gracias a OSMnx podremos descargar de forma automática conjuntos de datos para un municipio, un barrio, una calle o una distancia y todo con una estructura topológica basada en arcos y nodos que nos permitirá su estudio y análisis.
NetworkX
NetworkX es una biblioteca de Python para el estudio de grafos y análisis de redes. Combinado la potencia de análisis con los datos descargados con OSMnx podremos realizar análisis de caminos más cortos, orientaciones, estadísticas sobre la red…

Toda la información sobre esta librería es accesible desde la dirección https://networkx.org/
Herramientas Python para análisis geográfico: Jupyter Lab y Conda
Para los siguientes ejemplos vamos a trabajar con Jupyter Lab, un entorno de trabajo interactivo web ideal para trabajar en el ámbito científico con Python. Gracias a esta aplicación podremos combinar elementos de código interactivo, textos, imágenes y otras fuentes de datos que se pueden manejar en proyectos científicos de todo tipo.
La instalación de las librerías se ha realizado mediante el gestor de paquetes de código abierto, multiplataforma Conda que nos facilitará también la gestión de entornos virtuales.
Todas estas aplicaciones pueden ser instaladas de forma independiente o usar la distribución Anaconda utilizada en ciencia de datos y que incluye un numeroso elenco de herramientas para ello.
Adquisición de datos viarios de OpenStreetMap con OSMnx
Una vez abierto Jupyter Lab, lo primero que vanos a necesitar es importar las geolibrerías que previamente hemos instalado gracias a Conda.
import osmnx as ox
import networkx as nx
Usando osmnx vamos a descargarnos la red viaria del barrio de Ciudad Jardín de la ciudad de Córdoba (España). Para ellos usaremos el método graph_from_place() que localiza el nombre del barrio en OpenStreetMap y descarga la red pensada para transporte con vehículo. Existen otras opciones como la consulta por coordenadas, distancia y los tipos de red pueden ser también de tipo ciclista o para peatones.
place_name = "Ciudad Jardín, Córdoba, Spain"
graph = ox.graph_from_place(place_name, network_type="drive")
Podemos después obtener una imagen de la red apreciando los arcos y nodos del grafo descargado usando plot_graph()
fig, ax = ox.plot_graph(graph, node_color="r")

Existen otras opciones interesantes dentro de la librería. Si lo deseamos, obtener un visor interactivo con la red usando Folium.
ox.plot_graph_folium(graph, popup_attribute='name',
color='red', weight=2, opacity=0.7)

Con la función save_graph_geopackage () guardaremos los datos en formato vectorial para poder usarlos en nuestro GIS. En el ejemplo guardaremos los datos en formato geopackage y los cargaremos en QGIS.
ox.save_graph_geopackage(graph, filepath="cordoba_net.gpkg")

Análisis de camino más corto
Usaremos la función de OSMnx que nos va a calcular la ruta óptima entre dos nodos del mapa.
En primer lugar debemos definir las variables de nodos de origen y destino más cercano a partir de unas coordenadas.
orig = ox.distance.nearest_nodes(graph, X=-4.7943378, Y=37.8831953)
dest = ox.distance.nearest_nodes(graph, X=-4.7870238, Y=37.8831438)
Estos datos los usaremos posteriormente para realizar el cálculo de la ruta más corta basada en la distancia.
route = ox.shortest_path(graph, orig, dest, weight="length")
fig, ax = ox.plot_graph_route(graph, route, node_size=0)

La librería permite también añadir los datos de tiempo de viaje basados en las limitaciones de velocidad de las vías según estén almacenadas en OpenStreetMap. Así, una ruta podría ser más corta pero no ser la óptima por un límite de velocidad menor respecto en la que esté permitido ir más rápido.
Si en vez de trabajar con viales pensados para el tráfico rodado, descargamos el grafo añadiendo caminos y senderos para peatones, podemos ver que la ruta difiere al interior. La imagen muestra como no se tiene en cuenta el sentido de la circulación y además no dirige por senderos dentro de un parque cercano.

Análisis estadísticos y de centralidad
Con todas estas herramientas Python y los datos obtenidos podemos realizar análisis más concretos sobre la red.
Volvemos a usar OSMnx para obtener un informe de estadísticas de la red (total de nodos, longitud total de la red, distancia media de tramos, nº de intersecciones, total de segmentos de calle…)
ox.basic_stats(graph_drive)

Con NetworkX podemos realizar también estudios de centralidad identificando aquellas vías más críticas o influyentes de la red. En el ejemplo se calcula la suma de las distancias de ruta más cortas de un nodo a todos los demás nodos de la red y obteniendo los viales más centralizados.
edge_centrality = nx.closeness_centrality(nx.line_graph(graph))
nx.set_edge_attributes(graph, edge_centrality, "edge_centrality")
ec = ox.plot.get_edge_colors_by_attr(graph, "edge_centrality", cmap="inferno")
fig, ax = ox.plot_graph(graph, edge_color=ec, edge_linewidth=3, node_size=0)

Conclusión
Como podemos apreciar Python puede ser un gran aliado para el trabajo con datos de tipo geoespacial, en este caso de tipo de red. Los scripts que programemos pueden ser posteriormente reaprovechados para otros tipos de áreas o estudios, permitiendo así sacarle la máxima rentabilidad a nuestro trabajo con estas potentes librerías.
¿Quieres comentarnos algo? Adelante!