SHP 파일 구조


SHP 파일 구조
shapefile 파일인 shp 파일 구조에 대해서 설명드립니다. Python 라이브러리 pyshp를 이용하여 shp 파일 읽기 저장된 좌표값과 속성 정보들을 확인해 보도록 하겠습니다. shp 파일 뷰어 QGIS 프로그램 사용법을 함께 알려드립니다.

이 글에서 사용된 전체 예제 코드는 아래의 명령어로 다운 받으실 수 있습니다. 우리나라 행정구역 지도 SHP 파일을 이용하여, SHP 파일 구조를 분석하고자 하시는 분들은 아래 페이지 내용을 함께 참고해 주시기 바랍니다.

우리나라 지도 SHP

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

shapefile 포맷

SHP 파일 포맷은 벡터 형태의 지리 정보를 저장할 수 있는 공개 포맷으로 ESRI에서 개발되었습니다. ESRI 소프트웨어 뿐만 아니라, 다양한 GIS(Geographic Information System) 소프트웨어에서 사용되고 있습니다. shapefile을 구성하는 주요 파일은 형태가 저장된 shp 파일, 인덱스 정보가 저장된 shx, 그리고 속성정보가 저장된 dbf 파일 등으로 구성됩니다. 이 글 에서는 pyshp라는 Python 모듈을 이용하여 학습해 보도록 하겠습니다.

pyshp 설치

pyshp는 ESRI shapefile 파일 포맷을 읽고, 쓸 수 있는 Python 라이브러리입니다. 먼저 아래의 명령어를 이용하여 pyshp를 설치해 주시기 바랍니다.

$ sudo -H pip install pyshp

그리고 아래의 소스코드를 다운받아 주시기 바랍니다. 소스코드에 첨부된 shapefile를 읽는 예제를 학습하도록 하겠습니다.

$ git clone https://github.com/GeospatialPython/pyshp 

shapefile 파일 읽기

pyshp 라이브러리를 이용하기 위해서는 가장 먼저, python 코드에서 아래와 같이 모듈을 import 해주셔야 합니다.

import shapefile

그리고 shp 파일 읽기 위해서는 가장 먼저 Reader 객체를 생성해 주셔야 합니다. Reader 객체는 아래와 같이 shapefile 의 이름을 지정하면서 생성할 수 있습니다.

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

확장자를 제외한 이름을 지정하면, shp 파일을 포함하여 인덱스 파일등을 함께 읽습니다.

shapefile 메타 데이터 읽기

shapefile은 파일 컨텐츠에 대한 다양한 메타 데이터를 포함하고 있습니다. 먼저 shapefile의 geometry 구체적인 타입을 shapeType 속성 값으로 확인 할 수 있습니다.

print sf.shapeType
5

shapeType 속성값은 0부터 31사이의 값을 갖고, 구체적인 값은 아래와 같습니다.

  • NULL = 0
  • POINT = 1
  • POLYLINE = 3
  • POLYGON = 5
  • MULTIPOINT = 8
  • POINTZ = 11
  • POLYLINEZ = 13
  • POLYGONZ = 15
  • MULTIPOINTZ = 18
  • POINTM = 21
  • POLYLINEM = 23
  • POLYGONM = 25
  • MULTIPOINTM = 28
  • MULTIPATCH = 31

shapefile에서 Geometry 정보 읽기

shapefile의 Geometry 정보는 실제 지역들을 표시하는 꼭지점과 점들의 모음으로, 모든 shapefile 의 유형은 점들을 저장한 것입니다.
그리고 이러한 점들의 메타데이터를 이용하여 어떻게 소프트웨어에서 처리 할수 있는지 결정되어 집니다.

아래와 같이 shapefile의 Geometry 리스트는 shapes() 함수를 호출하면서 가져올 수 있습니다.

shapes = sf.shapes()

위의 함수를 이용하여, 전체 리스트를 가져 올 수 있을 뿐만 아니라 아래와 같이 shape() 함수에 인덱스를 직정하면서 특정한 shape 를 가져올 수도 있습니다. 인덱스틑 0부터 시작하기 때문에 아래의 코드는 8번째 shape를 가져오는 것입니다.

s = sf.shape(7)
print ['%.3f' % coord for coord in s.bbox]

그리고 아래의 내용은 가져온 shape의 bounding box를 출력하는 내용입니다.

['-122.450', '37.801', '-122.442', '37.808']

shape의 속성정보를 확인하기 위해서는 아래와 같이 사용합니다.

for name in dir(shapes[3]):
    if not name.startswith('_'):
        print name
bbox
parts
points
shapeType

