Niveau | Intermédiaire |
Logiciels utilisés |
Quantum GIS (QGIS) divers modules Python (au choix) |
Plateforme | Windows | Mac | Linux | FreeBSD |
Que faire, si comme moi, vous n'avez pas le courage de créer une extension chaque fois que vous voulez effectuer un traitement spécifique à l'aide d'un script Python ?
Bien évidemment, en utilisant la Console Python. Si vous connaissez bien Python, les avantages sont évidents comme nous allons le voir.
La Console Python
La Console Python permet de tout faire dans QGIS, même en utilisant PyQt pour ceux qui le désirent vraiment (voir osgeo-org.1560.n6.nabble.com/question-to-possible-enhancements-td4122157.html#a4122159) :
Mais comment lancer un script externe ou une commande Shell depuis cette console qui est elle-même un script Python ? Indépendamment de QGIS, il existe plusieurs solutions en Python pour exécuter cette tâche :
Avec la commande execfile
Dans la Console Python :
>>> execfile("test.py")
Le script va bien être exécuté, mais si je veux passer des arguments et récupérer des résultats, la solution est de passer par sys.argv :
>>>import sys
>>>sys.argv=[mes_arguments]
>>>execfile("test.py") # pour autant que test.py traite le(s) sys.argv
Avec execfile(), le script est exécuté par l'interpréteur courant dans le même environnement. De ce fait, toute variable définie dans test.py sera aussi disponible dans la Console Python après exécution du script.
Par exemple, soit le simple script suivant qui définit la variable salut :
Le résultat dans la console :
Il est aussi possible de lancer n'importe quel exécutable, mais la communication s'avère plus délicate. Il vaut mieux passer par le module subprocess.
avec le module subprocess
Il permet, à l'inverse d'execfile, de lancer des processus parallèles (avec des exécutables différents, dans un environnement différent) avec des paramètres et de récupérer facilement les résultats. Ces processus peuvent être des applications tierces, des commandes Shell ou des scripts Ruby, Python, etc.
Ce module est préconisé pour remplacer les diverses commandes os.popen docs.python.org/dev/library/subprocess.html#replacing-os-popen-os-popen2-os-popen3. Pour bien comprendre ce qu'il fait, voir jimmyg.org/blog/2009/working-with-python-subprocess.html ou blog.doughellmann.com/2007/07/pymotw-subprocess.html. Il fonctionne suivant les principes des pipes Unix (fr.wikipedia.org/wiki/Tube_%28shell%29)
>>>import subprocess
>>>mesParams = .....
>>>proc = subprocess.Popen(['python','test.py','mesParams'], stdout=subprocess.PIPE)
>>> # ou sys.executable appelle l'exécutable Python, quelque soit le système d'exploitation >>>proc = subprocess.Popen([sys.executable,'test.py','myParams'], stdout=subprocess.PIPE)
>>># exploitation des résultats
>>>sortie = proc.communicate()[0] # ou proc.stdout.read()
Puisque la commande fait appel à un exécutable précis, il est possible de lancer des scripts avec diverses versions de Python (python3 est mon exécutable de la version 3.x de Python alors que QGIS utilise l'exécutable python qui correspond sur mon Mac à Python 2.6) et de récupérer les résultats:
>>> a = subprocess.Popen(['python3', 'test2.py'],stdout=subprocess.PIPE)
Il est aussi possible de lancer n'importe quel exécutable en lui passant des paramètres et en récupérant les résultats (avec des problèmes avec QGIS sur les systèmes Windows). Illustrons son usage avec une commande inutile (gdalinfo) puisque GDAL est intégré à QGIS :
J'utilise cette technique pour communiquer avec les commandes de GMT ou de R (exécution d'un script avec la commande Rscript, plutôt que d'utiliser les extensions utilisant R pour QGIS qui, honnêtement, ne fonctionnent pas très bien), entre autres choses.
>>> b = subprocess.Popen(['Rscript','monscript.R','mesParams'], stdout=subprocess.PIPE)
Soit le script trivial en R suivant :
a <- 10 / (3 + 2) print(a)
Dans la console :
Il faut noter que je n'ai pas réussi à faire fonctionner l'autre commande pour appeler un exécutable, subprocess.call (alors qu'il n'y a aucun problème dans le Shell normal).
Il y aurait aussi la solution PyRO (Python Remote Object) qui permet de faire communiquer « en direct » deux processus Python qui s'exécutent en même temps, mais mes premiers résultats avec la Console Python ne sont pas concluants.
Avec la commande import(module)
Pour importer un script comme un module Python qui renvoie des résultats, il faut:
- que le script ait des classes ou des fonctions qui renvoient des résultats après leur avoir passé des paramètres;
- ajouter le répertoire où se situe le script Python au PYTHONPATH (avec le module sys) ou changer de répertoire de travail avec os.chdir;
- importer le script comme un module;
- exécuter une des classes ou une des fonctions du script.
>>>import sys
>>>sys.path.append("/Users/Shared/")
>>>import test
>>>mesParams = .....
>>># et exécution d'une des classes/fonctions du module
>>>final = test.mafonction(mesParams)
ou
>>>import os
>>>os.chdir("/Users/Shared/")
>>>import test
Sur Windows, où l'installation du Python de QGIS est indépendante de celle éventuellement installée de manière standard, la commande sys.path.append permet d'utiliser les modules de l'installation standard, pour autant que les versions de Python soient les mêmes. Sinon, il est toujours possible d'importer un module qui utilise le module subprocess. En effet, soit le script suivant qui utilise subprocess pour appeler le script R précédent :
sortieR.py
import subprocess def result(): a = subprocess.Popen(['Rscript','/Users/martinlaloux/test.R'], stdout=subprocess.PIPE) sortie = a.stdout.read() return sortie if __name__ == '__main__': result()
- 3295 lectures
Le résultat dans la Console Python sera :
Je peux ainsi lancer les scripts « création automatique d'un fichier style à partir d'un fichier texte délimité » et « création automatique d'un fichier style à partir d'un fichier shapefile » (www.portailsig.org/content/creation-automatique-d-un-fichier-style-partir-d-un-fichier-texte-delimite), directement depuis la console, avec une petite modification pour que la fonction accepte le fichier à traiter comme argument :
>>>import creastyle2
>>># création d'un fichier style à partir d'un fichier shapefile
>>>creastyle2.traitement("test.shp")
Avec la commande import(module) et les modules PyQGIS de la console
Jusqu'à présent, nous n'avons utilisé que du Python « standard » sans nécessairement faire appel aux modules de PyQGIS. Gary Sherman a récemment montré comment l'utilisation de l'objet iface (qgis.utils.iface) permet de créer des scripts externes qui peuvent interagir complètement avec QGIS (spatialgalaxy.net/2012/01/27/qgis-running-scripts-in-the-python-console/)
L'exemple qu'il donne est un script (traduit ici) qui permet de charger et d'afficher dans QGIS tous les fichiers shapefiles d'un répertoire donné.
loader.py (traduction de l'original de Gary Sherman)
#!/usr/bin/env Python # encoding: utf-8 """Charge tous les fichiers shapefile d'un répertoire et les affiche dans QGIS Ce script (loader.py) fonctionne dans la console Python. Exécution: from loader import Loader ldr = Loader(qgis.utils.iface) ldr.load_shapefiles('/mon/chemin/du/répertoire/des_shapefiles') """ from glob import glob from os import path class Loader: def __init__(self, iface): """Initialisation en utilisant qgis.utils.iface """ self.iface = iface def load_shapefiles(self, shp_path): """Charge tous les fichiers shapefiles trouvés dans le répertoire""" print u"Ajout des fichiers shapefiles du répertoire %s" % path.join(shp_path, "*.shp") shps = glob(path.join(shp_path, "*.shp")) for shp in shps: (shpdir, shpfile) = path.split(shp) self.iface.addVectorLayer(shp, shpfile, 'ogr' )
- 3972 lectures
Et donc, depuis la console :
Plus loin avec l'extension Script Runner
Poursuivant son travail, Gary Sherman a ensuite automatisé le processus en créant une extension qui permet de lancer automatiquement ces scripts, Script Runner (spatialgalaxy.net/2012/01/29/script-runner-a-plugin-to-run-python-scripts-in-qgis/), disponible depuis le menu Extension/Installateur d'extensions python.
La seule différence avec l'exemple précédent est qu'il est nécessaire d'ajouter une fonction permettant à l'extension d'exécuter le script : run_script
def run_script(iface):
ldr = Loader(iface)
ldr.load_shapefiles('/Users/Shared/Dropbox/transfert')
En revanche, pas moyen de passer des paramètres, ils doivent être intégrés dans le script.
Conclusions
Il y a donc une « vie » Python sans nécessairement devoir créer des extensions. Pour vos traitements courants, si vous connaissez bien Python, la simple Console Python suffit.
Comme vous pouvez le constater sur la capture d'écran de Script Runner, je modifie progressivement mes divers scripts pour être compatibles avec l'extension (même ceux qui n'interfèrent pas directement avec QGIS comme le traitement de fichiers shapefiles avec Shapely ou Fiona, mais je peux ensuite les charger automatiquement dans QGIS).
Exemple de résultat du traitement réalisé avec un script Python à partir de Script Runner avec le module matplotlib
Sur les listes de QGIS, un site a déjà été proposé pour partager ces scripts : plugins.qgis.org/snippets/
Tous les traitements ont été effectués sur Mac OS X avec QGIS versions 1.7.3, 1.8 dev et 1.9 dev. et Python 2.6 (et 3.2).
Site officiel : execfileSite officiel : module subprocess
Site officiel : GMT ("Generic MappingTool")
Site officiel : Rscript
Site officiel : module PyRO
licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique Commerciale 2.0 France
Commentaires
je ne suis pas un robot
je ne suis pas un robot
erreur dernier script
Traceback (most recent call last):
File "", line 1, in
File "C:/OSGeo4W/apps/qgis/./python\qgis\utils.py", line 309, in _import
mod = _builtin_import(name, globals, locals, fromlist, level)
ImportError: No module named loader
comment faire pour le résoudre merci
QGIS, ScriptRunner, matplotlib & linéaments
Une question posée à votre intention, concernant la représentation des directions de linéaments par rose diagrams, a été posée ici :
http://gis.stackexchange.com/questions/24260/how-to-add-direction-and-di...
Merci beaucoup pour votre aide.
Paramètre
A noter qu'il est maintenant possible (je ne sais pas depuis quand) de passer des paramètres, une interface s'ouvrer permettant de les saisir, c'est extrèmement pratique.
voir http://spatialgalaxy.net/2013/03/18/new-version-of-the-qgis-script-runne... et surtout l'aide de script runner https://github.com/g-sherman/Script-Runner/blob/master/doc/index.rst : passing argument
Poster un nouveau commentaire