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