5

I can find nearby features in a layer by using QgsSpatialIndex: Finding the nearest line to a point in QGIS? Using this method, we need to feed in all existing features and query it with a point to get back the nearby features.

However I wonder what is indexed vector layer, the option that can be enabled when creating a new in-memory layer. I thought that it would perform indexing for all features and would give better performance during querying. Therefore, there must be a way to issue a nearby query on the layer itself without explicitly initialising QgsSpatialIndex, or else why should I turn on the index option?

I can turn on index in Layer Properties > General > Create spatial index or it will be turned on by default if I create a temporary scratch layer. I notice that it improves the speed of rendering.

Now in my PyQGIS script, how can I take advantage of the existing index without creating a QgsSpatialIndex class to query nearby features or doing any nearest neighbor analysis?

spIndex = QgsSpatialIndex()
for pointFeatures in pointsLayer.getFeatures():
    spIndex.insertFeature(pointFeat)
nearbyPointFeatureIds = spIndex.nearestNeighbor(testPoint, 3)

My concern is why I should create my own in-memory index again in the first three lines above. Have I missed that I can get something like a QgsVectorLayer.spatialIndex.nearestNeighbor() from the layer itself?

  • Do you have a code sample to clarify what you mean? – alphabetasoup Apr 3 '17 at 8:25
  • Do you know what is the purpose of indexing layer? You can see the example in the link. – CallMeLaNN Apr 3 '17 at 8:52
  • @CallMeLaNN, was my answer helpful? – mgri Apr 21 '17 at 13:27
3

From what I know, you are comparing different things (even if their names are similar and this could be misleading).


As you correctly wrote, the QgsSpatialIndex() class is useful for finding nearest objects. The following text is an excerpt from the QGIS Documentation (the [...] and the bold style are added by me for the sake of clearness):

Spatial indexes can dramatically improve the performance of your code if you need to do frequent queries to a vector layer. [...] This can be a very time consuming task, especially if it needs to be repeated for several locations. If a spatial index exists for the layer, the operation is much more effective.

[...]

Spatial indexes are not created by default for a QGIS vector layer, but you can create them easily. This is what you have to do:

  • create spatial index — the following code creates an empty index

    index = QgsSpatialIndex()

The QgsSpatialIndex() class is only used temporarily and improves the performance of querying a shapefile.


Instead, a Spatial Index improves the performance of drawing a shapefile and it is generally stored on disk. The following text is an excerpt from the QGIS Documentation (the bold style is added by me for the sake of clearness):

To improve the performance of drawing a shapefile, you can create a spatial index. A spatial index will improve the speed of both zooming and panning. Spatial indexes used by QGIS have a .qix extension.

Use these steps to create the index:

  • Load a shapefile.
  • Open the Layer Properties dialog by double-clicking on the shapefile name in the legend or by right-clicking and choosing Properties from the popup menu.
  • In the tab General click the [Create Spatial Index] button.

Using PyQGIS, a spatial index would be created using the createSpatialIndex() module from the QgsVectorDataProvider class:

provider = layer.dataProvider()
index = provider.createSpatialIndex()

This will create a spatial index on the datasource and the .qix file in the same folder where the original shapefile is stored.


With these premises, I try to add something more to the answer in the case of dealing with memory layers instead of persistent shapefiles (the following needs to be intended as a personal opinion since I wasn't able to verify it).

I think that the following text, reported in the QGIS Documentation (the [...] are added by me for the sake of clearness):

[...]

The memory provider also supports spatial indexing, which is enabled by calling the provider’s createSpatialIndex() function. Once the spatial index is created you will be able to iterate over features within smaller regions faster (since it’s not necessary to traverse all the features, only those in specified rectangle).

A memory provider is created by passing "memory" as the provider string to the QgsVectorLayer constructor.

[...]

The URI can also specify the coordinate reference system, fields, and indexing of the memory provider in the URI. The syntax is:

[...]

`index=yes` (Specifies that the provider will use a spatial index)

refers to a Spatial Index and not to the QgsSpatialIndex() class, so it is only used for improving the performance of drawing the layer and this justifies why a QgsSpatialIndex() class is often called when a query on many features is needed.

  • Thanks to point out the createSpatialIndex() method. It indicate that Spatial Index do nothing in memory layer because it simply return false. That means actually memory layer does not support spatial index. Besides that, I can also conclude that there is no QgsSpatialIndex() created by memory layer or provider in order for me to just use it. So I have to create one and update whenever there are features added/removed! – CallMeLaNN Apr 24 '17 at 19:03
  • I just don't understand why the documentation said "The memory provider also supports spatial indexing". I found nothing in the QgsVectorLayer and QgsVectorDataProvider source code related to it. – CallMeLaNN Apr 24 '17 at 19:11
  • @CallMeLaNN I think it's related to the next sentence: which is enabled by calling the provider’s createSpatialIndex() function, so maybe it still refers to Spatial Index (and not QgsSpatialIndex()). – mgri Apr 24 '17 at 19:25
1

First question is 'what format is your data stored as'?

If you are talking a PostGIS table, for example, the spatial index WILL be used by default.

Regarding other data formats, this question indicates that a spatialite spatial index is used.

Yes. It does as it appears from looking at the source code for the Spatialite Data Provider.

And from that, I would assume that if an index exists, it'll be used. The QGIS QgsSpatialIndex() function is handy for use if the dataset doesn't already have an index.

  • 1
    It is just temporary scratch layer using in-memory data provider. I have a python script to retrieve data from MongoDb, create QgsFeatures and add into the layer. I just afraid if QgsSpatialIndex is redundant with what the index exists. So if it exists for memory layer, how to use it in python? – CallMeLaNN Apr 4 '17 at 5:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.