Vous générez un grand nombre de cartes à l'aide de PyQGIS?

10

Je dois faire un grand nombre (des centaines) de cartes de répartition des espèces. J'ai un fichier de formes qui contient les distributions pour chaque espèce, et pour chacune, je voudrais obtenir une carte sous forme d'image (jpg, png ou autre) qui contient le nom de l'espèce concernée, la légende (pour distinguer les zones de distributions annuelles, reproduction, non reproduction, etc ...).

J'aimerais utiliser QGIS pour ce faire.

Onesime
la source
1
Pourriez-vous nous en dire un peu plus sur les spécificités des cartes? Par exemple, voulez-vous que toutes ces cartes montrent la même zone, comme un continent ou un pays spécifique, ou voulez-vous que l'étendue de la carte change dynamiquement? De plus, voulez-vous tous les sous-types de plage sur une carte ou sont-ils sur plusieurs cartes? Selon ces réponses, votre problème pourrait être assez simple ou nécessiter un peu plus d'approche sophistiquée. Un bon endroit pour commencer à chercher est le plugin Atlas pour SIG, ou si vous avez ArcGIS 10 ou une version supérieure disponible, les cartes géographiques d'ESRI vous aideront également.
Jay Guarneri
1
Désolé pour le manque de détails. Oui pour toutes les cartes, ce sera la même zone (Europe). J'ai un shapefile avec toutes les espèces et, dans les attributs, la distribution correspondante. Ce fichier de formes, je peux facilement le diviser en différents fichiers de formes (un pour chaque espèce). A la fin, je voudrais avoir pour chaque espèce une photo, avec, à chaque fois, exactement la même zone (Europe), les mêmes couleurs (par exemple les distributions annuelles en vert foncé, se reproduisant en vert clair, ne se reproduisant pas en bleu, etc ...), la même légende, et comme titre le nom de l'espèce.
Onesime
Je pense que ce que vous devez faire est de planifier chaque étape que vous devez prendre pour créer chaque carte, puis coder les sélections et les exportations de carte en Python. Je sais que cela peut être fait facilement dans ArcGIS Python, mais je ne connais pas suffisamment l'interface QGIS Python pour donner beaucoup de conseils. Cependant, je suis convaincu que vous pouvez faire ce travail avec un seul fichier de forme.
Jay Guarneri
J'ai fait quelque chose de similaire avec QGIS en utilisant un plugin Python. Dans mon cas, mes couches étaient stockées dans PostGIS, mais je pense que vous pourriez faire quelque chose de similaire en utilisant un fichier de formes. Je suis heureux de partager mon code. Envoyez-moi un MP.
Brian Edmond
1
Pouvez-vous télécharger un échantillon de vos données pour que nous puissions jouer avec.
Nathan W

Réponses:

4

J'avais une exigence similaire et j'ai créé un plugin QGIS pour générer les cartes, basé sur un fichier de formes avec des localités ponctuelles pour toutes les espèces (il suppose un nom de taxon unique dans la table attributaire comme identifiant commun). Mes exigences n'étaient pas aussi complexes - je n'avais pas besoin d'informations saisonnières, de titres ou de légendes, mais cela peut être un point de départ utile pour vous. Pour les aspects plus complexes, vous devrez utiliser le composeur de cartes. Voir le livre de recettes PyQGIS pour en savoir plus.

Brancher

Le plugin automatise la création des cartes et vous permet de configurer les étendues, la résolution et d'autres aspects. Il applique le même style à la sortie que votre superposition de grille. Actuellement, il ne fonctionne que sur la version de développement de QGIS (1.9 ou ultérieure).

Script sextante

Avant de créer le plugin, j'ai élaboré la logique en utilisant SEXTANTE. Ce script utilisateur devrait également fonctionner en 1.8 (je ne l'ai pas testé). Le fichier de style de distribution (.qml) est le style des distributions de sortie (il ignore le style de la superposition de distribution). Actuellement, il place les mappes de sortie dans le répertoire temp en fonction des paramètres par défaut de votre système d'exploitation (/ tmp sous Linux et divers emplacements dans Windows - définis par la variable d'environnement TEMP). Vous pouvez assez facilement définir cela vous-même dans le code. Vous devrez également modifier l'étendue et la résolution de sortie dans le code (et la couleur d'arrière-plan si vous souhaitez une couleur différente pour la mer).

