Todos los que trabajamos con herramientas SIG, nos hemos encontrado alguna vez con un problema de análisis espacial básico que no hemos sabido resolver, no por falta de medios, sino por no conocer bien las posibilidades de nuestro software.
Algunas de estas necesidades puntuales, son relativamente fáciles desde el punto de vista de la lógica espacial. Sin embargo, no sabemos cómo plasmar esos resultados en un campo de forma automática (por ejemplo).
Pues bien, a través de QGIS tenemos distintas alternativas. Una de ellas y que ofrece potentes funcionalidades, es la posibilidad de crear y añadir funciones propias, que pueden ser integradas como expresiones personalizadas. Estas pueden ser añadidas a través del editor de funciones, utilizando instrucciones específicas en Python.
¿Dónde encontrar el editor de funciones de QGIS?
El editor de funciones de QGIS puede encontrarse en cualquier herramienta de trabajo con expresiones, como la Calculadora de Campos o bien la Búsqueda o Selección de geometrías pro expresión.

Si pulsamos sobre el editor de funciones, se nos abrirá la ventana del editor. En esta (si no tenemos aún alguna función personalizada), nos debería aparecer una única función de muestra llamada “default”. Esta no tiene mayor importancia y es utilizada a modo de ejemplo por QGIS.

Para crear una nueva función, vamos a pulsar sobre el icono (+) que aparece en verde en la parte inferior izquierda. Tras hacer clic para crear una nueva función, tendremos que introducir un nombre para esta.

Tras introducir el nombre de la función, aparecerá un pequeño código de ejemplo. Este deberá ser modificado y guardaremos el código presionando sobre “Guardar y cargar funciones”.

Función personalizada: añadir nombres de geometrías que intersectan de otra capa
Vamos a crear una función que permita, al usuario, obtener en un nuevo campo, el nombre de las geometrías que intersectan de otra capa. En el caso de que múltiples elementos intersecten en nuestra geometría, los nombres podrán ser concatenados utilizando un separador personalizado.
A continuación, vamos a ir explicando el código paso a paso.
Lo primero es importar los módulos que vamos a requerir en la función. Para ello utilizamos las siguientes instrucciones en la parte inicial:
from qgis import *
from qgis.core import *
from qgis.gui import *
Una vez importados los módulos necesarios, vamos a empezar con la parte principal de la función. Uno de los pasos imprescindibles es indicar el parámetro args y el parámetro group. El primero lo dejaremos como ‘auto’ para indicar que utilice los parámetros que vamos a definir en la función Python y en el segundo parámetro vamos a introducir el nombre del menú sobre el que se integrará la función.
@qgsfunction(args='auto', group='Funciones Propias')
Los menús por defecto son los que aparecen en la imagen a continuación:

Si indicamos un nombre de menú que no aparece en el listado, este se creará y añadirá de forma automática.
Para crear la función vamos a utilizar la siguiente estructura de encabezado y prestaremos especial atención a esta parte.
def add_intersect_names(layer, field_copy, separator, feature, parent):
def: palabra reservada en Python para crear una función
add_intersect_names: nombre que vamos a dar a nuestra función
layer, field_copy, separator: parámetros de entradalayer: nombre de la capa de intersección
field_copy: campo desde el que queremos obtener el valor a seleccionar
separator: separador (en el caso de haber múltiples intersecciones, se concatenarán los elementos con este separador)
feature: es el objeto QgsFeature que contiene los datos de geometría y atributos del elemento (obligatorio)
parent: refiere a la clase desde la que se hereda (obligatorio)
Dentro de la función y prestando especial atención a la identación, vamos a introducir las instrucciones que permiten dar sentido a nuestra función.
layer_int= QgsProject.instance().mapLayersByName(layer)[0]
feature_name_int= list()
for f1 in layer_int.getFeatures():
if f1.geometry().intersects(feature.geometry()):
feature_name_int.append(f1[field_copy])
if len(feature_name_int) > 0:
return str(separator.join(feature_name_int))
else:
return ''
Con la ayuda de estas líneas:
- Seleccionamos la capa de intersección.
- Creamos una lista vacía
- Recorremos las geometrías de la capa introducida y comprobamos la intersección con nuestra geometría objetivo.
- Si hay intersección, se añade el nombre del campo indicado en la lista.
- Si la longitud de la lista es superior a 0 (hay intersección), se copian los distintos elementos.
- Si no hay elementos que intersecten con nuestra geometría se devolverá un valor en blanco
Una vez creada y editada nuestra función, debemos guardar los cambios.
Puedes encontrar el código completo aquí:
from qgis import *
from qgis.core import *
from qgis.gui import *
@qgsfunction(args='auto', group='Funciones Propias')
def add_intersect_names(layer, field_copy, separator, feature, parent):
layer_int= QgsProject.instance().mapLayersByName(layer)[0]
feature_name_int= list()
for f1 in layer_int.getFeatures():
if f1.geometry().intersects(feature.geometry()):
feature_name_int.append(f1[field_copy])
if len(feature_name_int) > 0:
return str(separator.join(feature_name_int))
else:
return ''
¿Cómo utilizar la función?
En este ejemplo vamos a cargar la capa de Espacios Naturales Protegidos de España (obtenida en la página del Ministerio para la Transición Ecológica y el Reto Demográfico) y la capa de Provincias de España (obtenida en la página del Centro Nacional de Información Geográfica).
El objetivo será obtener el nombre de las provincias que intersectan con cada uno de nuestros ENP. Para garantizar el correcto funcionamiento de la función, vamos a utilizar la función fixgeometries, conocida como Corregir Geometrías.
Para ello vamos a utilizar la Calculadora de Campos. En esta vamos a indicar que queremos crear un nuevo campo con el nombre “Prov” de tipo texto y con una longitud de 255. Para hacer uso de nuestra función, vamos a introducir el nombre exacto de la función y los parámetros necesarios, a excepción de los parámetros obligatorios, que no son necesarios:
add_intersect_names('Recintos_Provinciales','NAMEUNIT', ', ')

A continuación, podemos observar el resultado. Ya tenemos en una columna todas las provincias que intersectan en nuestra capa de Espacios Naturales Protegidos.

Si te ha gustado este post y quieres saber más sobre funcionalidades Python en QGIS, matricúlate en nuestros cursos de PyQGIS: Programación de Scripts en Python para QGIS o Python para ArcGIS y QGIS: Geoprocesos con ArcPy y PyQGIS.
¿Quieres comentarnos algo? Adelante!