FieldPyculator - калькулятор полей с использованием выражений на Python для QGIS: различия между версиями

Материал из GIS-Lab
Перейти к навигации Перейти к поиску
 
(не показаны 24 промежуточные версии 2 участников)
Строка 1: Строка 1:
{{Статья|Черновик}}
{{Статья|Опубликована|fieldpyculator}}
{{Аннотация|Использование выражений на языке Python для операций с полями в QGIS}}
 
Одной из наиболее частых задач при работе с векторными данными является обработка атрибутивных полей. Не менее часто приходится производить массовое изменение атрибутивных данных, как например заполнение поля значениями, вычисленными на основе других столбцов слоя. Возможность вычисления поля для всех записей в слое - обязательный признак современной ГИС общего назначения, и от удобства использования этого инструмента напрямую зависит скорость обработки атрибутивной информации.
Одной из наиболее частых задач при работе с векторными данными является обработка атрибутивных полей. Не менее часто приходится производить массовое изменение атрибутивных данных, как например заполнение поля значениями, вычисленными на основе других столбцов слоя. Возможность вычисления поля для всех записей в слое - обязательный признак современной ГИС общего назначения, и от удобства использования этого инструмента напрямую зависит скорость обработки атрибутивной информации.


Строка 7: Строка 9:


== Получение и установка ==  
== Получение и установка ==  
Расширение доступно из [http://gis-lab.info/programs/qgis/qgis-repo.xml репозитория ГИС-Лаб].
Расширение доступно из [http://plugins.qgis.org/plugins/field_pyculator/ официального репозитория].


FieldPyculator разработан для QGIS версии 1.7.0 или старше и не имеет зависимостей.
FieldPyculator разработан для QGIS версии 1.7.0 или старше и не имеет зависимостей.
Строка 13: Строка 15:
Исходный код модуля можно получить выполнив команду:
Исходный код модуля можно получить выполнив команду:
<pre>git clone git://github.com/yellow-sky/FieldPyculator.git</pre>
<pre>git clone git://github.com/yellow-sky/FieldPyculator.git</pre>


== Работа с расширением ==  
== Работа с расширением ==  
После подключения и запуска расширения с помощью кнопки [[Файл:FieldPyculatorIcon.png]] или из меню Plugins->Field puculator->Field pyculator появится главное окно.
После подключения и запуска расширения с помощью кнопки [[Файл:FieldPyculatorIcon.png]] или из меню Plugins->Field pyculator->Field pyculator появится главное окно.
[[Файл:FieldPyculatorMainForm.png|center|]]
[[Файл:FieldPyculatorMainForm.png|center|]]
Верхняя часть окна содержит название активного векторного слоя, выпадающий список для выбора редактируемого поля и кнопка начала/завершения редактирования активного слоя. Так же, с помощью флажка "Update only selected features" можно регулировать какие из записей будут обновлены - все  или только выбранные с использованием стандартных инструментов QGIS.


Панель "Advanced" содержит поле для ввода "глобального" кода. Этот код будет выполнен только один раз, перед циклом обработки каждой  записи. В этом блоке удобно производить все подготовительные действия: импортировать необходимые модули, расчитывать переменные, которые будут использоваться при вычислении каждой из записей.


Панель "Existing fields and vars" содержит название всех полей редактируемого слоя. Двойной клик по элементу списка "Fields" приводит к его добавлению в выражение для расчета поля, а так же заполнению списка "Values" урезанным набором значений выбранного поля. При нажатии кнопки "Get all" урезанный набор значений будет замещен полным, что может занять достаточно продолжительный период времени.<br />Так же на панели расположены кнопки добавления в выражение специальных переменных: "$id" и "$geom". При обработке выражения, эти переменные будут содержать соответственно идентификатор обрабатываемой записи и её геометрию.
Верхняя часть окна содержит название активного векторного слоя, выпадающий список для выбора редактируемого поля и кнопку начала/завершения редактирования активного слоя. Так же, с помощью флажка "Update only selected features" можно регулировать какие из записей будут обновлены - все  или только выбранные с использованием стандартных инструментов QGIS.
[[Файл:Top.png|center|]]
 
 
Панель "Advanced" содержит поле для ввода "глобального" кода. Этот код будет выполнен один раз, перед циклом обработки каждой  записи. В этом блоке удобно производить все подготовительные действия: импортировать необходимые модули, рассчитывать переменные, которые будут использоваться при вычислении каждой из записей.
[[Файл:FieldPyculatorAdvanced.png|center|]]
 
Панель "Existing fields and vars" содержит название всех полей редактируемого слоя. Двойной клик по элементу списка "Fields" приводит к добавлению выбранного поля в выражение для расчета, а так же заполнению списка "Values" урезанным набором значений выбранного поля. При нажатии кнопки "Get all" урезанный набор значений будет заменен полным, что может занять достаточно продолжительный период времени.<br />Так же на панели расположены кнопки добавления в выражение специальных переменных: "$id" и "$geom". При обработке выражения эти переменные будут содержать соответственно идентификатор обрабатываемой записи и её геометрию.
[[Файл:FieldPyculatorFields.png‎|center|]]
 
 
Код, вычисляющий значение редактируемого поля содержится в "Field Expression". Код может содержать функции, объявления переменных, и иметь сколь угодно сложную структуру. '''Но обязательным условием является объявление переменной "value" для всех веток выполнения кода.''' Значение этой переменной будет присвоено редактируемому полю.<br />
'''Имена полей слоя необходимо заключать в угловые скобки''' (При добавлении из списка, скобки добавляются автоматически).<br />
Кнопка 'Run' запускает процесс расчета.
[[Файл:FieldPyculatorFoot.png‎|center|]]


Код, вычисляющий значение редактируемого поля содержится в "Field Expression". Код может содержать функции, объявления переменных, и иметь сколь угодно сложную структуру. Но обязательным условием является объявление переменной "value"для всех веток выполнения кода. Значение этой переменной будет присвоенно редактируемому полю.
Имена полей слоя необходимо заключать в угловые скобки (При добавления из списка, скобки добавляются автоматически).




== Примеры работы ==
== Примеры работы ==
Для примеров воспользуемся результатми [http://gis-lab.info/qa/prj-uik.html проекта проверки УИКов г. Москвы]. Точечный слой можно скачать [http://gis-lab.info/data/elect11/uik-verified.7z тут].
Для примеров воспользуемся результатами [http://gis-lab.info/qa/prj-uik.html проекта проверки УИКов г. Москвы]. Точечный слой можно скачать [http://gis-lab.info/data/elect11/uik-verified.7z тут].
 


=== Заполнения поля GUID'ами ===
=== Заполнение поля GUID'ами ===
Допустим, нам необходимо каждому объекту слоя присвоить уникальный идентификатор, что бы в дальнейшем иметь возможность связывать наш слой с данными, созданными на базе этого слоя (id типа int крайне ненадежная штука).
Допустим, нам необходимо каждому объекту слоя присвоить уникальный идентификатор, чтобы в дальнейшем иметь возможность связывать наш слой с данными, созданными на базе этого слоя (id типа int крайне ненадежная штука).
Создадим новый столбец 'guid' типа string размером 36 символов.
Создадим новый столбец 'guid' типа string размером 36 символов.
Запустив расширение и включив редактирование слоя, выбираем в выпадающем списке созданное поле 'guid'.
Запустив расширение и включив редактирование слоя, выбираем из выпадающего списка созданное поле 'guid'.
В поле глобального кода добавляем импорт нужного нам модуля (для этого нужно активировать переключатель 'Advanced'):
В поле глобального кода добавляем код для импорта нужного нам модуля (для этого необходимо активировать переключатель 'Advanced'):


<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
Строка 46: Строка 59:
value = str( uuid.uuid4() )
value = str( uuid.uuid4() )
</syntaxhighlight>
</syntaxhighlight>
В результате новое поле будет заполнено сгенерированными guid'ами:
В результате, новое поле будет заполнено сгенерированными guid'ами:
[[Файл:FieldPyculatorGuid.png‎|800px|center|]]




=== Обработка текстовых полей ===
=== Обработка текстовых полей ===
Работа с текстовыми атрибутами - одна из наиболее частых и в то же время запутанных. Связанно это с тем, что текстовая информация достаточно часто бывает неструктурированной.<br />
Работа с текстовыми атрибутами - одна из наиболее частых и в то же время запутанных. Связанно это с тем, что текстовая информация достаточно часто бывает неструктурированной.<br />
Пример. Рассмотрим поле ADDR_O слоя УИКов. Как можно сразу заметить, адреса записаны в произвольной форме, а различные формы записи перемешаны. Согласитесь, поле ADDR_V выглядит более структурированным. Давайте представим что у нас его нет, и попытаемся расчитать его из поля ADDR_O. Создадим дополнительное поле, для записи результата: 'ADDR_O_N' типа string и размером 250 символов.<br />
Пример. Рассмотрим поля ADDR_O и ADDR_V слоя УИКов. Как можно заметить, в поле ADDR_O адреса записаны в произвольной форме, а различные формы записи перемешаны. Форма записи в поле ADDR_V выглядит более структурированной.  
[[Файл:FieldPyculatorStr.png|center|]]
 
Давайте представим, что у нас нет поля ADDR_V, и попытаемся рассчитать его, использую поле ADDR_O. Создадим дополнительное поле, для записи результата: 'ADDR_O_STR' типа string и размером 250 символов.<br />
Пишем код обработки поля:
Пишем код обработки поля:
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
#переводим в верхний регистр
if <ADDR_O>:
addr_upper = <ADDR_O>.upper()
#переводим в верхний регистр
#удаляем вхождения ДОМ и №
addr_upper = <ADDR_O>.upper()
addr_cleaned = addr_upper.replace(u'ДОМ',u'ф') .replace(u'№','')
#удаляем вхождения ДОМ и №
 
addr_cleaned = addr_upper.replace(u'ДОМ','').replace(u'№','')
#удаляем лишние запятые (все после первой)
 
#addr_cleaned
#удаляем лишние запятые (все после первой) и пробелы после зпт
#удаляем лишнее пробелы после запятых
parts = addr_cleaned.partition(',')
 
addr_cleaned = parts[0]+','+parts[2].replace(',','').lstrip()
#если УЛ. идет перед названием, то переносим
if addr_cleaned.startswith(u'УЛ.'):
    addr_cleaned = addr_cleaned.replace(u'УЛ.', '')
    addr_cleaned = addr_cleaned.replace(',', u' УЛ.,')
   
#меняем К. на КОРП.
addr_cleaned = addr_upper.replace(u'К.', u'КОРП.')
 
#удаляем лишние пробелы
value = addr_cleaned.lstrip()


ДОПИСАТЬ!
#если УЛ. идет перед названием, то переносим
if addr_cleaned.startswith(u'УЛ.'):
    addr_cleaned = addr_cleaned.replace(u'УЛ.', '')
    addr_cleaned = addr_cleaned.replace(',', u' УЛ.,')
#меняем К. на КОРП. и С. на СТР.
addr_cleaned = addr_cleaned.replace(u'К.', u'КОРП.').replace(u'С.', u'СТР.')
#удаляем лишние пробелы
value = addr_cleaned.strip()
else:
value = <ADDR_O>
</syntaxhighlight>
</syntaxhighlight>


=== Заполнение поля только для определенных строк ===
После выполнения получаем поле, готовое к интеграции и автоматизированной обработке:
Достаточно часто необходимо обновить в слои только записи, удовлетворяющие определенному условию. Для выполнения этой операции с помощью стандартного калькулятора полей необходимо последовательно выполнить два действия: выбрать необходимые строки (с помощью расширенного поиска в таблице атрбутов) и при выполнении расчета в окне калькуляторе активировать переключатель "Обновить только выделенные объекты". Такая двухходовка неудобна по многим причинам - стандартный механизм выбора может далеко не все, калькулятор так же ограничен стандартным набором операций, и, если необходимо выполнить такие присвоения несколько раз, то можно легко ошибиться в выборках.<br />
[[Файл:FieldPyculatorStrRes.png|center|]]
Попробуем выполнить это с помощью плагина. Создадим в слое УИКов новое поле - "Type" типа string размером 100 символов. Для всех школ и гимназий присвоим значение "school", для библиотек - "library", а всем остальным - "other".
 
 
=== Изменение строк, удовлетворяющих условию ===
Достаточно часто возникает необходимость обновить в слое только записи, удовлетворяющие определенному условию. Для выполнения этой операции с помощью стандартного калькулятора полей необходимо последовательно выполнить два действия: выбрать необходимые строки (с помощью расширенного поиска в таблице атрибутов) и при выполнении расчета в окне калькулятора активировать переключатель "Обновить только выделенные объекты". Такая двухходовка неудобна по многим причинам - стандартный механизм выбора может далеко не все, калькулятор так же ограничен стандартным набором операций, и при необходимости выполнить несколько подобных присвоений вероятность ошибиться в выборках вырастает.<br />
Попробуем выполнить эту операции с помощью плагина. Создадим в слое УИКов новое поле - "type" типа string размером 100 символов. Для всех школ и гимназий присвоим значение "school", для библиотек - "library", а всем остальным - "other".


Код вычисления поля:
Код вычисления поля:
Строка 92: Строка 114:


Результат выполнения:
Результат выполнения:
[[Файл:FieldPyculatorType.png|center]]


Так, за один проход мы сделали то, что стандартным калькулятором можно сделать за 5 шагов.
Так, за один проход мы сделали то, что стандартным калькулятором можно сделать за 5 шагов.




=== Замещение JOIN'a с последующем присвоением значений ===
=== Замещение JOIN'a с последующим присвоением значений ===
По сути этот пример является развитием предыдущего.
По сути этот пример является развитием предыдущего.
Допустим нам необходимо заменить значения одного из полей в строгом соответствии с какой либо таблицей (Обычно такая потребность возникает, когда необходимо заменить чиловой код типа объекта на название этого типа). Стандартными функциями QGIS это можно сделать следующим образом:<br />
Допустим нам необходимо заменить значения одного из полей в строгом соответствии с какой либо таблицей (Обычно такая потребность возникает, когда необходимо заменить чиcловой код типа объекта на название этого типа). Стандартными функциями QGIS это можно сделать следующим образом:<br />
1) Создать таблицу, с двумя полями - код и его название<br />
1) Создать таблицу, с двумя полями - код и его название<br />
2) Добавить эту таблицу в проект и выполнить JOIN с нужным слоем<br />
2) Добавить эту таблицу в проект и выполнить JOIN с нужным слоем<br />
3) В калькуляторе полей присвоить новое значение обрабатываемому полю, равное соответствующему значение из присоединеной таблицы<br />
3) В калькуляторе полей присвоить новое значение обрабатываемому полю, равное соответствующему значение из присоединенной таблицы<br />


