Coğrafi konum verisi ile çalışmanın temelleri için öncelikle bu soruya bakabilirsiniz. Here Maps'in çevrimiçi servislerini kullanarak ilerleyeceğiz. Bunun için öncelikle linki takip ederek ücretsiz APP_ID
ve API_KEY
almanız gerekiyor. Bu uygulamada geopy
ve görselleştirme için plotly
ile mapbox
kütüphanelerini de kullanacağız. Mapbox için de bir kullanıcı tokenı almanız gerekiyor, linki takip ederek bunu ücretsiz alabilirsiniz.
Gerekli kütüphaneleri yükleyelim ve yukarıdaki linkleri takip ederek aldığımız kodları eklyelim.
import pandas as pd
import requests
import json
from geopy.distance import geodesic
import plotly.graph_objs as go
import plotly.io as pio
pio.renderers.default = "browser"
here_app_id = '###'
here_api_key= '###'
mapbox_token = "###"
mapbox_access_token = mapbox_token
İki nokta arasındaki rota problemi oldukça karmaşık bir iş. En kısa yolu bulmak da bir mesele ama işin içerisine trafik, uzak durulması gereken bölgeler, araç çeşidi gibi parametreler de girdiğinde iyice zorlaşıyor. Ben bir yaya için iki nokta arasındaki en kısa yolu bulan bir örnek vereceğim. Here Maps'in rota bulma apisini kullanarak bunu yapacağız. Bu api https://route.ls.hereapi.com/routing/7.2/calculateroute.json adresinden ulaşılan bir rest servisi olarak çalışıyor, detaylı bilgi için bu linke bakabilirsiniz. routingpy
ve herepy
adlı kütüphaneler bu servisi python üzerinden rahatça kullanmamıza olanak tanıdıklarını söylüyorlar fakat güncel API_KEY
ile çalışmıyorlar. Biz kendimiz python üzerinden aşağıdaki rest çağrısı ile bunu çözeceğiz.
payload = {'apiKey': here_api_key, 'waypoint0':'geo!40.984216,29.021948',
'waypoint1':'geo!40.98861,29.03451',
'mode': 'fastest;pedestrian;traffic:disabled'}
r = requests.get('https://route.ls.hereapi.com/routing/7.2/calculateroute.json', params=payload)
Yukarıdaki kodda payload atacağımız get
isteğinin parametrelerini tanımlıyor. Bunun içerisindeki waypoint
değerleri geo!
işaretinden sonra enlem ve boylam bilgilerini içeriyor. Bu istekten dönen cevap uzunca ve içerisinde bir çok bilgi olan bir metin. Bu metni aşağıdaki kodla json formatına çevirelim.
a = json.loads(r.text)
Bunun içerisinden iki nokta arasındaki rotayı tanımlayan enlem boylam bilgilerine aşağıdaki gibi ulaşabilirsiniz.
l = [i['position'] for i in a['response']['route'][0]['leg'][0]['maneuver']]
df = pd.DataFrame.from_dict(l)
df.head()
latitude longitude
0 40.984250 29.021920
1 40.983907 29.024076
2 40.987040 29.025675
3 40.988628 29.026726
4 40.988402 29.028701
Bu verisetinde ardışık koordinatlar arasında dümdüz gidiyoruz, kıscası rotamız bu.
Şimdi bu rota üzerinde hareket eden birisini görselleştirelim. Bunun için rota boyunca eşit uzunluklarda noktalar oluşturmamız lazım, bunu geopy
kütüphanesinden geodesic
fonksiyonunu kullanacağız.
# i ve i+1 numaralı satırlar arasındaki mesafe
dist_ar = [geodesic(df.loc[i], df.loc[i+1]).m for i in range(len(df)-1)]
# mesafeleri 10 metrelik kaç adımda gidebileceğimizi hesaplayalım
num_steps = [ max(round(dist/10),1) for dist in dist_ar]
# 10 metrelik adımlarla elde ettiğimiz enlem boylam bilgileri
new_lats = [ df['latitude'].iloc[j] * (1-(i / num_steps[j]))
+ df['latitude'].iloc[j+1] * (i) / num_steps[j]
for j in range(len(df)-1)
for i in range(num_steps[j]) ]
new_lons = [ df['longitude'].iloc[j] * (1-(i / num_steps[j]))
+ df['longitude'].iloc[j+1] * (i) / num_steps[j]
for j in range(len(df)-1)
for i in range(num_steps[j]) ]
# Varış noktasını da ekleyelim
new_lats.append(df['latitude'].iloc[-1])
new_lons.append(df['longitude'].iloc[-1])
Artık plotly ile bu rota üzerinde yürüyüşün animasyonunu yapabiliriz.
lats = new_lats
lons = new_lons
data = [go.Scattermapbox(
lat= [29.021948],
lon= [40.984216],
#customdata = df['ADDRESS'],
mode='markers',
marker=dict(
size= 6,
color = 'gold',
opacity = .8,
),
)]
layout = go.Layout(autosize=False,
mapbox= dict(accesstoken=mapbox_token,
bearing=10,
pitch=10,
zoom=14,
center= dict(lat=40.9884,lon=29.027),
style = 'dark'
#style=shaz13_custom_style
),
width=900,
height=600,
title = "Yuruyus")
frames = [dict(data= [dict(type='scattermapbox',
lat= lats[k:k+1],
lon= lons[k:k+1] )],
traces= [0],
name='frame{}'.format(k)
)for k in range(1, len(new_lats))]
layout.update(updatemenus=[dict(type='buttons', showactive=False,
y=0,
x=1.05,
xanchor='right',
yanchor='top',
pad=dict(t=0, r=10),
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=100,
redraw=True),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate'
)
]
)
]
)
],
);
fig=go.Figure(data=data,layout=layout, frames=frames)
fig.show()
Sonuç: