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完全な関数を追加しました。2つのレイヤーの交差をチェックし、交差が見つかったときに1つのレイヤーを他のレイヤーの属性で更新するという考え方です。
Snorfalorpagus 2013

どのデータ型を使用していますか?
Nathan W

どちらのレイヤーもESRIシェイプファイル(ポリゴン)です。layer_targetには905のフィーチャ(建物)があり、layer_bufferedには1155のフィーチャ(オープンスペース)があり、異なるバッファー(100m、50m、20m、10m、5m)を表すポリゴンが重なっているため、「距離」属性があります。
Snorfalorpagus 2013

1
どのようにデータにアクセスしますか?(つまり、ネットワーク、従来のディスク、SSD経由)?単一の書き込み操作のI / Oオーバーヘッドに時間がかかる可能性はありますか?テストとして:変更されたすべての属性をメモリにバッファリングしてから、最後にdataProvider.changeAttributeValues()を1回呼び出すことができますか。
Matthias Kuhn

回答:


7

問題は、の呼び出しごとにQgsDataProvider.changeAttributeValues()、関連するすべてのオーバーヘッドを伴う新しいトランザクションを開始することでした(データプロバイダーとシステム構成によって異なります)。

最初にレイヤーで機能が変更されると(のようにQgsVectorLayer.changeAttributeValue())、すべての変更がメモリにキャッシュされます。これは、はるかに高速で、最後に1つのトランザクションでコミットされます。

スクリプト内(つまり、ベクターレイヤー編集バッファーの外)で同じバッファリングを実行しQgsDataProvider.changeAttributeValues()、ループの外で1回呼び出すことで、1つのトランザクションでコミットできます。

最近のQGISバージョンには、このための便利なショートカットもあります。

with edit(layer):
    for fid in fids:
        layer.changeAttributeValue(fid, idx, value)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.