कुशलतापूर्वक QgsSpatialIndex द्वारा दी गई सुविधाओं तक कैसे पहुँचें?


9

PyQGIS कुकबुक कैसे स्थानिक सूचकांक स्थापित करने के लिए बताते हैं लेकिन यह केवल अपने उपयोग के आधे बताते हैं:

स्थानिक सूचकांक बनाएं - निम्न कोड एक खाली सूचकांक बनाता है

index = QgsSpatialIndex()

इंडेक्स में सुविधाएँ जोड़ें - इंडेक्स QgsFeature ऑब्जेक्ट लेता है और इसे आंतरिक डेटा संरचना में जोड़ता है। आप मैन्युअल रूप से ऑब्जेक्ट बना सकते हैं या प्रदाता की अगली कॉल के लिए पिछले कॉल से एक का उपयोग कर सकते हैं ()

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

मैंने बड़े परिणाम सेट पर इसका उपयोग नहीं किया है इसलिए पुष्टि नहीं कर सकता।
गजरमैन

1
मैं इस बात की पुष्टि और, मेरे मामले में, rtree भी तेजी से QgsSpatialIndex () की तुलना में है (के निर्माण के लिए Planar रेखांकन बहुत बड़ा पोलीलाइंस परतों से, मॉड्यूल के स्थानांतरण सुडौल साथ PlanarGraph PyQGIS में। लेकिन फियोना, सुडौल और rtree साथ समाधान अब भी है सबसे तेज)
जीन

1
मेरा मानना ​​है कि प्रश्न विभिन्न अनुक्रमण विधियों की गति के बजाय लौटी हुई फीचर आईडी से वास्तविक सुविधाओं को प्राप्त करने के बारे में है ।
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 लुक्स के लिए कुल समय कई मिनटों से लेकर सेकंड्स तक चला गया।
होवार्ड टवेइट

5

तुलना के लिए , क्यूजीआईएस, आर्कजीआईएस, पोस्टजीआईएस, आदि के बिना पायथन में अधिक कुशल स्थानिक जुड़ाव देखें । समाधान प्रस्तुत उपयोग अजगर मॉड्यूल फियोना , सुडौल और rtree (स्थानिक सूचकांक)।

PyQGIS और एक ही उदाहरण के साथ दो परतों, pointऔर polygon:

यहां छवि विवरण दर्ज करें

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- ट्री 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, आदि के बिना पायथन में शामिल होते हैं :

  • बिना और सूचकांक के, आपको सभी ज्यामितीय (बहुभुज और बिंदुओं) के माध्यम से पुनरावृत्त होना चाहिए।
  • एक बाउंडिंग स्पेसियल इंडेक्स (QgsSpatialIndex ()) के साथ, आप केवल उन जिओमेट्री के माध्यम से पुनरावृत्ति करते हैं, जो आपके वर्तमान ज्यामिति ('फ़िल्टर' के साथ प्रतिच्छेद करने का एक मौका है जो गणना और समय की काफी मात्रा बचा सकते हैं ...)।
  • आप अपने कोड (QgsSpatialIndex) (और rtree के साथ ) को गति देने के लिए QGIS स्थानिक सूचकांक का उपयोग करने के साथ PyQGIS के साथ अन्य स्थानिक सूचकांक पायथन मॉड्यूल ( rtree , पर्ट्री या क्वाडट्री ) का भी उपयोग कर सकते हैं।
  • लेकिन एक स्थानिक सूचकांक एक जादू की छड़ी नहीं है। जब डेटासेट के एक बहुत बड़े हिस्से को पुनः प्राप्त करना होता है, तो एक स्थानिक सूचकांक कोई गति लाभ नहीं दे सकता है।

जीआईएस से में अन्य उदाहरण: क्यूजीआईएस में एक बिंदु के लिए निकटतम रेखा कैसे खोजें? [डुप्लिकेट]


सभी अतिरिक्त स्पष्टीकरण के लिए धन्यवाद। मूल रूप से, आपका समाधान एक तानाशाह के बजाय एक सूची का उपयोग करता है जैसा कि स्नोर्फ़ालोपरागस ने किया था। तो वहाँ वास्तव में कोई layer.getFeatures ([आईडी]) समारोह ... हो रहा है
UnderDark

इस स्पष्टीकरण का उद्देश्य विशुद्ध रूप से ज्यामितीय है और एक परत जोड़ना बहुत आसान है। [[आईडी]] समारोह के रूप में और अधिक कुशल स्थानिक में शामिल होने के बिना पायथन में QGIS, ArcGIS, PostGIS, आदि
जीन

0

जाहिर तौर पर अच्छा प्रदर्शन प्राप्त करने का एकमात्र तरीका लेयर.गेटफ्रीचर्स () से कॉल को टालना या बंडल करना है, भले ही फ़िल्टर एक फिड की तरह सरल हो।

अब, यहाँ जाल: कॉलिंग getFeatures महंगा है। यदि आप इसे एक वेक्टर लेयर पर कहते हैं, तो QGIS को डेटा स्टोर (लेयर प्रोवाइडर) के लिए एक नया कनेक्शन सेटअप करने के लिए आवश्यक होगा, डेटा को वापस करने के लिए कुछ क्वेरी बनाएं और प्रदाता से वापस आने पर प्रत्येक परिणाम को पार्स करें। यह धीमा हो सकता है, खासकर यदि आप किसी प्रकार के दूरस्थ परत के साथ काम कर रहे हैं, जैसे कि वीपीएन कनेक्शन पर पोस्टजीआईएस तालिका।

स्रोत: http://nyalldawson.net/2016/10/speeding-up-your-pyqgis-scripts/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.