Germán Carrillo
2020
MSc. en Geoinformática (Münster, Alemania)
Colaborador oficial de QGIS desde 2009!
Co-administrador de GeoTux
Coordinador general de QGIS Colombia (2018-2020)
¿Dónde me encuentras?
Curso de introducción a PyQGIS
"Creemos que por lo menos algunos analistas realmente necesitarán aprender a programar.
Piensa en ello como aprendiendo a cocinar. Puedes preferir pasta fresca a macarrones gratinados en caja, pero si no quieres quedar atrapado comiendo la última, debes aprender a cocinar o pagar a alguien más para que lo haga por ti.
Aprender a programar es como aprender a cocinar de otra manera: puede ser un proceso muy gradual. Un día estás sentado comiendo tus macarrones gratinados y decides mejorarlos con un poco de Tabasco, mostaza o salsa inglesa. Bingo! Pronto estarás poniéndole además queso rallado. (Continúa...)
Curso de introducción a PyQGIS
(...) Descubres que los ingredientes que compras para un plato pueden ser mezclados para hacer otro. Empiezas a quedarte un rato en el pasillo de las especias en el supermercado. La gente empieza a comprarte utensilios de cocina. Llegas al punto donde eres capaz de experimentar con recetas.
Aunque pocas personas se conviertan en chefs, muchos aprenden a cocinar suficientemente bien para satisfacer sus propias necesidades.
Si no programas, tu proceso de investigación siempre estará a merced de aquellos que lo hacen."
Traducido de http://sgillies.net
Curso de introducción a PyQGIS
Así como en la cocina, en programación se cometen errores...
Curso de introducción a PyQGIS
Así como en la cocina, en programación es normal olvidar ingredientes, y es normal recurrir a la documentación, o incluso al código de otros...
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Guido van Rossum, principios de 90's
Inspirado en 'Monthy Python'
Lenguaje interpretado (semi)
Tipado dinámico y fuertemente tipado
Multiplataforma
Sintaxis sencilla que lo hace muy legible
Curso de introducción a PyQGIS
¡Escribamos algo de Python!
Intérprete de Python
Tipos de datos
Condicionales y ciclos
Funciones
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
QGIS API (C++):
QGIS API (Python):
PyQGIS Cookbook:
https://docs.qgis.org/latest/en/docs/pyqgis_developer_cookbook/
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
Ctrl
+
Alt
+
P
Curso de introducción a PyQGIS
2. Macros del proyecto
Proyecto --> Propiedades...
Curso de introducción a PyQGIS
3. Acciones
Propiedades de la capa --> Acciones
Curso de introducción a PyQGIS
4. Expresiones personalizadas en Python
Diálogo de expresiones --> Editor de Funciones
Curso de introducción a PyQGIS
5. Algoritmos de Geoprocesamiento
Ventana de Procesamiento --> Scripts
Curso de introducción a PyQGIS
6. Plugins
Curso de introducción a PyQGIS
7. Scripts 'standalone' (sin la GUI de QGIS)
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
Curso de introducción a PyQGIS
¡Necesitamos saber qué es una clase y qué es un objeto!
Curso de introducción a PyQGIS
Programas más comprensibles y más fáciles de mantener.
¡Se basa en Objetos!
Los objetos:
Representan mejor la complejidad del mundo real.
Tienen estado y comportamiento.
Interactúan con otros objetos.
Curso de introducción a PyQGIS
Caso 1: Aplicaciones gráficas (Qt5).
Los objetos son: ventanas, botones, diálogos, etc.
Caso 2: Aplicación para SIG (QGIS).
Conclusión:
"Un objeto es la representación de un concepto
en el sistema."
Los objetos son: tablas, capas vectoriales, capas ráster, un mapa, la simbología de una capa, botón 'Acercar', etc.
Curso de introducción a PyQGIS
Un objeto es una representación. Es concreto y particular.
Ejemplo: Botón “Acercar mapa”, Botón "Panear".
Las clases se agrupan en librerías:
Ejemplo: Librería Controles gráficos de usuario (GUI).
Incluso se puede hablar de cosas más generales, esto es,
de clases más abstractas. Ejemplo: Clase Botón.
Para conceptos (generales) se habla de Clases.
Ejemplo: Clase Botón de navegación.
Curso de introducción a PyQGIS
Conceptos (abstractos) del sistema.
Pueden actuar como moldes o prototipos para crear objetos.
Tienen propiedades y métodos.
La clase Botón puede tener...
Propiedades como: Size, Text, Icon
Métodos como: run()
El objeto Botón "Acercar mapa" también tiene:
Size (32x32), Text (""), Icon (acercar.png), run() (acercar.py)
Los objetos de una clase, heredan sus propiedades y métodos.
Curso de introducción a PyQGIS
Clase (Concepto, plantilla, molde)
Objeto (Instancia de una clase)
Imágenes: https://www.iconfinder.com/icons/4835095/code_coding_page_programming_web_web_page_icon
https://www.iconfinder.com/icons/618630/bubble_dream_happy_idea_speech_talk_think_icon
Curso de introducción a PyQGIS
Cuando abrimos QGIS, podemos acceder a sus objetos
QgisInterface
iface
Curso de introducción a PyQGIS
Escribamos código Python para manipular información
geográfica...
Usando iface
Accediendo a capas y a sus propiedades
Creando campos
Análisis espacial (cruce de capas)
Modificando capas
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
2. Macros del proyecto
Curso de introducción a PyQGIS
Fuente: https://definicion.de/macro/
"[...] secuencia de instrucciones almacenadas para posibilitar la ejecución organizada de una orden. Esto quiere decir que una macroinstrucción permite que una única orden desencadene una secuencia de varias instrucciones.
...
[...] Es posible almacenar una macro en el propio software en el que se ejecuta, ya sea mediante un botón o una cierta combinación de teclas."
Curso de introducción a PyQGIS
openProject() saveProject() closeProject()
Curso de introducción a PyQGIS
Cuando se abra este proyecto... abrir la consola de Python!
Curso de introducción a PyQGIS
¿Otros casos de uso?
openProject() saveProject() closeProject()
¿Y si quiero una acción para todos mis proyectos?
Curso de introducción a PyQGIS
Script para ejecutar código Python cada vez que inicia QGIS.
¿Dónde guardar el script?
/home/USER/.local/share/QGIS/QGIS3/
startup.py
C:\Users\USER\AppData\Roaming\QGIS\QGIS3\
Curso de introducción a PyQGIS
import qgis
from console import console
def open_console():
if not console._console:
# Initialize the console (QGIS knows how)
qgis.utils.iface.actionShowPythonDialog().trigger()
console._console.setVisible(True)
qgis.utils.iface.initializationCompleted.connect(open_console)
Curso de introducción a PyQGIS
Siempre que se inicie QGIS... abrir la consola de Python
from qgis.utils import iface
from console import console
if not console._console:
# We need to initialize the console (QGIS knows how)
# and respect the opened/closed state from last session
iface.actionShowPythonDialog().trigger()
console._console.setVisible(console._console.isUserVisible())
console._console.console.shell.runcode("""
L = None
def clc(layer):
global L
L = layer
iface.currentLayerChanged.connect(clc)
""")
console._console.console.shellOut.clearConsole()
Curso de introducción a PyQGIS
Siempre que se inicie QGIS...
enlazar variable "L" con la capa activa
1. Consola de Python y editor de scripts
2. Macros del proyecto
3. Acciones
Curso de introducción a PyQGIS
Capa
Feature (objeto)
Lienzo (mapa)
Campo
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
3ra Jornada de Talleres Internos
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
2. Macros del proyecto
3. Acciones
4. Expresiones personalizadas en Python
Curso de introducción a PyQGIS
Buena forma de automatizar en QGIS... ¡sin programar!
Conjunto de funciones disponibles para seleccionar, filtrar, combinar, formatear, convertir, calcular, ..., y agregar valores en QGIS.
Hay condicionales y también variables globales, del proyecto, de la capa, del usuario, etc.
¡Están por todos lados en QGIS!
A veces (muy pocas veces) NO encontramos la que necesitamos.
¡Pero podemos crear nuestras propias funciones... con Python!
Curso de introducción a PyQGIS
Editor de funciones
Diálogo de expresiones --> Editor de Funciones
Curso de introducción a PyQGIS
Ejemplo: Dado un punto, obtener su valor de altura desde DEM
from qgis.core import (qgsfunction, QgsProject, QgsRaster)
@qgsfunction(args='auto', group='Custom', usesgeometry=True)
def get_elevation(feature, parent):
layers = QgsProject.instance().mapLayersByName("DEM")
if layers: # Any layer called DEM?
rLayer = layers[0]
geom = feature.geometry()
geom.convertToSingleType() # Single points are required
ident = rLayer.dataProvider().identify(geom.asPoint(),
QgsRaster.IdentifyFormatValue)
if ident.isValid():
return ident.results()[1] # Read from band 1
return NULL
raster_value('DEM', 1, $geometry)
Tiempo después...
Curso de introducción a PyQGIS
Ejemplo 2: Obtener un código QR
(usado para los certificados de QGIS Colombia)
from qgis.core import (QgsProject, NULL, qgsfunction)
@qgsfunction(args='auto', group='Custom')
def qr(evento, taller, cc, feature, parent):
if evento and taller and cc:
import os, qrcode
base_dir = QgsProject.instance().fileInfo().path()
qr_dir = os.path.join(base_dir, "qr")
filename = "{}-{}-{}".format(evento, taller, cc.replace('.',).replace("'",))
url = "http://qgisusers.co/media/{}.pdf".format(filename)
if not os.path.exists(qr_dir):
os.makedirs(qr_dir)
filepath = os.path.join(qr_dir, "qr-{}.png".format(filename))
qr = qrcode.QRCode(box_size=10,border=2)
qr.add_data(url)
qr.make(fit=True)
img = qr.make_image()
img.save(filepath)
return filepath
else:
return NULL
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
2. Macros del proyecto
3. Acciones
4. Expresiones personalizadas en Python
5. Algoritmos de Geoprocesamiento
Curso de introducción a PyQGIS
En C++ o en Python.
Usando Python tenemos 2 opciones: clases o decoradores.
Reciben entradas (capas, números, etc.) y retornan salidas.
Escribimos metadatos y QGIS crea el diálogo automáticamente.
Útiles para reusarlos en modelos complejos, mezclando algoritmos incluso de otros proveedores.
Curso de introducción a PyQGIS
QGIS docs:
https://docs.qgis.org/latest/en/docs/user_manual/processing/scripts.html
Definiendo parámetros de entrada:
https://api.qgis.org/api/master/classQgsProcessingParameterDefinition.html
Definiendo parámetros de salida:
https://api.qgis.org/api/master/classQgsProcessingOutputDefinition.html
Leyendo parámetros:
https://api.qgis.org/api/master/classQgsProcessingAlgorithm.html
¡Otros scripts!
Curso de introducción a PyQGIS
Processing agrega widgets dependiendo del tipo de entrada
que elijamos...
Curso de introducción a PyQGIS
Nota: Los scripts con decoradores no pueden ser agregados a proveedores
personalizados. Esto implica que no pueden instalarse desde plugins.
from qgis.processing import alg
@alg(name='my_script', label='Rename field from vector layer',
group='examplescripts', group_label='Example scripts')
# 'INPUT' is the recommended name for the main input parameter
@alg.input(type=alg.VECTOR_LAYER, name='INPUT', label='Input vector layer')
# 'OUTPUT' is the recommended name for the main output parameter
@alg.output(type=alg.VECTOR_LAYER, name='OUTPUT',
label='Vector layer with renamed field')
def my_script(instance, parameters, context, feedback, inputs):
...
Decoradores: "Syntactic sugar". Actúan sobre métodos y/o clases.
Curso de introducción a PyQGIS
Ejemplo: Renombrar un campo
Entradas:
Vector layer
Campo a renombrar
Nombre nuevo para el campo
Salidas:
Vector layer
Curso de introducción a PyQGIS
Opciones de salida para capas vectoriales:
Modificar la capa de entrada y retornarla
Ver ejemplo anterior (rename field)
Crear una capa nueva y retornarla (capa original intacta)
Para ello se usan los Feature Sink
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
2. Macros del proyecto
3. Acciones
4. Expresiones personalizadas en Python
5. Algoritmos de Geoprocesamiento
6. Plugins
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Qt5 (C++):
PyQt5:
https://www.riverbankcomputing.com/static/Docs/PyQt5/module_index.html
PyQt5 examples:
https://github.com/pyqt/examples
Curso de introducción a PyQGIS
Core
GUI
Widgets
qgis.PyQt.QtCore
qgis.PyQt.QtGui
qgis.PyQt.QtWidgets
Funcionalidad núcleo no gráfica.
QObject, QFile, QSettings, QRegExp, SIGNALS-SLOTS...
Funcionalidad núcleo gráfica.
QIcon, QColor, QFont, QCursor, QMouseEvent...
Controles gráficos de usuario para interfaces.
QWidget, QDialog, QPushButton, QMessageBox, QMenu...
Curso de introducción a PyQGIS
Aplicación para
diseñar
interfaces
gráficas de Qt
Genera archivos
.ui (XML)
Permite:
+ Definir propiedades de los widgets.
+ Agrupar widgets en layouts.
+ Usar widgets propios de QGIS (custom widgets)
+ Administrar recursos (archivos externos, ej. íconos).
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Agrupan y organizan
widgets en una interfaz
Layouts más usados:
Horizontal/Vertical
Grid
Form
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Comunicación
entre objetos de Qt.
Los objetos no se conocen entre sí.
(Bajo acoplamiento)
Los objetos emiten señales, no saben si
alguien las recibe o no. (Encapsulamiento)
SIGNALS
Se emiten cuando ocurre un evento.
Objetos de Qt tienen SIGNALS predefinidas.
Podemos crear nuevas SIGNALS y emitirlas.
SLOTS
Función llamada en respuesta a una SIGNAL.
Objetos de Qt tienen SLOTS predefinidos.
Podemos crear nuevos SLOTS.
Curso de introducción a PyQGIS
Las conexiones SIGNAL-SLOT
las hace el(la) desarrollador(a).
SIGNALS
Pueden conectarse a cero o muchos SLOTS.
Pueden conectarse a otras SIGNALS.
SLOTS
Pueden conectarse a cero o muchas SIGNALS.
Como son funciones, podemos llamarlas.
Más info en: https://doc.qt.io/qt-5/signalsandslots.html
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS
__init__(iface)
initGUI()
unload()
run()
Crear GUI del plugin en QGIS (¿toolbar?, ¿menú?).
Definir conexiones SIGNAL-SLOT.
Remover GUI del plugin (toolbars, menús, etc.) de QGIS.
Desconectar SIGNAL-SLOTs (si es necesario).
Procesar datos o llamar diálogos del plugin.
(opcional)
Obtener acceso a objeto iface para interactuar con QGIS.
Curso de introducción a PyQGIS
__init__(iface), initGUI(), unload(), run()
¡Veámoslas en acción!
Icon adapted from https://www.iconfinder.com/paomedia
Clic a la imagen :)
Curso de introducción a PyQGIS
Test plugin repo: https://github.com/gacarrillor/test
Plugin reloader
First aid
Plugin builder
(Opcional)
Curso de introducción a PyQGIS
1. Ve a la carpeta de plugins de QGIS (ver instrucciones).
2. En esa carpeta crea una carpeta llamada "minimal".
3. Ve a https://github.com/wonder-sk/qgis-minimal-plugin
4. Crea los archivos __init__.py y metadata.txt copiando
el contenido del QGIS Minimal Plugin de Martin Dobias.
5. Reinicia QGIS y activa el plugin "Minimal".
Curso de introducción a PyQGIS
Extendamos el Minimal Plugin...
Curso de introducción a PyQGIS
Extendamos el plugin con diálogo...
Curso de introducción a PyQGIS
Un plugin un poco más completo...
Curso de introducción a PyQGIS
1. Consola de Python y editor de scripts
2. Macros del proyecto
3. Acciones
4. Expresiones personalizadas en Python
5. Algoritmos de Geoprocesamiento
6. Plugins
7. Scripts 'standalone' (sin la GUI de QGIS)
Curso de introducción a PyQGIS
Se busca generar productos diarios/semanales/mensuales (vectores, rásters, mapas, reportes, estadísticas) a partir de una BD que se alimenta con frecuencia.
Se busca ejecutar periódicamente un ETL, obteniendo datos de diferentes servicios web de fuentes oficiales para almacenarlos en una BD local.
Una entidad oficial obtiene datos de terceros mediante formulario web y quiere hacer una validación de calidad automática.
Curso de introducción a PyQGIS
Windows
GNU/Linux
Open OSGeo4w Shell --> Run python-qgis-ltr.bat
Prepare environment with PYTHONPATH and LD_LIBRARY_PATH.
export PYTHONPATH=/path/to/qgis/output/python/
export LD_LIBRARY_PATH=/path/to/qgis/lib/
Curso de introducción a PyQGIS
¡No tenemos iface!
Curso de introducción a PyQGIS
from qgis.core import (QgsApplication, QgsVectorLayer)
# Details about the prefix: https://gis.stackexchange.com/a/155852/4972
# Hint: print(QgsApplication.showSettings())
QgsApplication.setPrefixPath("/docs/dev/qgis/QGIS/3_14_0/output/", True)
qgs = QgsApplication([], False) # No GUI
qgs.initQgis()
airport_layer = QgsVectorLayer("/path/to/data.gpkg|layername=Airports",
"airport",
"ogr")
print("Layer name:", airport_layer.name())
print("Layer is valid:", airport_layer.isValid())
qgs.exit()
Curso de introducción a PyQGIS
# Source: https://gis.stackexchange.com/a/279937/4972
import sys
from qgis.core import QgsApplication
from qgis.analysis import QgsNativeAlgorithms
QgsApplication.setPrefixPath('/docs/dev/qgis/QGIS/3_14_0/output', True)
qgs = QgsApplication([], False)
qgs.initQgis()
# Append the path where processing plugin can be found
sys.path.append('/docs/dev/qgis/QGIS/3_14_0/output/python/plugins')
import processing
from processing.core.Processing import Processing
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
params = {'POLYGONS':'/path/to/polygons.gpkg',
'LINES':'/path/to/lines.gpkg',
'LEN_FIELD':'LENGTH',
'COUNT_FIELD':'COUNT',
'OUTPUT':'TEMPORARY_OUTPUT'}
res = processing.run("native:sumlinelengths", params)
for feature in res['OUTPUT'].getFeatures():
print(feature['name'], feature['LENGTH'])
qgs.exit()
Curso de introducción a PyQGIS
$ qgis_process run native:sumlinelengths
--POLYGONS="/path/to/polygons.gpkg"
--LINES="/path/to/lines.gpkg"
--LEN_FIELD=LENGTH
--COUNT_FIELD=COUNT
--OUTPUT=/tmp/gpkg/output_sum.gpkg
Curso de introducción a PyQGIS
¿Ves alguna diferencia?
Hay otros escenarios en donde puedes usar Python con QGIS:
Aplicaciones gráficas standalone Plugins de QGIS Server
Fuente: Plugin QGIS Server y roles
Fuente: Visor de PyQGIS
Curso de introducción a PyQGIS
PyQGIS samples:
https://github.com/webgeodatavore/pyqgis-samples
Victor Olaya's QGIS Python Course:
https://github.com/volaya/qgis-python-course
Diagrama de clases PyQGIS (cuidado, es para QGIS v2!):
https://labs.webgeodatavore.com/partage/diagramme_principal.html
PyQGIS in a day:
https://courses.spatialthoughts.com/pyqgis-in-a-day.html
Curso PyQGIS 3 impartido junto a M. Kuhn en Colombia:
Curso de introducción a PyQGIS
Curso de introducción a PyQGIS