Tốc độ chỉnh sửa các thuộc tính trong QGIS từ plugin Python


9

Tôi đang cố gắng chỉnh sửa giá trị của một thuộc tính cho từng tính năng trong một lớp bằng cách sử dụng plugin QGIS Python. Tôi đã thấy rằng thực hiện việc này ngoài chế độ chỉnh sửa chậm hơn nhiều so với khi chỉnh sửa (thậm chí bao gồm cả việc thực hiện các chỉnh sửa). Xem mã dưới đây (các dòng có thể hoán đổi cho nhau tại cùng một điểm trong một vòng lặp). Sự khác biệt về tốc độ cho tập dữ liệu mẫu của tôi là 2 giây (chế độ chỉnh sửa) so với 72 giây (không phải chế độ chỉnh sửa).

Sửa đổi một thuộc tính trong chế độ chỉnh sửa:

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

Sửa đổi một thuộc tính bên ngoài chế độ chỉnh sửa:

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

Đây có phải là một hành vi dự kiến? Tôi không cần người dùng có thể hoàn tác các thay đổi, vì vậy tôi không nghĩ mình cần sử dụng chế độ chỉnh sửa.

Chỉnh sửa 1: Xem mã đầy đủ bên dưới với cả hai phiên bản được bao gồm (nhưng đã nhận xét):

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)

Cả hai phương pháp đều tạo ra cùng một kết quả, nhưng việc viết thông qua nhà cung cấp dữ liệu mất nhiều thời gian hơn. Hàm phân loại độ gần của các tính năng xây dựng với các trường gần đó (màu tím) bằng cách sử dụng bộ đệm được tạo trước (màu nâu-ish). Gần


1
Điều đó có vẻ không đúng. Bạn có thể chia sẻ thêm bất kỳ mã của bạn.
Nathan W

@NathanW Tôi đã thêm chức năng hoàn chỉnh. Ý tưởng là kiểm tra hai lớp cho các giao điểm, sau đó cập nhật một lớp với thuộc tính của lớp khác khi tìm thấy giao lộ.
Snorfalorpagus

Bạn đang sử dụng loại dữ liệu nào?
Nathan W

Cả hai lớp một Shapefiles ESRI (đa giác). Layer_target có 905 tính năng (tòa nhà), layer_buffered có 1155 tính năng (không gian mở) với các đa giác chồng chéo đại diện cho các bộ đệm khác nhau (100m, 50m, 20m, 10m, 5m) - do đó thuộc tính 'khoảng cách'.
Snorfalorpagus

1
Dữ liệu của bạn được truy cập như thế nào? (tức là qua mạng, đĩa truyền thống, SSD)? Có thể, chi phí I / O cho một thao tác ghi là tốn thời gian không? Để kiểm tra: bạn có thể thử đệm tất cả các thuộc tính đã thay đổi của mình trong bộ nhớ và sau đó gọi dataProvider.changeAttributionValues ​​() một lần ở cuối.
Matthias Kuhn

Câu trả lời:


7

Vấn đề là, mỗi cuộc gọi để QgsDataProvider.changeAttributeValues()bắt đầu một giao dịch mới với tất cả chi phí liên quan (tùy thuộc vào nhà cung cấp dữ liệu và cấu hình hệ thống)

Khi các tính năng được thay đổi trên lớp đầu tiên (như trong QgsVectorLayer.changeAttributeValue()), tất cả các thay đổi được lưu trong bộ nhớ, cái gì nhanh hơn nhiều và sau đó được cam kết trong một giao dịch cuối cùng.

Bộ đệm tương tự có thể đạt được trong tập lệnh, (tức là bên ngoài bộ đệm chỉnh sửa lớp vectơ) và sau đó được cam kết trong một giao dịch bằng cách gọi QgsDataProvider.changeAttributeValues()một lần, bên ngoài vòng lặp.

Ngoài ra còn có một phím tắt tiện dụng cho việc này trong các phiên bản QGIS gần đây:

with edit(layer):
    for fid in fids:
        layer.changeAttributeValue(fid, idx, value)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.