Download data Jalan di Openstreetmap menggunakan Jupyter Notebook


Kali ini kita akan menjelaskan tahapan membuat Geojson dari Jalan yang disediakan Openstreetmap. Data tersebut Kita olah dan Jadikan Satu file. Pertama Kali yaitu Kita mendownload data dari Jupyter Notebook.
import os
import requests
import geopandas as gpd
from shapely.geometry import LineString
# Folder penyimpanan data
data_folder = "data"
os.makedirs(data_folder, exist_ok=True)
# Query Overpass API untuk jalan di area tertentu
def fetch_osm_data(area_name, area_query):
print(f"๐ฅ Mengunduh data jalan untuk {area_name}...")
query = f"""
[out:json];
area[name="{area_query}"]->.searchArea;
(way["highway"](area.searchArea););
out body; >; out skel qt;
"""
url = "http://overpass-api.de/api/interpreter"
response = requests.get(url, params={"data": query})
if response.status_code == 200:
data = response.json()
if "elements" in data and len(data["elements"]) > 0:
print(f"โ
Data untuk {area_name} berhasil diunduh.")
return data
else:
print(f"โ ๏ธ Tidak ada data yang ditemukan untuk {area_name}")
else:
print(f"โ Gagal mengambil data untuk {area_name}")
return None
# Konversi data dari Overpass API ke GeoDataFrame
def convert_to_gdf(osm_data):
if not osm_data or "elements" not in osm_data:
print("โ ๏ธ Data kosong atau tidak valid.")
return None
ways = []
nodes = {node["id"]: (node["lon"], node["lat"]) for node in osm_data["elements"] if node["type"] == "node"}
for element in osm_data["elements"]:
if element["type"] == "way" and "nodes" in element:
coordinates = [nodes[node_id] for node_id in element["nodes"] if node_id in nodes]
if len(coordinates) > 1:
ways.append({"geometry": LineString(coordinates), "highway": element.get("tags", {}).get("highway", "unknown")})
if not ways:
print("โ ๏ธ Tidak ada jalan yang ditemukan di data OSM.")
return None
return gpd.GeoDataFrame(ways, geometry="geometry", crs="EPSG:4326")
# Daftar wilayah yang akan diunduh, "x":"y", x mewakili official name, y mewakili name
districts = {
"Kota Bandung": "Bandung",
"Kabupaten Bandung": "Bandung",
"Kota Cimahi": "Cimahi",
"Kabupaten Bandung Barat": "Bandung Barat"
}
# Looping unduh data dan simpan
for area_name, area_query in districts.items():
osm_data = fetch_osm_data(area_name, area_query)
if osm_data:
gdf = convert_to_gdf(osm_data)
if gdf is not None and not gdf.empty:
file_path = os.path.join(data_folder, f"{area_name.lower().replace(' ', '_')}_roads.geojson")
gdf.to_file(file_path, driver="GeoJSON")
print(f"๐ Data jalan untuk {area_name} berhasil disimpan di: {file_path}")
else:
print(f"โ ๏ธ Tidak ada data yang dapat disimpan untuk {area_name}")
print("๐ Semua proses selesai!")
Data bisa dicari ataupun ditambah dari Districts. dan Apabila terjadi error , bisa dicari di website osm. Kemudian bila berhasil, kita preview dulu hasilnya dengan kode dan hasilnya seperti dibawah.
import os
import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx
from tqdm import tqdm # Untuk indikator loading
# Folder penyimpanan data
data_folder = "data"
# Daftar wilayah yang akan divisualisasikan
districts = [
"kota_bandung_roads.geojson",
"kabupaten_bandung_roads.geojson",
"kota_cimahi_roads.geojson",
"kabupaten_bandung_barat_roads.geojson"
]
# Buat figure utama
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()
# Looping dengan tqdm untuk progress bar
for idx, file_name in enumerate(tqdm(districts, desc="Memuat data")):
file_path = os.path.join(data_folder, file_name)
if os.path.exists(file_path):
gdf = gpd.read_file(file_path)
if not gdf.empty:
# Konversi ke CRS Web Mercator agar sesuai dengan contextily
gdf = gdf.to_crs(epsg=3857)
# Plot data jalan
ax = axes[idx]
gdf.plot(ax=ax, linewidth=1, color="blue")
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik)
ax.set_title(file_name.replace("_", " ").replace(".geojson", "").title())
ax.axis("off")
else:
print(f"โ ๏ธ File {file_name} kosong atau tidak valid.")
else:
print(f"โ ๏ธ File {file_name} tidak ditemukan.")
# Menampilkan plot
plt.tight_layout()
plt.show()
print("๐ Visualisasi selesai!")
Kemudian kita clip dengan cara seperti dibawah.
import os
import geopandas as gpd
import pandas as pd
from shapely.geometry import box
# Folder penyimpanan data
data_folder = "data"
# Daftar file GeoJSON yang akan digabungkan
districts = [
"kota_bandung_roads.geojson",
"kabupaten_bandung_roads.geojson",
"kota_cimahi_roads.geojson",
"kabupaten_bandung_barat_roads.geojson"
]
# Batas wilayah (xmin, ymin, xmax, ymax) untuk Bandung Raya
clip_bounds = [107.0934, -7.3432, 107.9791, -6.6032] # Sesuaikan jika diperlukan
# Buat bounding box sebagai GeoDataFrame
clip_geom = gpd.GeoDataFrame(
{"geometry": [box(*clip_bounds)]},
crs="EPSG:4326" # Pastikan CRS sesuai dengan GeoJSON yang digunakan
)
# List untuk menyimpan data dari masing-masing GeoJSON
gdf_list = []
# Loop untuk membaca dan menggabungkan data
for file_name in districts:
file_path = os.path.join(data_folder, file_name)
if os.path.exists(file_path):
gdf = gpd.read_file(file_path)
if not gdf.empty:
gdf["source"] = file_name # Tambahkan kolom sumber data
gdf_list.append(gdf)
else:
print(f"โ ๏ธ File {file_name} kosong atau tidak valid.")
else:
print(f"โ ๏ธ File {file_name} tidak ditemukan.")
# Gabungkan semua GeoDataFrame menjadi satu
if gdf_list:
merged_gdf = gpd.GeoDataFrame(pd.concat(gdf_list, ignore_index=True), crs="EPSG:4326")
# Clip data dengan bounding box
clipped_gdf = merged_gdf.clip(clip_geom)
# Simpan hasil clip ke file GeoJSON baru
clipped_geojson_path = os.path.join(data_folder, "clipped_roads_bandung_raya.geojson")
clipped_gdf.to_file(clipped_geojson_path, driver="GeoJSON")
print(f"โ
Berhasil di-clip! File disimpan di: {clipped_geojson_path}")
else:
print("โ Tidak ada data yang bisa di-clip.")
Setelah berhasil, baru kita preview hasilnya
Kemudian kita attach ketinggian dari dem dan tempelkan ke line dengan kode berikut:
import geopandas as gpd
import rasterio
import requests
import numpy as np
from rasterio.io import MemoryFile
from shapely.geometry import LineString, MultiLineString
# URL DEM (gantilah dengan sumber yang valid)
dem_url = "https://s3.amazonaws.com/elevation-tiles-prod/geotiff/10/550/344.tif"
# Mengunduh file DEM dari URL ke memori
response = requests.get(dem_url)
response.raise_for_status()
# Membuka file DEM langsung dari memori
with MemoryFile(response.content) as memfile:
with memfile.open() as dem:
# Baca data jalan (GeoJSON)
geojson_path = "data/clipped_roads_bandung_raya.geojson"
gdf = gpd.read_file(geojson_path)
# Konversi CRS GeoDataFrame ke CRS DEM
gdf = gdf.to_crs(dem.crs)
# Fungsi untuk mendapatkan ketinggian rata-rata dari DEM
def extract_elevation(geom):
elevations = []
if isinstance(geom, LineString): # Jika LineString langsung ambil koordinatnya
coords = list(geom.coords)
elevations = list(dem.sample(coords))
elif isinstance(geom, MultiLineString): # Jika MultiLineString, pecah menjadi LineString
for line in geom.geoms:
coords = list(line.coords)
elevations.extend(dem.sample(coords)) # Tambahkan semua sampel ketinggian
elevations = np.array(elevations).flatten()
return np.mean(elevations) if len(elevations) > 0 else None
# Tambahkan kolom elevasi ke GeoDataFrame
gdf["elevation"] = gdf.geometry.apply(extract_elevation)
# Simpan hasilnya ke GeoJSON
output_geojson = "data/roads_with_elevation_from_url.geojson"
gdf.to_file(output_geojson, driver="GeoJSON")
print("โ
Data jalan dengan ketinggian dari URL berhasil disimpan:", output_geojson)
Subscribe to my newsletter
Read articles from Hidayatullah directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Hidayatullah
Hidayatullah
Hi, my name is Hidayatullah. I am a GIS Engineer, Analyst, Specialist, and everything related to GIS. With over 5 years of experience, I am highly proficient in ArcGIS and QGIS. I specialize in spatial topology methods, least square adjustment measurement methods, PostGIS with PostgreSQL, RDBMS databases, spatial generalization by scale, WebGIS Geoserveer/Mapserver/Mapproxy, and more. If you're interested in my services, feel free to reach out via email at genhidayatullah@icloud.com.