Как сослаться на другой слой в полевом калькуляторе?

26

Есть ли способ выбрать атрибут из слоя многоугольника и вставить значение в виртуальное поле точечного слоя, используя «в» в калькуляторе полей?

CASE
 WHEN within($geometry, geometry_polygon) THEN attribute_polygon
END

введите описание изображения здесь

Лунное море
источник
1
Почему бы не использовать для этого плагин 'Point sampling tool'?
Якоб
Потому что мне нужны динамические обновления при создании новых точек или перемещении существующих точек.
Лунное море
Вам лучше было бы писать сценарии этого взаимодействия, чем полагаться на готовые инструменты.
nagytech
К сожалению, у меня нет опыта написания сценариев.
Лунное море
@LunarSea Я написал ниже пример для вас, но вы, возможно, должны настроить его в соответствии со своими потребностями.
nagytech

Ответы:

22

Пространственные объединения доступны в полевом калькуляторе после установки плагина refFunctions.

geomwithin(targetLayer,targetField)
Лунное море
источник
Плагины намного проще, чем использование собственного скрипта. Благодарность!
jpmc26
geomwithin ( 'targetLayer', 'Таргет-филд').
Раджа
19

Встроенный калькулятор поля не поддерживает пространственные объединения между слоями объектов. Но, если вы посмотрите на пост Натана в редакторе функций для выражений qgis, вы сможете понять, что мы можем написать сценарий нашего взаимодействия с данными.

Следующий скрипт позволит вам выразить то, что вы после. Он работает путем перебора всех объектов на слое многоугольника и, если есть пространственное соединение, то ссылается на табличные данные из указанного столбца:

from qgis.core import *
from qgis.gui import *
from qgis.utils import iface

allfeatures = None
index = QgsSpatialIndex()
indexMade = 0
refLayer = None

@qgsfunction(args="auto", group='Custom')
def spatialJoinLookup(layerName, refColumn, defaultValue, geom, feature, parent):

    if geom is None:
        return defaultValue

    # globals so we don't create the index, refLayer more than once
    global allfeatures
    global index
    global indexMade
    global refLayer

    # Get the reference layer
    if refLayer is None:
        for layer in iface.mapCanvas().layers():
            if layerName == layer.name():
                refLayer = layer
                break
    if refLayer is None:
        raise Exception("Layer [" + layerName + "] not found")

    # Create the index if not exists
    if indexMade == 0:
        index = QgsSpatialIndex()
        allAttrs = layer.pendingAllAttributesList()
        layer.select(allAttrs)
        allfeatures = {feature.id(): feature for (feature) in refLayer.getFeatures()}
        for f in allfeatures.values():
            index.insertFeature(f)
        indexMade = 1

    # Use spatail index to find intersect 
    fid = None
    ids = index.intersects(geom.boundingBox())
    for id in ids:
        fid = id
        break # Only get the first match.
    if fid is not None:
        return allfeatures[fid].attribute(refColumn)

    # Default
    return defaultValue

Пример слоя многоугольника

Ниже приведен пример слоя многоугольника, который у вас может быть. Я также создал соответствующий точечный слой, который вы увидите на последнем изображении.

введите описание изображения здесь

Использование выражения

Обратите внимание: если вы хотите использовать отдельный столбец, вы должны изменить второй аргумент, чтобы он соответствовал имени столбца в наборе данных многоугольника. Например, вы можете использовать столбец «AreaNumber», но он должен соответствовать типу столбца в настройках калькулятора поля.

введите описание изображения здесь

Результат

Вы можете видеть, что значение столбца по умолчанию было применено там, где нет пространственного соединения, а другие сопоставили правильные данные. Обратите внимание, что сценарий, который я дал, будет включен только в первом матче. Вам нужно будет создать какую-то другую бизнес-логику, если ваши полигоны перекрываются.

введите описание изображения здесь

nagytech
источник
Большое спасибо, ваш скрипт работает нормально, используя 'geom' вместо 'geometry' в первом операторе 'if'. Такое объединение геометрий может быть весьма полезным, например, для создания нескольких меток на многоугольниках.
Лунное море
Извините, я не знаю, как я это пропустил. Надеюсь, проблем с производительностью нет - я пробовал только с небольшим набором записей.
nagytech
Имея только 100+ точечных функций, QGIS борется с проблемами производительности. Добавление нового точечного объекта - это действительно боль, даже если точечный объект не отображается на холсте. В противном случае при увеличении QGIS ускоряется. Я пробовал `CASE WHEN $ scale <10000 THENatialJoinLookupI ('Polygons', 'AreaName', 'None', $ geometry) END ', но это не работает. Что я могу сделать, чтобы улучшить производительность?
Лунное море
@LunarSea Я обновил функцию, чтобы использовать пространственный индекс. Это должно быть значительно быстрее.
nagytech
Спасибо за вашу помощь. Пространственное соединение теперь намного быстрее, но, к сожалению, что-то не работает должным образом. Я получаю разные результаты для точек в пределах одного и того же многоугольника.
Лунное море
8

Это можно сделать в полевом калькуляторе с функцией aggregate(). В точечном слое создайте новое поле с выражением калькулятора поля следующим образом:

aggregate(
layer:= 'polygon_layer_name',
aggregate:='concatenate',
expression:=joining_field_name,
concatenator:=', ',
filter:=intersects($geometry, geometry(@parent))
)

Где layerимя слоя многоугольника написано как строка, aggreagateэто агрегатная функция (может использоваться также сумма и т. Д.), expressionЭто поле из значений будет взято, concatenatorэто соединение символьной строки (должно быть установлено, даже в этом случае) и filterоснованная на функциях фильтрации по выражению (в этом случае геометрия слоя пересекается с геометрией родительского слоя).

Для получения дополнительной информации проверьте документацию Агрегатов QGIS .

Для автоматического обновления могут использоваться виртуальные поля или вы можете установить выражение в качестве значения по умолчанию в настройках формы атрибутов в свойствах слоя ( документация по настройке формы атрибута ).

введите описание изображения здесь

Ото Калаб
источник
3
Следует отметить, что пространственные функции (с geometry(@parent)) поддерживаются только начиная с QGIS 3 и далее. На всякий случай, если кто-то читает это, все еще использует 2.18 ...
she_weeds
Спасибо. Работает как шарм.
spatialthoughts