본문 바로가기
GIS Tech/GIS Data Process

지도상 영역의 GeoJSON Polygon 생성 웹앱 만들기 (Python)

by mpv 2021. 1. 10.

지도상 영역에 대한 GeoJSON Polygon 생성

GIS 데이터를 다루다보면 선택한 영역 내의 데이터를 쿼리해야 될 경우가 있다. 이럴때 본 앱을 켜고 영역을 선택하여 만들어진 GeoJSON 을 활용하면 편리할 것이다. 본 웹앱은 Python Flask와 카카오 지도 API의 create-polygon예제를 참고하여 만들었다. 전체 코드는 GitHub에 정리해두었다.

 

그리고 시작하기 앞서 developers.kakao.com/console/내 어필리케이션 > 앱 설정 > 플랫폼 > Web 플랫폼 수정 에서 사용할 웹 호스트 주소를 등록해두고, JavaScript 앱 키를 얻는다.

flaskapp.py

from flask import Flask, request, render_template
import os
import myconstants
app = Flask(__name__)

host = myconstants.host
appkey = myconstants.appkey
lat, lng = 37.558309, 126.925776

@app.route('/')
def home():
    return render_template('createpolygon.html', appkey=appkey, lat=lat, lng=lng)
    
if __name__ == '__main__':
    app.run(host=host, port=5000, debug=True)

flaskapp.py 파일을 다음과 같이 만들고 host와 appkey를 입력한다. 코드의 경우 개인정보 유출 방지를 위해 객체화 하였다.

 

가장 중요한 createpolygon.html 파일은 다각형 영역 설정 이후 path (= polygon.getPath() )를 이용하여 아래와 같이 shp 텍스트를 생성하여 textarea에 반영한다.

 

createpolygon.html 일부 (전체코드)

var shp = {};
shp['type'] = 'Polygon';
shp['coordinates'] = [[]]

for (var i in path){
  var lng = path[i].getLat();
  var lat = path[i].getLng();
  shp['coordinates'][0].push([lng, lat]);
}
var lng = path[0].getLat();
var lat = path[0].getLng();
shp['coordinates'][0].push([lng, lat]);

document.getElementById("geop").innerHTML = JSON.stringify(shp);

전체코드는 github.com/SuminHan/geojson-query 에 저장되어있으며 

python flaskapp.py

로 실행 가능하다.

 

추가: geojson으로 원하는 영역의 gpd 데이터 geowithin 쿼리

 

우리가 원하는 범위의 Polygon이 아래와 같은 형태라고 하자.

yunnam_large = {'type': 'Polygon',
 'coordinates': [[[126.92572992898702, 37.55835818322421],
   [126.92616538295539, 37.55864227038824],
   [126.92658623986753, 37.55938810776263],
   [126.92677406036564, 37.56118120785994],
   [126.9282886257802, 37.56334452890169],
   [126.92638553613328, 37.56494713073428],
   [126.9243245551222, 37.565900883346934],
   [126.9196036221869, 37.5667807387447],
   [126.91729357199945, 37.56765310878508],
   [126.91688686271446, 37.566950046607175],
   [126.911545990937, 37.56548655281125],
   [126.91632828606713, 37.56035436030137],
   [126.91882134961368, 37.55750895062923],
   [126.92156261652076, 37.555222270447274],
   [126.92572992898702, 37.55835818322421]]]}

그리고 현재 pandas의 df가 아래의 내용과 같다고 하자.

df = pd.DataFrame(insta_locs)

우선 geopandas 형태로 gdf를 만든다.

gdf = gpd.GeoDataFrame(
    df, geometry=gpd.points_from_xy(x=df.lng, y=df.lat)
)
gdf.crs = 'EPSG:4326'

그리고 다음과 같이 query 가능하다.

from shapely.geometry import Point, Polygon
gg = Polygon(yunnam_large['coordinates'][0])
gdf = gdf[gdf.geometry.within(gg)]

이후 Zip으로 저장하고싶으면 다음과같이 한다.

import os, zipfile

save_gdf = gdf.copy()
save_gdf.crs = 'EPSG:4326'

save_dir = 'dir_name'
save_name = 'file_name'

if not os.path.isdir(save_dir):
    os.mkdir(save_dir)
save_gdf.to_file(save_dir + '/' + save_name + '.shp', encoding='euc-kr')

fantasy_zip = zipfile.ZipFile(save_dir + '/' + save_name + '.zip', 'w')
for ext in ['cpg', 'dbf', 'shp', 'shx', 'prj']:
    fantasy_zip.write(save_dir + '/' + save_name + '.' + ext, save_name + '.' + ext, compress_type = zipfile.ZIP_DEFLATED)
fantasy_zip.close()

 

댓글