Генерация большого количества карт с использованием PyQGIS?

10

Я должен сделать большое количество (сотни) карт распространения видов. У меня есть шейп-файл, который содержит распределения для каждого вида, и для каждого я хотел бы получить карту в виде изображения (jpg, png или иным образом), содержащего название соответствующего вида, легенду (чтобы выделить области ежегодные распределения, разведение, разведение и т. д. ...).

Я хотел бы использовать QGIS для этого.

Onesime
источник
1
Не могли бы вы указать немного больше о специфике карт? Например, хотите ли вы, чтобы на всех этих картах отображалась одна и та же область, например, определенный континент или страна, или вы хотите, чтобы экстент карты динамически изменялся? Кроме того, вы хотите, чтобы все подтипы диапазона на одной карте или они на нескольких картах? В зависимости от этих ответов ваша проблема может быть довольно простой или может потребовать более сложного подхода. Хорошее место для начала - это плагин Atlas для ГИС, или, если у вас есть ArcGIS 10 или более поздняя версия, карты ESRI также помогут.
Джей Гварнери
1
Извините за отсутствие деталей. Да для всех карт, это будет один и тот же район (Европа). У меня есть один шейп-файл со всеми видами и в атрибутах соответствующее распределение. Этот шейп-файл, я могу легко разбить его на разные шейп-файлы (по одному для каждого вида). В конце я хотел бы иметь для каждого вида по одному изображению, в котором в каждый момент времени была бы одна и та же область (Европа), одинаковые цвета (например, ежегодные распределения в темно-зеленом цвете, размножение в светло-зеленом цвете, отсутствие размножения в синий и т. д.), та же легенда, а в качестве заголовка название вида.
Onesime
Я думаю, что вам нужно планировать каждый шаг, который вам нужно сделать, чтобы создать каждую карту, а затем кодировать выборки и экспортировать карту в Python. Я знаю, что это легко сделать в ArcGIS Python, но я недостаточно знаю интерфейс QGIS Python, чтобы дать много рекомендаций. Однако я уверен, что вы можете сделать эту работу с одним шейп-файлом.
Джей Гварнери
Я сделал нечто подобное с QGIS, используя плагин Python. В моем случае мои слои были сохранены в PostGIS, но я думаю, что вы могли бы сделать нечто подобное, используя шейп-файл. Я рад поделиться своим кодом. ПМ мне.
Брайан Эдмонд
1
Можете ли вы загрузить образец ваших данных для нас, чтобы играть с.
Натан W

Ответы:

4

У меня было похожее требование и я создал плагин QGIS для генерации карт на основе шейп-файла с точечными местоположениями для всех видов (в качестве общего идентификатора предполагается уникальное имя таксона в таблице атрибутов). Мои требования не были такими сложными - мне не нужна была сезонная информация, названия или легенды, но это может быть полезной отправной точкой для вас. Для более сложных аспектов вам нужно будет использовать составитель карт. Смотрите кулинарную книгу PyQGIS для получения дополнительной информации об этом.

Plugin

Плагин автоматизирует создание карт и позволяет настраивать экстенты, разрешение и другие аспекты. Он применяет тот же стиль к выводу, что и оверлейная сетка. В настоящее время он работает только на разрабатываемой версии QGIS (1.9 или более поздней).

Скрипт Sextante

Прежде чем я сделал плагин, я разработал логику с помощью SEXTANTE. Этот пользовательский скрипт также должен работать в 1.8 (еще не проверял). Файл стиля распространения (.qml) - это стиль выходных распределений (он игнорирует стиль наложения распределения). В настоящее время он размещает выходные карты в каталоге temp на основе значений по умолчанию вашей операционной системы (/ tmp в Linux и различных местах в Windows - определяется переменной среды TEMP). Вы можете довольно легко определить это самостоятельно в коде. Вам также нужно будет отредактировать экстент и выходное разрешение в коде (и цвет фона, если вы хотите другой цвет для моря).

#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
источник
Привет всем, Спасибо за все ваши ответы. Чтобы дать вам еще несколько элементов, это данные, полученные из BirdLife (пример для specie: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). Вкратце, существует один шейп-файл со всеми полигонами для всех видов (так, для некоторых из них много строк для одного вида), и есть атрибут, который соответствует сезонному распределению (со значениями от 1 до 5, соответствующими различным применениям). ), еще один для происхождения и т. д. Легенда и название не является обязательным.
Onesime
- Я использую слой страны в фоновом режиме, просто для удобного расположения. - Для цвета, отличающегося от значения атрибута «сезонный», я думаю, для этого подойдет файл .qml. - При желании, для заголовка и легенды, я думаю, мне нужно использовать файл от композитора, если он слишком сложный, я могу добавить его с помощью другого программного обеспечения. - Операция должна быть повторена для всех видов, поэтому это соответствует выбору по атрибуту, который будет использоваться для присвоения имени окончательной фотографии.
Onesime
Я попробовал плагин «Атлас», но он кажется более подходящим для разных мест, в моем случае, это все время для одной и той же области: Европы. Я попробовал плагин «Диспетчер карт распределения», который, кажется, соответствует этому пункту, потому что возможно исправить область покрытия, но мне не нужен процесс, который пересекает точки со слоем сетки, так как у меня уже есть слой многоугольника. Я пытался в ArcGis, но это совершенно то же самое для плагина QGis Atlas, решение, кажется, заключается в написании скрипта Python ...
Onesime
Поэтому я думаю, что я буду использовать Sextante на основе сценария «rudivonstaden» (спасибо за это!) И адаптировать его к моему случаю. Наконец, извините за эти разные комментарии, но есть ограничение на количество символов ...
Onesime
@Onesime, за исключением заголовка и легенды, я думаю, что вы сможете адаптировать скрипт sextante выше, чтобы делать то, что вам нужно. Вероятно, вам нужно будет удалить selectbylocationшаг и добавить дополнительный selectbyattributeи saveselectedfeaturesшаг для каждого сезона (смените grid_layerна all_localities). Затем загрузите больше файлов .qml и добавьте свои сезонные шейп-файлы (верхний слой добавляется первым). Если вы не уверены, как, я мог бы попытаться отредактировать сценарий выше, чтобы более или менее работать.
rudivonstaden
2

Я потратил немного времени, чтобы работать над этим сегодня. Поэтому я внес некоторые изменения в ваш сценарий. Мне не нужно добавлять дополнительный атрибут selectbyattribute и saveselectedfeatures, так как я использую файлы .qml и поле Seasonal находится в одном шейп-файле. Ниже вы можете увидеть, что я сделал:

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

Если у вас есть какие-либо замечания или советы по его улучшению, не стесняйтесь.

Чтобы улучшить его, лучше всего, когда мы выберем экстент (например, для Европы), он использует этот экстент для выбора только видов, включенных в этот экстент. Это потому, что я получаю карты для всех видов, даже для тех, которые находятся за пределами Европы, например (поэтому у меня много пустых карт). Как вы думаете, это возможно?

Ура,

Onesime

Onesime
источник