Rendre le champ de la table d'attributs QGIS automatique?

9

Je travaille d'une manière à faire des projets hydrologiques en utilisant QGIS et une feuille de calcul Excel que j'ai. Pour ce faire, je souhaite extraire des informations sur les lignes, incluses dans une couche vectorielle, qui représente une section de tuyau.

Les informations que je dois extraire sont:

  • Numéro d'identification
  • Longueur
  • Coordonnées de début et de fin X, Y

J'ai trouvé un moyen de capturer ce champ en utilisant la "$ longueur" et un autre algorithme pour les coordonnées X et Y, mais pour cela, je dois ouvrir la table Attributs, mettre les expressions dans chaque colonne d'attribut et cliquer pour mettre à jour les champs.

Existe-t-il un moyen lorsque je trace une ligne ces champs sont remplis automatiquement? Autrement dit, je trace / modifie une ligne (début de modification ou nœud final) et lorsque j'ouvre la table des attributs, les champs de longueur et les coordonnées X, Y sont remplis et mis à jour.

LeoNazareth
la source
1
Pas vraiment sûr si c'est possible en mode édition comme cela se fait dans une table temporaire. Mais vous pourriez avoir un aperçu des actions. Vous pouvez les utiliser par exemple pour exécuter du code python pour compléter vos calculs. Eh bien, vous devez appuyer sur un bouton supplémentaire pour l'exécuter à partir de la table d'attribution. Vous pouvez voir les possibilités qui existent et voir si cela correspond à votre idée.
Mat

Réponses:

7

Si vous n'avez besoin que de ces champs dans QGIS , vous pouvez utiliser des champs virtuels. Celles-ci permettent d'utiliser une expression (comme $length) qui dépend d'autres valeurs ou de la géométrie.

Ouvrez la calculatrice de champ, ajoutez un nouveau champ avec la longueur du nom, cochez la case "Champ virtuel" et entrez $lengthcomme expression (ou autre chose pour les autres champs).

Ceux-ci ne seront cependant pas enregistrés dans le fichier Excel.

Si vous souhaitez garder un fichier Excel synchronisé avec un fichier shp pour la géométrie et inclure des champs dérivés dans le fichier excel, il existe un plugin appelé ShpSync qui connaît ce concept et met à jour les champs automatiquement lorsque les fonctionnalités sont modifiées, ajoutées ou supprimées.

Matthias Kuhn
la source
En fait, la réponse ci-dessous fonctionne exactement comme je veux le faire, mais ce plugin que vous avez dit fonctionnera pour la prochaine étape de mon projet. Merci pour votre aide
LeoNazareth
15

Question interessante! Je ne connais pas d'autre moyen de réaliser ce que vous voulez, mais d'utiliser PyQGIS.

Lisez le code ci-dessous. Il a quelques textes en elle: 'lines', 'length', 'startX', 'startY', 'endX', 'endY'. Vous pouvez ajuster ces noms dans le script pour qu'il fonctionne sur vos données. Le premier est votre nom de calque, tandis que le reste correspond aux noms de champ. Je suppose que votre couche de lignes contient ces champs (après tout, vous voulez que les valeurs y soient écrites).

Une fois que vous avez ajusté le nom de votre couche et les noms des champs que vous souhaitez mettre à jour automatiquement, copiez et collez le script dans la console QGIS Python.

Si tout se passe bien, vous devriez pouvoir voir que les valeurs des champs sont automatiquement mises à jour dans deux scénarios: 1) lorsque de nouvelles entités sont ajoutées et 2) lorsque des géométries sont modifiées.

# Initialize required variables
myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
lengthField = myLayer.fieldNameIndex( 'length' )
startXField = myLayer.fieldNameIndex( 'startX' )
startYField = myLayer.fieldNameIndex( 'startY' )
endXField = myLayer.fieldNameIndex( 'endX' )
endYField = myLayer.fieldNameIndex( 'endY' )

# Slot, updates field values
def updateFeatureAttrs( fId, geom=None ):
    f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
    if not geom:
        geom = f.geometry() 
    myLayer.changeAttributeValue( fId, lengthField, geom.length() )
    myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
    myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
    myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
    myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )

# Update feature attributes when new features are added or geometry changes
myLayer.featureAdded.connect( updateFeatureAttrs )
myLayer.geometryChanged.connect( updateFeatureAttrs )

Voilà comment cela fonctionne:

Mises à jour automatiques des champs dans QGIS

Si vous rencontrez des problèmes lors de l'exécution du script, ajoutez un commentaire sous cette réponse.

Il peut être utile que cette fonctionnalité soit déjà disponible lorsque vous ouvrez votre projet QGIS. Si c'est le cas, dites-moi, je pourrais poster des instructions pour le faire.


