フィールド計算機で別のレイヤーを参照する方法は?


26

フィールド計算機の「内」を使用して、ポリゴンレイヤーから属性を選択し、ポイントレイヤーの仮想フィールドに値を挿入する方法はありますか?

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

ここに画像の説明を入力してください


1
これに「ポイントサンプリングツール」プラグインを使用しないのはなぜですか?
ヤコブ

新しいポイントを作成するとき、または既存のポイントを移動するときに動的な更新が必要だからです。
月の海

すぐに使用できるツールに頼るよりも、この対話をスクリプト化する方が良いでしょう。
nagytech

残念ながら、スクリプト作成の経験はありません。
月の海

@LunarSea以下の例を作成しましたが、ニーズに合わせて調整する必要があるかもしれません。
nagytech

回答:


22

refFunctionsプラグインをインストールすると、フィールド計算機で空間結合が利用可能になります。

geomwithin(targetLayer,targetField)

プラグインは、カスタムスクリプトを使用するよりもはるかに簡単です。ありがとう!
jpmc26

geomwithin( 'targetLayer'、 'targetField')。
ラジャ

19

デフォルトでは、フィールド計算機はフィーチャレイヤー全体の空間結合をサポートしていません。しかし、qgis式の関数エディターに関するNathanWの投稿を見ると、独自のデータ相互作用をスクリプト化できることがわかります。

次のスクリプトを使用すると、目的を表現できます。ポリゴンレイヤー上のすべてのフィーチャを反復処理し、空間結合がある場合は、指定された列から表形式のデータを参照します。

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

ポリゴンレイヤーの例

以下は、使用する可能性のあるポリゴンレイヤーの例です。また、最終画像に表示される対応するポイントレイヤーも作成しました。

ここに画像の説明を入力してください

式の使用

別の列を使用する場合は、2番目の引数を変更して、ポリゴンデータセットの列名と一致させる必要があります。たとえば、「AreaNumber」列を使用できますが、フィールド計算機設定の列タイプと一致する必要があります。

ここに画像の説明を入力してください

結果

空間結合がない場所にデフォルトの列値が適用され、他の値が正しいデータと一致していることがわかります。指定したスクリプトは、最初の一致でのみ参加することに注意してください。ポリゴンが重なっている場合は、他のビジネスロジックを作成する必要があります。

ここに画像の説明を入力してください


多くのおかげで、スクリプトは最初の「if」ステートメントで「geometry」の代わりに「geom」を使用して正常に動作しています。この方法でジオメトリを結合すると、たとえばポリゴンに複数のラベルを作成する場合に非常に便利です。
月の海

申し訳ありませんが、私はそれを見逃した方法がわかりません。パフォーマンスの問題がないことを願っています-非常に小さなレコードのサブセットでのみ試しました。
nagytech

100以上のポイントフィーチャしか持たないQGISは、パフォーマンスの問題に苦労しています。新しいポイントフィーチャを追加することは、実際のキャンバスにポイントフィーチャが表示されていなくても、本当に苦痛です。それ以外の場合は、QGISでのズームが高速化されます。「$ scale <10000 THEN spatialJoinLookupI( '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ベースの機能をフィルタリングされon expression(この場合、レイヤージオメトリと親レイヤーのジオメトリを交差させます)。

詳細については、QGISのドキュメントを集計してください。

自動更新のために使用することができる仮想フィールドをかのようにして式を設定することができますデフォルト値での属性は、フォームの設定レイヤープロパティを属性フォームの設定マニュアルを参照して)。

ここに画像の説明を入力してください


2
空間関数(with geometry(@parent))はQGIS 3以降でのみサポートされることに注意してください。これを読んでいる人がまだ2.18を使用している場合に備えて...
she_weeds

ありがとうございました。魔法のように機能します。
空間思考
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.