top of page
  • Foto do escritorCarlos Silva

Como usar a API Python OpenRouteService?

Atualizado: 19 de mar.

Muitas vezes eu preciso fazer consultas rápidas de distância e em quantidades inviáveis de fazer no Google Maps uma a uma. É uma demanda de informação recorrente para planejamento operacional e estratégico já que transportar coisas tem alto custo. Por isso achei a solução do OpenRouteService muito interessante pra resolver esse problema.


O primeiro passo é criar uma conta e criar uma chave no openrouteservice.org, a documentação é boa ao ponto de eu não querer entrar em detalhes aqui, basicamente você faz um login (pode ser com sua conta do github) e vai na aba Dashboard para criar uma chave. Na aba API Playground também mostra muita coisa interessante.


Fazendo uma uma requisição através da API Python OpenRouteService


Você pode encontrar mais detalhes sobre alguns parâmetros na documentação do github e mais sobre os tipos de roteamento aqui. Aqui estou fazendo uma consulta de Ponta Grossa - PR até o porto de Paranaguá - PR, que é uma rota logística convencional para escoamento de produtos industriais.

key='Sua chave aqui' #Chave da API
client = openrouteservice.Client(key) #Fazendo a conexão com o serviço 
coords = ((-50.184777 , -25.122125),(-48.519270 , -25.503800)) #Coordenadas de origem e destino, pode ter coordenadas intermediárias
 
routes = client.directions(coordinates=coords,
                           profile='driving-hgv', #Tipo de rota, nesse caso , transporte logístico e afins
                           format='geojson', #Formato de saída
                           validate=False,
                           radiuses=5000, #Raio em metros de busca de trechos de estrada
                           extra_info=["waycategory", #Categoria de caminho
                                       "waytype", #Tipo de caminho
                                       "surface"] #Tipo de superfície
                           )
#Salvando os resultados em um json
import json
with open('data.json', 'w') as f:
    json.dump(routes, f)


Geometria e a distância.


Dentro desse arquivo geojson existe muitas coisas, porém vou ressaltar duas, a geometria e a distância.

# A quantidade de quilômetros da rota e as coordenadas que compõem a geometria da linha
dist = str(round(routes['features'][0]['properties']['summary']['distance']/1000,2))+" km"
print(dist)
LineString(routes['features'][0]['geometry']['coordinates'])

Também é possível ver atributos extras da rota, mas tem que indicar no momento da requisição que você deseja eles, veja aqui na documentação.

routes['features'][0]['properties']['extras']

Se verificarmos o tipo de superfície encontramos o tipo 3 e 1, que são asfalto e pavimentada respectivamente.

routes['features'][0]['properties']['extras']['surface']['summary']

Dando uma olhada com o folium percebe-se que ele prefere ir pelo anel rodoviário de Curitiba, que não é a rota mais curta porém é recomendado para o tipo de transporte que foi parametrizado.


E se eu quiser saber a rota de várias origens e destinos de uma vez só?


Primeiro vou montar um DataFrame com as origens e destinos.

DataTable = {'Rota': ['Imbaú, PR - Ponta Grossa, PR', 'Ponta Grossa, PR - Curitiba, PR'],
     'OrigemLong':[-50.7516409,-50.2396862],
     'OrigemLat':[-24.4603571,-25.0622996],
     'DestinoLong':[-50.2396862,-49.337566],
     'DestinoLat':[-25.0622996,-25.431829],
     }
df = pd.DataFrame(data=DataTable)

Com a função abaixo eu consigo pegar as informações desse DataFrame e pedir para extrair do serviço a informação da distância e da geometria e criar um GeoDataFrame com as rotas, a lógica das informações é igual a anterior, só que vou linha a linha capturando as informações e fazendo as solicitações e depois adiciono elas como novas colunas no GeoDataFrame.

def openrouteservice_dist(df,                         #DataFrame
                          OrigemLong,                 #Longitude da origem
                          OrigemLat,                  #Latitude da origem
                          DestinoLong,                #Longitude do destino
                          DestinoLat,                 #Latitude do destino
                          key,                        #Chave da API
                          radiuses=5000,              #Raio de busca de estradas
                          profile='driving-hgv',      #Tipo ded roteamento
                          printprocess=False):        #Printar em que linha está roteando
                          
  dist = []
  geo = []

  for i in df.index:
    coords = ((df[OrigemLong][i],df[OrigemLat][i]),(df[DestinoLong][i],df[DestinoLat][i]))
    client = openrouteservice.Client(key=key) 
    routes = client.directions(coordinates=coords,
                               profile=profile,
                               format='geojson',
                               validate=False,
                               radiuses=radiuses)
    dist.append(round(routes['features'][0]['properties']['summary']['distance']/1000,2))
    geo.append(LineString(routes['features'][0]['geometry']['coordinates']))
    time.sleep(2)
    if printprocess:
      print(i)
  df['Dist'] = dist
  df['geometry']=geo
  df = gp.GeoDataFrame(df)
  return df

df = openrouteservice_dist(df,'OrigemLong','OrigemLat','DestinoLong','DestinoLat',
                           key, radiuses=5000, profile='driving-hgv')
                           
#Criando uma Shapefile das rotas geradas
df.set_crs(epsg=4326).to_file('routes.shp')  


Bonûs


Também posso ter resultados parecidos fazendo requests sem ter que usar a API Python do OpenRouteService.

import requests
body = {"locations":[[9.70093,48.477473],[9.207916,49.153868],[37.573242,55.801281],[115.663757,38.106467]],"metrics":["distance"],"units": "km"}

headers = {
    'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8',
    'Authorization': 'Sua chave aqui',
    'Content-Type': 'application/json; charset=utf-8'
}
call = requests.post('https://api.openrouteservice.org/v2/matrix/driving-hgv', json=body, headers=headers)

print(call.status_code, call.reason)
print(call.text)


Considerações finais

  • O resultado das consultas é detalhado e bem parametrizável.

  • Existe um limite de consultas do plano gratuito (2000/Dia e 40/min), porém é um projeto Open Source, e existe uma documentação de instalação.

  • É uma solução mais rápida, detalhada e de melhor desempenho do que a do meu último post sobre roteamento, você pode dar uma olhada nele aqui.

Referências



 





323 visualizações0 comentário

Posts recentes

Ver tudo
Post: Blog2_Post
Post: Blog2 Custom Feed
bottom of page