เล่นกับแผนที่และกราฟด้วย OSMnx

Janebhop Sawaengchob
3 min readJan 26, 2019

--

Tutorial นี้ตอนนี้ใช้ไม่ได้แล้วนะครับ เนื่องจาก library ปรับ version และการทำงานไปเยอะมาก ถ้ามีเวลาว่างจะกลับมาแก้นะครับ

สัปดาห์ก่อนได้งานให้ศึกษาตัว OSMnx เป็น library บน Python พัฒนาโดย Geoff Boeing อาจารย์ด้านผังเมือง ซึ่งใน library ตัวนี้ อธิบายสรรพคุณได้แจ่มมาก บอกว่าสามารถโหลดแผนที่จาก openstreetmap และเซฟเป็นไฟล์ไว้ใช้ต่อๆไปได้หลายรูปแบบ กำหนดขอบเขตของแผนที่ที่ต้องการได้(จะเลือกเป็นชื่อเมือง, พิกัด ก็ตามสะดวก) อีกทั้งยังพัฒนาให้ใช้กับ NetworkX ที่สามารถคำนวณในลักษณะของ Graph Theory ได้อีกด้วย สามารถไปอ่านต่อได้ใน Paper click here

ในส่วนของวันนี้ผมจะเล่นแค่บาง feature ของ OSMnx โดยจะทำการหา shortest path ระหว่าง สองจุดบนแผนที่

import osmnx as ox
import networkx as nx
import matplotlib.pyplot as plt
from descartes import PolygonPatch

อย่างที่บอก OSMnx มันดึงข้อมูลจาก openstreetmap จึงสามารถระบุตำแหน่งของข้อมูลได้ ในตัวอย่างผมจะดึงข้อมูลเส้นทางรถยนต์จากตำแหน่งที่ตั้ง มีจุดศูนย์กลางคือ มหาวิทยาลัยขอนแก่น ในระยะ 5 กิโลเมตร (อันที่จริงมันดึงข้อมูลได้หลายแบบ click here รวมทั้งสามารถเลือกชนิดของเส้นทางได้ด้วย)

adress = 'Khon Kaen University'
network_type = 'drive'
distance=5000
G=ox.graph_from_address(adress, distance=distance, distance_type='bbox',network_type=network_type)
ox.plot_graph(G)
ภาพที่ 1 drive graph ที่มีจุดศูนย์กลางคือ มหาวิทยาลัยขอนแก่น รัศมี 5 กม.

ต่อไปผมจะเลือกจุดเริ่มต้น คือ central plaza khon kaen และปลายทาง คณะวิทยาศาสตร์ มข.(sc kku) โดยใช้ module geocode เพื่อ get coordinate เป็นพิกัด latitude, longitude (ทั้งนี้ชื่อของสถานที่ ควรไปตรวจสอบดูใน openstreetmap ดูก่อน แต่ถ้าเรารู้ coordinate แล้วก็จะง่ายขึ้น)

sc_kku = ox.geocode( 'Faculty of Science, Khon Kaen')
central_kk = ox.geocode('centralplaza Khon Kaen')
sc_kku_node = ox.get_nearest_node(G, sc_kku)
central_kk_node = ox.get_nearest_node(G, central_kk)

เนื่องจาก coordinate ในแผนที่อาจจะไม่ตรงกันกับ node ในกราฟจึงใช้ get_nearest_node เพื่อหา node ที่ใกล้ที่สุด

ภาพที่ 2 จุดสีแดงคือ sc kku ส่วนจุดสีเขียวคือ node ที่ใกล้ที่สุด

จากนั้นผมจะหาเส้นทางที่ใกล้ที่สุดจาก central khon kaen ไป sc kku โดยใช้ module shortest_path ของ NetworkX ซึ่งวิธี default คือการใช้ Dijkstra’s algorihm โดยกราฟของเรามี weight ของ edge บนกราฟเป็นระยะทางจริงระหว่าง node

