pyQGISでできることのまとめ（自分用）



[FOSS4G Advent Calendar 2019　　14日目の記事です。](https://qiita.com/advent-calendar/2019/foss4g)

最近のマイブームとして、「QGISのpythonコンソールで処理を動かす」というのにワクワクしてます。

###pythonコンソールとは


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/97c5b679-a570-53b9-080a-91e10bbee2e9.png)


のことです。
コンソール内に、pythonコードを書き込むとGUI同様にQGISの操作がきるというヤツです。

前々から、いろいろネットでコードを調べつついたのですが、これを機に「こうしたい時はこう書く」みたいな自分なりのTipsを整理したいと思います。

書き方が乱雑ですいません。
アクセスが伸びれば、需要があるんだなぁということで、アドベントカレンダー後も更新して行けたらと思います。
あ、QGISはバージョン３以降での想定です

では早速。


## データの追加
### ベクタレイヤ

```
iface.addVectorLayer('追加するデータソース','追加した時のレイヤ名','ogr')
```

- レイヤ名は実際には「追加した時のレイヤ名+ファイル名」になるので、３つ目の引数は空白('')にするのがおすすめです。

- ３つ目の引数はプロバイダの指定ですが、'ogr'固定で良いと思います。


### ラスタレイヤ

```
iface.addRasterLayer('追加するファイルのデータソース','追加した際のレイヤ名')
```
- こちらはogrの指定はいらないんですね。
- こちらもレイヤ名は「``追加した際のレイヤ名``＋ファイル名」になるので、第２引数は空白('')が良いです。

### csv（デリミティッドテキスト）レイヤ

```
#csvファイルの定義
uri = 'csvのファイルパス?delimiter= {}&crs=epsg:4326&xField={}&yField={}'.format('区切り文字', 'xフィールド名', 'yフィールド名')

#読み込み
csvlayer = QgsVectorLayer(uri, 'csvPoint', 'delimitedtext') 

#レイヤに追加
QgsProject.instance().addMapLayer(csvlayer)

```
- １行目で読み込みcsvの設定します。パスは絶対ぱすで。相対パスだとなぜかうまくいかないです。
- ２行目でcsvを読み込みます
- 読み込んだだけだとレイヤとして追加されないので、３行目でレイヤに追加します。




## レイヤの取得


```
# 追加されているレイヤのリストを取得
layers = iface.mapCanvas().layers() 
```


```
#アクティブレイヤを取得
layer = iface.activeLayer()
```
```

#レイヤ名を指定して取得
layer = QgsProject.instance().mapLayersByName('レイヤ名')[0]
```





## レイヤ情報の抽出
レイヤの情報を見ることができます。

```
#レイヤ名
layer.name()

#座標系
layer.crs().authid()

#エンコーディング
layer.dataProvider().encoding()

#データタイプ(ベクターなら０、ラスターなら1が返ってきます。）
layer.type

#ジオメトリ(ポイントなら0、ラインなら１、ポリゴンなら２が返ってきます。）
layer.geometryType()


#データのバウンディイングボックスの座標
layer.extent()

#データのパス
layer.dataProvider().dataSourceUri()

#フィーチャの数をカウント
layer.featureCount()

#選択地物のカウント
layer.selectedFeatureCount()


```
レイヤのパスが取得できるということは、レイヤのリストからパスを取得して、E社のAソフトに同様にレイヤを移植することができそうですね。
[チラッ](https://qiita.com/nishi_bayashi/items/c556d703848f4529e2d2)


### エンコーディングの指定

```
layer.setProviderEncoding(u'文字コード')
```
文字コードは``Shift_JIS``とか``UTF-8``とかお好みで


### レイヤのエクスポート
```

QgsVectorFileWriter.writeAsVectorFormat('保存するレイヤ','保存先パス','文字コード','出力形式')
```

- ファイル形式は``ESRI Shapefile``,``GeoJSON``,``kml``などお好みで



## プロセッシング
### プロセッシングモジュールのインポート
```
import processing
```
プロセッシング関係のコマンドを打つ時はprocessingモジュールをインポートする必要があります。


### プロセッシングの検索
```
search = "検索したいキーワード"
for processing in QgsApplication.processingRegistry().algorithms():
    if search in processing.id():
        print (processing.id())
```
例えばbufferというキーワードで検索すると、以下のようにbufferに関わるプロセッシング名が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/4dc8ad4a-6feb-a3f7-f0ca-252ac224c46c.png)




### プロセッシングのヘルプ


```
processing.algorithmHelp("プロセッシング名")
```

プロセッシングで検索して出てきたプロセッシング名を打ち込むと、そのプロセッシングを実行する際のヘルプが表示されます。（以下は、native:bufferの例）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/334df6b7-e5c2-86ec-3b34-5aa4c82bbc42.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/eb148515-3b0d-2fcc-1615-7f532f406e0d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/d02f4eff-f50a-4148-8137-1d8e002254f4.png)

