QgsSpatialIndex tarafından döndürülen özelliklere verimli bir şekilde nasıl erişilir?


9

PyQGIS Cookbook kayma dizin kurmak açıklar ama sadece onun kullanım yarısını açıklıyor:

uzamsal dizin oluştur - aşağıdaki kod boş bir dizin oluşturur

index = QgsSpatialIndex()

index'e özellikler ekleme - index QgsFeature nesnesini alır ve bunu iç veri yapısına ekler. Nesneyi manuel olarak oluşturabilir veya önceki çağrıdan sağlayıcının nextFeature () öğesine bir tane kullanabilirsiniz.

index.insertFeature(feat)

uzamsal dizin bazı değerlerle dolduğunda, bazı sorgular yapabilirsiniz

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

Döndürülen özellik kimliklerine ait gerçek özellikleri elde etmenin en etkili adımı nedir?

Yanıtlar:


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>

Teşekkürler! Snorfalorpagus, setFilterFids'in yayınladığı çözümden önemli ölçüde daha yavaş olacağını belirtti. Bunu onaylıyor musunuz?
underdark

Büyük sonuç kümelerinde kullanmadım, bu yüzden onaylayamıyorum.
gsherman

1
Ben onaylıyorum ve benim durumumda, rtree QgsSpatialIndex () 'den bile daha hızlı ( çok büyük çoklu katman katmanlarından Düzlemsel Grafiklerin inşası için , PlanarGraph modülünün PyQGIS'de Shapely ile transpozisyonu . Ama Fiona, Shapely ve rtree ile çözüm hala en hızlı)
gen

1
Soru, çeşitli indeksleme yöntemlerinin hızı yerine , döndürülen özellik kimlikleri gerçek özellikleri elde etmek hakkında olduğuna inanıyorum .
gsherman

7

Konuyla ilgili bir blog gönderisinde Nathan Woodrow aşağıdaki kodu sağlar:

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)

Bu, bir QgsFeature öğesini FID'sini kullanarak hızlı bir şekilde aramanızı sağlayan bir sözlük oluşturur.

Çok büyük katmanlar için bunun çok fazla bellek gerektirdiğinden özellikle pratik olmadığını gördüm. Bununla birlikte, alternatif (istenen özelliğe rastgele erişim) layer.getFeatures(QgsFeatureRequest().setFilterFid(fid))kullanımının nispeten çok yavaş olduğu görülmektedir. SWIG OGR bağlarını kullanan eşdeğer çağrı bundan layer.GetFeature(fid)daha hızlı göründüğü için bunun neden olduğundan emin değilim .


1
Sözlük kullanmak çok daha hızlıydı layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)). 140 bin özellikli bir katman üzerinde çalışıyordum ve 140 bin aramanın toplam süresi birkaç dakikadan saniyeye çıktı.
Håvard Tveite

5

Karşılaştırmalar için QGIS, ArcGIS, PostGIS, vb olmadan Python'da Daha Verimli Mekansal birleşime bakın . Solüsyon sunulan kullanım Python modülleri Fiona , düzgün ve RTree (Mekansal Dizin).

PyQGIS ve aynı örnekle iki katman pointve polygon:

resim açıklamasını buraya girin

1) Mekansal indekssiz:

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 uzamsal indeksi ile:

# 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

Bu endeksler ne anlama geliyor?

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, vb olmadan Python'a Daha Verimli Mekansal katılma ile aynı sonuçlar :

  • İndeks olmadan, tüm geometrileri (çokgenler ve noktalar) tekrarlamanız gerekir.
  • Sınırlayıcı bir uzamsal indeksle (QgsSpatialIndex ()), yalnızca mevcut geometrinizle kesişme şansı olan geometriler aracılığıyla yinelenirsiniz (önemli miktarda hesaplama ve zaman kazandırabilen 'filtre' ...).
  • Kodunuzu hızlandırmak için QGIS uzamsal dizin kullanma (QgsSpatialIndex () ve rtree ile ) gibi PyQGIS ile diğer uzamsal dizin Python modüllerini ( rtree , Pyrtree veya Quadtree ) kullanabilirsiniz.
  • ancak bir Mekansal Endeks sihirli bir değnek değildir. Veri kümesinin çok büyük bir kısmının alınması gerektiğinde, bir Uzamsal Dizin herhangi bir hız avantajı sağlayamaz.

GIS se'deki diğer örnek: QGIS'te bir noktaya en yakın hattı nasıl bulabilirim? [çiftleme]


Tüm ek açıklamalar için teşekkürler. Temel olarak, çözümünüz Snorfalorpagus'un yaptığı gibi bir dikte yerine bir liste kullanıyor. Yani gerçekten hiç layer.getFeatures ([ids]) işlevi yok gibi görünüyor ...
underdark

Bu açıklama amacı sadece geometrik ve olduğu gibi bir layer.getFeatures ([kimlikleri]) işlevi eklemek çok kolaydır QGIS, ArcGIS, PostGIS, vs olmadan Python katılması daha etkili olarak Yer
gen

0

Görünüşe göre iyi performans elde etmenin tek yöntemi, filtre bir fid kadar basit olsa bile, layer.getFeatures () öğesine yapılan çağrıları önlemek veya paketlemektir.

Şimdi, işte tuzak: getFeatures'ı çağırmak pahalı. Bir vektör katmanında çağırırsanız, QGIS'in veri deposuna (katman sağlayıcı) yeni bir bağlantı kurması, verileri döndürmek için bir sorgu oluşturması ve her sonucu sağlayıcıdan döndürülürken ayrıştırması gerekir. Bu, özellikle VPN bağlantısı üzerinden PostGIS tablosu gibi bir tür uzak katmanla çalışıyorsanız yavaş olabilir.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.