Pengolahan Geojson dengan Python

advertisement
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
Contoh Pengolahan Data GeoJSON Menggunakan shapely,
geopandas, dan plotly (in Python)
Contents
¢ 1. Low-level Operations menggunakan shapely
¢
2. Implementasi geopandas
© 3. Reference
# data wrangling, inspecting and utilities modules
import pandas as pd
import numpy as np
import geopandas
# informative chart modules
import plotly.express as px
import matplotlib.pyplot as plt
# geo module
from shapely.geometry import Polygon, MultiPolygon, Point
# utilities
import random
import warnings
import json
# setting pandas options
pd.set_option('‘display.float',
‘{:,.2f}'.format)
pd.set_option(‘display.max_columns', 75)
pd.set_option('display.max_rows', 75)
pd.set_option(‘display.max_info_columns', 5@)
warnings. filterwarnings('ignore', category=DeprecationWarning)
1. Low-level Operations menggunakan shapely
Package shapely memiliki banyak tipe geometri (lihat dokumentasi untuk info lebih jelasnya). Kita akan menggunakan tipe geometri yang paling
sering dioperasikan menggunakan file geojson: Point, Polygon, dan MultiPolygon. Object geometry shapely bersifat immutable.
Contoh implementasi: random sampling point di dalam polygon
Berikut adalah polygon DKI Jakarta (tidak termasuk kepulauan seribu). Polygon ini merupakan polygon level 7 (administratif level provinsi).
@) Geoman.io
[on
Editor
Leaflet--Geoman
_Leaflet-Geoman Pro
Kramat
| +
ns
Gaga
Karet
<
embor
ey
/
Prete
ta=[r kad)
{ }
+ as
|
Budiarto)
{
tt
i
t
|
J
Bekasi
ns
\
ha
XC
a,
i
hf
2
ber |i
Tangerang
A See
4
/
i
"
\
7
{
Cikiwul
:
Jatisari
»
ae
:
ey
ji
Cikupa
«1
Pejuang
Fae Selatan
Jatake=
pe
é O a
x
/ \\
!
‘
LOS
,
|
Kebalen
(Siipl}
2
Pi)
as
>
:
\
i
EAL
Legok
Dy
Be
“Sy
ti
|
}
UT
:
Ly akarta
~1
im,
IN We
)
kee
«
iC
Oo
1 of
Wy ees |
87 Da8n
So Mog
{
fait
Tangerang
S ‘a
4
-
J
“Pal
A al
arel
Marunda
i
L
yes!
2
a *”
:
Bi
y
Giftung
di
ll
lee
Cileduk
%;
hy
.
“
J
f
bk
j
ell ih
Br
}
Tugu
Sr
Telaju
J
Ee
me
as
je
mend
Kita akan membuat polygon diatas dalam bentuk object shapely:
filename = 'data\DKI_JAKARTA_lv1_1.json'
with open(filename, ‘r') as f:
poly_geojson_1 = json. load(f)
poly_coord = poly_geojson_1['features'][@]['geometry'][' coordinates’ ][@]
poly_obj = Polygon(shell=poly_coord)
Dalam code diatas:
e Kita membaca file geojson menggunakan package json
© Koordinat polygon kita akses didalam object json dari tahap sebelumnya
e Kita meng-construct shapely.Polygon dengan menggunakan koordinat polygon sebagai shell kwags.
Kita bisa memanfaatkan attribut dan method dari object shapely.Polygon. Katakanlah kita mau mengecek apakah suatu titik koordinat berada di
area DKI Jakarta. Kita gunakan geometri point, yaitu shapely. Point.
Mengapa perlu menggunakan shapely.Point? Ini karena method yang akan kita gunakan (shapely. Polygon. contains) mengharuskan kita untuk
passing argument berupa object shapely.
coordinate = (106.91497998166815, -6.254602478608049)
p = Point(coordinate)
print(f‘ coordinate in DKI Jakarta: {poly_obj.contains(p)}')
coordinate in DKI Jakarta: True
Dengan menggunakan method shapely.Polygon.contains() kita mengeceka apakah shapely.Point berada di dalam polygon tersebut.
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON.
html
1/6
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
Problem di atas dapat kita kembangkan lagi, sebagai contoh: Tentukan 100 titik sampling secara random di dalam lingkup DKI Jakarta.
Kode dibawah adalah contoh solusi dari problem tersebut:
def generate_random_points(polygon: object, num_points):
minx, miny, maxx, maxy = polygon.bounds
points = []
while len(points) < num_points:
x = random.uniform(minx, maxx)
y = random.uniform(miny, maxy)
p = Point(x, y)
if polygon.contains(p):
points.append((y, x))
return np.array(points)
# generate random points inside polygon
sampling points = generate_random_points(poly_obj, 100)
# plot
fig = px.scatter_mapbox(
lat=sampling_points[:, @], lon=sampling_points[:, 1],
color_discrete_sequence=np.repeat('red', len(sampling_points)
)
)
fig.update_layout(
title='Sampling Points’,
mapbox_style="stamen-toner",
autosize=True,
hovermode='closest',
mapbox=dict(zoom=9)
)
fig.show(renderer='iframe'
)
Sampling Points
Dalam kode diatas:
e Kita menggunakan attribute shapely.Polygon.
bound untuk mendapatkan informasi terkait boundary polygon.
e Kita generate random point di dalam range boundary tersebut
e Kita cek, apakah titik tersebut berada di dalam polygon? Jika tidak, kita generate ulang titiknya sampai jumlah titik yang didapat sesuai
Dapat kita lihat bahwa semua titik berada di dalam lingkup administratif DKI| Jakarta.
Multipolygon
shapely.MultiPolygon adalah object untuk menyimpan deretan Polygon.
filename = 'data\DKI_JAKARTA_lv1_3.json'
with open(filename, ‘r') as f:
poly_geojson_3 = json.load(f)
districts = {}
for feature in poly_geojson_3['features']:
districts[feature[ ‘properties’ ]['NAME_3']] = Polygon(feature[' geometry‘ ]
[‘ coordinates‘ ][@][@])
poly_districs = MultiPolygon([values for values in districts.values()])
Kita bisa mengakses object di dalam MultiPolygon:
print(f'Luas area: {poly_districs.geoms[1].area}')
coordinate = (106.91497998166815, -6.254602478608049)
p = Point(coordinate)
print(f'Coordinate in geoms: {poly_districs.geoms[1].contains(p)}')
Luas area: @.0008776349999998809
Coordinate in geoms:
False
2. Implementasi geopandas
Package geopandas adalah kombinasi antara pandas dan shapely sebagai package untuk mengoperasikan geometric object. Object utamanya yaitu
GeoDataFrame.
Membuat GeoDataFrame dengan Membaca GeoJSON
Kita bisa membuat GeoDataFrame menggunakan geopandas.read_file:
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON.html
2/6
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
jakarta_gdf = geopandas.read_file( 'data\DKI_JAKARTA_lvl_3.json')
jakarta_gdf = jakarta_gdf.rename(
columns={
"COUNTRY': ‘country',
"NAME_1': ‘province’,
"NAME_2': ‘city’,
"NAME_3': 'district'}
jakarta_gdf = jakarta_gdf[['‘country',
"province',
‘city',
‘district’,
‘geometry']]
jakarta_gdf.head()
country
province
city
district
geometry
0
Indonesia
JakartaRaya
JakartaBarat
Cengkareng
1
Indonesia
JakartaRaya
JakartaBarat
Grogolpetamburan
2
Indonesia
JakartaRaya
JakartaBarat
Kalideres
3
Indonesia
JakartaRaya
JakartaBarat
Kebonjeruk
eee 0260,
4
Indonesia
JakartaRaya
JakartaBarat
Kembangan
MULTIPOLYGON (((106.72020
-6.22420, 106.71760 ...
eeeBriO, ee io
eee 15270, enpas
seen etyio0 eee
ee
he
Dari GeoDataFrame diatas kita dapat setiap features dari GeoJSON DKI Jakarta level 3. Kolom geometry menyimpan object shapely:
sample = jakarta_gdf.geometry[@]
print(type(sample)
)
sample
<class 'shapely.geometry.multipolygon.MultiPolygon'
>
Operasi yang Melibatkan GeoPandas
GeoPandas mempunyai tools untuk mengolah GeoDataFrame (satu atau lebih). Dalam contoh kali ini, kita akan menggabungkan dua
GeoDataFrame menggunakan geopandas.sjoin.
Di dalam repository ini terdapat data yang berisi jarak dari suatu titik (lat, long) terhadap fasilitas publik terdekat (dalam contoh ini adalah rumah
sakit). Dataset ini berisi records berikut:
TT =
to Bio Tech Sarana, JI. Sungai Bambu No.6, RT.1/
destinasi terdekat dari titik
s
VW Bi
m Hotels
my
i bah
:
Priok W
Q More
”
boom
Koja Regional
con
Pa
16 min (5.5 km)| durasi tempuhdan jarak rS ;
3 J
fm 22 min
astest
te now Gue
to traff
ton:
Ji, Bandar Il No.44
swabadak
Sel,
K
Koja,
Jkt
Jtsra, Daerah Khusus |bukota Jakarta 1423
>
Take JL. Bandar I, JL Patimura and J. Alur Laut
to
JL Plumpang Semper in Rawabadak Selatan
>
>
TakeJth Yos Sudarse
Sungai Bambu Pool
Jt. Sungai Bambu/Jt
Drive to JI. Sungai Bambu in 1
ty
di
Mabarthacasing)
Usheu Sunter
Bio Tech Sarana
ji.
Sungai BambuNo.6, RT.1/RW.4,
}
Qrecsiecsiee
J
él. Hotel
Re yale Jakarta
Mailof indonesia ©
@ Wits Sabienc 02 9
Sungai Bamb
——
e
E,
Kita akan meng-construct satu GeoDataFrame menggunakan dataset ini!
sampling
df = pd.read_csv('‘data\dki_data_akses_hospital.csv')
sampling _df.head()
waktu
tag
2023020 06.13-
.
mengemudi
lat
-6.25
long
tag_tujuan
tujuan_terdekat
durasi_tempuh
durasi_tempuh_unit jarak_tempuh jarak_tempuh_unit
rute
106.91
.
hospital
Harum Sisma
Medika Hospital,
JL. Lobi dan UGD
9.00
.
min
2.50
km
JI. Elang
Malindo
106.91
.
hospital
Harum Sisma
Medika Hospital,
JL. Lobi dan UGD
9.00
.
min
2.50
km
JI. Raya
Jatiwaringin
106.91
.
hospital
Medika Hospital,
JL. Lobi dan UGD
9.00
.
min
2.50
km
JI. Elang
Malindo V
JL. Lobi dan UGD
9.00
min
2.50
km
Malindo III
Harum Sisma
Medika Hospital,
JL Lobi dan UGD
9.00
.
min
2.50
km
_
JI. Wirajasa
04
2023021 06.13-
.
mengemudi
-6.25
04
20232
0206.13-
Harum Sisma
.
mengemudi
-6.25
04
202302-
3 06.13-
Harum Sisma
.
mengemudi
-6.25
.
106.91
hospital
106.91
.
hospital
Medika Hospital,
.
JI. Elang
04
4
20230206.13-
.
mengemudi
-6.25
04
Dapat kita lihat bahwa data tersebut dalam long format. Dalam satu destinasi terdapat banyak rute (jalan) yang dilalui dari titik ke destinasi
terdekat.
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON.html
3/6
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
Dalam contoh ini, kita tidak membutuhkan data rute ini:
sampling
df = sampling df\
-drop(columns=['‘rute'])\
.drop_duplicates()\
.reset_index(drop=True)
sampling _df.head()
0
waktu
tag
20230206.13-
.
mengemudi
lat
-6.25
long
tag_tujuan
tujuan_terdekat
durasi_tempuh
durasi_tempuh_unit jarak_tempuh jarak_tempuh_unit
106.91
.
hospital
Harum Sisma
Medika Hospital,
JI Lobi dan UGD
9.00
.
min
2.50
km
106.92
.
hospital
Rumah Sakit
Harapan
Jayakarta, Blok
12.00
.
min
5.70
km
12.00
.
min
3.70
km
22.00
.
min
9.70
km
6.00
min
1.50
km
04
1
20230206.13-
.
mengemudi
-6.22
05
KM No.18, ...
2023-
2
0206.13-
RS Grha Kedoya,
.
mengemudi
-6.18
:
hospital
106.78
JI. Panjang
No.26,
06
2023023 06.13-
RT.15/RW.7....
.
mengemudi
-6.16
106.96
.
hospital
Gading Pluit
Hospital
mengemudi
-6.34
106.82
hospital
Sibroh Maalisi, JI.
.
07
ad
4
06_1307
Hospital Ali
Wr. Sila No.1...
Kolom lat dan long adalah 100 titik sampling yang kita dapat sebelumnya.
Sekarang kita akan convert DataFrame diatas menjadi GeoDataFrame:
sampling gdf = geopandas.GeoDataFrame(data=sampling
df)
sampling _gdf.head()
waktu
tag
2023020 06.13-
.
mengemudi
lat
-6.25
long
tag_tujuan
tujuan_terdekat
durasi_tempuh
durasi_tempuh_unit jarak_tempuh jarak_tempuh_unit
106.91
.
hospital
Harum Sisma
Medika Hospital,
JL Lobi dan UGD
9.00
.
min
2.50
km
106.92
:
hospital
Rumah Sakit
Harapan
Jayakarta, Blok
12.00
.
min
5.70
km
12.00
.
min
3.70
km
04
2023021 06.13-
.
mengemudi
-6.22
05
KM No.18, ...
2023-
2
0206.13-
RS Grha Kedoya,
.
mengemudi
-6.18
.
hospital
106.78
JI. Panjang
No.26,
06
3
20230206.13-
RT.15/RW.7....
.
mengemudi
-6.16
106.96
.
hospital
Gading Pluit
Hospital
22.00
.
min
9.70
km
mengemudi
-6.34
106.82
hospital
Hospital Ali
Sibroh Maalisi, JI.
.
Wr. Sila No.1...
6.00
min
1.50
km
07
ad
4
06_1307
GeoDataFrame diatas belum sepenuhnya menjadi gdf karena kekurangan satu data vital: geometric spatial data. Oleh karena itu, kita akan
membuat satu kolom geometric yang mengandung geometric dalam format shapely.Point:
sampling _gdf = sampling _gdf.assign(
geometry=lambda x: geopandas.GeoSeries.from_xy(x.long, x.lat)
)
sampling _gdf = geopandas.GeoDataFrame(sampling_gdf, crs=4326)
Kita akan menggabungkan kolom [district, geometry] dari jakarta_gdf ke dalam sampling_gdf dengan menggunakan codes berikut:
sampling _gdf_joined = \
geopandas.sjoin(
jakarta_gdf[[‘city',
‘district’,
‘geometry']],
sampling _gdf,
how='inner', predicate='contains')
sampling _gdf_joined.head()
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON.html
4/6
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
city
0
district
JakartaBarat
geometry
index_right
MULTIPOLYGON
2023-
(((106.70850
02-
Cengkareng
6.18110,
31 06.13-
106.70040 ...
25
MULTIPOLYEON
0
JakartaBarat
waktu
Cengkareng
6.18110
0
1
Cengkareng
JakartaBarat
JakartaBarat
Cengkareng
Grogolpetamburan
6 181 10
106.70040 ...
long
tag_tujuan
06 14-
mengemudi
-6.18
106.71
.
hospital
06 13AS
MULTIPOLYGON
(((106.70850
6.18110,
20230264 06.13-
106.70040 ...
47
MULTIPOLYGON
(((106.79450
6.15270,
20230214 06.13-
106.79940 ...
14
durasi_tempuh
durasi_tempuh_unit |
Keluarga
Medika, JI. Raya
.
8.00
min
21.00
min
11.00
min
13.00
.
min
10.00
.
min
No.74 R...
Pondok Indah
mengemudi
-6.17
106.72
hospital
Hospital - Puri
Indah, JI. Puri I...
2023:
61
tujuan_terdekat
Klinik Citra
.
- 00
MuLTIPOLYGON
JakartaBarat
lat
2023:
87
106.70040 ..
0
tag
Pondok Indah
mengemudi
.
mengemudi
-6.17
-6.13
106.73
hospital
106.73
.
hospital
Hospital - Puri
Indah, JI. Puri I...
Ciputra Hospital
CitraGarden
City, JI. Satu
Ma...
.
mengemudi
-6.16
106.78
.
hospital
RS Grha Kedoya,
JI. Panjang
No.26,
RT.15/RW.7....
Perhatikan bahwa kita menggunakan operasi contains, sama seperti low-level operations yang sudah dijelaskan sebelumnya. Hanya dengan
menggunakan geopandas.sjoin, operasi ini dilakukan row-wise (vectorized).
Contoh Output: Geospatial Plot
Dari GeoDataFrame diatas, terdapat MULTIPOLYGON geometry. Kita bisa menggunakan dataframe diatas untuk membuat plot berdasarkan polygon
tersebut, dalam contoh ini akan dihasilkan plot level kecamatan.
agg_sampling
df = sampling _gdf_joined\
.groupby(‘district')\
.agg({'durasi_tempuh':
.reset_index()
‘mean’,
‘geometry’: lambda x: x.values[@]})\
aggsampling
df = geopandas.GeoDataFrame(agg
samplingdf, crs=4326)
fig, ax = plt.subplots()
agg samplingdf.plot('durasi_tempuh', legend=True, ax=ax)
ax.set_title('Rata-rata Durasi Tempuh (menit) ke Rumah Sakit Terdekat'
)
plt.show()
Rata-rata Durasi Tempuh (menit) ke Rumah Sakit Terdekat
-—6.10
5
16
—6.15 5
14
—6.20 5
12
10
—6.25 5
8
—6.30 4
6
—6.35 5
4
106.70 106.75
106.80 106.85 106.90
106.95
Di atas adalah contoh penggunaan GeoDataFrame.plot(). Dalam contoh di atas, kita melakukan aggregate mean untuk durasi tempuh
berdasarkan kecamatan. Terdapat missing records di beberapa titik kecamatan.
Selain menggunakan GeoDataFrame.plot(), kita bisa menggunakan plotly untuk menghasilkan plot interaktif:
# plot
filename = 'data\DKI_JAKARTA_lv1_3.json'‘
with open(filename, ‘r') as f:
poly_geojson_3 = json.load(f)
fig = px.choropleth(
data_frame=agg sampling df,
geojson=poly_geojson_3,
locations='district',
color='durasi_tempuh'
,
featureidkey='properties.NAME_3',
fitbounds='locations',
basemap_visible=False,
title='Rata-rata Durasi Tempuh (menit) ke Rumah Sakit Terdekat',
)
fig.show(renderer='iframe’ )
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON. html
5/6
6/9/23, 3:13 PM
Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python) — Contoh Pengolahan Data GeoJSON Menggunakan shapely, geopandas, dan plotly (in Python)
Rata-rata Durasi Tempuh (menit) ke Rumah Sakit Terdekat
durasi_tempuh
a
8
3. Reference
Data GeoJSON didapat dari: GADM.
Online GeoJSON editor menggunakan: Geoman.io.
https://nbarizki.github.io/posts/GEOJSON/html/GEOJSON. html
6/6
Download