एक पायथन प्लगइन से QGIS में संपादन विशेषताओं की गति


9

मैं QGIS पायथन प्लगइन का उपयोग करके एक परत में प्रत्येक विशेषता के लिए एक विशेषता के मूल्य को संपादित करने की कोशिश कर रहा हूं। मैंने पाया है कि संपादन करते समय (संपादन संपादित करने सहित) की तुलना में संपादन मोड के बाहर ऐसा करना बहुत धीमा है। नीचे कोड देखें (एक लूप में एक ही बिंदु पर विनिमेय लाइनें)। मेरे नमूना डेटासेट की गति में अंतर 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
यह सही नहीं लगता। क्या आप अपने किसी भी कोड को साझा कर सकते हैं
नाथन डब्ल्यू

@NathanW मैंने पूरा फ़ंक्शन जोड़ा है। चौराहों के लिए दो परतों की जांच करने का विचार है, फिर एक परत को दूसरी परत की विशेषता के साथ अद्यतन करें जब एक चौराहा मिलता है।
स्नोरफालोर्पस

आप किस डेटा प्रकार का उपयोग कर रहे हैं?
नाथन डब्ल्यू

दोनों एक ESRI शेपफाइल्स (बहुभुज) को परत करते हैं। Layer_target में 905 विशेषताएं (भवन) हैं, layer_buffered में 1155 विशेषताएं (खुली जगह) हैं, जिसमें विभिन्न बफ़र्स (100 मीटर, 50 मीटर, 20 मीटर, 10 मीटर, 5 मीटर) का प्रतिनिधित्व करने वाले बहुभुज हैं - इसलिए 'दूरी' विशेषता है।
स्नोरफालोर्पस

1
आप डेटा को कैसे एक्सेस कर सकते हैं? (यानी नेटवर्क, पारंपरिक डिस्क, एसएसडी)? क्या यह संभव है, कि मैं / O ओवरहेड एक एकल लिखने के लिए समय लेने वाली है? एक परीक्षण के रूप में: क्या आप मेमोरी में अपनी सभी बदली हुई विशेषताओं को बफ़र करने का प्रयास कर सकते हैं और अंत में एक बार dataProvider.changeAttributeValues ​​() को कॉल कर सकते हैं।
मथायस कुह्न

जवाबों:


7

समस्या यह थी, कि प्रत्येक कॉल QgsDataProvider.changeAttributeValues()सभी संबंधित ओवरहेड (डेटा प्रदाता और सिस्टम कॉन्फ़िगरेशन के आधार पर) के साथ एक नया लेनदेन शुरू करने के लिए करता है।

जब पहले (जैसा कि QgsVectorLayer.changeAttributeValue()) परत पर सुविधाओं को बदल दिया जाता है, तो स्मृति में सभी बदलावों को कैश किया जाता है, जो बहुत तेज होता है और फिर अंत में एक ही लेनदेन में प्रतिबद्ध होता है।

उसी बफ़रिंग को स्क्रिप्ट के भीतर (यानी वेक्टर लेयर एडिट बफर के बाहर) प्राप्त किया जा सकता है और फिर QgsDataProvider.changeAttributeValues()लूप के बाहर एक बार कॉल करके एक ट्रांजैक्शन में प्रतिबद्ध किया जा सकता है।

हाल ही में QGIS संस्करणों में इसके लिए एक आसान शॉर्टकट भी है:

with edit(layer):
    for fid in fids:
        layer.changeAttributeValue(fid, idx, value)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.