Mineração de Dados Geoespaciais - Anexo I

Fernando Ferraz Ribeiro

Beth Leite Soares

O objetivo deste notebook é juntar dados de um shapefile com um mapa do Open Street Maps(OSM)

Testando o ambiente de trabalho (conda environment)

Mostrando o caminho que o servidor Jupyter carrega o interpretador Python (python.exe) e carregas o anbiente (\envs)

In [1]:
import os
import sys
print(sys.executable)
pathFix = sys.prefix
print(pathFix)
C:\Users\ffrib\AppData\Local\conda\conda\envs\Geodata_2018_12_08\python.exe
C:\Users\ffrib\AppData\Local\conda\conda\envs\Geodata_2018_12_08

Lidando com erros do ambiente (WINDOWS ONLY)

Algumas bibliotecas importadas apresentam um erro apenas na plataforma Windows.

Caso esteja rodando no windows e tenha problemas com o sistema de coordenadas de referência (crs), rode a linha de comando abaixo:

In [2]:
pathFix = pathFix .replace('\\', '/')
print(pathFix)
os.environ["PROJ_LIB"] =   pathFix + "/Library/share"
C:/Users/ffrib/AppData/Local/conda/conda/envs/Geodata_2018_12_08

mais informações no Post sobre o Erro

Importando Bibliotecas

In [3]:
# Biblioteca basica de programação científica em python
import numpy as np
# biblioteca de análise de dados
import pandas as pd
# biblioteca de gráficos
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.colors as colors
# Bibliotecas geopandas
import geopandas as gpd
# biblioteca de redes complexas
import networkx as nx
# biblioteca para acessar dados do Open sreet maps
import osmnx as ox
# ler dados remotamente da internet
In [4]:
%matplotlib inline
ox.config(use_cache=True, log_console=True)
ox.__version__
Out[4]:
'0.8.2'

Criando coordenadas de recorte

In [5]:
# coordenada inicial x
xSC = 555000
# variação da coordenada x
deltaX = 2000
# coordenada inicial y
ySC = 8570000
# variação da coordenada y
deltaY = 2000

Limites da importaçâo

In [6]:
from shapely.geometry import Polygon

recorte = gpd.GeoSeries([ Polygon([(xSC,ySC), (xSC + deltaX , ySC), (xSC + deltaX, ySC + deltaY ), (xSC, ySC + deltaY )]) ])

A geometria criada pela linha de comando acima, embora tenha as corrdenadas relativas ao sistema de projeção Sigras 2000, não tem nenhuma informação georreferenciada. É preciso informar qual o sistema de coordinadas de referência utilizado ( coordenates reference sistem - crs). O Bloco de código abaxo informa que as coordenadas do recorte devem ser tratadas com o sistema Sigras 2000. com unidades em metro.

In [7]:
# colocando em coordenaadas SIRGAS 2000
recorte.crs = {'proj': 'utm', 'zone': 24, 'south': True, 'ellps': 'aust_SA', 'units': 'm', 'no_defs': True}

Carregando shapes

In [8]:
# importando Shape dos bairros - polígonos
bairros = gpd.read_file('../shapefiles/BaseSSA/Limites/bairros_fim.shp', bbox = recorte )

# importando Shape das edificaçõs - polilinhas
edf = gpd.read_file('../shapefiles/BaseSSA/edificacoes_polyline.shp', bbox = recorte)

# importando shape de pontos
edf_pt = gpd.read_file('../shapefiles/BaseSSA/edificacoes_point.shp', bbox = recorte)

Mostrando os dados dos shapes

dados do shape bairros

