PyQGIS フューチャー選択サンプル

PyQGISでフューチャー選択の方法を調べたので、サンプルとしてまとめました。作成したサンプルは次のサイトを参考にしました。

gis.stackexchange.com

webgeodatavore.github.io

gis.stackexchange.com

docs.qgis.org

stackoverflow.com

docs.qgis.org


マウスで選択

使い方

f:id:Chiakikun:20200128003707p:plain

①マウスカーソルでフューチャーを一つ選択するサンプルです。ベクタレイヤを選択した状態でプラグインを実行してください。

  

f:id:Chiakikun:20200128004143p:plain

②カーソルが「+」になるので、アクティブレイヤのフューチャーを選択すると、属性編集ダイアログが表示されます。編集すると当然内容が変わるので、大事なデータの場合は『キャンセル』ボタンを押下してください。

こちらにインストール用zipファイルを置いておきました。

コード

featureselect_sample.py

class FeatureSelectSample:

~~

        # キャンバスウィンドウ上でのマウスイベントの設定
        self.mouseEventSample = FeatureSelectionTool(self.canvas)

~~

    def execSample(self):
        if self.action.isChecked():
            self.mouseEventSample.setLayer(self.iface.activeLayer())
            self.mouseEventSample.featureIdentified.connect(self.editAttribute)

~~

    # フューチャーを一つ選択した時に呼ばれる。
    def editAttribute(self, feature):
        self.layer.removeSelection() 
        self.layer.select(feature.id()) 

~~

class FeatureSelectionTool(qgis.gui.QgsMapToolIdentifyFeature):
    def __init__(self, canvas):
        self.canvas = canvas
        qgis.gui.QgsMapToolIdentifyFeature.__init__(self, self.canvas)

    def keyPressEvent( self, e ):
        pass

12行目 フューチャー選択の対象とするレイヤを設定しています。これが無いといくらマップをクリックしても13行目で設定しているself.editAttributeが呼ばれません。

19~20行目 フューチャーをマウスでクリックしただけでは選択状態にならないので、ここで選択状態にしています。

こちらにソースを置いておきます。


式で選択

使い方

f:id:Chiakikun:20200128004812p:plain

①クエリ式でフューチャーを選択するサンプルです。ベクタレイヤをアクティブにした状態でプラグインを実行すると、上のダイアログが表示されます。

 

f:id:Chiakikun:20200128004846p:plain

③対象フィールドを選択して、クエリ式を入力します。クエリ式でフューチャーが選択可能なら画像のように表示されます。

今回は国土交通省からダウンロードできる行政区画のシェープのフィールド「N03_001」の値で「島」が入っているレコードを抽出するために、次の式を使いました。

    Like '%島%'

 

f:id:Chiakikun:20200128005703p:plain

④式が有効であれば赤丸のボタンが有効になります。

 

f:id:Chiakikun:20200128005747p:plain

⑤『実行』ボタンを押下すると、クエリ式で抽出できたレコードのみの属性テーブルが表示されます。

 

f:id:Chiakikun:20200128005940p:plain

⑥クエリで抽出できたフューチャーが選択されている状態になっています。

こちらにインストール用zipを置いておきました。

コード

featureselectexpr_sample_dialog.py

class FeatureSelectExprSampleDialog(QtWidgets.QDialog, FORM_CLASS):

~中略~

    def testPush(self):
        self.query = ''

        query = '"' + self.fieldsBox.currentText() + '" ' + self.queryEdit.text()

        features = self.layer.getFeatures(qgis.core.QgsFeatureRequest().setFilterExpression(query))
        if len(list(features)) == 0:
            return

        self.query = query
        QtWidgets.QMessageBox.information(None, '情報', 'エラーなし')
        self.execButton.setEnabled(True)
        self.saveButton.setEnabled(True)

~中略~

    def execPush(self):
        QSettings().setValue("/Qgis/dockAttributeTable", True)
        self.layer.selectByExpression(self.query)
        self.iface.showAttributeTable(self.layer, self.query)

~略~

10行目 8行目で作ったクエリ式を使ってフューチャーの抽出をしています。

23行目 8行目で作ったクエリ式を使って抽出できるフューチャーを選択状態にしています。

24行目 8行目で作ったクエリ式を使って抽出できるフューチャーのみを属性テーブルに表示させています。

こちらにソースを置いておきます。

リレーションで選択

使い方

f:id:Chiakikun:20200209233626p:plain

①選択した親レイヤのフューチャーと関係を持つ子レイヤのフィールドを選択状態にするサンプルです。ここでは国土数値情報ダウンロードサービスからダウンロードできる行政区画と避難所を使います。行政区画のフィールド「N03_007」の値と避難所のフィールド「p20_001」は1対多の関係が見られたので...

 

f:id:Chiakikun:20200209233653p:plain

プラグインを実行すると上のようなダイアログが表示されるので、親レイヤに「行政区画」、フィールドに「N03_007」、子レイヤに「避難所」、フィールドに「p20_001」を設定して、実行ボタンを押下します。

 

