Estou procurando uma maneira de definir automaticamente bairros nas cidades como polígonos em um gráfico.
Minha definição de bairro tem duas partes:
- Um quarteirão : uma área dividida entre várias ruas, em que o número de ruas (arestas) e cruzamentos (nós) é no mínimo três (um triângulo).
- Uma vizinhança : para qualquer bloco, todos os blocos diretamente adjacentes a esse bloco e o próprio bloco.
Veja esta ilustração para um exemplo:
Por exemplo, B4 é um bloco definido por 7 nós e 6 arestas conectando-os. Como a maioria dos exemplos aqui, os outros blocos são definidos por 4 nós e 4 arestas conectando-os. Além disso, o bairro de B1 inclui B2 (e vice-versa) enquanto B2 também inclui B3 .
Estou usando o osmnx para obter dados de ruas do OSM.
- Usando osmnx e networkx, como posso percorrer um gráfico para encontrar os nós e arestas que definem cada bloco?
- Para cada bloco, como posso encontrar os blocos adjacentes?
Estou trabalhando em direção a um pedaço de código que usa um gráfico e um par de coordenadas (latitude, longitude) como entrada, identifica o bloco relevante e retorna o polígono para esse bloco e a vizinhança, conforme definido acima.
Aqui está o código usado para fazer o 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)
e minha tentativa de encontrar panelinhas com número diferente de nós e graus.
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)
Teoria que pode ser relevante:
Respostas:
Encontrar blocos urbanos usando o gráfico é surpreendentemente não trivial. Basicamente, isso equivale a encontrar o menor conjunto de anéis menores (SSSR), que é um problema completo do NP. Uma revisão deste problema (e problemas relacionados) pode ser encontrada aqui . No SO, há uma descrição de um algoritmo para resolvê-lo aqui . Até onde eu sei, não existe uma implementação correspondente em
networkx
(ou em python). Tentei essa abordagem brevemente e depois a abandonei - meu cérebro não está preparado para esse tipo de trabalho hoje. Dito isto, concederei uma recompensa a qualquer pessoa que possa visitar esta página posteriormente e publicarei uma implementação testada de um algoritmo que encontra o SSSR em python.Em vez disso, segui uma abordagem diferente, aproveitando o fato de que o gráfico é garantido como plano. Resumidamente, em vez de tratar isso como um problema gráfico, tratamos isso como um problema de segmentação de imagem. Primeiro, encontramos todas as regiões conectadas na imagem. Em seguida, determinamos o contorno em torno de cada região, transformamos os contornos das coordenadas da imagem em longitudes e latitudes.
Dadas as seguintes importações e definições de função:
Carregue os dados. Faça o cache das importações, se estiver testando isso repetidamente - caso contrário, sua conta poderá ser banida. Falando por experiência aqui.
Remova nós e arestas que não podem fazer parte de um ciclo. Esta etapa não é estritamente necessária, mas resulta em contornos mais agradáveis.
Converta plotagem em imagem e encontre regiões conectadas:
Para cada região rotulada, localize o contorno e converta as coordenadas de pixel de contorno novamente em coordenadas de dados.
Determine todos os pontos no gráfico original que caem dentro (ou sobre) o contorno.
Descobrir se dois quarteirões são vizinhos é bastante fácil. Basta verificar se eles compartilham um nó:
fonte
Não tenho certeza absoluta de que
cycle_basis
irá fornecer os bairros que você procura, mas, se isso acontecer, é simples obter o gráfico do bairro:fonte
nx.Graph(G)
isso, estou perdendo muitas informações (tipo de direcionamento e multigraph), por isso estou tendo dificuldades para verificar sua resposta, pois não consigo relacionar o novo gráficoI
com meu gráfico originalG
.Não tenho código, mas acho que quando estiver na calçada, se continuar virando à direita em cada esquina, percorrerei as bordas do meu bloco. Eu não conheço as bibliotecas, então vou falar algo aqui.
Na verdade, é um algoritmo a ser usado para sair de um labirinto: mantenha a mão direita na parede e ande. Não funciona no caso de loops no labirinto, você apenas dá voltas. Mas dá uma solução para o seu problema.
fonte
Esta é uma implementação da ideia de Hashemi Emad . Funciona bem desde que a posição inicial seja escolhida de forma que exista uma maneira de avançar no sentido anti-horário em um círculo apertado. Para algumas arestas, principalmente na parte externa do mapa, isso não é possível. Não faço ideia de como selecionar boas posições iniciais ou como filtrar soluções - mas talvez alguém tenha uma.
Exemplo de trabalho (começando com a borda (1204573687, 4555480822)):
Exemplo, em que essa abordagem não funciona (começando com a borda (1286684278, 5818325197)):
Código
fonte