pyQGIS를 이용한 벡터 데이터 처리 8 : 새로운 SHP 파일 생성하기

새로운 벡터 데이터 파일을 생성하는 코드를 순차적으로 나열하면 먼저 필드를 정의합니다.

QgsProject.instance().removeAllMapLayers()

fields = QgsFields()
fields.append(QgsField("id", QVariant.Int))
fields.append(QgsField("name", QVariant.String))
fields.append(QgsField("value", QVariant.Double))

그리고 생성할 SHP 파일명을 지정하고 Writer 객체를 생성합니다. 속성 문자셋은 UTF-8로 지정했고 지오메트리 타입은 Point로 지정했습니다. 좌표계는 EPSG:5179입니다.

fileName = "D:/__Data__/new_point.shp"

writer = QgsVectorFileWriter(
    fileName, 
    "UTF-8", 
    fields,
    QgsWkbTypes.Point, 
    QgsCoordinateReferenceSystem("EPSG:5179"),
    "ESRI Shapefile"
)

이 Writer 객체를 통해 피쳐를 기록할 수 있고 피쳐를 기록하는 코드를 함수로 작성해 둡니다.

def createFeature(x, y, attributes):
    feat = QgsFeature()
    geom = QgsGeometry.fromPointXY(QgsPointXY(x, y))
    feat.setGeometry(geom)
    feat.setAttributes(attributes)
    return feat

위의 함수를 사용하여 4개의 피쳐를 기록합니다.

writer.addFeature(createFeature(971195, 1841488, [1, "김형준", 10.21]))
writer.addFeature(createFeature(971295, 1841488, [2, "홍길동", 20.31]))
writer.addFeature(createFeature(971195, 1841588, [3, "일지매", 25.16]))
writer.addFeature(createFeature(971295, 1841588, [4, "임꺽정", 17.54]))

생성된 SHP 파일을 Close하기 위해 다음 코드를 추가합니다.

del(writer)

이제 생성된 SHP 파일을 레이어로 추가합니다.

layer = QgsVectorLayer(fileName, "새로운 레이어", "ogr")
QgsProject.instance().addMapLayers([layer])

결과는 다음과 같습니다.

SHP 파일의 속성 값의 경우 Length와 Precision 값을 지정할 수 있는데, 위의 코드 중 필드를 추가하는 코드를 다음과 같이 Length와 Precision과 함께 처리가 가능합니다.

fields.append(QgsField("id", QVariant.Int, None, 5))
fields.append(QgsField("name", QVariant.String, None, 40))
fields.append(QgsField("value", QVariant.Double, None, 10, 4))

pyQGIS를 이용한 벡터 데이터 처리 7 : 새 피쳐 추가하기, 피쳐 제거하기

벡터 레이어에 새로운 피쳐를 추가하는 코드는 다음과 같습니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

caps = layer.dataProvider().capabilities()
if caps & QgsVectorDataProvider.AddFeatures:
    feat = QgsFeature(layer.fields())
    feat.setAttribute("RN", "테스트로") # feat.setAttributes([.., .., .., ...])
    geom = QgsGeometry.fromWkt("MULTILINESTRING((968963 1820821, 993152 1819742, 993567 1844387))")
    feat.setGeometry(geom)
    result, outFeature = layer.dataProvider().addFeatures([feat])
    print(result, outFeature)

다음은 피쳐를 삭제하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

caps = layer.dataProvider().capabilities()
fids = []

if caps & QgsVectorDataProvider.DeleteFeatures:
    features = layer.getFeatures()
    for feat in features:
        if feat["RN"] == "테스트로":
            fids.append(feat.id())
    res = layer.dataProvider().deleteFeatures(fids)
    print(res, len(fids))            
    
#layer.triggerRepaint()

pyQGIS를 이용한 벡터 데이터 처리 6 : 피쳐의 속성 및 좌표 편집

이미 저장되어 있는 피쳐의 속성과 좌표를 변경하는 코드를 살펴보겠습니다. 먼저 피쳐의 속성값을 변경하는 코드는 다음과 같습니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])
layer.selectByExpression('"RN_CD" = \'3251036\'')
idxField = layer.fields().indexOf('RN')

features = layer.selectedFeatures()
with edit(layer):
    for f in features:
        layer.changeAttributeValue(f.id(), idxField, "짱기로")

위의 코드는 먼저 RN_CD의 값이 3251036인 피쳐를 선택하고 선택된 피쳐의 RN 필드의 값을 “짱기로”로 변경하는 코드입니다.

다음은 위와 동일한 조건으로 피쳐를 선택하고 선택된 피쳐의 좌표를 편집하는 코드입니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])
layer.selectByExpression('"RN_CD" = \'2348142\'')

features = layer.selectedFeatures()
with edit(layer):
    for f in features:
        geom = QgsGeometry.fromWkt("MULTILINESTRING((968963 1820821, 993152 1819742, 993567 1844387))")
        layer.changeGeometry(f.id(),geom)

새롭게 정의할 도형의 좌표를 WKT 형식으로 지정하였습니다.

pyQGIS를 이용한 벡터 데이터 처리 5 : 피쳐 선택하고 저장하기

가장 먼저 피쳐의 ID 값으로 선택하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)

아래는 선택된 피쳐를 순회하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)
QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

selectid = [0, 1, 2, 3, 4]
layer.select(selectid)

selection = layer.selectedFeatures()
for feat in selection:
    print(feat['RN'])

다음은 SQL의 Where 조건 형태의 조건으로 피쳐를 선택하고 선택된 피쳐만을 새로운 SHP 파일로 저장하는 코드입니다.

QgsProject.instance().removeAllMapLayers()

layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])
layer.selectByExpression('"RN" like \'%로\'')

fn = "D:/__Data__/aa.shp"
writer = QgsVectorFileWriter.writeAsVectorFormat(layer, fn, 
    "utf-8", 
    driverName="ESRI ShapeFile", 
    onlySelected=True
)

print("DONE")

newLayer = QgsVectorLayer(fn, "aa")
QgsProject.instance().addMapLayers([newLayer])

다음은 사각형 영역을 지정해서 이 영역과 교차하는 피쳐를 선택하는 코드입니다.

QgsProject.instance().removeAllMapLayers()
layer = QgsVectorLayer("D:/__Data__/세종특별자치시_36000/TL_SPRD_MANAGE.shp", "TL_SPRD_MANAGE", "ogr")
QgsProject.instance().addMapLayers([layer])

areaOfInterest = QgsRectangle(982413, 1835226, 987413, 1840226)
request = QgsFeatureRequest().setFilterRect(areaOfInterest)

selected = []

for feature in layer.getFeatures(request):
    selected.append(feature.id())
    
layer.select(selected)