¿Hacer que el campo de tabla de atributos QGIS sea automático?

9

Estoy trabajando para hacer proyectos hidrológicos usando QGIS y una hoja de cálculo de Excel que tengo. Para hacer esto, quiero extraer alguna información de las líneas, incluida en una capa vectorial, que representa una sección de tubería.

La información que necesito extraer es:

  • Número de identificación
  • Longitud
  • X, Y coordenadas de inicio y fin

He encontrado una manera de capturar este campo usando el "$ length" y otro algoritmo para las coordenadas X e Y, pero para eso necesito abrir la tabla de Atributos, poner las expresiones en cada columna de atributos y hacer clic para actualizar los campos.

¿Hay alguna forma de dibujar una línea cuando estos campos se completan automáticamente? Es decir, dibujo / edito una línea (inicio de edición o nodo final) y cuando abro la tabla de atributos, los campos de longitud y las coordenadas X, Y se rellenan y actualizan.

Leo Nazaret
fuente
1
No estoy seguro si es posible mientras está en modo de edición, como se hace en una tabla temporal. Pero podrías echar un vistazo a las acciones. Puede usarlos, por ejemplo, para ejecutar código de Python para completar sus cálculos. Bueno, tienes que presionar un botón extra para ejecutarlo desde la tabla de atributos. Puede echar un vistazo a las posibilidades que existen y ver si se ajusta a su idea.
Mate

Respuestas:

7

Si solo necesita estos campos dentro de QGIS , puede usar campos virtuales. Permiten usar una expresión (como $length) que depende de otros valores o de la geometría.

Abra la calculadora de campo, agregue un nuevo campo con la longitud del nombre, marque la casilla de verificación "Campo virtual" e ingrese $lengthcomo expresión (o algo más para los otros campos).

Sin embargo, estos no se guardarán en el archivo de Excel.

Si desea mantener un archivo de Excel sincronizado con un archivo shp para geometría e incluir campos derivados en el archivo de Excel, hay un complemento llamado ShpSync que conoce este concepto y actualiza los campos automáticamente cuando las características se cambian, agregan o eliminan.

Matthias Kuhn
fuente
De hecho, la respuesta a continuación funciona exactamente como quiero hacerlo, pero este complemento que dijiste funcionará para el siguiente paso de mi proyecto. Gracias por su ayuda
LeoNazareth
15

¡Interesante pregunta! No conozco ninguna otra forma de lograr lo que quieres, pero usando PyQGIS.

Lee el código a continuación. Tiene algunos textos en que: 'lines', 'length', 'startX', 'startY', 'endX', 'endY'. Puede ajustar esos nombres en el script para que funcione en sus datos. El primero es su nombre de capa, mientras que el resto corresponde a los nombres de campo. Supongo que su capa de línea tiene esos campos (después de todo, desea que los valores se escriban allí).

Una vez que haya ajustado el nombre de su capa y los nombres de los campos que desea actualizar automáticamente, copie y pegue el script en la consola QGIS Python.

Si todo va bien, debería poder ver que los valores de campo se actualizan automáticamente en dos escenarios: 1) Cuando se agregan nuevas características y 2) Cuando se modifican las geometrías.

# 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 )

Así es como funciona:

Actualizaciones automáticas de campos en QGIS

Si tiene algún problema al ejecutar el script, agregue un comentario debajo de esta respuesta.

Puede ser útil para usted tener esta funcionalidad ya disponible cuando abra su proyecto QGIS. Si ese es el caso, dígame, podría publicar instrucciones para hacerlo.


EDITAR:

Para que esta funcionalidad esté disponible cada vez que abra su proyecto QGIS (es decir, un .qgsarchivo que contenga, entre otros, su capa de línea), debe seguir estos pasos:

  1. Vaya a QGIS->Project->Project Properties->Macros, marque la Python macrosopción y reemplace todo el código con este (ajuste los valores que indican los nombres de sus capas y campos):

    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. Asegúrese de habilitar las macros en su proyecto, de esta manera: Settings->Options->General->Enable macros: Always.

  3. Guarde su proyecto QGIS.

Ahora, cada vez que abra el .qgsarchivo que acaba de guardar, los atributos de su capa de línea se actualizarán automáticamente cuando agregue una nueva característica o modifique una geometría (es decir, ya no es necesario copiar nada en la Consola QGIS Python).


2da EDICIÓN:

Acabo de publicar un complemento llamado AutoFields para ayudar a las personas a resolver este tipo de problemas. Incluso hice un video que muestra cómo resolver su problema, puede verlo en:

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

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

Germán Carrillo
fuente
2
Esto es exactamente lo que estaba buscando. En realidad, estaba usando su código para captar las coordenadas X, Y, que he encontrado en su respuesta anterior en este enlace de publicación , la misma que publica ahora. Ya he probado la automatización y funciona perfectamente. Guardé el código de Python como un archivo ".pycl". Si me puede explicar cómo puede estar disponible cuando abro mi proyecto QGIS, será genial. Gracias por la ayuda
LeoNazareth
1
Alemán, ¡esa fue una respuesta increíble! ¡Gracias! ¡Aprendí mucho de ti con lo que publicaste!
jbgramm
1
De hecho, estoy trabajando en un complemento que te permitirá hacer exactamente eso. Como puedo dedicar a su desarrollo solo mi tiempo libre, no puedo decirte una fecha de lanzamiento esperada. Mientras tanto, puede ejecutar mi primer fragmento de código después de agregar Tramo.shp, ajustando: myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'Tramo' )[0]Si está realmente interesado en mi futuro complemento, envíeme cualquier sugerencia que tenga, le agradecería. Puedes contactarme en GeoTux .
Germán Carrillo
1
Eso será genial para mí (y para mucha gente, por supuesto), ya estoy usando el código con este ajuste que usted sugirió. Esperaré ansiosamente su nuevo complemento, y si pienso en algo útil, me pondré en contacto con usted. Gracias por todo.
LeoNazareth
1
@LeoNazareth, ¿te gustaría probar el complemento? Se está preparando, pero me gustaría realizar algunas pruebas antes de lanzarlo. Si está dispuesto a probarlo, envíeme un correo electrónico .
Germán Carrillo
2

Para QGIS 3, vaya a Layers Properties=> Attributes Form=> elija su campo con valores de geometría (por ejemplo, area) => escriba $areaen el Defaults valuecuadro y marque Apply default value on update. Esto también podría ser útil: $perimeter, $y, $x,$id

Señor che
fuente
1

Pondría los datos en una base de datos (PostGIS) y extraería los datos a QGIS con una vista (probablemente materializada).

nielsgerrits
fuente