ÉDITER:

Pour que cette fonctionnalité soit disponible à chaque fois que vous ouvrez votre projet QGIS (c'est-à-dire un .qgsfichier contenant, entre autres, votre couche de ligne), vous devez suivre ces étapes:

  1. Allez dans QGIS->Project->Project Properties->Macros, cochez l' Python macrosoption et remplacez le code entier par celui-ci (ajustez les valeurs en indiquant les noms de vos calques et champs):

    from qgis.core import QgsMapLayerRegistry, QgsFeatureRequest
    def openProject():    
        # Initialize required variables
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
    
        # Update feature attributes when new features are added or geometry changes
        myLayer.featureAdded.connect( updateFeatureAttrs )
        myLayer.geometryChanged.connect( updateFeatureAttrs )
    
    # Slot, updates field values
    def updateFeatureAttrs( fId, geom=None ):
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
        lengthField = myLayer.fieldNameIndex( 'length' )
        startXField = myLayer.fieldNameIndex( 'startX' )
        startYField = myLayer.fieldNameIndex( 'startY' )
        endXField = myLayer.fieldNameIndex( 'endX' )
        endYField = myLayer.fieldNameIndex( 'endY' )
        f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
        if not geom:
            geom = f.geometry() 
        myLayer.changeAttributeValue( fId, lengthField, geom.length() )
        myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
        myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
        myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
        myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )
    
    def saveProject():
        pass
    
    def closeProject():
        pass
  2. Assurez-vous d' activer les macros sur votre projet, de cette façon: Settings->Options->General->Enable macros: Always.

  3. Enregistrez votre projet QGIS.

Désormais, chaque fois que vous ouvrez le .qgsfichier que vous venez d'enregistrer, les attributs de votre couche de ligne sont automatiquement mis à jour lorsque vous ajoutez une nouvelle entité ou modifiez une géométrie (c'est-à-dire, plus besoin de copier quoi que ce soit dans la console QGIS Python).


2e EDIT:

Je viens de publier un plugin appelé AutoFields pour aider les gens à résoudre ce genre de problèmes. J'ai même fait une vidéo montrant comment résoudre votre problème, vous pouvez le regarder sur:

https://vimeo.com/germap/autofields-geometric-properties

Documentation AutoFields: http://geotux.tuxfamily.org/index.php/en/geo-blogs/item/333-autofields-plugin-for-qgis

Germán Carrillo
la source
2
Ceci est exactement ce que je cherchais. En fait, j'utilisais votre code pour capturer les coordonnées X, Y, que j'ai trouvées dans votre ancienne réponse dans ce lien de message , le même que vous postez maintenant. J'ai déjà testé l'automatisation et cela fonctionne parfaitement. J'ai enregistré le code Python dans un fichier ".pycl". Si vous pouvez m'expliquer comment il peut être disponible lorsque j'ouvre mon projet QGIS, ce sera génial. Merci par l'aide.
LeoNazareth
1
L'allemand, c'était une réponse géniale! Merci! J'ai beaucoup appris de vous avec ce que vous avez publié!
jbgramm
1
Je travaille actuellement sur un plugin qui vous permettra de faire exactement cela. Comme je ne peux consacrer à son développement que mon temps libre, je ne peux pas vous dire de date de sortie prévue. En attendant, vous pouvez exécuter mon premier extrait de code après avoir ajouté Tramo.shp, en ajustant: myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'Tramo' )[0]Si vous êtes vraiment intéressé par mon futur plugin, veuillez m'envoyer vos suggestions, je vous en serais reconnaissant. Vous pouvez me contacter à GeoTux .
Germán Carrillo
1
Ce sera génial pour moi (et pour beaucoup de gens, bien sûr), j'utilise déjà le code avec cet ajustement que vous avez suggéré. J'attendrai avec impatience votre nouveau plugin, et si je pense à quelque chose d'utile je vous contacte. Merci pour tout.
LeoNazareth
1
@LeoNazareth, souhaitez-vous tester le plugin? Il se prépare, mais j'aimerais effectuer quelques tests avant de le publier. Si vous êtes prêt à le tester, envoyez-moi un e-mail .
Germán Carrillo
2

Pour QGIS 3, allez dans Layers Properties=> Attributes Form=> choisissez votre champ avec des valeurs de géométrie (dans l'exemple, area) => tapez $areadans la Defaults valuecase et cochez Apply default value on update. Cela pourrait aussi être utile: $perimeter, $y, $x,$id

Camarade Che
la source
1

Je voudrais mettre les données dans une base de données (PostGIS) et extraire les données vers QGIS avec une vue (probablement matérialisée).

nielsgerrits
la source