2

I am looking for a way to run select by location, specific to the features of the 'INTERSECT' layer. I have got bus locations and bus stops and want to figure out when the bus has entered and left individual stops.

enter image description here

Here the orange dots are the bus stops (with varying radius) and the purple ones are the GPS locations of one bus.

With the standard logic, select by location select the GPS locations in all stops and I cannot discriminate when the bus has visited individual stops.

I am using this command for the selection:

processing.run("native:selectbylocation", {'INPUT':Course,'PREDICATE':[0,6],'INTERSECT':Stops,'METHOD':0})
2
  • So you want to select one stop at a time even though the buffered bus polygon intersects multiple stop features?
    – artwork21
    Commented Dec 3, 2019 at 13:52
  • Sorry I didn't make it clear. The orange dots are the stops (with varying radius) and the purple ones are the GPS locations of one bus. Otherwise, I want to make selection for each stop individually
    – FunTimes
    Commented Dec 3, 2019 at 13:54

2 Answers 2

4

SQL queries are really optimal but I offer you an alternative that will create a layer of gps points for each stop.

My starting layers enter image description here

# Identification of gps layer
gps = QgsProject.instance().mapLayersByName("gps")[0] 
# Identification of stops layer
stops = QgsProject.instance().mapLayersByName("stops")[0] 

# List : Field with unique identifiers in your stop layer (FID for me)
index = [feature["FID"] for feature in stops.getFeatures()] 

# loop on the list
for i in index:
    # remove selection of gps layer
    gps.removeSelection()
    # remove selection of stops layer  
    stops.removeSelection() 

    # Apply selection 
    stops.selectByExpression('"FID" ='+str(i),QgsVectorLayer.SetSelection) 
    # New layer with my selection
    selection_stops =    stops.materialize(QgsFeatureRequest().setFilterFids(stops.selectedFeatureIds())) 

    # Selectbylocation
    processing.run("native:selectbylocation", {'INPUT':gps,'PREDICATE':[0],'INTERSECT':selection_stops,'METHOD':0}) 

    # New gps layer with the result
    gps_stop = gps.materialize(QgsFeatureRequest().setFilterFids(gps.selectedFeatureIds())) 
    # add the layer to qgis project
    QgsProject.instance().addMapLayer(gps_stop) 
    # rename the layer with the name of stop intersection 
    gps_stop.setName('gps in stop '+str(i)) 

# remove selection of gps layer
gps.removeSelection() 
# remove selection of stops layer 
stops.removeSelection() 

Result

enter image description here

3
  • Thank you very much for your solution. I ran the code and it does exactly what you described. However, I would like to avoid the creation of too many files as I am planning to execute it many many times.
    – FunTimes
    Commented Dec 4, 2019 at 14:14
  • With pleasure! There are algorithms to merge layers but this is another subject and it would be necessary to complete the code. Good luck ! Commented Dec 4, 2019 at 14:21
  • 1
    Another option using this method would be to process the selection layer and keep it in-memory and not add it to the project, see gis.stackexchange.com/questions/76594/…
    – artwork21
    Commented Dec 4, 2019 at 17:17
3

From DB Manager > Virtual Layers > SQL Window, you can run the following query (replace the tables and fields names with real ones) :

SELECT
  bus_stops.id, -- change here the field name id with identifier bus stop field
  MIN(gps.time) AS bus_entered, -- change here the field name time for the gps field with time
  MAX(gps.time) AS bus_left -- same here
FROM
  my_table_bus_stop AS bus_stop, -- change here my_table_bus_stop
  my_table_gps AS gps -- change here my_table_gps
WHERE
  ST_CONTAINS(bus_stop.geometry, gps.geometry)
GROUP BY
  bus_stops.id -- change here too

You can see the result in DB Manager or load it as a Virtual Layer without geometry.

3
  • Thank you very much for your suggestion. I had to change it only slightly and it worked perfectly. Added a Distinct in the beginning: SELECT Distinct(bus_stops.id) Could not make it work otherwise.
    – FunTimes
    Commented Dec 4, 2019 at 13:47
  • There is no need of a DISTINCT with a GROUP BY. Commented Dec 4, 2019 at 13:49
  • Yes, I just ran it without the distinct and it was successful. Many cheers for your help!
    – FunTimes
    Commented Dec 4, 2019 at 13:53

Your Answer

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

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