route = nx.shortest_path(G, central_kk_node,
sc_kku_node,weight='length')
fig, ax = ox.plot_graph_route(G, route, fig_height=10,
fig_width=10,
show=False, close=False,
edge_color='black',
orig_dest_node_color='green',
route_color='green')
ax.scatter(sc_kku[1], sc_kku[0], c='red', s=100)
ax.scatter(central_kk[1], central_kk[0], c='blue', s=100)
plt.show()
ภาพที่ 3 เส้นทางจาก central khon kaen ไป sc kku

จากภาพที่ 3 จะสังเกตว่าเส้นทางที่ใช้จะเป็นเส้นทางเดินรถจริงๆ เพราะ graph ของ OSMnx มีลักษณะเป็นกราฟระบุทิศทาง(Directed graph) จึงรู้ว่าเส้นทางต่างๆเป็น one-way หรือไม่

route_length = nx.shortest_path_length(G, central_kk_node,sc_kku_node,weight='length')/1000
print('%.2f'%route_length, 'km')

โดยเส้นทางที่ใกล้ที่สุดมีระยะทาง 6.42 กิโลเมตร นอกจากนี้ยังมีอีกตัวอย่างคือ การทำ Isochrone map แต่น่าเสียดาย graph ไม่บอกความหนาแน่นของ traffic (ถ้ามีด้วยนี่โคตรโกง 555) ใน ตัวอย่าง จึงสร้างความเร็วเฉลี่ยของการเดินทางเองโดยในตัวอย่างนี้ผมจะใช้ความเร็วเฉลี่ย 50 km/h เป็นเส้นทางที่วิ่งได้ใน 3, 5 และ 8 นาทีตามลำดับ จากจุดศูนย์กลางคือ คณะวิทยาศาสตร์ มข.

trip_times = [3, 5, 8] #in minutes
travel_speed = 50 #speed in km/hour
#km per hour to m per minute
meters_per_minute = travel_speed * 1000 / 60
for u, v, k, data in G.edges(data=True, keys=True):
data['time'] = data['length'] / meters_per_minute
#Isochrone mapiso_colors = ox.get_colors(n=len(trip_times), cmap='Reds',start=0.3, return_hex=True)isochrone_polys = []
for trip_time in sorted(trip_times, reverse=True):
subgraph = nx.ego_graph(G, sc_kku_node, radius=trip_time, distance='time')
node_points = [Point((data['x'], data['y'])) for node, data in subgraph.nodes(data=True)]
bounding_poly = gpd.GeoSeries(node_points).unary_union.convex_hull
isochrone_polys.append(bounding_poly)
#plot the network then add isochrones as colored descartes polygon patchesfig, ax = ox.plot_graph(G, fig_height=8, show=False, close=False, edge_color='k', edge_alpha=0.2, node_color='none')for polygon, fc in zip(isochrone_polys, iso_colors):
patch = PolygonPatch(polygon, fc=fc, ec='none', alpha=0.6, zorder=-1)
ax.add_patch(patch)
plt.show()
ภาพที่ 4 Isochrone map

OSMnx เหมาะสำหรับทำ analytics บนแผนที่ซึ่งมีข้อมูลพื้นฐานมาให้พอสมควร และที่สำคัญคือฟรี หากมีความผิดพลาดหรือข้อเสนอแนะอะไรติชมไว้ได้ครับ

code ทั้งหมด อยู่ใน Colab นี้ >>> OSMnx_tutorial แต่ถ้าใช้ Colab เล่นจะมีปัญหา libspatialindex เป็นของ Rtree package ซึ่งมีคนแก้ไขปัญหานี้ไว้ ที่นี่

Reference:

Boeing, G. (2017). OSMnx: New methods for acquiring, constructing, analyzing, and visualizing complex street networks. Computers, Environment and Urban Systems, 65, 126–139.

--

--

No responses yet