#Definition of inputs and outputs
#==================================
##[Scratch]=group
##all_localities=vector
##taxon_field=field all_localities
##africa_map=vector
##sa_map=vector
##grid_layer=vector
##distribution_style_file=file

#Algorithm body
#==================================
from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteVectorWriter import SextanteVectorWriter
import tempfile
import os

def print_map(taxon,taxon_shp):
    #load taxon layer (necessary?)
    #QGisLayers.load(taxon_shp,name = "taxon",style = distribution_style_file)
    taxon_layer = QgsVectorLayer(taxon_shp,"taxon","ogr")
    QgsMapLayerRegistry.instance().addMapLayer(taxon_layer)
    taxon_layer.loadNamedStyle(distribution_style_file)

    # create image (dimensions 325x299)
    img = QImage(QSize(325,299), QImage.Format_ARGB32_Premultiplied)

    # set image's background color
    color = QColor(192,192,255)   # blue sea
    img.fill(color.rgb())

    # create painter
    p = QPainter()
    p.begin(img)
    p.setRenderHint(QPainter.Antialiasing)

    render = QgsMapRenderer()

    # create layer set
    africa_layer = QGisLayers.getObjectFromUri(africa_map)
    sa_layer = QGisLayers.getObjectFromUri(sa_map)
    #taxon_layer = QGisLayers.getObjectFromUri(taxon_shp)

    lst = []
    lst.append(taxon_layer.id())    
    lst.append(sa_layer.id())
    lst.append(africa_layer.id())

    render.setLayerSet(lst)

    # set extent (xmin,ymin,xmax,ymax)
    rect = QgsRectangle(14.75,-36.00,34.00,-21.00)
    render.setExtent(rect)

    # set output size
    render.setOutputSize(img.size(), img.logicalDpiX())

    # do the rendering
    render.render(p)
    p.end()

    # save image
    #outdir = os.path.dirname(os.path.abspath(output))
    tempdir = tempfile.gettempdir()
    img.save(os.path.join(tempdir,taxon+".png"),"png")

    # remove taxon layer from project
    QgsMapLayerRegistry.instance().removeMapLayers([taxon_layer.id()])

tempdir = tempfile.gettempdir()   
taxa = sextante.runalg('qgis:listuniquevalues', all_localities, taxon_field, None)['UNIQUE_VALUES'].split(";")
for taxon in taxa:
    sextante.runalg('qgis:selectbyattribute', all_localities, taxon_field, 0, taxon)
    sextante.runalg('qgis:selectbylocation', grid_layer, all_localities, 0)
    filename = os.path.join(tempdir,"taxon.shp")    #memory file better?
    sextante.runalg('qgis:saveselectedfeatures', grid_layer, filename)
    print_map(taxon,filename)
