QGISのプラグイン作成 Matplotlibを使ってグラフを作成するサンプル
はじめに
QGISのプラグインでグラフを作成し、画像として保存します。
グラフにするデータとして、ここではDEMから取得した標高値を使います。
このプラグインの使い方
ここからダウンロードできるzipをインストールして、graph_sample.pyの以下の部分を適当に編集してください。
self._llcrs = 4326 self._xycrs = 2451 # 千葉県のDEMでテストしたので9系になってます。 self._savedir = 'c:\\users\\〇〇\\desktop\\pic\\' # 横断図の保存先 self._odanlinespan = 100 # 横断線の間隔 self._odanlinelength = 200 # 横断線の片側の長さ self._odanpointspan = 10 # 横断線上のサンプリング間隔
DEMのラスタをアクティブにした状態でプラグインを実行すると、10秒ほど経ってマウスカーソルが✚になり、ラバーバンドでラインが描画できるようになります。描画したら右クリックで確定します。
しばらく(描画したラインの長さによっては大分)待たされますが、描画したラインを横断するように点が作成されます。各点にはDEMから取得した標高が入っています。
各点の標高値を使って、グラフが作成されます。
このような画像になります。
コード
~略~ import matplotlib.pyplot as plt import numpy as np from .rubberband import RubberBand from .getrasterpixelvalue import GetRasterPixelValue import datetime import math class GraphSample(QgsMapTool): # lineLLを垂直に横断する点列を作成する def addOdansen(self, lineLL, key): ~略~ # startpnt、endpntが成す線分の、startpntからlength分進んだ位置を中心に、線分を横断する線を作成する。 def odansen(startpnt, endpnt, length, cnt): ~略~ for i in range(-self._odanlinelength, self._odanlinelength + self._odanpointspan, self._odanpointspan): xypnt = QgsGeometry().fromPointXY(destination(center, rad, i)) llpnt = transformCRS(xypnt, self._xycrs, self._llcrs) elev = self.gr.getValueInterpolation(llpnt.asPoint()) self.addFeature(self.hol, llpnt, [key, cnt, i, elev]) ~略~ def setFeature(self, geom): def getNumber(feature): return feature['pointcount'] key = datetime.datetime.now().strftime('%Y%m%d%H%M%S') # 縦断線と横断線を紐付けるキー self.addFeature(self.ver, geom, [key]) # 縦断線レイヤに、描画したラインを追加 self.addOdansen(geom, key) # 描画したラインを横断する点列を横断戦レイヤに追加 # グラフ作成 features = list(self.hol.getFeatures(QgsFeatureRequest().setFilterExpression('"key"='+'\'' + key + '\''))) linenumbers = sorted(set([f['linecount'] for f in features])) for linenumber in linenumbers: linenode = sorted([f for f in features if f['linecount'] == linenumber], key=getNumber) # 'pointcount'の値順に並び変える fig, ax = plt.subplots() y = np.array([l['elev'] for l in linenode]) x = np.array([l['pointcount'] for l in linenode]) ax.set_title(str(linenode[0]['key']) + '_' + str(linenumber)) ax.plot(x, y, '-') plt.savefig(self._savedir + str(linenode[0]['key']) + '_' + str(linenumber) + '.png') # 一時レイヤ作成 def createTemporaryLayer(self, layername, type, fieldsstr): ~略~ # レイヤにレコード追加 def addFeature(self, layer, geometry, attrs): ~略~ def start(self): # このプログラム使うときはこの辺を調整してください self._llcrs = 4326 self._xycrs = 2451 # 千葉県のDEMでテストしたので9系になってます。 self._savedir = 'c:\\users\\me\\desktop\\pic\\' # 横断図の保存先 self._odanlinespan = 100 # 横断線の間隔 self._odanlinelength = 200 # 横断線の片側の長さ self._odanpointspan = 10 # 横断線上のサンプリング間隔 if self.iface.activeLayer() is not qgis.core.QgsRasterLayer: ~略~ self.gr = GetRasterPixelValue(self.iface.activeLayer()) maptool = RubberBand(self.iface, self.canvas, QgsWkbTypes.LineGeometry) maptool.getObject.connect(self.setFeature) self.ver = self.createTemporaryLayer('縦断線', 'LineString', '&field=key:string') self.hol = self.createTemporaryLayer('横断線', 'Point', '&field=key:string&field=linecount:integer&field=pointcount:integer&field=elev:double') self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 ~略~
7行目 描画したラインを横断する点を、点が格納されているレイヤ(self.hol)から取得してきます。
8行目 横断線の本数を取得しています。
9行目 7行目で取得した点の中から、作成するグラフに使う点を取得しています。
12~16行目 グラフを準備します。縦軸には標高、横軸には描画したラインからの距離を使います。
17行目 作成したグラフを保存しています。
ソース全文
最後までご覧頂き、ありがとうございました