f:id:Chiakikun:20200209233721p:plain

③一度押下すると、もう一度押すまでは凹んだままの状態になり...

 

f:id:Chiakikun:20200209233826p:plain

④行政区画のフューチャーを選択する度に、選択した行政区画の「N03_007」と避難所の「p20_001」が同じ値のフューチャーのみが選択され、属性ウィンドウに表示されます。

こちらにインストール用zipファイルを置いておきました。

コード

featureselectrelation_sample_dialog.py

~中略~

    def showEvent(self, e):
        # このプログラム実行中は属性テーブルは選択中のフューチャーしか表示しない
        self.oldsetting = QSettings().value("/Qgis/attributeTableBehaviour")
        QSettings().setValue("/Qgis/attributeTableBehavior", "ShowSelected")

~中略~

    def pushExec(self, checked):

        if checked == True:
            self.iface.actionSelect().trigger()

            # リレーションをここで張って...
            self.rel = qgis.core.QgsRelation()
            self.rel.setReferencingLayer(self.childLayer.id())
            self.rel.setReferencedLayer(self.parentLayer.id())
            self.rel.addFieldPair(self.comboChildField.currentText(), self.comboParentField.currentText())
            self.rel.setId('適当なID')
            self.rel.setName('適当な名前')
            qgis.core.QgsProject.instance().relationManager().addRelation(self.rel)

            self.parentLayer.selectionChanged.connect(self.showChildren)
            self.iface.setActiveLayer(self.parentLayer)

~中略~


        for c in self.rel.getRelatedFeatures(features[0]):
            child.select(c.id())

        selectedlayer = self.iface.activeLayer()
        try:
            self.iface.setActiveLayer(child)
            self.iface.mainWindow().findChild(QtWidgets.QAction, 'mActionOpenTable' ).trigger()
        finally:
            self.iface.setActiveLayer(selectedlayer)


こちらにソースを置いておきます。


インターセクトで選択

使い方

f:id:Chiakikun:20200302224229p:plain

①選択したフューチャーに重なる別レイヤのフューチャーを選択状態にして、Dドライブ直下に保存するサンプルです。プラグインを実行するとダイアログが表示されるので、マウス選択するフューチャーのレイヤ(ここでは行政区画)と、そのフューチャーに重なるフューチャーのレイヤ(ここでは避難所)をコンボボックスから選択します。

 

f:id:Chiakikun:20200302224245p:plain

②コンボボックスにレイヤを設定したらマウスで「比較対象の地物のあるレイヤ」に設定したレイヤのフューチャーを選択します。

 

f:id:Chiakikun:20200302224303p:plain

③『実行』ボタンを押下すると、マウス選択したフューチャーに重なる「選択する地物のあるレイヤ」で設定したレイヤのフューチャーが選択状態になります。また、選択されたフューチャーはDドライブに保存されます。

こちらにインストール用zipを置いておきました。

コード

featureselectintersect_sample_dialog.py

class FeatureSelectIntersectSampleDialog(QtWidgets.QDialog, FORM_CLASS):

~~

    def changeSelect(self, string):
        if self.comboSelectLayer.currentText() == '': return
        self.selectLayer = qgis.core.QgsProject.instance().mapLayersByName(self.comboSelectLayer.currentText())[0]


    def changeTarget(self, string):
        if self.comboTargetLayer.currentText() == '': return
        self.targetLayer = qgis.core.QgsProject.instance().mapLayersByName(self.comboTargetLayer.currentText())[0]


    def pushExec(self):

~~

        areas = []
        inGeom = features[0].geometry()
        # 矩形で大まかに取得してから、インターセクトで細かく取得する
        cands = self.selectLayer.getFeatures(qgis.core.QgsFeatureRequest().setFilterRect(inGeom.boundingBox())) # 「https://qgis.org/api/classQgsFeatureRequest.html」のexample
        for sf in cands:
            if inGeom.intersects(sf.geometry()):
                areas.append(sf.id())
        self.selectLayer.select(areas)

        res = qgis.core.QgsVectorFileWriter.writeAsVectorFormat(self.selectLayer, 'd:\\' + self.selectLayer.name() + '.shp', 'System', self.selectLayer.crs(), 'ESRI Shapefile', True)

ソースコードこちらに置いておきました。


複数のレイヤのフューチャーを一度に選択

使い方

f:id:Chiakikun:20200304215016p:plain

プラグインを実行するとマウスカーソルが「+」になるので、マップをクリック

して、そのまま引っ張ると上のように矩形が描けます。

 

f:id:Chiakikun:20200304215133p:plain

②ボタンを離すと矩形に重なるフューチャーが選択状態になります。

こちらにインストール用zipを置いておきました。

このプラグインはほとんどPyQGIS developer cookbookの「8.4. カスタムマップツールズの書き込み」そのままなので、コードは省略しました。

最後までご覧頂き、ありがとうございました。お疲れ様でした。