Estoy tratando de editar el valor de un atributo para cada característica en una capa utilizando un plugin de QGIS Python. He encontrado que hacer esto fuera del modo de edición es mucho más lento que mientras se edita (incluso incluyendo la confirmación de las ediciones). Véase el código siguiente (líneas intercambiables en el mismo punto de un bucle). La diferencia de velocidad para mi conjunto de datos de muestra es de 2 segundos (modo de edición) frente a 72 segundos (sin modo de edición).
Modificar un atributo en modo de edición:
layer.changeAttributeValue(feature.id(), 17, QtCore.QVariant(value))
Modificar un atributo fuera del modo de edición:
layer.dataProvider().changeAttributeValues({ feature.id() : { 17 : QtCore.QVariant(value) } })
¿Es un comportamiento esperado? No necesito que el usuario pueda deshacer los cambios, así que no creo que necesite usar el modo de edición.
Editar 1: Vea el código completo a continuación con ambas versiones incluidas (pero comentadas):
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)
Ambos métodos producen el mismo resultado, pero la escritura a través del proveedor de datos lleva mucho más tiempo. La función clasifica la proximidad de las características del edificio a los campos cercanos (púrpura) utilizando topes precreados (marrón).
1 votos
Eso no parece correcto. ¿Puedes compartir algo más de tu código?
0 votos
@NathanW He añadido la función completa. La idea es comprobar dos capas para las intersecciones, a continuación, actualizar una capa con el atributo de la otra capa cuando se encuentra una intersección.
0 votos
¿Qué tipo de datos está utilizando?
0 votos
Ambas capas son Shapefiles ESRI (polígono). La capa_objetivo tiene 905 rasgos (edificios), la capa_buffered tiene 1155 rasgos (espacios abiertos) con polígonos superpuestos que representan diferentes topes (100m, 50m, 20m, 10m, 5m) - de ahí el atributo "distancia".
0 votos
@NathanW Al releer tu comentario: el campo es un entero.
1 votos
¿Cómo se accede a sus datos? (es decir, a través de la red, del disco tradicional, del SSD)? ¿Es posible que la sobrecarga de E/S para una sola operación de escritura consuma mucho tiempo? Como prueba: puede intentar almacenar todos los atributos modificados en la memoria y luego llamar a dataProvider.changeAttributeValues() una vez al final.
0 votos
@MatthiasKuhn Los datos se almacenan en un disco duro local tradicional. He probado a almacenar en el buffer todos los cambios y llamar a dataProvider.changeAttributeValues() una vez al final - esto parece arreglarlo. Creo que es la solución que buscaba.
0 votos
Muy bien. He añadido un texto de respuesta para futuras referencias. Sería bueno, si usted puede copiar las partes pertinentes de su script allí.