QgsSpatialIndex에서 반환 한 기능에 효율적으로 액세스하는 방법은 무엇입니까?


9

PyQGIS 요리 책은 공간 인덱스를 설정하는 방법에 대해 설명하지만, 그것은 단지 그것의 사용의 절반을 설명합니다 :

공간 인덱스 만들기 — 다음 코드는 빈 인덱스를 만듭니다.

index = QgsSpatialIndex()

인덱스에 기능 추가-인덱스는 QgsFeature 객체를 가져 와서 내부 데이터 구조에 추가합니다. 객체를 수동으로 만들거나 공급자의 nextFeature ()에 대한 이전 호출에서 하나를 사용할 수 있습니다.

index.insertFeature(feat)

공간 인덱스가 일부 값으로 채워지면 쿼리를 수행 할 수 있습니다

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

반환 된 기능 ID에 속하는 실제 기능을 가져 오는 가장 효율적인 단계는 무엇입니까?

답변:


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>

감사! Snorfalorpagus는 setFilterFids가 게시 한 솔루션보다 상당히 느릴 것이라고 언급했습니다. 이것을 확인합니까?
underdark

큰 결과 집합에 사용하지 않았으므로 확인할 수 없습니다.
gsherman

1
내가 확인하고, 내 경우에는, RTREE가 더 빨리 QgsSpatialIndex ()보다 (의 건설 평면 그래프 매우 큰 폴리 라인 레이어에서, 모듈의 전위 매끈한와 PlanarGraph PyQGIS한다.하지만 피오나, 매끈한 및 RTREE와 해결책은 아직입니다 가장 빠른)
gene

1
나는 다양한 인덱싱 방법의 속도보다는 반환 된 기능 ID 에서 실제 기능을 얻는 것에 대한 질문이라고 생각합니다 .
gsherman

7

에서 주제에 대한 블로그 게시물 , 나단 우드는 다음 코드를 제공합니다 :

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)

이를 통해 FID를 사용하여 QgsFeature를 빠르게 찾을 수있는 사전이 생성됩니다.

매우 큰 레이어의 경우 많은 메모리가 필요하므로 특히 실용적이지 않다는 것을 알았습니다. 그러나 사용하는 대체 기능 (원하는 기능에 대한 임의 액세스)은 layer.getFeatures(QgsFeatureRequest().setFilterFid(fid))상대적으로 매우 느린 것 같습니다. SWIG OGR 바인딩을 사용하는 동등한 호출 layer.GetFeature(fid)이 이것보다 훨씬 빠르기 때문에 이것이 왜 그런지 잘 모르겠습니다 .


1
사전을 사용했다 매우 것보다 훨씬 빠르기 때문에 layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)). 140k 기능이있는 레이어를 작업하고 있었으며 140k 조회의 총 시간은 몇 분에서 몇 초로 단축되었습니다.
Håvard Tveite

5

비교를 위해 QGIS, ArcGIS, PostGIS 등이없는 Python 에서 보다 효율적인 공간 조인을보십시오 . 제시된 솔루션은 Python 모듈 Fiona , Shapelyrtree (공간 인덱스)를 사용합니다.

PyQGIS와 같은 예제에서 두 개의 레이어 pointpolygon:

여기에 이미지 설명을 입력하십시오

1) 공간 인덱스가없는 경우 :

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) 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

이 지수는 무엇을 의미합니까?

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)]]

QGIS, ArcGIS, PostGIS 등이없는 Python의보다 효율적인 공간 조인 과 같은 결론 :

  • 없는 색인과 색인을 사용하면 모든 도형 (다각형 및 점)을 반복해야합니다.
  • 경계 공간 인덱스 (QgsSpatialIndex ())를 사용하면 현재 지오메트리 (상당한 양의 계산 및 시간을 절약 할 수있는 '필터')와 교차 할 수있는 지오메트리를 통해서만 반복 할 수 있습니다.
  • 당신은 또한 다른 공간 인덱스 파이썬 모듈 (사용할 수 있습니다 RTREE , Pyrtree 또는 쿼드 트리 에로 PyQGIS과)를 , A는 코드의 속도로 공간 인덱스를 QGIS 사용 (QgsSpatialIndex ()와 함께 RTREE )
  • 그러나 공간 인덱스는 마술 지팡이가 아닙니다. 데이터 집합의 많은 부분을 검색해야하는 경우 공간 인덱스는 속도 이점을 제공 할 수 없습니다.

GIS se의 다른 예 : QGIS에서 가장 가까운 점을 찾는 방법은 무엇입니까? [복제]


모든 추가 설명에 감사드립니다. 기본적으로 솔루션은 Snorfalorpagus와 마찬가지로 dict 대신 목록을 사용합니다. 그래서 실제로 layer.getFeatures ([ids]) 함수가없는 것 같습니다 ...
underdark

이러한 설명의 목적은 순전히 기하학적이고 같이 그것은 layer.getFeatures ([식별자]) 기능을 추가하는 것은 매우 쉽다 QGIS, 한 ArcGIS PostGIS와 등없이 파이썬 조인 더 효율적인 공간
유전자

0

분명히 성능이 좋은 유일한 방법은 필터가 fid처럼 단순하더라도 layer.getFeatures () 호출을 피하거나 묶는 것입니다.

이제 함정이 있습니다. getFeatures 호출은 비쌉니다. 벡터 계층에서 호출하면 QGIS는 데이터 저장소 (계층 제공자)에 대한 새로운 연결을 설정하고, 데이터를 리턴하기위한 쿼리를 작성하고, 제공자에서 리턴 한대로 각 결과를 구문 분석해야합니다. VPN 연결을 통한 PostGIS 테이블과 같은 일부 유형의 원격 계층으로 작업하는 경우 특히 느릴 수 있습니다.

출처 : http://nyalldawson.net/2016/10/speeding-up-your-pyqgis-scripts/

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.