Если же количество уникальных значений этого поля не так велико, то можно упростить процедуру, написав достаточно компактный код.
Если же количество уникальных значений этого поля не так велико, то можно упростить процедуру, написав достаточно компактный код.
Для примера, переведем строчный тип, соданный в предыдущем примере в числовой (иногда ведь приходится производить и обратную операцию :).
Для примера переведем строчный тип, созданный в предыдущем примере, в числовой (иногда ведь приходится производить и обратную операцию :).
Откроем окно плагина, в выпадающем списке выбирем поле "type". В списке Fields выберем это же самое поле и нажимаем кнопку "Get all", что бы получить все значения этого поля.
Откроем окно плагина, из выпадающего списке выберем поле "type". В списке Fields выбираем это же самое поле и нажимаем кнопку "Get all", чтобы получить все значения этого поля.


Пишем глобальный код:
Пишем глобальный код:
Строка 127: Строка 150:
И код для вычисления поля:
И код для вычисления поля:
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">
value = table[<Type>]
value = table[<type>]
</syntaxhighlight>
</syntaxhighlight>


После выполнения, строчный код стал числовым (а вернее псевдо числовым, так как мы не создавали новое поле с типом int, а записали числа в это же строчное поле):
После выполнения, строчный код стал числовым (а вернее псевдочисловым, так как мы не создавали новое поле с типом int, а записали числа в существующее строчное поле):
[[Файл:FieldPyculatorTypeCode.png|center]]
 
 
=== Работа с геометриями ===
Переменная $geom дает доступ к геометрии обрабатываемой строки. Переменная содержит объект типа QgsGeometry, работа с которым описана в [http://gis-lab.info/docs/qgis/cookbook/geometry.html PyQGIS documentation]. Так же можно многое почерпнуть в [http://qgis.org/api/classQgsGeometry.html QGIS API].<br />
 
Простой пример. Необходимо обновить поля LAT и LONG в слое УИКов, после очередного обновления геометрий. Открываем форму расширения, из выпадающего списка полей выбираем поле LAT, запускаем редактирование. В поле кода вычисления поля пишем и запускаем обработку:
<syntaxhighlight lang="python">
value = $geom.asPoint().y()
</syntaxhighlight>
Не завершая редактирование, выбираем второй столбец - LONG, код обработки меняем на:
<syntaxhighlight lang="python">
value = $geom.asPoint().x()
</syntaxhighlight>
Запускаем обработку и завершаем редактирование.<br />
В данном случае мы знаем что тип слоя - точечный, cоответственно мы можем выполнить преобразование ''asPoint()'', и получить координаты ''x()'' и ''y()''.<br />
Для линейных объектов мы можем выполнять операцию расчета длины - ''$geom.length()'', a для полигональных расчета площади - ''$geom.area()''.
 
 
Рассмотрим более сложный пример. Допустим мы хотим проверить адреса в слое УИКов с помощью обратного геокодинга (Не будем обращать внимание на уже существующие поля LAT и LONG,тем более что геометрии могли быть отредактированы). Воспользуемся api, предоставляемое сервисом [http://wiki.openstreetmap.org/wiki/Nominatim Nominatim], а так же модулем [http://docs.python.org/library/json.html json] стандартной библиотеки python для разбора ответа сервера. Для сохранения результатов создадим новое поле ADDR_OSM типа string размером 250 символов. '''Будьте осторожны! Обработка большого количества записей с обращением к интернет сервисам может занять большое количество времени! Особенно для медленных соединений!'''
 
Глобальный код:
<syntaxhighlight lang="python">
import json
import sys
import urllib2
url = 'http://nominatim.openstreetmap.org/reverse?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1'
</syntaxhighlight>
 
Код вычисления поля:
<syntaxhighlight lang="python">
try:
f = urllib2.urlopen ( url % ($geom.asPoint().y(),$geom.asPoint().x()))
resp_str = unicode(f.read(),  'utf-8')
resp = json.loads(resp_str)
if resp.has_key('address'):
addr = resp['address']
if addr.has_key('pedestrian'):
value = addr['pedestrian']
else:
value = addr['road']
if addr.has_key('house_number'):
value = value+', '+addr['house_number']
else:
value = 'Not found'
except:
value = 'Error: '+unicode(sys.exc_info()[1])
</syntaxhighlight>
Результат:
[[Файл:FieldPyculatorGeocoding.png|center]]
 
== Дополнительные ссылки ==
Python:
* [http://docs.python.org/ Python documentation]
 
PyQGIS:
* [http://qgis.org/pyqgis-cookbook/ PyQGIS Cookbook]
* [http://gis-lab.info/docs/qgis/cookbook/ Перевод PyQGIS Cookbook]
 
Другое:
* [http://qgis.org/api QGIS API]
* [http://pypi.python.org/pypi/Shapely Shapely - Python библиотека для работы с геометриями]
* [http://gis-lab.info/qa/ogr-python.html Работа с векторными данными при помощи OGR и Python]
* [http://gis-lab.info/qa/grass64-python.html Создание скрипта на Python для ГИС GRASS]
* [http://code.google.com/intl/ru-RU/apis/maps/documentation/geocoding/#ReverseGeocoding Обратный геокодинг от Google]


== Контакты ==
== Контакты ==
[https://github.com/yellow-sky/FieldPyculator/issues Баг трекер на GitHub]
Если вы нашли ошибку или у вас есть предложения по улучшению расширения - напишите на [http://mailto:nikulin.e@gmail.com email] или в [https://github.com/yellow-sky/FieldPyculator/issues баг трекер на GitHub].
[[Категория:Расширения QGIS]]

Текущая версия от 06:08, 21 ноября 2013

Эта страница опубликована в основном списке статей сайта
по адресу http://gis-lab.info/qa/fieldpyculator.html


Использование выражений на языке Python для операций с полями в QGIS

Одной из наиболее частых задач при работе с векторными данными является обработка атрибутивных полей. Не менее часто приходится производить массовое изменение атрибутивных данных, как например заполнение поля значениями, вычисленными на основе других столбцов слоя. Возможность вычисления поля для всех записей в слое - обязательный признак современной ГИС общего назначения, и от удобства использования этого инструмента напрямую зависит скорость обработки атрибутивной информации.

Ядро QGIS имеет достаточно продвинутый калькулятор полей. Но его основной минус - невозможность использования функций, отличных от тех, что заложены разработчиками. На этот случай, в других ГИС обычно предусматривается возможность использования скриптовых языков, для создания необходимых функций обработки (например ArcGIS Desktop позволяет в калькуляторе полей активировать режим, при котором вычисление полей можно производить с использованием JavaScript или VB Script).

Для исправления этого недостатка QGIS было разработано расширение, позволяющее производить вычисление полей с помощью интерпретатора языка Python и использовать практически все доступные для него библиотеки. Идея впервые была предложена Raymond Nijssen. Но к сожалению, его плагин FieldEvaluator до сих пор находится на стадии глубокой разработки и позволяет вычислять лишь выражения на Python, не давая возможности использовать всю мощь этого языка. Данное расширение, по сути, позволяет пользователю создавать сколь угодно сложный алгоритм для вычисления значений, и имеет чуть более удобный интерфейс. Будем надеяться, Раймонд не обидится за то что мы предложили еще одну реализацию его идеи.

Получение и установка

Расширение доступно из официального репозитория.

FieldPyculator разработан для QGIS версии 1.7.0 или старше и не имеет зависимостей.

Исходный код модуля можно получить выполнив команду:

git clone git://github.com/yellow-sky/FieldPyculator.git

Работа с расширением

После подключения и запуска расширения с помощью кнопки FieldPyculatorIcon.png или из меню Plugins->Field pyculator->Field pyculator появится главное окно.

FieldPyculatorMainForm.png


Верхняя часть окна содержит название активного векторного слоя, выпадающий список для выбора редактируемого поля и кнопку начала/завершения редактирования активного слоя. Так же, с помощью флажка "Update only selected features" можно регулировать какие из записей будут обновлены - все или только выбранные с использованием стандартных инструментов QGIS.

Top.png


Панель "Advanced" содержит поле для ввода "глобального" кода. Этот код будет выполнен один раз, перед циклом обработки каждой записи. В этом блоке удобно производить все подготовительные действия: импортировать необходимые модули, рассчитывать переменные, которые будут использоваться при вычислении каждой из записей.

FieldPyculatorAdvanced.png

‎ Панель "Existing fields and vars" содержит название всех полей редактируемого слоя. Двойной клик по элементу списка "Fields" приводит к добавлению выбранного поля в выражение для расчета, а так же заполнению списка "Values" урезанным набором значений выбранного поля. При нажатии кнопки "Get all" урезанный набор значений будет заменен полным, что может занять достаточно продолжительный период времени.
Так же на панели расположены кнопки добавления в выражение специальных переменных: "$id" и "$geom". При обработке выражения эти переменные будут содержать соответственно идентификатор обрабатываемой записи и её геометрию.

FieldPyculatorFields.png


Код, вычисляющий значение редактируемого поля содержится в "Field Expression". Код может содержать функции, объявления переменных, и иметь сколь угодно сложную структуру. Но обязательным условием является объявление переменной "value" для всех веток выполнения кода. Значение этой переменной будет присвоено редактируемому полю.
Имена полей слоя необходимо заключать в угловые скобки (При добавлении из списка, скобки добавляются автоматически).
Кнопка 'Run' запускает процесс расчета.

FieldPyculatorFoot.png


Примеры работы

Для примеров воспользуемся результатами проекта проверки УИКов г. Москвы. Точечный слой можно скачать тут.


Заполнение поля GUID'ами

Допустим, нам необходимо каждому объекту слоя присвоить уникальный идентификатор, чтобы в дальнейшем иметь возможность связывать наш слой с данными, созданными на базе этого слоя (id типа int крайне ненадежная штука). Создадим новый столбец 'guid' типа string размером 36 символов. Запустив расширение и включив редактирование слоя, выбираем из выпадающего списка созданное поле 'guid'. В поле глобального кода добавляем код для импорта нужного нам модуля (для этого необходимо активировать переключатель 'Advanced'):

import uuid


Код, для вычисления поля выглядит следующим образом:

value = str( uuid.uuid4() )

В результате, новое поле будет заполнено сгенерированными guid'ами:

FieldPyculatorGuid.png


Обработка текстовых полей

Работа с текстовыми атрибутами - одна из наиболее частых и в то же время запутанных. Связанно это с тем, что текстовая информация достаточно часто бывает неструктурированной.
Пример. Рассмотрим поля ADDR_O и ADDR_V слоя УИКов. Как можно заметить, в поле ADDR_O адреса записаны в произвольной форме, а различные формы записи перемешаны. Форма записи в поле ADDR_V выглядит более структурированной.

FieldPyculatorStr.png

Давайте представим, что у нас нет поля ADDR_V, и попытаемся рассчитать его, использую поле ADDR_O. Создадим дополнительное поле, для записи результата: 'ADDR_O_STR' типа string и размером 250 символов.
Пишем код обработки поля:

if <ADDR_O>:
	#переводим в верхний регистр
	addr_upper = <ADDR_O>.upper()
	#удаляем вхождения ДОМ и №
	addr_cleaned = addr_upper.replace(u'ДОМ','').replace(u'№','')

	#удаляем лишние запятые (все после первой) и пробелы после зпт
	parts = addr_cleaned.partition(',')
	addr_cleaned = parts[0]+','+parts[2].replace(',','').lstrip()

	#если УЛ. идет перед названием, то переносим
	if addr_cleaned.startswith(u'УЛ.'):
	    addr_cleaned = addr_cleaned.replace(u'УЛ.', '')
	    addr_cleaned = addr_cleaned.replace(',', u' УЛ.,')
	
	#меняем К. на КОРП. и С. на СТР.
	addr_cleaned = addr_cleaned.replace(u'К.', u'КОРП.').replace(u'С.', u'СТР.')
	
	#удаляем лишние пробелы
	value = addr_cleaned.strip()
else:
	value = <ADDR_O>

После выполнения получаем поле, готовое к интеграции и автоматизированной обработке:

FieldPyculatorStrRes.png


Изменение строк, удовлетворяющих условию

Достаточно часто возникает необходимость обновить в слое только записи, удовлетворяющие определенному условию. Для выполнения этой операции с помощью стандартного калькулятора полей необходимо последовательно выполнить два действия: выбрать необходимые строки (с помощью расширенного поиска в таблице атрибутов) и при выполнении расчета в окне калькулятора активировать переключатель "Обновить только выделенные объекты". Такая двухходовка неудобна по многим причинам - стандартный механизм выбора может далеко не все, калькулятор так же ограничен стандартным набором операций, и при необходимости выполнить несколько подобных присвоений вероятность ошибиться в выборках вырастает.
Попробуем выполнить эту операции с помощью плагина. Создадим в слое УИКов новое поле - "type" типа string размером 100 символов. Для всех школ и гимназий присвоим значение "school", для библиотек - "library", а всем остальным - "other".

Код вычисления поля:

addr_ext_lower = <ADDR_V_EXT>.lower()
value = 'other'
if  u'школа' in addr_ext_lower or u'гимназия' in addr_ext_lower:
	value = 'school'
if u'библиотека' in addr_ext_lower:
	value = 'library'

Результат выполнения:

FieldPyculatorType.png

Так, за один проход мы сделали то, что стандартным калькулятором можно сделать за 5 шагов.


Замещение JOIN'a с последующим присвоением значений

По сути этот пример является развитием предыдущего. Допустим нам необходимо заменить значения одного из полей в строгом соответствии с какой либо таблицей (Обычно такая потребность возникает, когда необходимо заменить чиcловой код типа объекта на название этого типа). Стандартными функциями QGIS это можно сделать следующим образом:
1) Создать таблицу, с двумя полями - код и его название
2) Добавить эту таблицу в проект и выполнить JOIN с нужным слоем
3) В калькуляторе полей присвоить новое значение обрабатываемому полю, равное соответствующему значение из присоединенной таблицы

Если же количество уникальных значений этого поля не так велико, то можно упростить процедуру, написав достаточно компактный код. Для примера переведем строчный тип, созданный в предыдущем примере, в числовой (иногда ведь приходится производить и обратную операцию :). Откроем окно плагина, из выпадающего списке выберем поле "type". В списке Fields выбираем это же самое поле и нажимаем кнопку "Get all", чтобы получить все значения этого поля.

Пишем глобальный код:

table =  { 
'library' : 1000,
'other' : 2000,
'school' : 3000
}

В достаточно простой форме мы определяем соответствие кодов и их названий. Если бы мы делали присвоение названий, то каждая строчка выглядела бы наоборот:

#пример!!!
table =  { 
1000 : 'library',
2000 : 'other',
3000 : 'school'
}

И код для вычисления поля:

value = table[<type>]

После выполнения, строчный код стал числовым (а вернее псевдочисловым, так как мы не создавали новое поле с типом int, а записали числа в существующее строчное поле):

FieldPyculatorTypeCode.png


Работа с геометриями

Переменная $geom дает доступ к геометрии обрабатываемой строки. Переменная содержит объект типа QgsGeometry, работа с которым описана в PyQGIS documentation. Так же можно многое почерпнуть в QGIS API.

Простой пример. Необходимо обновить поля LAT и LONG в слое УИКов, после очередного обновления геометрий. Открываем форму расширения, из выпадающего списка полей выбираем поле LAT, запускаем редактирование. В поле кода вычисления поля пишем и запускаем обработку:

value = $geom.asPoint().y()

Не завершая редактирование, выбираем второй столбец - LONG, код обработки меняем на:

value = $geom.asPoint().x()

Запускаем обработку и завершаем редактирование.
В данном случае мы знаем что тип слоя - точечный, cоответственно мы можем выполнить преобразование asPoint(), и получить координаты x() и y().
Для линейных объектов мы можем выполнять операцию расчета длины - $geom.length(), a для полигональных расчета площади - $geom.area().


Рассмотрим более сложный пример. Допустим мы хотим проверить адреса в слое УИКов с помощью обратного геокодинга (Не будем обращать внимание на уже существующие поля LAT и LONG,тем более что геометрии могли быть отредактированы). Воспользуемся api, предоставляемое сервисом Nominatim, а так же модулем json стандартной библиотеки python для разбора ответа сервера. Для сохранения результатов создадим новое поле ADDR_OSM типа string размером 250 символов. Будьте осторожны! Обработка большого количества записей с обращением к интернет сервисам может занять большое количество времени! Особенно для медленных соединений!

Глобальный код:

import json
import sys
import urllib2
url = 'http://nominatim.openstreetmap.org/reverse?format=json&lat=%f&lon=%f&zoom=18&addressdetails=1'

Код вычисления поля:

try:
	f = urllib2.urlopen ( url % ($geom.asPoint().y(),$geom.asPoint().x()))
	resp_str = unicode(f.read(),  'utf-8')
	resp = json.loads(resp_str)
	if resp.has_key('address'):
		addr = resp['address']
		if addr.has_key('pedestrian'):
			value = addr['pedestrian']
		else:
			value = addr['road']
		if addr.has_key('house_number'):
			value = value+', '+addr['house_number']
	else:
		value = 'Not found'
except:
	value = 'Error: '+unicode(sys.exc_info()[1])

Результат:

FieldPyculatorGeocoding.png

Дополнительные ссылки

Python:

PyQGIS:

Другое:


Контакты

Если вы нашли ошибку или у вас есть предложения по улучшению расширения - напишите на email или в баг трекер на GitHub.