QGIS 기반 공간통계

QGIS의 레이어 이용 샘플 분석

앞에서 실행시킨 샘플은 아래 링크에서 보면 소스의 줄번호를 알 수 있어 편리하다.

https://gist.github.com/anonymous/edcfc24a167b66c32f46#file-global_morans_i-py-L1

 

이제 분석 없이 실행시킨 소스를 분석해 보자. 소스가 90줄로 길어지긴 했지만, 부분 부분 나누어 보면 그리 어렵지는 않다. 각 지역들간의 관계를 나타네는 Weight를 만들고 분석대상 값을 모아, 이를 Moran 객체에 주면 공간자기상관관계가 분석되어 수치로 나온다.

이 과정이 QGIS와 연동해 데이터를 가져오고 진행과정과 결과를 화면에 표시해주는 부분이 들어가 소스가 조금 길어졌을 뿐이다.


 

# coding=utf-8

먼저 한국 개발자에게는 1행이 매우 중요하다.

파이썬에서 샵(#)으로 시작하는 행은 주석이니 중요하지 않아 보이지만, 실은 아래에 라틴문자가 아닌 글자들이 섞여 있고, 이 글자들은 UTF-8이라는 코드페이지 즉 문자표현 규칙을 사용하고 있다는 것을 알려주는 역할을 하고 있다. 이해하지 말고 한글이 한자라도 들어간다면 무조건 넣자.

 

from pysal import W, Moran

import numpy as np

import qgis

from qgis.core import *

from qgis.gui import QgsMessageBar

from PyQt4.QtGui import QProgressBar

from PyQt4.QtCore import *

import matplotlib.pyplot as plt

3~10행은 사용할 라이브러리들을 파이썬에게 알려주는 코드다. pysal은 공간분석을 위한 라이브러리, numpy는 수학계산 기초라이브러리, qgis는 QGIS 기능을 사용하기 위한 라이브러리, PyQt4는 QGIS에서 UI 구성등을 위해 사용하는 Qt 라이브러리, matplotlib는 그래프 그리기를 위한 라이브러리다.

 

# 전역변수 설정

TEST_DIST = 100000

NAME_FIELD = "SGG"

VALUE_FIELD = u"노인비율"

13~16행은 내부적으로 사용할 상수값을 정의해 놓은 부분이다. TEST_DIST는 인접지역으로 판단할 지역 센트로이드(Centroid)간의 거리 기준을, NAME_FIELD는 지역명이 담긴 필드를, VALUE_FIELD는 공간통계 분석을 할 값이 담긴 필드이름을 각각 담고 있다.

여기서 주의 할 것이 u"노인비율"처럼 한글 텍스트 앞에는 꼭 u라는 글자를 꼭 붙여서 유니코드임을 명확히 해줘야만 오류가 안생긴다.

 

# 레이어 선택

oLayer = iface.activeLayer()

if not oLayer:

  raise UserWarning(u"레이어를 먼저 선택해야 합니다.")  # 종료

 

layerName = oLayer.name()

layerType = oLayer.geometryType()

crs = oLayer.crs()

 

# ID 리스트 확보

oIDs = oLayer.allFeatureIds()

21~31행의 코드는 현재 QGIS에서 선택중인 레이어(activeLayer)를 가져와 이름과 타입 좌표계(crs)를 알아보고 모든 객체(allFeature)의 ID를 가져와 oIDs라는 변수에 저장하고 있다.

여기서 iface는 QGIS와의 연결을 담당하는 인터페이스 객체로 QGIS 파이썬 콘솔에서만 기본적으로 존재하는 객체다. 나중에 프로그램이 발전하여 플러그인 형태가 되면 꼭 이 iface를 인자로 넘겨주고 지속적으로 관리해야 QGIS와의 인터페이스가 가능해 진다.

 

# Progress 생성

progressMessageBar = iface.messageBar().createMessage(u"레이어 정보 수집중...")

progress = QProgressBar()

progress.setMaximum(len(oIDs))

progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)

progressMessageBar.layout().addWidget(progress)

iface.messageBar().pushWidget(progressMessageBar, iface.messageBar().INFO)

33~39행은 약 10초 정도 소요되는 아무 메시지 없이는 프로그램에 문제가 생긴 것으로 오인할 수도 있는 시간동안 작업이 진행중임을 사용자에게 알리기 위해 진행상태를 보여주게 하기위한 진행상태 바(QProgressBar)를 보여주게 하는 코드다.

 

# centroid,value(y),name 모으기

centroidList = []

dataList = []

nameList = []

for i, oID in enumerate(oIDs):

  progress.setValue(i)

 

  iFeature = oLayer.getFeatures(QgsFeatureRequest(oID)).next()

  iGeom = iFeature.geometry().centroid()

  centroidList.append(iGeom)

  data = iFeature[VALUE_FIELD]

  dataList.append(data)

  name = iFeature[NAME_FIELD]

  nameList.append(name)

41~54행은 각 지역의 중심점(centroid)와 분석에 쓸 데이터, 지역이름을 QGIS Layer에서 모으는 코드다. 파이썬의 특징적인 문법인 for i, oID in enumerate(oIDs): 구문으로 ID 리스트 요소와 몇번째임을 나타내는 i 값을 결합해서 루프를 돌려주고 있다.

progress.setValue(i)는 진행상태 바의 표시값을 변경시키는 코드고, 이 부분부터 들여쓰기가 되어여 있음에 주의하여야 한다. 파이썬에서 이렇게 들여쓰면 앞 문장(for)의 하위 코드임을 표시하는 것이고, 들여쓰기가 잘못된 경우 파이썬에서는 오류가 발생한다.

Layer에서 얻은 객체(feature)에서는 geometry()로 도형을 얻어 여기서 다시 중심점(centroid())를 추출하고 있다. 객체에서 컬럼의 값을 얻는 것은 feature[컬럼명]으로 얻어 낼 수 있음도 알아두자.

 

# 통계 대상 값 수집

y = np.array(dataList)

56~57행은 앞의 루프에서 얻어 파이썬의 어레이([])에 모아둔 통계분석 대상 데이터를 NumPy의 Array로 변환하는 코드다. PySAL은 대부분의 데이터를 NumPy.array로 처리하고 있으며, Moran 모듈도 데이터를 NumPy.array로만 받을 수 있다.

 

# Progress 제거

iface.messageBar().clearWidgets()

59~60행은 데이터 수집이 끝났으니 진행상태 바를 없에 주는 코드다.

 

# Weight Matrix 계산 위한 정보 수집

neighbors = {}

weights = {}

for iID, iCent in zip(oIDs, centroidList):

  iRowNeighbors = []

  iRowWeights = []

  for jID, jCent in zip(oIDs, centroidList):

      # 동일 지역인 경우 제외

      if iID == jID:

          continue

      # 기준거리 이내인 경우 인접한 것으로 기록

      dist = iCent.distance(jCent)

      if dist <= TEST_DIST:

          iRowNeighbors.append(jID)

          iRowWeights.append(

댓글

댓글 본문
버전 관리
BJ Jang
현재 버전
선택 버전
공동공부
graphittie 자세히 보기