rudivonstaden
la source
Salut à tous, Merci pour toutes vos réponses. Pour vous donner quelques éléments supplémentaires, il s'agit de données provenant de BirdLife (un exemple pour l'espèce: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). En bref, il y a un fichier de formes avec tous les polygones pour toutes les espèces (donc, pour certaines d'entre elles, plusieurs lignes pour une seule espèce), et il y a un attribut qui correspond à la distribution saisonnière (avec des valeurs de 1 à 5 correspondant à différentes utilisations ), un autre pour l'origine etc. La légende et le titre ne sont pas indispensables.
Onesime
- J'utilise une couche de pays en arrière-plan, juste pour un emplacement facile. - Pour la couleur différente pour la valeur différente de l'attribut "saisonnier", je pense que pour cela, un fichier d'utilisation .qml convient. - En option, pour le titre et la légende, je pense que je dois utiliser un fichier du compositeur, si c'est trop dur, je peux l'ajouter avec un autre logiciel. - L'opération doit être répétée pour toutes les espèces, cela correspond donc à une sélection par attribut, qui sera utilisée pour donner le nom de l'image finale.
Onesime
J'ai essayé le plugin "Atlas", mais il semble être plus approprié pour différents endroits, dans mon cas, c'est tout le temps pour la même zone: l'Europe. J'ai essayé le plugin "Distribution map manager" qui semble correspondre à ce point car il est possible de fixer la zone de couverture, mais je n'ai pas besoin du processus qui intersecte les points avec une couche de grille car j'ai déjà une couche de polygone. J'ai essayé dans ArcGis, mais il en est de même pour le plugin QGis Atlas, la solution semble être d'écrire un script python ...
Onesime
Je pense donc que je vais utiliser Sextante, basé sur le script "rudivonstaden" (merci pour ça!) Et pour l'adapter à mon cas. Enfin, Désolé pour ces différents commentaires, mais il y a une limite de nombre de caractères ...
Onesime
@Onesime, sauf pour le titre et la légende, je pense que vous pourrez adapter le script sextante ci-dessus pour faire ce dont vous avez besoin. Vous devrez probablement supprimer l' selectbylocationétape, et d' ajouter un montant supplémentaire selectbyattributeet saveselectedfeaturespour chaque saison (changement étape grid_layerà all_localities). Ensuite, chargez plus de fichiers .qml et ajoutez ajoutez vos fichiers de formes saisonniers (couche supérieure ajoutée en premier). Si vous ne savez pas comment, je pourrais probablement essayer de modifier le script ci-dessus pour travailler plus ou moins.
rudivonstaden
2

J'ai pris peu de temps pour y travailler aujourd'hui. J'ai donc apporté quelques modifications à votre script. Je n'ai pas besoin d'ajouter une étape selectbyattribute et saveelectedfeatures supplémentaire car j'utilise un fichier .qml et le champ saisonnier est dans le même fichier de formes. Ci-dessous, vous pouvez voir ce que j'ai fait:

#Definition of inputs and outputs
#==================================
##[Scratch]=group
##all_localities=vector
##taxon_field=field all_localities
##seasonal_field=field all_localities
##countries_map=vector
##distribution_style_file=file
##output_folder=folder

#Algorithm body
#==================================
from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteVectorWriter import SextanteVectorWriter
import tempfile
import os

def print_map(taxon,taxon_shp):
#load taxon layer (necessary?)
#QGisLayers.load(taxon_shp,name = "taxon",style = distribution_style_file)
taxon_layer = QgsVectorLayer(taxon_shp,"taxon","ogr")
QgsMapLayerRegistry.instance().addMapLayer(taxon_layer)
taxon_layer.loadNamedStyle(distribution_style_file)

# create image (dimensions 325x299)
img = QImage(QSize(325,299), QImage.Format_ARGB32_Premultiplied)

# set image's background color
color = QColor(221,249,254)   # blue sea
img.fill(color.rgb())

# create painter
p = QPainter()
p.begin(img)
p.setRenderHint(QPainter.Antialiasing)

render = QgsMapRenderer()

# create layer set
countries_layer = QGisLayers.getObjectFromUri(countries_map)
taxon_layer = QGisLayers.getObjectFromUri(taxon_shp)

lst = []
lst.append(taxon_layer.id())    
lst.append(countries_layer.id())
render.setLayerSet(lst)

# set extent (xmin,ymin,xmax,ymax)
rect = QgsRectangle(-11,32,39,71)
render.setExtent(rect)
# set output size
render.setOutputSize(img.size(), img.logicalDpiX())

# do the rendering
render.render(p)
p.end()

#save image
#outdir = os.path.dirname(os.path.abspath(output))
tempdir = output_folder
img.save(os.path.join(tempdir,taxon+".png"),"png")

# remove taxon layer from project
QgsMapLayerRegistry.instance().removeMapLayers([taxon_layer.id()])

tempdir = tempfile.gettempdir()  

taxa = sextante.runalg('qgis:listuniquevalues', all_localities, taxon_field, None)        ['UNIQUE_VALUES'].split(";")

for taxon in taxa:
sextante.runalg('qgis:selectbyattribute', all_localities, taxon_field, 0, taxon)
filename = os.path.join(tempdir,"taxon.shp")    #memory file better?
sextante.runalg('qgis:saveselectedfeatures', all_localities, filename)
print_map(taxon,filename)

Si vous avez des remarques ou des conseils pour l'améliorer, n'hésitez pas.

Pour l'améliorer, le mieux serait de sélectionner l'étendue (par exemple l'Europe), il utilise cette étendue pour sélectionner uniquement les espèces incluses dans cette étendue. Ceci parce que j'obtiens des cartes pour toutes les espèces, même celles qui sont hors d'Europe par exemple (j'ai donc beaucoup de cartes vides). Pensez-vous que c'est possible?

À votre santé,

Onesime

Onesime
la source