Python 플러그인에서 QGIS의 속성 편집 속도


9

QGIS Python 플러그인을 사용하여 레이어의 각 기능에 대한 속성 값을 편집하려고합니다. 편집 모드 외부 에서이 작업을 수행하는 것이 편집하는 동안보다 편집 속도가 훨씬 느리다는 것을 알았습니다. 아래 코드를 참조하십시오 (루프에서 같은 지점에서 서로 바꾸어 쓸 수있는 줄). 샘플 데이터 세트의 속도 차이는 2 초 (편집 모드)와 72 초 (편집 모드 아님)입니다.

편집 모드에서 속성 수정 :

layer.changeAttributeValue(feature.id(), 17, QtCore.QVariant(value))

편집 모드 외부에서 속성 수정 :

layer.dataProvider().changeAttributeValues({ feature.id() : { 17 : QtCore.QVariant(value) } })

이것이 예상되는 동작입니까? 사용자가 변경 내용을 취소 할 필요가 없으므로 편집 모드를 사용할 필요가 없다고 생각합니다.

편집 1 : 두 버전이 모두 포함되어 있지만 아래에 전체 코드가 표시되어 있지만 주석 처리되었습니다.

def run(self):
    try:
        # create spatial index of buffered layer
        index = QgsSpatialIndex()
        self.layer_buffered.select()
        for feature in self.layer_buffered:
            index.insertFeature(feature)

        # enable editing
        #was_editing = self.layer_target.isEditable()
        #if was_editing is False:
        #    self.layer_target.startEditing()

        # check intersections
        self.layer_target.select()
        self.feature_count = self.layer_target.featureCount()
        for feature in self.layer_target:
            distance_min = None
            fids = index.intersects(feature.geometry().boundingBox())
            for fid in fids:
                # feature's bounding box and buffer bounding box intersect
                feature_buffered = QgsFeature()
                self.layer_buffered.featureAtId(fid, feature_buffered)
                if feature.geometry().intersects(feature_buffered.geometry()):
                    # feature intersects buffer
                    attrs = feature_buffered.attributeMap()
                    distance = attrs[0].toPyObject()
                    if distance_min is None or distance < distance_min:
                        distance_min = distance
                if self.abort is True: break
            if self.abort is True: break

            # update feature's distance attribute
            self.layer_target.dataProvider().changeAttributeValues({feature.id(): {self.field_index: QtCore.QVariant(distance_min)}})
            #self.layer_target.changeAttributeValue(feature.id(), self.field_index, QtCore.QVariant(distance_min))

            self.calculate_progress()

        # disable editing
        #if was_editing is False:
        #    self.layer_target.commitChanges()

    except:
        import traceback
        self.error.emit(traceback.format_exc())
    self.progress.emit(100)
    self.finished.emit(self.abort)

두 방법 모두 동일한 결과를 생성하지만 데이터 공급자를 통한 쓰기는 훨씬 오래 걸립니다. 이 함수는 사전 생성 된 버퍼 (갈색)를 사용하여 건물 지형지 물을 인근 필드 (보라색)에 근접하게 분류합니다. 근접


1
옳지 않은 것 같습니다. 더 이상 코드를 공유 할 수 있습니까?
Nathan W

@NathanW 완전한 기능을 추가했습니다. 아이디어는 두 레이어의 교차점을 확인한 다음 교차점이 발견되면 한 레이어를 다른 레이어의 속성으로 업데이트하는 것입니다.
Snorfalorpagus

어떤 데이터 유형을 사용하고 있습니까?
Nathan W

두 레이어 모두 ESRI 셰이프 파일 (다각형)입니다. layer_target에는 905 개의 기능 (건물)이 있고 layer_buffered에는 서로 다른 버퍼 (100m, 50m, 20m, 10m, 5m)를 나타내는 겹치는 다각형이있는 1155 개의 기능 (공백 공간)이 있으므로 '거리'특성이 있습니다.
Snorfalorpagus

1
데이터에 어떻게 접근합니까? (예 : 네트워크, 기존 디스크, SSD)? 단일 쓰기 작업에 대한 I / O 오버 헤드가 시간 소모적 일 수 있습니까? 테스트로 : 변경된 모든 속성을 메모리에 버퍼링 한 다음 끝에 dataProvider.changeAttributeValues ​​()를 한 번 호출 할 수 있습니다.
Matthias Kuhn

답변:


7

문제는 데이터 호출 QgsDataProvider.changeAttributeValues()및 시스템 구성에 따라 모든 관련 오버 헤드로 새 트랜잭션 을 시작하기위한 각 호출이

(와 같이 QgsVectorLayer.changeAttributeValue()) 레이어에서 기능이 먼저 변경되면 모든 변경 사항이 메모리에 캐시되어 훨씬 빨라지고 결국 하나의 단일 트랜잭션으로 커밋됩니다.

스크립트 내에서 (즉, 벡터 레이어 편집 버퍼 외부에서) 동일한 버퍼링을 수행 한 다음 QgsDataProvider.changeAttributeValues()루프 외부에서 한 번 호출하여 한 트랜잭션에서 커밋 할 수 있습니다.

최근 QGIS 버전에는 이에 대한 편리한 바로 가기가 있습니다.

with edit(layer):
    for fid in fids:
        layer.changeAttributeValue(fid, idx, value)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.