Створення великої кількості карт за допомогою PyQGIS?


10

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

Я хотів би використовувати QGIS для цього.


1
Не могли б ви вказати трохи більше про специфіку карт? Наприклад, ви хочете, щоб усі ці карти показували ту саму область, як певний континент чи країна, або ви хочете, щоб масштаби карти динамічно змінювалися? Крім того, ви хочете, щоб усі підтипи діапазону були на одній карті чи вони є на кількох картах? Залежно від цих відповідей, ваша проблема може бути досить простою, або вона може зажадати трохи більш складного підходу. Гарне місце, щоб почати шукати - плагін Atlas для ГІС, або якщо у вас є ArcGIS 10 або більше, картографічні книжки ESRI також допоможуть.
Джей Гуарнері

1
Вибачте за відсутність деталей. Так, для всіх карт, це буде однакова область (Європа). У мене є одна формафайлу з усіма видами і, за атрибутами, відповідний розподіл. Це форма файлу, я можу легко розділити його на різні форми (по одному для кожного виду). Зрештою, я хотів би мати для кожного виду по одній картині з кожним разом точно однаковою площею (Європа), однаковими кольорами (наприклад, щорічні розповсюдження в темно-зеленому, розведення в світло-зеленому, не розмноження в синій і т. д. ...), та сама легенда, і як заголовок назва виду.
Onesime

Я думаю, що вам потрібно зробити, це спланувати кожен крок, який потрібно зробити, щоб зробити кожну карту, а потім зашифрувати виділення та експортувати карти в Python. Я знаю, що це можна зробити легко в ArcGIS Python, але я не знаю достатньо інтерфейсу QGIS Python, щоб дати багато вказівок. Однак я впевнений, що ви можете зробити цю роботу за допомогою одного формату.
Джей Гуарнері

Я зробив щось подібне з QGIS, використовуючи плагін Python. У моєму випадку мої шари зберігалися в PostGIS, але я думаю, ви могли зробити щось подібне, використовуючи filefile. Я радий поділитися своїм кодом. PM мене.
Брайан Едмонд

1
Чи можете ви завантажити зразок своїх даних для нас, щоб грати.
Nathan W

Відповіді:


4

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

Підключати

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

Сценарій Sextante

Перш ніж зробити плагін, я розробив логіку за допомогою SEXTANTE. Цей сценарій користувача також повинен працювати в версії 1.8 (не перевіряли його). Файл стилю розподілу (.qml) - це стиль вихідних розподілів (він ігнорує стиль накладення розподілу). В даний час він розміщує вихідні карти в темп-каталозі на основі за замовчуванням у вашій операційній системі (/ 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)

Привіт усім, дякую за всі ваші відповіді. Щоб дати вам ще кілька елементів, це дані, що надходять від BirdLife (приклад для конкретного: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). Коротко кажучи, є один файл форми з усіма багатокутниками для всіх видів (так, для деяких з них багато рядків для одного виду), і є атрибут, який відповідає сезонному розподілу (зі значеннями від 1 до 5, що відповідають різним видам використання ), один за походженням тощо. Легенда та назва не обов'язкові.
Onesime

- Я використовую шар країни у фоновому режимі, просто для зручного розташування. - Для іншого кольору, що відрізняється від атрибута "сезонне", я вважаю, що для цього підходить файл .qml. - За бажанням і легендою, я думаю, що я повинен використовувати файл композитора, якщо він занадто важкий, я можу додати його за допомогою іншого програмного забезпечення. - Операцію потрібно повторити для всіх видів, тому це відповідає вибору за атрибутом, який буде використаний для назви кінцевої картини.
Onesime

Я спробував плагін "Atlas", але він, здається, більше підходить для різних локацій, у моєму випадку він весь час для однієї і тієї ж області: Європа. Я спробував плагін "Менеджер карт розподілу", який, здається, відповідає в цій точці, тому що можна зафіксувати зону покриття, але мені не потрібен процес, який перетинає точки з шаром сітки, оскільки у мене вже є багатокутний шар. Я спробував в ArcGis, але це абсолютно те саме для плагіна QGis Atlas, здається, рішення полягає в тому, щоб написати сценарій пітона ...
Onesime

Тому я думаю, що я буду використовувати Sextante, заснований на сценарії "rudivonstaden" (спасибі за це!) Та адаптувати його до моєї справи. Нарешті, вибачте за ці різні коментарі, але існує обмеження кількості символів ...
Onesime

@Onesime, за винятком заголовка та легенди, я думаю, ви зможете адаптувати сценарій sextante вище, щоб зробити все, що вам потрібно. Вам, ймовірно, потрібно буде видалити selectbylocationкрок, і додати додатковий selectbyattributeта saveselectedfeaturesкрок для кожного сезону (змінити grid_layerна all_localities). Потім завантажте більше .qml файлів і додайте додавання ваших сезонних файлів форм (верхній шар додається першим). Якщо ви не впевнені, як, я, можливо, спробую відредагувати вищезазначений сценарій для більш-менш роботи.
rudivonstaden

2

Сьогодні мені було потрібно небагато часу для роботи над цим. Тому я внесла деякі зміни до вашого сценарію. Мені не потрібно додавати додатковий крок виділення для розподілу та збереження вибраних функцій, оскільки я використовую файли. Нижче ви можете побачити, що я зробив:

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

Якщо у вас є якісь зауваження чи поради щодо їх покращення, не соромтеся.

Щоб покращити його, найкраще було б, коли ми вибираємо ступінь (для прикладу Європи), вона використовує цю міру для вибору лише видів, що входять до цієї міри. Це тому, що я отримую карти для всіх видів, навіть тих, які є, наприклад, поза Європою (тому у мене багато порожніх карт). Як ви вважаєте, це можливо?

Ура,

Онісіме

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.