Saya mencoba mengedit nilai atribut untuk setiap fitur dalam sebuah layer menggunakan plugin QGIS Python. Saya menemukan bahwa melakukan ini di luar mode pengeditan jauh lebih lambat daripada saat mengedit (bahkan termasuk melakukan pengeditan). Lihat kode di bawah ini (garis dipertukarkan pada titik yang sama dalam satu lingkaran). Perbedaan kecepatan untuk dataset sampel saya adalah 2 detik (mode edit) vs 72 detik (bukan mode edit).
Mengubah atribut dalam mode edit:
layer.changeAttributeValue(feature.id(), 17, QtCore.QVariant(value))
Mengubah atribut di luar mode edit:
layer.dataProvider().changeAttributeValues({ feature.id() : { 17 : QtCore.QVariant(value) } })
Apakah ini perilaku yang diharapkan? Saya tidak membutuhkan pengguna untuk dapat membatalkan perubahan, jadi saya rasa saya tidak perlu menggunakan mode edit.
Sunting 1: Lihat kode lengkap di bawah ini dengan kedua versi disertakan (tetapi dikomentari):
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)
Kedua metode menghasilkan hasil yang sama, tetapi menulis melalui penyedia data membutuhkan waktu lebih lama. Fungsi mengklasifikasikan kedekatan fitur bangunan ke bidang terdekat (ungu) menggunakan buffer yang dibuat sebelumnya (brown-ish).
Jawaban:
Masalahnya adalah, bahwa setiap panggilan untuk
QgsDataProvider.changeAttributeValues()
memulai transaksi baru dengan semua overhead terkait (tergantung pada penyedia data dan konfigurasi sistem)Ketika fitur diubah pada layer pertama (seperti pada
QgsVectorLayer.changeAttributeValue()
) semua perubahan di-cache dalam memori, apa yang jauh lebih cepat dan kemudian dilakukan dalam satu transaksi tunggal pada akhirnya.Buffer yang sama dapat dicapai dalam skrip, (yaitu di luar buffer edit layer vektor) dan kemudian dilakukan dalam satu transaksi dengan memanggil
QgsDataProvider.changeAttributeValues()
sekali, di luar loop.Ada juga jalan pintas yang berguna untuk ini dalam versi QGIS terbaru:
sumber