5

I'm still a newbie at Python and I'm having issues selecting and loading polygons intersecting others with PyQGIS.

I managed to use PyQGIS to achieve that operation with shapefiles stored in my laptop but I haven't found a solution to proceed the same treatment on shapefiles stored in PostGIS.

This is what I came to so far :

from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtCore import QSettings
from PyQt4.QtCore import QSettings
from qgis.core import QgsVectorLayer, QgsDataSourceURI
import processing

uri = QgsDataSourceURI()
uri.setConnection("localhost", "5432", "name of my database", "my user name", "my password")
uri.setDataSource("database schema", "table name", "geom")
couche = "PM"
layer1 = QgsVectorLayer(uri.uri(), couche, "postgres")
if not layer1.isValid:
    print ('Chargement de la couche: echec !')
else:
    QgsMapLayerRegistry.instance().addMapLayer(layer1)


uri.setDataSource("database schema", "table name2", "geom")
couche = "batiments"
layer2 = QgsVectorLayer(uri.uri(), couche, "postgres" )

subset_layer2 = processing.runalg('qgis:extractbylocation', layer2,layer1,['intersects'],0.0,None)


uri.setDataSource("rbal", "parcelles", "geom")
couche = "parcelles"
layer3 = QgsVectorLayer(uri.uri(), couche, "postgres" )

subset_layer3 = processing.runalg('qgis:extractbylocation', layer3,layer1,['intersects'],0.0,None)

When I run the code I don't get any error but the treatment is loading forever without returning any results...


EDIT:

With that script I've managed to select all the polygons contained in layer2 that intersect layer1 but I do have to load layer2 to do so. Is there a way to select and load those intersecting polygons without loading the whole layer in the first place ?

uri = QgsDataSourceURI()
uri.setConnection("localhost", "5432", "name of my database", "my user name", "my password")
uri.setDataSource("database schema", "table name", "geom")
couche = "PM"
layer1 = QgsVectorLayer(uri.uri(), couche, "postgres")
if not layer1.isValid:
    print ('Chargement de la couche: echec !')
else:
    QgsMapLayerRegistry.instance().addMapLayer(layer1)


uri.setDataSource("database schema", "table name2", "geom")
couche = "batiments"
layer2 = QgsVectorLayer(uri.uri(), couche, "postgres" )
if not layer2.isValid:
    print ('Chargement de la couche: echec !')
else:
    QgsMapLayerRegistry.instance().addMapLayer(layer2)

feats_layer1 = layer1.getFeatures()
for feat in feats_layer1:
    geom_layer1 = feat.geometry()
feats_layer2 = layer2.getFeatures()

for feature in feats_layer2:
    if feature.geometry().intersects(geom_layer1):
        layer2.select(feature.id())
8
  • Hi Bera, Yes it's exactly what I'm looking for but unfortunately I shall use pyqgis to do so (if there is a way to do so of course)
    – wanderzen
    Commented Dec 18, 2020 at 12:59
  • That's why I thought of importing my layers from PostGIS (script in my question) before using qgis:extractbylocation but it doesn't work
    – wanderzen
    Commented Dec 18, 2020 at 13:00
  • It has to be uri = QgsDataSourceURI() in QGIS 2.14 :/ But do you mean my script works in QGIS 3.16 once uri = QgsDataSourceURI() is replaced by uri=QgsDataSourceUri() ?
    – wanderzen
    Commented Dec 18, 2020 at 13:26
  • 1
    If you use QGIS 3.*x*, don't use PyQt4 ! Convert it into PyQt5 or qgis.PyQt.QtCore. Commented Dec 18, 2020 at 14:58
  • Thanks for your reply J.Monticolo but I have to work with QGIS 2.*x* :)
    – wanderzen
    Commented Dec 18, 2020 at 15:00

1 Answer 1

4

Thanks to J.Monticolo I've found an existing solution on stackoverflow:

PyQGIS - Load a PostgreSQL/PostGIS layer from a SQL query

QgsDataSourceuRI and left outer join

EDIT:

Even though the links above provide (in my example) the best solution, there is a way to do the same thing only with PyQGIS:

from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtCore import QSettings
from PyQt4.QtCore import QSettings
from qgis.core import QgsVectorLayer, QgsDataSourceURI
from qgis.gui import QgsMapCanvas
import processing

uri = QgsDataSourceURI()
uri.setConnection("localhost", "5432", "name of my database", "my user name", "my password")
uri.setDataSource("database schema", "table name", "geom")
couche = "PM"
layer1 = QgsVectorLayer(uri.uri(), couche, "postgres")
if not layer1.isValid:
    print ('Chargement de la couche: echec !')
else:
    QgsMapLayerRegistry.instance().addMapLayer(layer1)


uri.setDataSource("database schema", "table name2", "geom")
couche = "batiments"
layer2 = QgsVectorLayer(uri.uri(), couche, "postgres" )
if not layer2.isValid:
    print ('Chargement de la couche: echec !')
else:
    QgsMapLayerRegistry.instance().addMapLayer(layer2)

inter_feats = []

feats_layer1 = layer1.getFeatures()
for feat in feats_layer1:
    geom_layer1 = feat.geometry()
feats_layer2 = layer2.getFeatures()

for feature in feats_layer2:
    if feature.geometry().intersects(geom_layer1):
        inter_feats.append(feature.id())
        
layer2.select(inter_feats)

intersecting_features = QgsVectorFileWriter.writeAsVectorFormat(layer2, 'C:/Users/Users/Documents/test.shp', "utf-8",  None, "ESRI Shapefile", onlySelected=True)


bati = QgsVectorLayer('C:/Users/Users/Documents/test.shp', "test", "ogr")
if not bat.isValid():
    print("Impossible de charger la couche !")

# add layer to the registry
QgsMapLayerRegistry.instance().addMapLayer(bati)
2
  • 1
    but the "more" PyQGIS solution needs to load the two whole layers into QGIS and after do the intersection. If your layers contains thousands of records, this isn't the best performance solution ! Commented Dec 21, 2020 at 14:43
  • I completely agree ! :)
    – wanderzen
    Commented Dec 21, 2020 at 14:44

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.