入力パラメータとして
- INPUT（入力レイヤ)
- DISTANCE（距離）
- SEGEMNTS(セグメント数）
- END_CAP_STYLE(線端スタイル）
- JOIN_STYLE(繋ぎ目のスタイル)
- MITER＿LIMIT（miter制限)
- DISSOLVE(結果をディゾルブするか否か）
- OUTPUT（出力レイヤ）

が必要ということがわかります。
これは、GUIでバッファを実行する時と同じ項目があることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/278130fb-a640-59fe-8f38-616e4e7d9f94.png)




## プロセッシングの実行
```
processing.run('プロセッシング名',{パラメーター})
```
これだけだとなんのこっちゃなので、ヘルプで確認したパラメータを元にバッファを実行してみます。


### バッファの実行
```
buffer = processing.run('native:buffer', {"INPUT": layer, "DISTANCE": 500, "OUTPUT": "test/testbuffer.shp"})

```
- オプションのパラメータは端折ってます。
- 実行結果をbufferという変数に入れております。
- この処理結果bufferを実行してみると、以下のように辞書形式で処理結果の保存場所が記録さております。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/670ff5cb-2c4e-3ed2-8e7c-df8e1a95eed3.png)


- 実行しただけだとレイヤに追加されないので、以下で実行結果をレイヤに追加することができます。

 
```
iface.addVectorLayer(buffer["OUTPUT"],"","ogr")
```

### 処理を実行してそれをそのままレイヤに追加したいなら以下でも可。

```
buffer = processing.runAndLoadResults('native:buffer', {"INPUT": layer, "DISTANCE": 500, "OUTPUT": "test/testbuffer.shp"})
```

### 出力を一時ファイルとして出力
OUTPUTを``'memory:'``とすると、ファイルとして保存せずに、一時ファイルとして出力することができます。（どんな結果が出るか試しに実行する時とか、処理の途中ファイルで保存したく無い時とか、上司に見られたくない処理を回すときにおすすめ）

```
buffer = processing.run('native:buffer', {"INPUT": layer, "DISTANCE": 500, "OUTPUT": 'memory:'})
```

出力結果を``memory:``にした場合、OUTPUTは以下のように記載されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/9365edc7-02de-a9ac-10bd-bfe1f001eb2e.png)

このレイヤをマップに追加しようとする場合、上記のような``iface.addVectorLayer``だとエラーになるので、その場合は以下で追加することができます。

```
QgsProject.instance().addMapLayer(buffer['OUTPUT'])
```


## プロセッシングについての裏技
ちょっとプロセッシングのコードを見たいだけなのに、ツール名探して、ヘルプ見て・・・ってちょっと煩わしい・・・・・
という人向けの裏技です。

GUIでも処理を実行すれば、プロセッシングツールボックスに履歴が残ります。
履歴は

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/9d711dd1-2b66-2439-09dc-84cbd5a8513d.png)

で確認できます。

開くと以下のウインドウで過去の実行したプロセッシング履歴が見れて、選択するとウインドウ下部にコードが表示されるので、これをコピーして、pythonコンソールで実行すればそのまま同じ処理が実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61492/880027fc-b1a3-1414-1f8f-18979153fc20.png)

あぁ、あの処理はこう書くのか。。。と勉強しやすいし、
試しに、GUIで処理を実行して、履歴からコードをコピーして、細かい設定を書き換える。という手段を自分はよく取ります。




いったんここまで・・・・（時間切れ）
今後も追加していきますのでたまに見にきてください。。



----
## ※2020/3/14 追記
[上](#レイヤ情報の抽出)にレイヤの範囲(バウンディイングボックス)の座標の調べ方は記載していますが、データの一つ一つのフィーチャのバウンディングボックスを調べたいということがあって調べたので追記します。


##フィーチャのバウンディングボックス取得
```
#とりあえずレイヤを取得
layer = iface.activeLayer()
#フィーチャクラスの取得
features = layer.getFeatures()
#forループで一つ一つのフィーチャを取得
for feature in features:
    geom = feature.geometry().boundingBox()
    print(geom)
```
とりあえずこれで以下のように各フィーチャの範囲が取得できます。（サンプルの数値は平面直角のデータで取得したので平面直角の値です）
`<QgsRectangle: 14099.1455739498269395 -169595.27998573053628206, 14369.9917462461417017 -168845.67491709906607866>`

ちなみにこの後以下のようにすれば、xmin,ymin,xmax,ymaxの値も取れます。

```
    gxmin = geom.xMinimum()
    gymin = geom.yMinimum()
    gxmax = geom.xMaximum()
    gymax = geom.yMaximum()
```




----
## ※2020/9/23 追記
レイヤの属性テーブル周り。


##属性テーブルの表示
```
#とりあえずレイヤを取得
layer = iface.activeLayer()
#フィーチャクラスの取得
iface.showAttributeTable(layer)
```

## フィールドカラム取得

```
#QgsFieldクラスのインスタンス生成
layer_field = layer.fields()

#フィールドのカラム名一覧取得
for i in layer_field:
    print(i.name())

```

## フィールドカラム名を指定して値を出力

```
#QgsFieldクラスのインスタンス生成
layer_field = layer.fields()

#フィールドのカラム名取得
for i in layer.getFeatures():
    print(i['カラム名'])

```

## 属性値で選択

```
layer.selectByExpression(('"カラム名"=\'値\''))
layer.selectByExpression(('"カラム名"=\'' + i + '\''))

select_layer = layer.materialize(QgsFeatureRequest().setFilterFids(layer.selectedFeatureIds()))
```

## プロジェクトの情報

```
#プロジェクトのcrs
crs = QgsProject.instance().crs()
```

ではまた。