Bir Python eklentisinden QGIS'deki nitelikleri düzenleme hızı


9

Bir QGIS Python eklentisi kullanarak bir katmanda her özellik için bir özniteliğin değerini düzenlemeye çalışıyorum. Bunu düzenleme modunun dışında yapmanın düzenleme sırasındakinden çok daha yavaş olduğunu fark ettim. Aşağıdaki koda bakın (satırlar bir döngü içinde aynı noktada değiştirilebilir). Örnek veri kümem için hız farkı 2 saniyedir (düzenleme modu) - 72 saniyedir (düzenleme modu değil).

Düzenleme modunda bir özniteliği değiştirme:

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

Düzenleme modunun dışındaki bir özelliği değiştirme:

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

Bu beklenen bir davranış mı? Değişiklikleri geri alabilmek için kullanıcıya ihtiyacım yok, bu yüzden düzenleme modunu kullanmam gerektiğini düşünmüyorum.

Düzenleme 1: Her iki sürümün de dahil olduğu (ancak yorum yapılan) aşağıdaki tam kodu inceleyin:

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)

Her iki yöntem de aynı sonucu verir, ancak veri sağlayıcı aracılığıyla yazmak çok daha uzun sürer. İşlev, önceden oluşturulmuş arabellekleri (brown-ish) kullanarak bina özelliklerinin yakın alanlara (mor) yakınlığını sınıflandırır. yakınlık


1
Bu doğru görünmüyor. Kodunuzu daha fazla paylaşabilir misiniz?
Nathan W

@NathanW Komple fonksiyonu ekledim. Fikir kavşak için iki katmanı kontrol etmek, ardından bir kavşak bulunduğunda bir katmanı diğer katmanın niteliğiyle güncellemektir.
Snorfalorpagus

Hangi veri türünü kullanıyorsunuz?
Nathan W

Her iki katman da bir ESRI Shapefiles (çokgen). Layer_target 905 özelliğe (bina) sahiptir, layer_buffered farklı tamponları (100m, 50m, 20m, 10m, 5m) temsil eden örtüşen çokgenlere sahip 1155 özelliğe (açık alan) sahiptir - dolayısıyla 'mesafe' niteliği.
Snorfalorpagus

1
Verilere nasıl erişilir? (yani ağ üzerinden, geleneksel disk, SSD)? Tek bir yazma işlemi için G / Ç ek yükünün zaman alıcı olması mümkün mü? Bir test olarak: bellekte değiştirilen tüm özniteliklerinizi arabelleğe almayı deneyebilir ve daha sonra dataProvider.changeAttributeValues ​​() işlevini sonunda bir kez çağırabilirsiniz.
Matthias Kuhn

Yanıtlar:


7

Sorun, QgsDataProvider.changeAttributeValues()ilgili tüm ek yük ile yeni bir işlem başlatmak için yapılan her çağrı (veri sağlayıcısına ve sistem yapılandırmasına bağlı olarak)

Önce katmandaki özellikler değiştiğinde (olduğu gibi QgsVectorLayer.changeAttributeValue()) tüm değişiklikler bellekte önbelleğe alınır, bu çok daha hızlıdır ve sonunda tek bir işlemde gerçekleştirilir.

Aynı arabelleğe alma komut dosyasında (yani vektör katmanı düzenleme arabelleğinin dışında) elde edilebilir ve daha sonra, bir işlem QgsDataProvider.changeAttributeValues(), döngü dışında bir kez çağrılarak gerçekleştirilebilir .

Ayrıca son QGIS sürümlerinde bunun için kullanışlı bir kısayol var:

with edit(layer):
    for fid in fids:
        layer.changeAttributeValue(fid, idx, value)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.