Làm cách nào để truy cập hiệu quả các tính năng được trả về bởi QssSpatial Index?


9

Các PyQGIS Cookbook giải thích làm thế nào để thiết lập các chỉ số không gian nhưng nó chỉ giải thích một nửa số sử dụng của nó:

tạo chỉ mục không gian - đoạn mã sau tạo một chỉ mục trống

index = QgsSpatialIndex()

thêm các tính năng vào chỉ mục - index lấy đối tượng QssFeature và thêm nó vào cấu trúc dữ liệu bên trong. Bạn có thể tạo đối tượng theo cách thủ công hoặc sử dụng một đối tượng từ cuộc gọi trước đến nhà cung cấp nextFeature () của nhà cung cấp

index.insertFeature(feat)

khi chỉ mục không gian được điền với một số giá trị, bạn có thể thực hiện một số truy vấn

# returns array of feature IDs of five nearest features
nearest = index.nearestNeighbor(QgsPoint(25.4, 12.7), 5)

Bước hiệu quả nhất để có được các tính năng thực tế thuộc về ID tính năng được trả về là gì?

Câu trả lời:


12
    # assume a list of feature ids returned from index and a QgsVectorLayer 'lyr'
    fids = [1, 2, 4]
    request = QgsFeatureRequest()
    request.setFilterFids(fids)

    features = lyr.getFeatures(request)
    # can now iterate and do fun stuff:
    for feature in features:
        print feature.id(), feature

    1 <qgis._core.QgsFeature object at 0x000000000E987510>
    2 <qgis._core.QgsFeature object at 0x000000000E987400>
    4 <qgis._core.QgsFeature object at 0x000000000E987510>

Cảm ơn! Snorfalorpagus đã đề cập rằng setFilterFids sẽ chậm hơn đáng kể so với giải pháp mà ông đã đăng. Bạn có xác nhận điều này?
underdark

Tôi chưa sử dụng nó trên các tập kết quả lớn nên không thể xác nhận.
gsherman

1
Tôi xác nhận và, trong trường hợp của tôi, rtree thậm chí còn nhanh hơn QssSpatial Index () (để xây dựng Đồ thị Planar từ các lớp polylines rất lớn, hoán vị mô-đun PlanarGraph với Shapely trong PyQGIS. Nhưng giải pháp với Fiona, Shapely và rtree vẫn là giải pháp. nhanh nhất)
gen

1
Tôi tin rằng câu hỏi là về việc có được các tính năng thực tế từ các id tính năng được trả về thay vì tốc độ của các phương pháp lập chỉ mục khác nhau.
gsherman

7

Trong một bài đăng trên blog về chủ đề này , Nathan Woodrow cung cấp mã sau:

layer = qgis.utils.iface.activeLayer()

# Select all features along with their attributes
allAttrs = layer.pendingAllAttributesList()
layer.select(allAttrs)
# Get all the features to start
allfeatures = {feature.id(): feature for (feature) in layer}

def noindex():
    for feature in allfeatures.values():
        for f in allfeatures.values():
            touches = f.geometry().touches(feature.geometry())
            # It doesn't matter if we don't return anything it's just an example

def withindex():
    # Build the spatial index for faster lookup.
    index = QgsSpatialIndex()
    map(index.insertFeature, allfeatures.values())

    # Loop each feature in the layer again and get only the features that are going to touch.
    for feature in allfeatures.values():
        ids = index.intersects(feature.geometry().boundingBox())
        for id in ids:
            f = allfeatures[id]
            touches = f.geometry().touches(feature.geometry())
            # It doesn't matter if we don't return anything it's just an example

import timeit
print "With Index: %s seconds " % timeit.timeit(withindex,number=1)
print "Without Index: %s seconds " % timeit.timeit(noindex,number=1)

Điều này tạo ra một từ điển cho phép bạn nhanh chóng tra cứu QSSFeature bằng FID.

Tôi đã thấy rằng đối với các lớp rất lớn thì điều này không thực tế lắm vì nó đòi hỏi nhiều bộ nhớ. Tuy nhiên, sự thay thế (truy cập ngẫu nhiên của tính năng mong muốn) sử dụng layer.getFeatures(QgsFeatureRequest().setFilterFid(fid))dường như tương đối chậm. Tôi không chắc tại sao lại như vậy, vì cuộc gọi tương đương sử dụng các ràng buộc SWIG OGR layer.GetFeature(fid)dường như nhanh hơn nhiều so với điều này.


1
Sử dụng một từ điển là rất nhanh hơn nhiều layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)). Tôi đã làm việc trên một lớp với các tính năng 140k và tổng thời gian cho các tra cứu 140k đã đi từ nhiều phút đến vài giây.
Håvard Tveite

5

Để so sánh, nhìn vào hiệu quả hơn không gian tham gia bằng Python mà không QGIS, ArcGIS, PostGIS, vv . Giải pháp được trình bày sử dụng các mô-đun Python Fiona , Shapelyrtree (Spatial Index).

Với PyQGIS và cùng một ví dụ hai lớp pointpolygon:

nhập mô tả hình ảnh ở đây

1) Không có chỉ số không gian:

polygons = [feature for feature in polygon.getFeatures()]
points = [feature for feature in point.getFeatures()]
for pt in points: 
    point = pt.geometry()
    for pl  in polygons:
        poly = pl.geometry()
        if poly.contains(point):
            print point.asPoint(), poly.asPolygon()
(184127,122472) [[(183372,123361), (184078,123130), (184516,122631),   (184516,122265), (183676,122144), (183067,122570), (183128,123105), (183372,123361)]]
(183457,122850) [[(183372,123361), (184078,123130), (184516,122631), (184516,122265), (183676,122144), (183067,122570), (183128,123105), (183372,123361)]]
(184723,124043) [[(184200,124737), (185368,124372), (185466,124055), (185515,123714), (184955,123580), (184675,123471), (184139,123787), (184200,124737)]]
(182179,124067) [[(182520,125175), (183348,124286), (182605,123714), (182252,123544), (181753,123799), (181740,124627), (182520,125175)]]

2) Với chỉ số không gian R-Tree PyQGIS:

# build the spatial index with all the polygons and not only a bounding box
index = QgsSpatialIndex()
for poly in polygons:
     index.insertFeature(poly)

# intersections with the index 
# indices of the index for the intersections
for pt in points:
    point = pt.geometry()
    for id in index.intersects(point.boundingBox()):
    print id
0
0
1
2

Những chỉ số này có nghĩa là gì?

for i, pt in enumerate(points):
     point = pt.geometry()
     for id in index.intersects(point.boundingBox()):
        print "Point ", i, points[i].geometry().asPoint(), "is in Polygon ", id, polygons[id].geometry().asPolygon()
Point  1 (184127,122472) is in Polygon  0 [[(182520,125175), (183348,124286), (182605,123714), (182252,123544), (181753,123799), (181740,124627), (182520,125175)]]
Point  2 (183457,122850) is in Polygon  0 [[(182520,125175), (183348,124286), (182605,123714), (182252,123544), (181753,123799), (181740,124627), (182520,125175)]]
Point  4 (184723,124043) is in Polygon  1 [[(182520,125175), (183348,124286), (182605,123714), (182252,123544), (181753,123799), (181740,124627), (182520,125175)]]
Point  6 (182179,124067) is in Polygon  2 [[(182520,125175), (183348,124286), (182605,123714), (182252,123544), (181753,123799), (181740,124627), (182520,125175)]]

Kết luận tương tự như trong Tham gia không gian hiệu quả hơn trong Python mà không có QGIS, ArcGIS, PostGIS, v.v . :

  • Không có và chỉ mục, bạn phải lặp qua tất cả các hình học (đa giác và điểm).
  • Với chỉ số không gian giới hạn (QssSpatial Index ()), bạn chỉ lặp qua các hình học có cơ hội giao với hình học hiện tại của bạn ('bộ lọc' có thể tiết kiệm một lượng tính toán và thời gian đáng kể ...).
  • Bạn cũng có thể sử dụng chỉ số không gian Python module khác ( rtree , Pyrtree hoặc quadtree ) với PyQGIS như trong Sử dụng một QGIS chỉ số không gian với tốc độ lên mã của bạn (với QgsSpatialIndex () và rtree )
  • nhưng Chỉ số không gian không phải là cây đũa thần. Khi một phần rất lớn của bộ dữ liệu phải được truy xuất, Chỉ mục không gian không thể mang lại bất kỳ lợi ích tốc độ nào.

Một ví dụ khác trong GIS se: Làm thế nào để tìm dòng gần nhất đến một điểm trong QGIS? [bản sao]


Cảm ơn tất cả các giải thích bổ sung. Về cơ bản, giải pháp của bạn sử dụng một danh sách thay vì một lệnh như Snorfalorpagus đã làm. Vì vậy, dường như thực sự không có chức năng layer.getFeatures ([ids]) ...
underdark

Mục đích của việc giải thích này hoàn toàn là hình học và nó là rất dễ dàng để thêm một layer.getFeatures ([id]) chức năng như trong hiệu quả hơn không gian tham gia bằng Python mà không QGIS, ArcGIS, PostGIS, vv
gen

0

Rõ ràng phương pháp duy nhất để có được hiệu năng tốt là tránh hoặc bó các lệnh gọi tới layer.getFeatures (), ngay cả khi bộ lọc đơn giản như một fid.

Bây giờ, đây là cái bẫy: gọi getFeatures là tốn kém. Nếu bạn gọi nó trên một lớp vectơ, QGIS sẽ được yêu cầu thiết lập kết nối mới đến kho lưu trữ dữ liệu (nhà cung cấp lớp), tạo một số truy vấn để trả về dữ liệu và phân tích từng kết quả khi được trả về từ nhà cung cấp. Điều này có thể chậm, đặc biệt nếu bạn đang làm việc với một số loại lớp từ xa, chẳng hạn như bảng PostGIS qua kết nối VPN.

nguồn: http://nyalldawson.net/2016/10/speeding-up-your-pyqgis-scripts/

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.