In [9]:
bairros.head()
Out[9]:
OBJECTID BR_ BR_ID NM_BAIRROS Shape_Leng Shape_Area geometry
0 89 2 1 Lobato 10290.734146 1.508163e+06 POLYGON ((556643.6323074758 8573040.904571733,...
1 91 2 1 Massaranduba 5027.152427 5.301521e+05 POLYGON ((555124.2668471506 8570956.484697679,...
2 92 2 1 Santa Luzia 5579.648112 3.957189e+05 POLYGON ((556131.141931782 8571133.633667247, ...
3 98 2 1 Alto do Cabrito 5031.429303 1.112943e+06 POLYGON ((557394.0547874847 8572993.633136973,...
4 99 2 1 Capelinha 3337.251376 4.201418e+05 POLYGON ((556500.9559292701 8570974.556498181,...

Dados do shape edificacoes

In [10]:
edf.head()
Out[10]:
ID geometry
0 357236 LINESTRING (555000.0316226622 8570905.59166144...
1 357238 LINESTRING (554999.0173801129 8570926.86740669...
2 357239 LINESTRING (555000.4686540046 8570930.90659893...
3 357240 LINESTRING (555002.9094328225 8570934.45588914...
4 357241 LINESTRING (555009.4978864561 8570930.67664492...
In [11]:
edf_pt.head()
Out[11]:
ID geometry
0 367175 (POINT (556360.5184374301 8570865.76962509))
1 367176 (POINT (556360.5184374301 8570865.76962509))
2 367177 (POINT (556360.5184374301 8570865.76962509))
3 367178 (POINT (556497.9771634268 8571237.37531103))
4 367179 (POINT (556360.5184374301 8570865.76962509))

Plotando imagens

limites do recorte

In [12]:
fig, layers = plt.subplots(figsize=(10,10)
                            #,dpi=30
                           )
# pltando a imagem de fundo
recorte.plot(ax = layers, color = 'blue', alpha = 1)
# Plotando os bairros

# layers - quadro o qual poderá ser alterado os valores de xmin, xmax, título e etc

# Plotando os bairros
bairros.plot(ax= layers, color='yellowgreen', edgecolor='black', linestyle="--", lw= 1.5, alpha=1) 

# Plotando as edificações com a cor vermelha
edf.plot(ax= layers, color='darkred', lw= 0.7)

try:
    edf_pt.plot(ax= layers, color='orange', lw= 0.7, )
except:
    pass
# titulo da figura
fig.suptitle('Imagem Teste', fontsize=16)

# limites do gráfico
layers.set_xlim(xSC, xSC + deltaX )
layers.set_ylim(ySC,  ySC + deltaY )

#fig.show()
Out[12]:
(8570000, 8572000)

Lendo Arquivos do banco de dados espaciais online Open Street maps

Através de arquivo baixado manualmente pelo site

In [13]:
gFile = ox.graph_from_file('../OSM/map.osm')
In [14]:
gFile
Out[14]:
<networkx.classes.multidigraph.MultiDiGraph at 0x1df6fd9f4e0>
In [15]:
fig, ax = ox.plot_graph(gFile)
plt.tight_layout()
<Figure size 432x288 with 0 Axes>

Baixando arquivos por coordenadas limite

O open street maps trabalha com coordenadas WGS84, definidas pelo código epsg 4326. O sistema WGS84 utiliza coordenadas em graus de latitude e longitude.

In [16]:
recorte.bounds
Out[16]:
minx miny maxx maxy
0 555000.0 8570000.0 557000.0 8572000.0

Para utilizar a mesma geometria limite da utilizada para a importação do Shapefile, é preciso converter o sistema de coordenadas de referência de Sigras 2000 para WGS84.

In [17]:
recorte_LL = recorte.to_crs({'init': 'epsg:4326'})
recorte_LL.bounds
Out[17]:
minx miny maxx maxy
0 -38.49299 -12.934936 -38.474516 -12.916815

O elemento de índice 0 da coluna geometry é um polígono da biblioteca shapely.

In [18]:
 type(recorte_LL.geometry[0])
Out[18]:
shapely.geometry.polygon.Polygon

segundo a documentação do comando ox.graph_from_polygon ele recebe como priméiro parâmetro um polígono ou multi-polígono da biblioteca citada.

O download do multi-grafo depende da conexão com a internet

In [19]:
gLatLon =  ox.graph_from_polygon(
                                   recorte_LL.geometry[0]
                                 , network_type = 'all_private'
                                 , truncate_by_edge = True
                                 , retain_all = True
                            )
In [20]:
gLatLon
Out[20]:
<networkx.classes.multidigraph.MultiDiGraph at 0x1df752f64a8>
In [21]:
ox.plot_graph(ox.project_graph(gLatLon))
Out[21]:
(<Figure size 449.029x432 with 1 Axes>,
 <matplotlib.axes._subplots.AxesSubplot at 0x1df75462320>)

Através do endereço (geocoding)

In [22]:
gCode = ox.graph_from_place('Salvador, Bahia, Brazil', network_type="drive")

O download do multi-grafo depende da conexão com a internet

In [24]:
gCode
Out[24]:
<networkx.classes.multidigraph.MultiDiGraph at 0x1df752e8438>
In [25]:
ox.plot_graph(ox.project_graph(gCode))
Out[25]:
(<Figure size 422.933x432 with 1 Axes>,
 <matplotlib.axes._subplots.AxesSubplot at 0x1df731987f0>)

Centralidade é uma medida da importância de um vértice em um grafo. Os critérios de medida da importância variam. Os quatro mais utilizados são:

1. grau
2. intermediação
3. proximidade
4. vetor próprio

O código abaixo calcula a centralidade de proximidade da malha viária da localidade gravada no grafo do OSM

Antenção!

O custo computacional do cálculo da centralidade cresce exponencialmente de acordo com o número de vértices do grafo(a execução do código abaixo pode demorar muitas horas)

In [122]:
# edge closeness centrality: convert graph to line graph so edges become nodes and vice versa
edge_centrality = nx.closeness_centrality(nx.line_graph(gCode))

O código abaixo desenha um gráfico mostrando, em escala de cores a varição da medida de centralidade da malha viária.

In [129]:
# list of edge values for the orginal graph
ev = [edge_centrality[edge + (0,)] for edge in gCode.edges()]

# color scale converted to list of colors for graph edges
norm = colors.Normalize(vmin=min(ev)*0.8, vmax=max(ev))
cmap = cm.ScalarMappable(norm=norm, cmap=cm.inferno)
ec = [cmap.to_rgba(cl) for cl in ev]

# color the edges in the original graph with closeness centralities in the line graph
fig, ax = ox.plot_graph(gCode, bgcolor=(0.1,0.3,0.0,0.0), axis_off=True, node_size=0, 
                        edge_color=ec, edge_linewidth=1.5, edge_alpha=1)

Juntando o arquivo do OSM com o Arquivo SHP

Trasnformando de Grafo OSM para geopandas Data frame

In [26]:
osm_pontos, osm_linhas = ox.save_load.graph_to_gdfs(gLatLon)
In [27]:
osm_linhas.head()
Out[27]:
bridge geometry highway key lanes length maxspeed name oneway osmid service u v
0 NaN LINESTRING (-38.4817005 -12.9226106, -38.48173... footway 0 NaN 5.818 NaN NaN False 431452585 NaN 592377792 4306484891
1 NaN LINESTRING (-38.4817005 -12.9226106, -38.48143... primary 0 2 293.516 60 Avenida Afrânio Peixoto True 258852462 NaN 592377792 3944737722
2 NaN LINESTRING (-38.4806693 -12.9168449, -38.48061... secondary_link 0 NaN 6.314 NaN NaN True 86577754 NaN 592378346 4306607916
3 NaN LINESTRING (-38.4806693 -12.9168449, -38.48063... primary 0 2 69.680 60 Avenida Afrânio Peixoto True 406250331 NaN 592378346 592378351
4 NaN LINESTRING (-38.4806036 -12.9174681, -38.48123... residential 0 NaN 233.994 NaN NaN False 88627556 NaN 592378351 1029167862

Sistemas de coordenadas

trasnformando para o sistema Sigras 2000

In [28]:
# Mudando o sistema de coordenadas de referência

# Para o Shape de Pontos
osm_pontos.to_crs(bairros.crs, inplace = True)
# Para o Shape de Bairros
osm_linhas.to_crs(bairros.crs, inplace = True)

Odenando as colunas do shape das linhas

In [29]:
# Ordenando as colunas das linhas para que a coluna de geometria fique por último
osm_linhas_cols = osm_linhas.columns.tolist()
osm_linhas_cols = [x for x in osm_linhas_cols if x != 'geometry']
osm_linhas_cols.append('geometry')
osm_linhas = osm_linhas[osm_linhas_cols]
In [30]:
osm_linhas.head()
Out[30]:
bridge highway key lanes length maxspeed name oneway osmid service u v geometry
0 NaN footway 0 NaN 5.818 NaN NaN False 431452585 NaN 592377792 4306484891 LINESTRING (556223.3656601022 8571360.65885263...
1 NaN primary 0 2 293.516 60 Avenida Afrânio Peixoto True 258852462 NaN 592377792 3944737722 LINESTRING (556223.3656601022 8571360.65885263...
2 NaN secondary_link 0 NaN 6.314 NaN NaN True 86577754 NaN 592378346 4306607916 LINESTRING (556336.5217465418 8571998.06138254...
3 NaN primary 0 2 69.680 60 Avenida Afrânio Peixoto True 406250331 NaN 592378346 592378351 LINESTRING (556336.5217465418 8571998.06138254...
4 NaN residential 0 NaN 233.994 NaN NaN False 88627556 NaN 592378351 1029167862 LINESTRING (556343.5093335714 8571929.12723277...
In [31]:
osm_pontos.head()
Out[31]:
highway osmid x y geometry
592377792 NaN 592377792 -38.4817 -12.9226 POINT (556223.3656601022 8571360.658852631)
592377803 NaN 592377803 -38.4805 -12.9169 POINT (556350.339344732 8571996.562528457)
592378346 NaN 592378346 -38.4807 -12.9168 POINT (556336.5217465418 8571998.061382545)
592378351 NaN 592378351 -38.4806 -12.9175 POINT (556343.5093335714 8571929.127232777)
592378362 NaN 592378362 -38.4815 -12.9222 POINT (556243.6960290928 8571404.168260001)

Estatística descritivas do DF osm_linhas

In [35]:
osm_linhas.describe(include='all')
Out[35]:
bridge highway key lanes length maxspeed name oneway service u v geometry
count 6 2054 2054.000000 33 2054.000000 33 232 2054 118 2.054000e+03 2.054000e+03 2054
unique 1 14 NaN 1 NaN 1 27 2 2 NaN NaN 2054
top yes residential NaN 2 NaN 60 Rua Padre Antônio Vieira False driveway NaN NaN LINESTRING (556536.1844486846 8571385.22782885...
freq 6 1713 NaN 33 NaN 33 46 2008 62 NaN NaN 1
mean NaN NaN 0.006816 NaN 74.858000 NaN NaN NaN NaN 1.708460e+09 1.708382e+09 NaN
std NaN NaN 0.082297 NaN 74.955946 NaN NaN NaN NaN 1.335574e+09 1.335211e+09 NaN
min NaN NaN 0.000000 NaN 2.301000 NaN NaN NaN NaN 5.923778e+08 5.923778e+08 NaN
25% NaN NaN 0.000000 NaN 32.251750 NaN NaN NaN NaN 1.005901e+09 1.005901e+09 NaN
50% NaN NaN 0.000000 NaN 53.966000 NaN NaN NaN NaN 1.005902e+09 1.005902e+09 NaN
75% NaN NaN 0.000000 NaN 95.081250 NaN NaN NaN NaN 1.583408e+09 1.583408e+09 NaN
max NaN NaN 1.000000 NaN 1139.594000 NaN NaN NaN NaN 5.769358e+09 5.769358e+09 NaN
In [98]:
fig2, layers2 = plt.subplots(figsize=(10,10)
                            #,dpi=30
                           )

recorte.plot(ax = layers2, color = 'blue', alpha = 1)
# Plotando os bairros
# Limites preto
# alpha - transparência
# layers - quadro o qual poderá ser alterado os valores de xmin, xmax, título e etc


bairros.plot(ax= layers2, color='yellowgreen', edgecolor='black', linestyle="--", lw= 1.5, alpha=1) 

# Plotando as edificações com a cor vermelha
edf.plot(ax= layers2, color='darkred', lw= 0.7)

try:
    edf_pt.plot(ax= layers2, color='orange', lw= 0.7, )
except:
    pass

# importados do OSM
osm_linhas.plot(ax= layers2, color='teal', lw= 0.8, )
osm_pontos.plot(ax= layers2, color='indigo', lw= 0.4, )

# titulo da figura
fig2.suptitle('Imagem Teste', fontsize=16)

# limites do gráfico
layers2.set_xlim(xSC, xSC + deltaX )
layers2.set_ylim(ySC,  ySC + deltaY )
Out[98]:
(8570000, 8572000)
In [119]:
osm_linhas.dtypes
Out[119]:
bridge       object
highway      object
key           int32
lanes        object
length      float64
maxspeed     object
name         object
oneway        int32
osmid        object
service      object
u             int64
v             int64
geometry     object
dtype: object

Devido a incompatibilidades entre as estruturas de dados do shapefile e do OSM algumas colunas precisam ser tratadas

In [118]:
osm_linhas.oneway = osm_linhas.oneway.astype(int)
osm_linhas.key = osm_linhas.key.astype(int)
osm_linhas.name = osm_linhas.name.astype(str)
osm_linhas.bridge = osm_linhas.bridge.astype(str)
In [120]:
osm_select = osm_linhas.filter( items= [ 'name', 'oneway','key','length', 'bridge' ,'geometry' ]) 
In [121]:
osm_select.to_file('./output/teste01.shp', driver='ESRI Shapefile')