주요 속성 정보는 아래와 같습니다.

  • shapeType : shape 유형의 정수형 값입니다.
  • shapeTypeName : shape 유형의 문자열 이름입니다.
  • bbox : 만약 shape가 여러 점들을 포함하고 있을 경우 bbox 값은 이러한 점들을 전체 사각형 정보를 포함합니다. 좌측 아래 (x, y) 값과, 우측 상단 좌표 값이 저장됩니다.
  • parts : shape 레코드가 여러 part를 갖을 경우, 이 속성값은 각각 part의 첫번째 포인트의 인덱스 값을 갖습니다. 오직 하나의 part만 가질경우 이 겂은 0이 됩니다.
  • points : shape 에서 각 점의 (x, y)좌표들의 튜플 값입니다.

shapefile에서 Record 값 읽기

Record 정보는 dbf 파일 안에 저장되어 있으며, 각각의 shape에 따른 속성값을 포함하고 있습니다. fields 라는 속성값에 Record 필드 정보가 저장되어 있으며, fields 정보는 4 가지로 구성되어 있습니다.

첫번째 내용은 필드이름이고, 두번째는 필드 유형입니다. 그리고 필드의 길이와 Number 필드에서 존재하는 십진수의 길이가 저장됩니다.
필드의 유형 종류는 아래와 같습니다.

  • C : 문자열 값
  • N : 숫자, 정수형이 될 수도 있고 아닐 수도 있음
  • F : 실수, (N과 동일)
  • L : 논리값
  • D : 날짜
  • M : 메모

예제 파일에서 fields 내용은 다음과 같이 확인 할 수 있습니다.

fields = sf.fields
print fields
[('DeletionFlag', 'C', 1, 0), ['AREA', 'N', 18, 5], ['BKG_KEY', 'C', 12, 0], ['POP1990', 'N', 9, 0], ['POP90_SQMI', 'N', 10, 1], ['HOUSEHOLDS', 'N', 9, 0], ['MALES', 'N', 9, 0], ['FEMALES', 'N', 9, 0], ['WHITE', 'N', 9, 0], ['BLACK', 'N', 8, 0], ['AMERI_ES', 'N', 7, 0], ['ASIAN_PI', 'N', 8, 0], ['OTHER', 'N', 8, 0], ['HISPANIC', 'N', 8, 0], ['AGE_UNDER5', 'N', 8, 0], ['AGE_5_17', 'N', 8, 0], ['AGE_18_29', 'N', 8, 0], ['AGE_30_49', 'N', 8, 0], ['AGE_50_64', 'N', 8, 0], ['AGE_65_UP', 'N', 8, 0], ['NEVERMARRY', 'N', 8, 0], ['MARRIED', 'N', 9, 0], ['SEPARATED', 'N', 7, 0], ['WIDOWED', 'N', 8, 0], ['DIVORCED', 'N', 8, 0], ['HSEHLD_1_M', 'N', 8, 0], ['HSEHLD_1_F', 'N', 8, 0], ['MARHH_CHD', 'N', 8, 0], ['MARHH_NO_C', 'N', 8, 0], ['MHH_CHILD', 'N', 7, 0], ['FHH_CHILD', 'N', 7, 0], ['HSE_UNITS', 'N', 9, 0], ['VACANT', 'N', 7, 0], ['OWNER_OCC', 'N', 8, 0], ['RENTER_OCC', 'N', 8, 0], ['MEDIAN_VAL', 'N', 7, 0], ['MEDIANRENT', 'N', 4, 0], ['UNITS_1DET', 'N', 8, 0], ['UNITS_1ATT', 'N', 7, 0], ['UNITS2', 'N', 7, 0], ['UNITS3_9', 'N', 8, 0], ['UNITS10_49', 'N', 8, 0], ['UNITS50_UP', 'N', 8, 0], ['MOBILEHOME', 'N', 7, 0]]

Record 정보는 records() 함수를 호출하면서, 리스트 형태로 가져올 수 있을 습니다. 그리고 record() 함수를 호출할때에 인덱스를 전달하면서, 특정한 레코드 값을 가져올 수도 있습니다.

shapefile 데이터 함께 읽기

shapes() 함수 도는 records() 함수를 읽어서 데이터를 각각 읽을 수도 있지만, SHP 파일에서 Shape 정보와 Record 정보를 한번에 읽을 수 있습니다. 아래의 내용은 shapeRecords()라는 함수를 사용하여 한번에 데이터를 읽는 방법을 나타냅니다.

shapeRecs = sf.shapeRecords()

print len(shapeRecs)

print shapeRecs[0].record[1:3]
print shapeRecs[0].shape.points[0:2]
663
['060750179029', 4531]
[(-122.420391, 37.863433), (-122.418705, 37.862144)]

SHP 파일 뷰어

QGIS 프로그램을 이용하여 SHP 파일의 내용을 확인 할 수 있습니다. 아래의 명령어를 이용하여 QGIS를 설치해 주시기 바랍니다.

$ sudo apt install qgis

그리고 다음 화면과 같이 QGIS 프로그램을 검색해서 실행합니다.

실행된 프로그램에서 [Layer] – [Add Layer] – [Add Vector Layer] 메뉴에서 shp 파일을 추가하면, 아래의 이미지 처럼 저장된 정보를 확인 할 수 있습니다.

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