5

I have a shapefile of thousands of polylines. I have select one feature, I want to select all other features that is within say 100m of the selected feature.

How do I achieve it by pyqgis?

enter image description here

  • Is the one feature selected using a mouseclick or from code? – weiji14 Jan 6 '17 at 2:05
  • it is from code, say select where fid = 1 – chenghopan Jan 6 '17 at 2:06
  • Do you want the 100m tolerance to be set from the selected feature's centre, bounding box rectangle, or as an actual 100m buffer from the line (note increasing order of complexity). – weiji14 Jan 6 '17 at 2:16
  • i want it to be the buffer – chenghopan Jan 6 '17 at 2:17
  • 2
    Welcome to gis.stackexchange! Please note that a good question on this site is expected to show some degree of research on your part, i.e. what you have tried and - if applicable - code so far. For more info, you can check our faq. – underdark Jan 8 '17 at 20:08
8

If you want to select all features that are within 100 m of the selected "buffer" feature you can use next code:

layer = iface.activeLayer()

feats = [ feat for feat in layer.getFeatures() ]

#selected feature fid = 0
geom_buffer = feats[0].geometry().buffer(100, -1)

#erasing selected feature in original list
del feats[0]

new_feats = [feat for feat in feats
             if feat.geometry().intersects(geom_buffer) ]

epsg = layer.crs().postgisSrid()

uri = "LineString?crs=epsg:" + str(epsg) + "&field=id:integer""&index=yes"

mem_layer = QgsVectorLayer(uri,
                           'line',
                           'memory')

prov = mem_layer.dataProvider()

for i, feat in enumerate(new_feats):
    feat.setAttributes([i])

prov.addFeatures(new_feats)

QgsMapLayerRegistry.instance().addMapLayer(mem_layer)

It produces a memory layer with features that match this condition.

I tried out above code with next line layer; where selected feature (id=0) was previously visualized as buffer by using its WKT format into QuickWKT plugin of QGIS.

enter image description here

After running the code, memory layer (red layer in next image) was obtained as expected:

enter image description here

4

This should give you some ideas.

lyr = qgis.utils.iface.activeLayer()
featDict = {feature.id(): feature for (feature) in lyr.getFeatures()}  #stores features in a dictionary for fast access
featIdx = QgsSpatialIndex(lyr.getFeatures())   #spatial index for faster spatial queries
bufDist = 100                                  #sets distance

for line in lyr.selectedFeatures():
    xyList = line.geometry().asPolyline()
    minx = min([xy[0] for xy in xyList])   #minimum x-coordinate
    maxx = max([xy[0] for xy in xyList])   #maximum x-coordinate
    miny = min([xy[1] for xy in xyList])   #minimum y-coordinate
    maxy = max([xy[1] for xy in xyList])   #maximum y-coordinate
    ids = featIdx.intersects(QgsRectangle(minx - bufDist, miny - bufDist, maxx + bufDist, maxy + bufDist))

    #lyr.selectByIds(ids)  #use this if you don't need total accuracy, much faster!!

    #For QGIS versions below 2.16        
    for id in ids:
        if featDict[id].geometry().distance(line.geometry()) < bufDist:
            lyr.select(id)

    #For QGIS 2.16 or above
    tids = []  #true ids of nearby features that we want to select
    for id in ids:
        if featDict[id].geometry().distance(line.geometry()) < bufDist:
            tids.append(id)
    lyr.selectByIds(tids, 1)   #AddToSelection, see https://qgis.org/api/classQgsVectorLayer.html#a2dbfa880644f08f8b9f77b6c28036c74 for SelectBehaviour
  • 1
    it says QgsVectorLayer' object has no attribute 'selectByIds', any ideas? – chenghopan Jan 6 '17 at 2:52
  • 1
    Ah, you're probably using a version older than 2.16 (see qgis.org/api/…). Hold on, I'll edit the code :). – weiji14 Jan 6 '17 at 2:54
  • what is the caution comment about ? Is it exceed the extent? – chenghopan Jan 6 '17 at 3:08
  • Yeah, I need to fix that actually. It's not exactly the minimum y-coordinate, the code just uses the y-coordinate from the node with the minimum x-coordinate. So if you have a complex zig-zagging line, that won't quite work. – weiji14 Jan 6 '17 at 3:13
  • yeah... I just added a pic of my data – chenghopan Jan 6 '17 at 3:20

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.