Upload
kosuke-asahi
View
14.102
Download
14
Embed Size (px)
DESCRIPTION
FOSS4G 2013 Hokkaidoハンズオン資料 QGIS ver 1.8版
Citation preview
QGISプログラミング入門FOSS4G 2013 Hokkaido 編
北海道地図株式会社 朝日孝輔
[email protected] (お仕事用) [email protected] (OSGeo っぽいご用件) [email protected] (個人のご用件)
1/36
目次1 本日の内容........................................................................................................................................32 本題に入る前の基礎知識.................................................................................................................4
2.1QGIS とは?................................................................................................................................42.2Qt とは?.....................................................................................................................................42.3Python とは?..............................................................................................................................5
3Python の基本的な文法.....................................................................................................................53.1 変数への代入............................................................................................................................53.2 組み込み型と扱い.....................................................................................................................63.3 制御フロー.................................................................................................................................83.4 関数............................................................................................................................................93.5 クラス........................................................................................................................................113.6 パッケージ................................................................................................................................12
4Python コンソールから操作..............................................................................................................134.1 すべての基本は QgisInterface から........................................................................................134.2 ユーザインタフェース編..........................................................................................................144.3 ベクトル編(図形にアクセス)....................................................................................................164.4 ベクトル編(描画設定)..............................................................................................................174.5Canvas イベント編.....................................................................................................................18
5Plugin の基本...................................................................................................................................195.1Plugin の基本構成...................................................................................................................195.2__init__.py................................................................................................................................195.3 処理本体が記載されたファイル..............................................................................................205.4 プラグインの追加確認.............................................................................................................215.5icon の追加...............................................................................................................................215.6QAction の slot への結びつけ.................................................................................................235.7 ダイアログの追加.....................................................................................................................24
6 デバッグ環境...................................................................................................................................297SEXTANTE 入門.............................................................................................................................29
7.1SEXTANTE とは?...................................................................................................................297.2Python コンソールから SEXTANTE.........................................................................................307.3 関数を利用する.......................................................................................................................327.4SEXTANTE スクリプト..............................................................................................................33
8QGIS 2.0 での変更点概要..............................................................................................................358.1 ベクトルレイヤ関係..................................................................................................................358.2Plugin のメタデータ..................................................................................................................358.3 その他......................................................................................................................................35
9 参考資料.........................................................................................................................................3610 最後に............................................................................................................................................36
2/36
1 本日の内容
このセッションでは、
• QGIS コアライブラリの構成といった前提知識の説明
• 簡単な Python 文法講習
• QGIS Python コンソールからの CUI による QGIS 操作
• QGIS Plugin 構成の説明
• QGIS へのメニューの追加
までを行います。
時間を見ながら、今後重要度が増すと思われる、SEXTANTE にも触れてみたいと思います。
QGIS 2.0 のリリースの時期ですが、このセッションでは QGIS 1.8 を基本に説明を行います。QGIS 2.0 から
API が変更されていますので、巻末で変更点のポイント、情報収集先について触れておきます。
本セッションで使用するデータは、Public Domain でデータを提供している NaturalEarth のものを使用して
います。
http://www.naturalearthdata.com
3/36
2 本題に入る前の基礎知識
2.1 QGISとは?
一般的な説明は抜きにします。
QGIS は C++で書かれており、インタフェース部分については Qt ライブラリを使用しています。QGIS の構成
は、コアライブラリ、アプリケーション本体、プラグインに大別出来ます。コアライブラリは、
• QGIS Core Library
• QGIS GUI Library
• QGIS Analysis Library
• Map Composer
• QGIS Network Analysis Library
に分かれています。Python コンソールから QGIS にアクセスする際、Plugin から QGIS にアクセスする際は、
これらのライブラリを通して、QGIS の機能を使用することになります。また、これらのライブラリを個別に使用して、
別なアプリケーションを作成することも可能となります。
C++で書かれている QGIS ですが、SIP というツールを使用して、Python 用インタフェースも提供されていま
す。Qt についても同様に Python 用のインタフェースが提供されています。これにより、プラグインを開発する場
合、C++で書く、Python で書く、の2通りの方法を選択出来ます。ただし、Python については全ての機能を使
用出来る訳ではなく、Python 用インタフェースが提供されている機能のみ使用出来るという点で注意が必要で
す。例として、データハンドリングの根幹に関するプラグインについては、アプリケーション全体の実行速度に影
響を与えるため Python での作成は出来なくなっています。C++、Python の使い分けとしては、
• Python はコンパイルの必要が無いが、C++ではコンパイルが必要といった開発環境
• QGIS のどの部分にアクセスするのか
• 配布先の OS を考慮した場合に、C++では OS にあったライブラリの作成が必要
といった点を考慮して決める必要があります。とはいえ、どちらで開発するのがお手軽かといえば、Python を使
用する場合になります。
2.2 Qtとは?
C++で書かれたアプリケーション・ユーザーインタフェースのフレームワークです。GoogleEarth や Skype が
Qt で作られています。Qt の特徴は単一のソースで、Windows、Linux、Mac Os といった様々なプラット
フォーム上で動作するアプリケーションが開発可能なことです。また様々な言語のバインディングが用意されて
おり、Python からも使用することが出来ます。開発環境として、QtCreater、GUI 開発環境として、Qt Designer といった環境が提供されており、開発が迅速に行えることも特徴です。
4/36
2.3 Pythonとは?
Python はプログラムの実行前にコンパイルを必要としないスクリプト言語または軽量言語と呼ばれる種類のプ
ログラミング言語です。他の言語に比べて文法がシンプルで習得がしやすい言語となっています。また、誰が書
いても同じような記述になるような工夫がされています。その一つとしてインデント(字下げ)が重要という点が挙
げられます。例えばループを表す際に、Python ではループ内のブロックのインデントを揃えることで表します。
QGIS のプラグイン開発にも利用出来ますし、ArcGIS の ArcPy での採用例もありますので、地理情報を扱う
技術者としては押さえておきたいプログラミング言語です。
3 Pythonの基本的な文法 この後の操作をスムーズにするため、Python の基本的な文法を押さえておきます。動作の確認は QGIS の
Python コンソールから行います。
3.1 変数への代入
Python では変数の型をあらかじめ指定しておく必要はなく、
変数名 = 代入する値、オブジェクトなど
を指定した際に変数が作成されます。変数名をタイプすると、変数に代入されている値・クラスを確認出来ます。
>>>test = 'foss4g'
>>>test
'foss4g'
作成済みではない変数がタイプされた際は、エラーとなります。
>>>test2
Traceback (most recent call last):File "<input>", line 1, in <module>NameError: name 'test2' is not defined
5/36
3.2 組み込み型と扱い
a) 数値型
数値型は整数型、浮動小数点型、複素数型が用意されています。ただし、ここでは複素数型は使用しないの
で、説明は省きます。
数値に足しては「+」「-」「*」「/」「%」「**」といった演算子を使用して計算を行えます。注意しておく点としては、
計算結果は数値の精度を保とうとして返されることがあげられます。例として整数/整数の計算結果は整数となり
ます。
>>>15/7
2
一方の数値が浮動小数点型の場合は、浮動小数点型の結果が返されます。
>>>15.0/7
2.142857142857143
計算の優先順位は、足し算・引き算より、掛け算・割り算が優先されるというように、通常の四則演算と同様です。
優先順位を明示する場合は、「(」「)」でくくります。
>>>1+2*3
7
>>>(1+2)*3
9
b) 文字列
Python では文字列は「'(シングルコーテーション)」もしくは「”(ダブルコーテーション)」で囲って表現します。
通常はシングルコーテーションを使用します。文字列中のコーテーション記号や、特殊記号はバックスラッシュで
エスケープします。
>>> 'foss4g'
'foss4g'
>>>'foss4g \'2013\' hokkaido'
“foss4g '2013' hokkaido”
>>>a = 'foss4g \nhokkaido'
>>>print a
foss4g
hokkaido
3 重のコーテーション記号を使うと、複数行にまたがった文字列を表現出来ます。
>>>a = '''foss4g
...2013
...hokkaido'''
6/36
>>>print a
文字列は添字表記で一部を参照することが可能です。最初の文字のインデックスが 0 になります。
>>>a = 'foss4g'
>>>a[0]
'f'
>>>a[1:2]
'o'
ただし文字列の一部を書き換えることは出来ないので、注意しておいて下さい。下記の処理はエラーになりま
す。
>>> a = 'foss4g'
>>>a[1] = 'b'
Python の文字列型は数値・アルファベットといった ASCII 文字を扱うための文字列型(string)と、マルチバイ
ト文字列を扱うためのユニコード文字列(unicode string)型があります。漢字、ひらがなといった日本語を扱う場
合、先頭のコーテーション記号の前に'u'を付けて下さい。下記コードの実行結果を比べてみて下さい。
>>>a = 'とっても簡単'
>>>a
>>>print a
>>>a = u'とっても簡単'
>>>a
>>>print a
文字列は”+”演算子で連結することが出来ます。
>>>a = 'foss4g' + 'hokkaido'
>>>print a
foss4ghokkaido
c) リスト
Python では別々のデータを1まとめにして使う場合の複合型がいくつか用意されています。そのうちもっとも
汎用的なのがリストになります。カンマで区切られた値を「[」「]」角括弧で囲んで表します。文字列と同様に添字
で各要素にアクセスすることが出来ます。
>>>a = ['foss4g', 2013, 'hokkaido', 'sapporo', u'テレビ塔']
>>>a
['foss4g', 2013, 'hokkaido', 'sapporo', u'\u30c6\u30ec\u30d3\u5854']
>>>a[1]
2013
>>>a[1:3]
[2013, 'hokkaido']
7/36
リストは連結することも出来ますし、要素を指定して入れ替えることも出来ます。
>>>a = ['foss4g', 2013] + ['hokkaido']
>>>a
['foss4g', 2013, 'hokkaido']
>>>a[1] = 2012
>>>a
['foss4g', 2012, 'hokkaido']
d) 辞書
辞書は他の言語において、”連想配列”として実装されているものです。辞書はキーと値のペアの集合になりま
す。キー:値のペアをカンマで区切り、「{」「}」波括弧で囲んで表します。
>>>a = {'event':'foss4g', 'year':2013}
>>>a['event']
'foss4g'
辞書中に特定のキーが存在しているかを調べる場合は、in を使用します。
>>>'event' in a
True
3.3 制御フロー
a) if文
他の言語と同様の if 文が用意されています。インデントには気をつけてください。
>>>x = 130
>>if x < 130:
… print 'small'
…elif x == 130:
… print 'equal'
...else:
… print 'big'
…
b) for文
Python の for 文が他の言語と違うところとして、任意のシーケンス(リスト、文字列)にわたって反復を行います。
>>>a = ['foss4g', 2013, 'hokkaido']
>>>for x in a:
8/36
… print x
…
foss4g
2013
hokkaido
数列にわたって反復を行う場合は、range()を使用します。range(10)は 0 から始まり、0 から始まる 10 個の値
からなるリストを生成します。開始数値を指定したり、増加数(減少数)を指定することも出来ます。
>>>range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>for i in range(2,10,2):
… print i
…
2
4
6
8
c) while文
while 文の使用方法は他の言語と変わりません。指定の条件を満たす間処理を繰り返します。
>>>cnt = 0
>>>while cnt < 10:
… print cnt
… cnt += 1
…
3.4 関数
a) 関数を利用する
for 文ですでに出てきていますが、range()は標準で用意されている組み込み関数です。関数を使用する場
合は、関数名に続き「(」「)」丸括弧で引き数を添えて関数を呼び出します。以下は引き数として文字列を渡すと、
文字数を返す len()の例になります。
>>>len('foss4g')
6
9/36
b) 関数を作る
関数の定義は def の後に関数名と引き数を丸括弧で囲んで行います。関数の処理本体は、行を変えてインデ
ントをして記述します。
>>>def test(a):
… print a
…
>>>test(10)
10
関数に戻り値がある場合は、処理本体内で return の後に記述します。
>>>def test(a):
… return a+10
…
>>>test(10)
20
引き数に省略可能なデフォルト値を指定しておくことも出来ます。
>>>def test(a=0):
… print a
…
>>>test()
0
c) 変数のスコープ
Python では関数内で定義された変数は関数の内部でしか使用出来ません。下記の例では関数の内部で変
数 a を、関数の外で変数 a が定義されていますが、別なものになります。
>>>def test(a):
… a += 10
… print a
…
>>>a = 100
>>>test(10)
20
>>>a
100
リストや辞書のような書き換え可能なオブジェクトを引き数として渡す場合は参照渡しになりますので、注意が
必要になります。
10/36
>>>def test(a):
… a += ['hokkaido']
… print a
…
>>>b = ['foss4g']
>>>test(b)
['foss4g', 'hokkaido']
>>>b
['foss4g', 'hokkaido']
3.5 クラス
a) クラスを作る
クラスの定義は class の後にクラス名を記述して行います。ラクスの内部には関数定義、クラス変数を記述しま
す。
>>>class test:
… def output(self):
… print 10
…
>>>a = test()
>>>a.output()
10
インスタンス生成時に実行される特別なメソッドとして__init__()を定義しておくことが出来ます。
>>>class test():
… def __init__(self):
… self.a = 10
… def output(self, c):
… print self.a + c
…
>>>b = test()
>>>b.output(10)
20
11/36
b) self
a)クラスを作るで作成したクラス中に定義されている関数の第一引数には”self”が指定されています。self を
指定しておくと、各関数内から自身のインスタンスへのアクセスが可能となります。
c) 継承
あるクラスをベースとして派生クラスを作成する場合は、下記のような記述をします。
>>>class 派生クラス名(ベースクラス名):
… クラスの記述
多重継承も行え、その場合はベースクラスを列挙します。
>>>class 派生クラス名(ベースクラス名 1, ベースクラス名2):
… クラスの記述
3.6 パッケージ
a) パッケージ
プログラムが長くなってきた場合、また再利用可能な部品に分けて管理しておく場合、ファイルに分割しておき
ます。その際に、ドット付きのモジュール名を使って構造化しておきます。A.B というモジュール名は、A という
パッケージの B というモジュールを表します。モジュール名と実体のディレクトリ、ファイルの関係は下記のように
なります。
A/ ------ ディレクトリ A
B.py --- ファイル B
b) import
import の構文として 1 パターンだけ紹介しておきます。
from A.B import *
上記の構文は、A/B.py からファイル内のクラス、関数全てを import することになります。
12/36
4 Pythonコンソールから操作
4.1 すべての基本はQgisInterfaceから
QGIS を起動して、Python コンソールを立ちあげて下さい。
このコンスールから Quantum GIS 環境にアクセスするためには
qgis.utils.ifaceオブジェクト(QgisInterface クラスのインスタンス)を利用して下さい。
という記述が最初に書かれています。QgisInterface クラスは、Python コンソールや、Plugin から QGIS アプリ
ケーションにアクセスする際に窓口になるクラスです。ここから、各GUI パーツ、読み込み済みのレイヤ等にアク
セスすることになります。
クラスの定義はドキュメントが公開されていますので、確認しましょう。
QGIS API Documentation http://www.qgis.org/api/index.html
ドキュメントのバージョンには注意してください。”QGIS API Documentation”の対応するバージョンが書か
れています。最新(開発版)のドキュメントになっていますので、対応するバージョンを選択して参照するようにし
てください。
QgisInterface クラスの定義を見てみましょう。1.8版のドキュメントはこちらになります。
http://qgis.org/api/1.8/classQgisInterface.html
13/36
こちらを選択
signal と slot という記述が出てきます。これは Qt の特長的な機能になります。メニューが選択される、ファイ
ルが選択されるといったある動作(signal)が発生した際に、その動作に関連付けられて実行される関数が slotになります。プログラム中では、signal と slot の関連付けは下記のような記述で行います。
QObject.connect(イベント発生元インスタンス、SIGNAL('メソッド名')、イベント受け取り先インスタン
ス、SLOT('メソッド名'))
では、実際に操作を行なってみます。qgis.utils.iface のままでは少々長いので、iface という変数に代入して
使用することにします。
>>>iface = qgis.utils.iface
4.2 ユーザインタフェース編
QGIS のユーザインタフェースを、そのクラスから大別してみます。
① 各メニューは QMenu クラスで出来ています
例えば、”プラグイン”メニューにアクセスして表示させることは、
>>>pluginMenu =iface.pluginMenu()
>>>pluginMenu.show()
のように行えます。また、”プラグイン”メニューへのメニュー追加/削除メソッドとして、
QgisInterface.addPluginMenu()
QgisInterface.removePluginMenu()
が用意されていることが、ドキュメントからわかります。
14/36
② 各ツールバーは QToolBar クラスで出来ています。
例えば、”プラグイン”ツールバーにアクセスして、表示/非表示を切り替えることは、
>>>pluginToolBar = iface.pluginToolBar()
>>>pluginToolBar.hide()
>>>pluginToolBar.show()
のように行えます。また、”プラグイン”ツールバーへのアイコン追加/削除メソッドとして、
QgisInterface.addToolBarIcon()
QgisInterface.removeToolBarIcon()
が用意されていることが、ドキュメントからわかります。
③ 読み込み済みのレイヤー一覧には QgisLegendInterface クラスのインスタンスからアクセス出来ます。
>>>legend = iface.legendInterface()
>>>legend.layers()
[]
データの読み込みがされていない状態では空のリストが帰ってきます。メニューから手動で、いくつかベ
クトルデータを追加してみて下さい。追加後に QgisLegendInterface にアクセスしてみると、レイヤが
追加されていることが確認出来ます。下記の例では、ベクトルレイヤを 1 つだけ追加してあります。
>>>legend.layers()
[<qgis.core.QgsVectorLayer object at 0x0CC376A8>]
リストの最初のレイヤについて、表示/非表示を切り替えてみましょう。
>>>layers = legend.layers()
15/36
②
③ ④
①
>>>legend.setLayerVisible(layers[0], False)
>>>legend.setLayerVisible(layers[0], True)
④ QMapCanvas クラスのインスタンスからアクセス出来ます。スケールを変更してみましょう。
>>>canvas = iface.mapCanvas()
>>>canvas.zoomScale(100000000)
4.3 ベクトル編(図形にアクセス)
ne_50m_admin_0_countries.shp を読み込み、各要素にアクセスしてみましょう。
C:\work\ne_50m_admin_0_countries.shp
を読み込むことを想定します。
① ベクトルデータの読み込み
>>>iface.addVectorLayer(r'C:\work\ne_50m_admin_0_countries.shp', 'countries', 'ogr')
最初の引き数は読み込むファイル名、2番目はレイヤ名称として使用されます、3番目の引き数は使用
する QgisDataProvider へのキーになります。QgisDataProvider はデータソースからの読み込み、書
き込み、ハンドリング全般を行うクラスです。通常、ベクトルデータを扱う場合は ogr を使用することで足
りるはずです。もしオリジナルのデータフォーマット等に対応して QgisDataProvider を用意した場合な
どは指定が必要になります。
② 選択されているレイヤを取得します。いまは 1 つのレイヤしか開いていませんので、先ほど読み込んだ
レイヤが返ってきます。
>>>layer = iface.activeLayer()
③ 全ての図形要素に順次アクセスしてみます。
まず dataProvider を取得して、対象とするデータの選択を行います。select()の際の第一引き数は図
形に付けて取得する属性のリストになります。これを指定しない場合、属性無しの図形が返ってきます。
第2引き数は範囲指定を行えますが、引き数を渡さない場合全域の選択となりますので、ここでは指定
しませんQgsFeature()という空の入れ物を用意しておき、dataProvider の nextFeature()メソッドを利
用して順次アクセスしていきます。
>>>provider = layer.dataProvider()
>>>allAttrs = provider.attributeIndexes()
>>>provider.select(allAttrs)
>>>feat = QgsFeature()
>>>while provider.nextFeature(feat):
… feat.geometry()
...
例では、各ベクトル要素に順次アクセスを行い、その図形クラス(QgsGeometry)を書き出しています。
④ 次に特定の属性をもったベクトル要素を選択しましょう。属性はリストに入れられています。目当ての属
性がリストの何番目の要素になっているかをあらかじめ調べておく必要があります。
16/36
国名は'name'属性に入っています。'name'属性がリストの何番目か調べておきましょう。
>>>idx = provider.fieldNameIndex('name')
属性がリストの何番目に入っているかわかったので、その属性を書きだしてみます。
>>>provider = layer.dataProvider()
>>>allAttrs = provider.attributeIndexes()
>>>provider.select(allAttrs)
>>>feat = QgsFeature()
>>>while provider.nextFeature(feat):
… map = feat.attributeMap()
… map[idx].toString()
...
⑤ 次に属性'name'が'Japan'のベクトル要素を選択して、その要素の範囲にズームしてみましょう。
>>>provider = layer.dataProvider()
>>>idx = provider.fieldNameIndex('name')
>>>allAttrs = provider.attributeIndexes()
>>>provider.select(allAttrs)
>>>feat = QgsFeature()
>>>while provider.nextFeature(feat):
… map = feat.attributeMap()
… if map[idx].toString() == u'Japan':
… break
...
>>>canvas = iface.mapCanvas()
>>>canvas.setExtent(feat.geometry().boundingBox())
>>>canvas.refresh()
4.4 ベクトル編(描画設定)
レイヤ全体の描画設定を変更してみましょう。描画で設定する色や塗りつぶし種別の指定に、PyQt のクラスが
必要になるので、読み込みます。
>>>from PyQt4 import QtGui, QtCore
QgsSymbol というシンボル設定を作成しておき、それを layer の描画指定に入れてあげるという手順で行いま
す。
>>>layer = iface.activeLayer()
>>>symbol = QgsSymbol(QGis.Polygon)
>>>symbol.setFillColor(QtGui.QColor(255, 0, 0))
>>>symbol.setFillStyle(QtCore.Qt.SolidPattern)
17/36
>>>renderer = QgsSingleSymbolRenderer(QGis.Polygon)
>>>renderer.addSymbol(symbol)
>>>layer.setRenderer(renderer)
>>>iface.mapCanvas().refresh()
4.5 Canvas イベント編
canvas上で発生するイベントを拾ってみましょう。canvas上でクリックされた位置と、その位置の地理座標を
QGISで用意しているメッセージビューワに表示します。QMapCanvas クラスではマウスクリックのイベントを拾う
ことが出来ません。QgsMapTool というクラスを継承した新しいクラスを作成しておき、イベント発生時の動作を
追加します。新しく作成したクラスをQMapCanvas クラスに設定することでイベントに対応させます。
>>>from qgis.gui import *
>>>class QgsMapToolClick(QgsMapTool):
... def canvasPressEvent(self, event):
… dPos = event.pos()
… mPos = self.toMapCoordinates(dPos)
… view = qgis.gui.QgsMessageViewer()
… view.setMessageAsHtml('<p>' + str(dPos.x()) + ',' + str(dPos.y()) + '</p><p>' + str(mPos.x()) + ',' + str(mPos.y()) + '</p>')
… view.showMessage(True)
…
>>>iface = qgis.utils.iface
>>>canvas = iface.mapCanvas()
>>>toolClick = QgsMapToolClick(canvas)
>>>canvas.setMapTool(toolClick)
18/36
5 Pluginの基本 この章では Python コンソールから一旦離れて、Plugin に必要なファイルをテキストエディタを使用して編集し
て頂きます。
5.1 Pluginの基本構成
QGIS の起動時に読み込まれる python プラグインは、
QGIS インストールディレクトリ/python/plugins
ユーザーのホームディレクトリ/.qgis/python/plugins
に入れておきます。通常、オリジナルのプラグインを作成した場合は、後者に配置することになります。windowsを想定しますが、
C:\Users\ユーザ名\.qgis\python\plugins\test
というディレクトリを作成してください。
QGIS は plugins ディレクトリ内の各ディレクトリを見ていき、
__init__.py
というファイルからプラグインの情報と読み取ります。また、__init__.py 内には、処理本体が記述されたクラスを
返す関数も記載しておきます。通常、処理本体は別なファイルに記述する方が判りやすいので、名前はなんで
もいいですが、最低もう1ファイル作成することになります。
5.2 __init__.py
以下の内容が記載されたファイルを用意します。
19/36
# -*- coding: utf-8 -*-import os,sys
def name(): return " プラグインテスト "
def description(): return " プラグインを追加出来るかテストです "
def version(): return "1.0"
def qgisMinimumVersion(): return "1.8"
def authorName(): return "asahi"
def classFactory(iface): from test import pluginTest return pluginTest(iface)
前提として、test.py というファイルが有り、pluginTest というクラスに処理が記載されているとしています。
QGIS へ渡すプラグインの基本情報として、
name : プラグイン名
description: プラグインの説明
version: プラグインのバージョン
qgisMinimumVersion: プラグインが動作する QGIS の最低バージョン
authorName: プラグイン作者名
を対応する各関数の返り値として記載します。もう1つ処理が記載されたクラスを返す関数を用意します。
classfactory: 処理が記載されたクラスを返す
ここでは、
test.py というファイルから pluginTest クラスを読み込む
pluginTest クラスのインスタンス作成 #QgisInterface のインスタンスを渡すのを忘れずに
という処理を記述しています。
5.3 処理本体が記載されたファイル
test.py の内容は以下にしておきます。
処理が記載されたクラスが最低限持つ必要があるメソッドは、
initGui(): プラグインが使用可になった場合に実行されるメソッド
unload(): プラグインが使用不可になった場合に実行されるメソッド
の2つになります。
QAction は、メニューやツールバーに追加されるユーザインタフェース部品になります。”test”という表記がさ
れるように作成しておき、initGui でプラグインメニューとプラグインツールバーに追加、unload で削除していま
す。
20/36
# -*- coding: utf-8 -*-from PyQt4.QtCore import *from PyQt4.QtGui import *from qgis.core import *
class pluginTest:
def __init__(self, iface): self.iface = iface def initGui(self): self.action = QAction("test", self.iface.mainWindow()) self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("plugin test", self.action) def unload(self): self.iface.removePluginMenu("plugin test", self.action) self.iface.removeToolBarIcon(self.action)
5.4 プラグインの追加確認
C:\Users\ユーザ名\.qgis\python\plugins\test に
__init__.py
test.py
が作成されていることを確認して、QGIS を起動してみましょう。
「プラグイン」→「プラグイン管理」メニューを選択して、「プラグインマネージャー」を表示します。
”プラグインテスト”というプラグインが使用出来るプラグインの一覧に追加されているはずです。チェックボック
スにチェックを入れて、プラグインを使用可にしましょう。
メニューとツールバーに”test”が追加されます。ただし、QAction に対して、動作を何も結びつけていないた
め、選択を行なっても何も行われない状態です。
5.5 iconの追加
動作を結びつける前に文字だけでは寂しい見た目を改善してみましょう。メニュー、ツールバーにアイコンを表
示させます。作成しているプラグインのディレクトリ内に、 表示させたい icon の画像ファイルがあるとしておきま
す。
icon/qgis-icon.png
icon として使用する画像ファイルへのパスを記述した、Qt のリソースファイルを用意します。ファイル名は、
21/36
resources_rc.qrc
としておきます。リソースファイルは xml で記述されており、内容は下記になります。
このファイル を Python のコードへ変換しておく必要がありますので、pyrcc4 コマンドで変換を行います。
Windows で OSGeo4W を使用している場合、OSGeo4W の command shell を起動して、プラグインを作成
しているディレクトリに移動してください。移動した後、
> pyrcc4 -o resources_rc.py resources_rc.qrc
を実行して resources_rc.py が作成されたことを確認してください。
次に test.py にて resources_rc.py を読み込み、QAction の第一引数で icon を指定するように変更します。
qgis を起動して、プラグインメニューを表示してみて下さい。icon が追加されていることを確認出来ます。
22/36
<RCC> <qresource> <file>icon/qgis-icon.png</file> </qresource></RCC>
# -*- coding: utf-8 -*-from PyQt4.QtCore import *from PyQt4.QtGui import *from qgis.core import *
import resources_rc
class pluginTest:
def __init__(self, iface): self.iface = iface def initGui(self): self.action = QAction(QIcon(":/icon/qgis-icon.png"), "test", self.iface.mainWindow()) self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("plugin test", self.action) def unload(self): self.iface.removePluginMenu("plugin test", self.action) self.iface.removeToolBarIcon(self.action)
5.6 QActionの slotへの結びつけ
次にメニューとツールバーに配置されている QAction に対して、動作を結びつけます。
1. QAction が選択された際の動作”triggered()”に対して、対応する slot を結びつけます
2. ここでは slot は自分自身の run()メソッドとしました
3. run()メソッド内の動作は、ファイルダイアログを開きファイルを選択→レイヤの追加とします
QFileDialog.getOpenFileName()の引数は、
親要素(ここではなし None)、ファイルダイアログのタイトル、ディレクトリパス、ファイル選択フィルタ
の順になります
test.py を下記の内容に書き換えます。
qgis を起動して、ベクトルレイヤの追加が出来るか確認してみて下さい。
23/36
# -*- coding: utf-8 -*-from PyQt4.QtCore import *from PyQt4.QtGui import *from qgis.core import *
import resources_rc
class pluginTest:
def __init__(self, iface): self.iface = iface def initGui(self): self.action = QAction(QIcon(":/icon/qgis-icon.png"), "test", self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("plugin test", self.action) def unload(self): self.iface.removePluginMenu("plugin test", self.action) self.iface.removeToolBarIcon(self.action) def run(self): filename = QFileDialog.getOpenFileName(None, "Open Vector File", "", "ESRI Shapefile (*.shp)") self.iface.addVectorLayer(filename, "added layer", "ogr")
5.7 ダイアログの追加
ここまでで、プラグインによりメニューを追加して、単一の決まった動作を行わせる事は出来ることになります。し
かし、より汎用的な機能を作成する場合、ダイアログを表示していくつかの選択肢を選んだ後に、動作を行わせ
る事が必要になります。ここでは、そこまで複雑な機能の作成は避けますが、オリジナルのダイアログを作成する
方法を説明しておきます。
ダイアログの作成には、QtDesinger を利用します。qt-project のホームページ(http://qt-project.org/downloads )から、環境にあった Qt Library のダウンロードを行い、インストールしてください。
インストールが正常に行われると、QtDesigner が windows のスタートメニューに加わっています。
24/36
QtDesigner を起動してください。最初に作成するフォーム種類の選択を行います。”Dialog without Buttons”を選択して、”作成”をクリックしてください。
”close”ボタンと、テキストとテキストフォームのみの簡単なダイアログを作成することにします。画面左のウィ
ジェットボックスから、”Push Botton”と”Text Edit”をドラッグしながら、Dialog 上に配置してください。Dialog自体の大きさも変更して、適当な大きさにします。”Push Botton”に表示されるラベルはボタンをダブルクリック
することで編集することが出来ます。”Close”としておきます。
レイアウトを整えたら、次に”Close”ボタンに Dialog を閉じる動作を結びつけます。右下に表示されているシ
グナル/スロットエディタを使用します。”+”を押して動作を増やした後に、<発信者><シグナル><受信者><ス
ロット>を順次選択して、”Close”ボタンの”clicked()”シグナルを、”Dialog”の”close()”スロットへ割り当てて
下さい。
25/36
用意されているスロットばかりではなく、自分でメソッドを追加したい場合には、”編集”メニュー→”シグナル/スロットを編集”を選択しておき、一旦空のメソッドを作成しておき後から編集するという方法も取れます。
配置した”Push Botton”と”Text Edit”にプログラムからアクセスする場合には、プロパティに表示され
る”objectName”で識別します。判りやすいものに変えておいた方が良いですが、今回は作成時に入れられる
名前のままで進みます。
26/36
作成の終了したダイアログは、”ファイル”メニュー→”名前を付けて保存”から、作成しているプラグインのディ
レクトリに保存しておきます。ここでは、ui_dialog.ui
というファイル名にしておきます。
作成したファイルですが、resources_rc.qrc の時と同様、このままでは Python から使用出来ません。
Python のコードへ変換しておく必要がありますので、ui ファイルを Python コードに変換してくれる pyuic4 コ
マンドを使用します。Windows で OSGeo4W を使用している場合、OSGeo4W の command shell を起動し
て、プラグインを作成しているディレクトリに移動してください。移動した後、> pyuic4 -o ui_dialog.py ui_dialog.ui
を実行して ui_dialog.py が作成されたことを確認してください。
作成した ui_dialog.py をプラグインに組み込んでいきます。ダイアログ管理クラスを作り、作成した
Ui_Dialog を継承させます。もし、QtDesigner のシグナル/スロット編集で空のメソッドを作成していた場合は、
ここで処理を記述することになります。
dialog.pyというファイルを作成し、下記の内容を記述しておきます。
27/36
# -*- coding: utf-8 -*-
from PyQt4.QtCore import *from PyQt4.QtGui import *from ui_dialog import Ui_Dialog
class Dialog(QDialog, Ui_Dialog): def __init__(self): QDialog.__init__(self) self.setupUi(self)
test.py の内容も書き換えます。
1. run メソッド内で、dialog を読み込み
2. canvas 上に表示されているレイヤ数を、dialog の textEdit に書き込み
3. dialog を表示
qgis を起動して、ダイアログが表示されるか確認してみましょう。
28/36
# -*- coding: utf-8 -*-from PyQt4.QtCore import *from PyQt4.QtGui import *from qgis.core import *
import resources_rc
class pluginTest:
def __init__(self, iface): self.iface = iface def initGui(self): self.action = QAction(QIcon(":/icon/qgis-icon.png"), "test", self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("plugin test", self.action) def unload(self): self.iface.removePluginMenu("plugin test", self.action) self.iface.removeToolBarIcon(self.action) def run(self): from dialog import Dialog dlg = Dialog() dlg.textEdit.setText(str(self.iface.mapCanvas().layerCount())) dlg.show() dlg.exec_()
6 デバッグ環境
スクリプトが短いうちは、エラーの際に表示されるメッセージを見ながら修正を行なっていくことも可能です。た
だし複雑な処理になってくると、スクリプトを実行させながらのデバックが欠かせなくなります。Eclipse+PyDevでデバッグに必要な環境を構築することが出来ます。
環境の構築は時間がかかるためここでは行いませんが、参考資料だけあげておきます。
• FOSS4G Tokyo の際のハンズオン補足資料
http://www.osgeo.jp/wp-content/uploads/2011/10/qgis_plugin_doc.pdf
• QGIS でアプリケーションを作成する/QGIS でプラグインを作成する
http://d.hatena.ne.jp/waigani/20101130
http://d.hatena.ne.jp/waigani/20101229
7 SEXTANTE入門
7.1 SEXTANTEとは?
SEXTANTE は QGIS で使える様々な解析機能をまとめるためのフレームワークです。GRASS,SAGA な
どで提供される解析機能を、SEXTANTE を通して統合してシームレスに使用することが出来ます。注意する
点としては、SEXTANTE自体はフレームワークなので、各々の解析機能(SAGA など)は別にインストールさ
れている必要があります。また、SEXTANTE はプラグインとして提供されていますので、「プラグイン」→
「Python プラグインを呼び出す...」から SEXTANTE をインストールしておき、「プラグインの管理...」から
SEXTANTE を使用可にしておいてください。
29/36
SEXTANTE が使用可になると、メニューに「Analysis」が追加されます。通常、SEXTANTE の機能を利用
する場合は、こちらから利用することになります。
7.2 Pythonコンソールから SEXTANTE
SEXTANTE は用意されている機能以外にも、Python で記述したスクリプトを追加登録することが出来ます。
まずは Python コンソールから SEXTANTE を使用して、どのような記述を行うのか、その仕組みを学習してみ
ましょう。
ne_50m_admin_0_countries.shp のみ 1 レイヤが読み込まれており、ここから”name”属性 = “Japan”の図
形を select、select した図形を別ファイルとして書き込みという一連の流れを行なってみます。
Python コンソールを開いて下さい。最初に行うおこなうことは SEXTANTE の import です。
>>>import sextante
使用出来る機能の一覧を表示してみましょう。
>>>sextante.alglist()
を実行すると、機能の説明----->機能名というフォーマットで機能の一覧が表示されます。
sextante.alglist()は文字列を引数として渡すことも出来ます。この場合、機能の説明に対して指定した文字列
でフィルターをかけることができます。”select”を含む機能を探しているとして、
>>>sextante.alglist('select')
を実行してみて下さい。qgis:selectbyattribute という機能を見つけることが出来ます。
この機能の使用方法を確認します。
>>>sextante.alghelp('qgis:selectbyattribute')
30/36
表示された使用方法から、引数が4つ必要なこと(最後の引数 RESULT は返り値の添字を表しているので指
定の必要はありません。)がわかります。
LAYERNAME : 入力するベクトルレイヤ(QgsVectorLayer もしくはファイル名)
ATTRIBUTE : 属性フィールド名
COMPARISON : 比較演算子
COMPARISONVALUE : 比較値
を引数で指定します。このうち COMPARISON には注意が必要です。この help では読み取れないのですが、
SEXTANTE Toolbox から”Select by attribute”を実行した際に”Comparison”に表示される選択肢(リスト)のインデックスになります。”==”が”0”となります。help だけではわからない部分もあるので、SEXTANTE Toolbox で表示されるフォームと比較しながら試してみることをおすすめします。
注)バージョンによっては選択肢が表示されるようです
31/36
qgis:selectbyattribute を実行してみましょう。
>>>layer = qgis.utils.iface.activeLayer()
>>>selectedResult = sextante.runalg('qgis:selectbyattribute', layer, 'name', 0, 'Japan')
実行には sextante.runalg()を使用します。最初の引数として機能名を、次の引数からは機能毎に必要とされ
る引数を列挙します。返り値は、実行結果を反映したファイル名が入った辞書になります。
>>>selectedResult
{'RESULT': u'C:\work\ne_50m_admin_0_countries.shp',}
qgis:selectbyattribute の場合、新しいファイルは作らず入力として指定したファイルを操作する機能ですの
で、入力ファイル名がそのまま返ってきます。
次に、SEXTANTE Toolbox に用意されているサンプルスクリプト script:saveselectedfeatures を使用して
選択した図形を別ファイルで保存します。Help を確認してみましょう。
>>>sextante.alghelp('script:saveselectedfeatures')
入力するベクトルレイヤ(もしくファイル名)と出力ファイルを指定することがわかります。ただし出力ファイル
は”None”としておいてください。テンポラリファイルとして作成してくれます。実行して、作成されたテンポラリファ
イルを読み込みます。
>>>saveResult = sextante.runalg('script:saveselectedfeatures', selectedResult['RESULT'], None)
>>>sextante.load(saveResult['output'])
このように SEXTANTE を使うことで、qgis 本体の機能、SEXTANTE で用意された機能といった別々に提
供された解析機能を同一のインタフェースから使用することが出来るようになります。
7.3 関数を利用する
SEXTANTE は解析機能を統一の手順で使えるようにしたフレームワークですが、その過程で用意された各
種便利クラスも使用することが出来ます。例えば、開発版の QGIS を OSGeo4W でインストールしたとして、
C:\OSGeo4W\apps\qgis-dev\python\plugins\sextante\core\QGisLayers.py
を覗いてみましょう。
レイヤへのアクセスクラスなどが用意されていて、QGIS Python API の使用方法としてとても参考になります。
読み込み済みのラスタレイヤ一覧を得る method は、QGisLayers クラスに、
32/36
のように用意されています。一度見てみることをおすすめします。
7.4 SEXTANTEスクリプト
QGIS-SEXTANTE cookbook http://qgissextante.blogspot.jp/
の紹介に留めておきます。まだ日本語でまとめた資料などありませんので、どなたかまとめてくださることを期待
しています。
また、SEXTANTE Toolbox の Scripts に登録されている機能は、右クリックから”Edit script”を選択するこ
とでスクリプトの中を見ることが出来ます。
例えば、”Hex grid from layer bounds”ですと、以下の内容になっています。
33/36
##input=vector##cellsize=number 1000.0##grid=output vectorfrom sextante.core.QGisLayers import QGisLayers
input = QGisLayers.getObjectFromUri(input)centerx = (input.extent().xMinimum() + input.extent().xMaximum()) / 2centery = (input.extent().yMinimum() + input.extent().yMaximum()) / 2width = (input.extent().xMaximum() - input.extent().xMinimum())height = (input.extent().yMaximum() - input.extent().yMinimum())sextante.runalg("qgis:creategrid", cellsize, cellsize, width, height, centerx, centery, 3, grid)
def getRasterLayers(): layers = QGisLayers.iface.legendInterface().layers() raster = list()
for layer in layers: if layer.type() == layer.RasterLayer: if layer.providerType() == 'gdal':#only gdal file-based layers raster.append(layer) return raster
機能を Excute した際のダイアログと比較すると、冒頭の”##”の部分で入力/出力に関するフォームを指定し
ていることがわかります。このような簡単な指定でフォームを作成することが出来ますので、対話的な操作が必要
になる機能以外は、SEXTANTE を利用して組み込む事が今後標準になると思われます。
34/36
8 QGIS 2.0での変更点概要
8.1 ベクトルレイヤ関係
ベクトルレイヤでの図形要素へのアクセス方法が簡素になっています。これまで、select()を行った上で各要素
を受け取っていましたが、QgsFeatureIterator クラスを通してのアクセスに変わっています。
>>>features = layer.getFeatures()
>>>for feature in features:
… pass
また属性へのアクセスも簡素になりました。
>>>feature['name']
のように属性名、もしくは属性のインデックスを直に QgsFeature クラスに指定することが出来ます。
8.2 Pluginのメタデータ
これまで__init__.py に書かれていたメタデータが別ファイルになっています。Metadata.txt を別に用意し、
のように記載する必要があります。__init__.py 内は、classFactory()のみになります。
こういった変更により、1.8 で動いていたプラグインは、2.0 との互換性が無くなっているので注意が必要です。
8.3 その他
その他にも多くの変更点があります。変更箇所の情報は下記から取得可能です。
http://hub.qgis.org/wiki/quantum-gis/Python_plugin_API_changes_from_18_to_20
http://hub.qgis.org/wiki/quantum-gis/API_changes_for_version_20
35/36
name=testdescription=testcategory=Pluginsversion=1.0experimental=FalseqgisMinimumVersion=2.0author=My [email protected]=./plugin.png
9 参考資料
わからないクラス、関数が出てきたら、基本は QGIS API Documentation から調べます。
http://www.qgis.org/api/
PyQt も必要な知識になります。
http://pyqt.sourceforge.net/Docs/PyQt4/classes.html
公式なテキストとして cookbook があります。
http://www.qgis.org/pyqgis-cookbook/
QGIS API のまとまった学習方法としては、このワークショップがお勧めです。
http://www.qgisworkshop.org/html/workshop/index.html
SEXTANTE に関する情報は、マニュアルを読むことが基本です。
http://qgis.readthedocs.org/en/latest/docs/user_manual/sextante/console.html
また 7.4 でもあげましたが、こちらを参照することがお勧めです。
http://qgissextante.blogspot.jp/
QGIS 2.0 での変更点は下記を参照ください。
http://hub.qgis.org/wiki/quantum-gis/Python_plugin_API_changes_from_18_to_20
http://hub.qgis.org/wiki/quantum-gis/API_changes_for_version_20
日本語で得られる情報はまだまだ少ないです。
月の杜工房 http://mf-atelier.sakura.ne.jp/
QGIS とか http://d.hatena.ne.jp/waigani/
真田工務店 http://blog.livedoor.jp/sanakazu/
10最後に 今後の活動の参考に致します。アンケートにご協力下さい。
https://sites.google.com/site/foss4ghokkaido/foss4g-2013-hokkaido/enq_handson
36/36