Estoy buscando una manera de definir automáticamente los barrios de las ciudades como polígonos en un gráfico.
Mi definición de vecindario tiene dos partes:
- Un bloque : un área cerrada entre varias calles, donde la cantidad de calles (bordes) e intersecciones (nodos) es un mínimo de tres (un triángulo).
- Un vecindario : para cualquier bloque dado, todos los bloques directamente adyacentes a ese bloque y al bloque mismo.
Vea esta ilustración para un ejemplo:
Por ejemplo, B4 es un bloque definido por 7 nodos y 6 aristas que los conectan. Como la mayoría de los ejemplos aquí, los otros bloques están definidos por 4 nodos y 4 bordes que los conectan. Además, el vecindario de B1 incluye B2 (y viceversa) mientras que B2 también incluye B3 .
Estoy usando osmnx para obtener datos de la calle de OSM.
- Usando osmnx y networkx, ¿cómo puedo atravesar un gráfico para encontrar los nodos y bordes que definen cada bloque?
- Para cada bloque, ¿cómo puedo encontrar los bloques adyacentes?
Estoy trabajando en un código que toma un gráfico y un par de coordenadas (latitud, longitud) como entrada, identifica el bloque relevante y devuelve el polígono para ese bloque y el vecindario como se definió anteriormente.
Aquí está el código utilizado para hacer el mapa:
import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt
G = ox.graph_from_address('Nørrebrogade 20, Copenhagen Municipality',
network_type='all',
distance=500)
y mi intento de encontrar camarillas con diferente número de nodos y grados.
def plot_cliques(graph, number_of_nodes, degree):
ug = ox.save_load.get_undirected(graph)
cliques = nx.find_cliques(ug)
cliques_nodes = [clq for clq in cliques if len(clq) >= number_of_nodes]
print("{} cliques with more than {} nodes.".format(len(cliques_nodes), number_of_nodes))
nodes = set(n for clq in cliques_nodes for n in clq)
h = ug.subgraph(nodes)
deg = nx.degree(h)
nodes_degree = [n for n in nodes if deg[n] >= degree]
k = h.subgraph(nodes_degree)
nx.draw(k, node_size=5)
Teoría que podría ser relevante:
Respuestas:
Encontrar bloques de ciudades usando el gráfico es sorprendentemente no trivial. Básicamente, esto equivale a encontrar el conjunto más pequeño de anillos más pequeños (SSSR), que es un problema NP-completo. Una revisión de este problema (y problemas relacionados) se puede encontrar aquí . En SO, hay una descripción de un algoritmo para resolverlo aquí . Por lo que puedo decir, no hay una implementación correspondiente en
networkx
(o en Python para el caso). Probé este enfoque brevemente y luego lo abandoné: mi cerebro no está preparado para ese tipo de trabajo hoy. Dicho esto, otorgaré una recompensa a cualquiera que visite esta página más adelante y publique una implementación probada de un algoritmo que encuentre el SSSR en Python.En cambio, he seguido un enfoque diferente, aprovechando el hecho de que se garantiza que el gráfico sea plano. Brevemente, en lugar de tratar esto como un problema gráfico, tratamos esto como un problema de segmentación de imagen. Primero, encontramos todas las regiones conectadas en la imagen. Luego determinamos el contorno alrededor de cada región, transformamos los contornos en las coordenadas de la imagen a longitudes y latitudes.
Dadas las siguientes importaciones y definiciones de funciones:
Cargar los datos. Guarde en caché las importaciones, si lo prueba repetidamente, de lo contrario su cuenta puede ser bloqueada. Hablando por experiencia aquí.
Pode nodos y bordes que no pueden ser parte de un ciclo. Este paso no es estrictamente necesario pero da como resultado contornos más bonitos.
Convierta la trama en imagen y encuentre regiones conectadas:
Para cada región etiquetada, encuentre el contorno y convierta las coordenadas del píxel del contorno nuevamente en coordenadas de datos.
Determine todos los puntos en el gráfico original que caen dentro (o sobre) el contorno.
Averiguar si dos bloques son vecinos es bastante fácil. Solo verifique si comparten un nodo:
fuente
No estoy completamente seguro de que eso
cycle_basis
te dará los vecindarios que buscas, pero si lo hace, es algo sencillo obtener el gráfico de vecindario:fuente
nx.Graph(G)
, estoy perdiendo mucha información (dirección y tipo de gráfico múltiple), por lo que me resulta difícil verificar su respuesta, ya que parece que no puedo relacionar el nuevo gráficoI
con Mi gráfico originalG
.No tengo un código, pero supongo que una vez que esté en la acera, si sigo girando a la derecha en cada esquina, recorreré los bordes de mi bloque. No conozco las bibliotecas, así que hablaré algo aquí.
En realidad, es un algoritmo para salir de un laberinto: mantén la mano derecha en la pared y camina. No funciona en caso de bucles en el laberinto, solo tienes que recorrer. Pero le da una solución a su problema.
fuente
Esta es una implementación de la idea de Hashemi Emad . Funciona bien siempre que se elija la posición inicial de tal manera que exista una forma de avanzar en sentido antihorario en un círculo cerrado. Para algunos bordes, en particular alrededor del exterior del mapa, esto no es posible. No tengo idea de cómo seleccionar buenas posiciones iniciales, o cómo filtrar soluciones, pero tal vez alguien más tenga una.
Ejemplo de trabajo (comenzando con edge (1204573687, 4555480822)):
Ejemplo, donde este enfoque no funciona (comenzando con edge (1286684278, 5818325197)):
Código
fuente