SHP GeoJSON 변환


SHP GeoJSON 변환
shapefile인 SHP 파일을 GeoJSON 파일로 변환하는 방법에 대해서 GeoJSON 예제 함께 설명드립니다. GeoJSON 포맷과 GeoJSON 변환 Python 스크립트를 함께 설명드리기 때문에 바로 사용할실 수 있습니다. 그리고 원하시는 경우 수정 후 사용 할 수 있습니다. SHP 파일 구조에 대해서 학습하기 위해서는 다음 페이지를 참고해 주시기 바랍니다.

SHP 파일 구조

GeoJSON 이란

GeoJSON 이란 간단한 지리정보 특징을 표현하기 위해서 만들어진 공개된 표준 포맷입니다. 좌표 정보와 함께 속성정보등을 함께 저장할 수 있으며 JSON 형태로 저장되게 됩니다. 보다 자세한 내용은 아래의 페이지를 참고해 주시기 바랍니다.

https://en.wikipedia.org/wiki/GeoJSON

GeoJSON 형태는 아래와 같습니다.

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [102.0, 0.5]
      },
      "properties": {
        "prop0": "value0"
      }
    }
  ]
}

GeoJSON 예제

먼저 다음 명령어를 이용하여, 예제 소스코드와 함께 SHP 파일을 다운로드 받아 주시기 바랍니다.

$ git clone https://hiseon.me/reps/shp-file-format.git && cd shp-file-format
$ git submodule init
$ git submodule update

이 글에서 사용될 예제 shp 파일은 pyshp 에서 사용되는 shapefile 파일로 다음과 같이 생겼습니다. 전체 예제 코드는 shp-to-geojson.py 파일의 내용을 참고해 주시기 바랍니다.

SHP GeoJSON 변환

먼저 아래와 같이 Python 모듈인 shapefile과 json을 로드합니다.

import shapefile
import json

그리고 아래의 코드를 이용하여, Reader 객체를 생성합니다.

path = "pyshp/shapefiles/blockgroups"
sf = shapefile.Reader(path)

확장자를 제거한 파일 이름을 지정하면, SHP 파일 및 SHX 등의 관련파일들을 함께 읽습니다.
다음은 고정된 첫번째 필드가 아닌 정의된 필드 정보로부터 필드 이름을 추출합니다.

fields = sf.fields[1:]
field_names = [field[0] for field in fields]

필드이름과 레코드를 결합한 속성 dictionary를 만들고, geometry 속성으로 shape 정보가 저장되도록 합니다.
이러한 데이터 구조로 buffer 리스트에 추가합니다.

buffer = []
for sr in sf.shapeRecords():
   atr = dict(zip(field_names, sr.record))

   geom = sr.shape.__geo_interface__
   buffer.append(dict(type="Feature", geometry=geom, properties=atr))

그리고, 아래와 같은 구조로 GeoJSON 형태를 만들어, 최종적으로 파일을 저장합니다.

geojson = open("pyshp-demo.geojson", "w")
geojson.write(json.dumps({"type": "FeatureCollection", "features": buffer}, indent=2, ensure_ascii=False))
geojson.close()

GeoJSON 파일

위에서 만든 스크립트를 실행한 결과의 일부 내용은 아래와 같습니다.

{
  "type": "FeatureCollection", 
  "features": [
    {
      "geometry": {
        "type": "MultiPolygon", 
        "coordinates": [
          [
            [
              [
                -122.420391, 
                37.863433
              ], 
              [
                -122.418705, 
                37.862144
              ], 
              [
                -122.419893, 
                37.860309
              ], 
              [
                -122.420391, 
                37.863433
              ]
            ]
          ]
        ]
      }, 
      "type": "Feature", 
      "properties": {
        "BKG_KEY": "060750179029", 
        "AGE_UNDER5": 611, 
        "MARHH_CHD": 16, 
        "AGE_30_49": 1513, 
        "POP1990": 4531, 
        "BLACK": 726, 
        "AGE_18_29": 1327, 
        "AMERI_ES": 37, 
        "SEPARATED": 62, 
        "FEMALES": 1912, 
        "DIVORCED": 106, 
        "AREA": 0.96761, 
        "UNITS3_9": 538, 
        "UNITS50_UP": 0, 
        "MALES": 2619, 
        "HOUSEHOLDS": 970, 
        "HISPANIC": 389, 
        "HSEHLD_1_M": 43, 
        "UNITS_1DET": 25, 
        "HSE_UNITS": 1045, 
        "HSEHLD_1_F": 20, 
        "POP90_SQMI": 4682.7, 
        "MARRIED": 1750, 
        "MOBILEHOME": 0, 
        "MARHH_NO_C": 878, 
        "OWNER_OCC": 0, 
        "OTHER": 123, 
        "UNITS10_49": 19, 
        "AGE_65_UP": 7, 
        "WHITE": 2943, 
        "NEVERMARRY": 501, 
        "MEDIAN_VAL": 0, 
        "WIDOWED": 19, 
        "UNITS2": 37, 
        "FHH_CHILD": 0, 
        "VACANT": 83, 
        "AGE_50_64": 51, 
        "MHH_CHILD": 0, 
        "UNITS_1ATT": 419, 
        "ASIAN_PI": 702, 
        "AGE_5_17": 1022, 
        "MEDIANRENT": 647, 
        "RENTER_OCC": 3548
      }
    }
  ]
}

( 본문 인용시 출처를 밝혀 주시면 감사하겠습니다.)