6

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

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Jan 6, 2017 at 1:46
8
  • Is the one feature selected using a mouseclick or from code? Commented Jan 6, 2017 at 2:05
  • it is from code, say select where fid = 1 Commented Jan 6, 2017 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). Commented Jan 6, 2017 at 2:16
  • i want it to be the buffer Commented Jan 6, 2017 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. Commented Jan 8, 2017 at 20:08

2 Answers 2

11

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

answered Jan 6, 2017 at 9:02
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
answered Jan 6, 2017 at 2:36
8
  • 1
    it says QgsVectorLayer' object has no attribute 'selectByIds', any ideas? Commented Jan 6, 2017 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 :). Commented Jan 6, 2017 at 2:54
  • what is the caution comment about ? Is it exceed the extent? Commented Jan 6, 2017 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. Commented Jan 6, 2017 at 3:13
  • yeah... I just added a pic of my data Commented Jan 6, 2017 at 3:20

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.