simplekmlは、PythonでKMLを作成するパッケージ。
KMLは、地理空間情報を記述するための書式の1つ。要は地図上にマーカー設置したりライン引いたりバルーンで情報表示したりできる。
これを読み取れる主要なアプリに、Google Earthがある。
Google EarthはGoogle MapsのPCアプリ版みたいなもので、衛星写真の地図をぐりぐり動かしたり拡大縮小できる。 KMLを用いると、その上にマーカーを置いたりラインを引いたりできる。
Google Earthは無償で利用できる上、数千件のデータを配置しても描画が高速。かなりの倍率までズームできるため、全体の概観から詳細の確認までできて便利。
(ただし、衛星写真をつなぎ合わせている関係上、使う写真の撮影時期や条件によって悪い箇所では見た目と10m規模の誤差は出るので、あくまで目安にとどめる)
> pip install simplekml
パッケージ管理ツールにAnacondaを使う場合は、標準レポジトリにないので、conda-forgeなどからインストール。
> conda install -c conda-forge simplekml
とりあえず点や線を描いたりスタイルを変えるのは、これを使えば簡単にできる。
それ以上のことは、そもそもKMLでどこまでのことが出来るのか自体をイマイチ知らないんだけど、ドキュメントを見る限りいろんなことが出来る模様。
せっかくプログラム的に書けるので、連続した緯度経度座標を一気にプロットするクラスを作ってみた。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
import simplekml class PlotKml: # スタイルは適当に、simplekmlやKMLのドキュメントを見つつ好みに変更する # マーカーのスタイル1 STYLE_I = simplekml.Style() STYLE_I.iconstyle.icon.href = 'http://maps.google.com/mapfiles/kml/shapes/placemark_circle_highlight.png' STYLE_I.labelstyle.scale = 0.66 STYLE_I.labelstyle.color = 'aaffffff' # マーカーのスタイル2 STYLE_H = simplekml.Style() STYLE_H.labelstyle.scale = 0.66 STYLE_H.labelstyle.color = 'aaffffff' # ラインのスタイル STYLE_LS = simplekml.Style() STYLE_LS.linestyle.width = 3 def __init__( self ): self .kml = simplekml.Kml() def new( self ): self .kml = simplekml.Kml() def draw_dots( self , lnglats, descriptions, style = None , linestring = True ): """ :param lnglats: [[lng, lat], [lng, lat], [], ...] :param descriptions: <name>属性に出力するタグ :param style: simplekml.Style のインスタンスまたはそのリスト :param linestring: 線が不要ならFalse """ # descriptionsは、lnglatsと同じ要素数の文字列のリストで与える。 # 対応する順番の文字列が、自動的に連番prefixを付与され、マーカーの横に添えられる # styleは、Noneなら全てデフォルト # simplekml.Styleの(単独の)インスタンスの場合は全てそのスタイルに # リストの場合はlnglatsと同じ要素数にする。対応する順番のマーカーがそのスタイルになる if descriptions is None : descriptions = [''] * len (lnglats) else : assert len (lnglats) = = len (descriptions) if style is None : style = [ self .STYLE_I] * len (lnglats) elif type (style) = = simplekml.Style: style = [style] * len (lnglats) elif type (style) = = list : assert len (lnglats) = = len (style) for idx, (lnglat, description) in enumerate ( zip (lnglats, descriptions)): pnt = self .kml.newpoint(name = str (idx) + ' ' + description, coords = [lnglat]) pnt.style = style[idx] if linestring: ls = self .kml.newlinestring(name = 'LineString' , coords = lnglats) ls.style = self .STYLE_LS def save( self , path): self .kml.save(path) # --使い方-- pk = PlotKml() pk.draw_dots([[ 135.26 , 34.32 ], [ 135.23 , 34.29 ], ...], # lnglats [ '2018/01/21' , '2018/01/22' , ...]) # descriptions pk.save( 'out.kml' ) pk.new() # リセット(これをしないと前のが残る。敢えて残すことも可) pk.draw_dots([[ - 112.35 , 42.89 ], ...], style = PlotKml.STYLE_H) pk.save( 'out2.kml' ) |
simplekml.Style
クラスは、Pointのアイコンやサイズ・LineStringやPolygonの太さや色・ラベルの色などを規定するものである。
適用するには、点やラインなどの個々のインスタンスに.style
属性があるので、そこに指定する。
個々のインスタンスは、kml.newpoint(), kml.newlinestring()
などで作成すれば返値で受け取れる。
この時、以下の2通りの方法がある。
Style
オブジェクトを定義しておき、それを与える同じStyleを適用する地物をいくつも量産するのであれば、後者の方がよい。前者だと、地物毎に新しいStyleが定義され、KMLのサイズが肥大化する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
kml = simplekml.Kml() # その場で定義 for _ in range ( 100 ): pnt = kml.newpoint(name = 'test1' , coords = [[ 0 , 0 ]]) pnt.style.labelstyle.color = simplekml.Color.blue # ラベル文字色 # => 全ての点でStyleインスタンスが別々になる(出力KMLで、Style定義が100回繰り返される) # 最初に定義してから与える style = simplekml.Style() style.labelstyle.color = simplekml.Color.blue # ラベル文字色 for _ in range ( 100 ): pnt = kml.newpoint(name = 'test2' , coords = [[ 0 , 0 ]]) pnt.style = style # => Styleインスタンスは1つのみ(出力KMLで、1回のStyle定義を各地物で使い回す) |
通常、KMLではLineStringにラベルは表示されないが、<gx:labelVisibility>1</gx:labelVisibility>
をLineのStyleに記述することで、そのname
属性が表示されるようになる。
これをsimpleKmlから利用するには、LineStyleに gxlabelvisibility = 1
を指定すればよい。
生KMLの記載方法は上記サイトまたはKML参照。
要は、通常用とホバー時用、2個のStyleを定義して、それらを囲った「StyleMap」を定義し、それぞれのStyleに「normal」「highlight」というキーを与える。 このStyleMapのIDを、各Point, Lineなどに適用するスタイルとして与えてやればよい。
これは、simpleKmlでは以下のようにできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# ホバーによって太さと色が変わるLineString STYLE_NORMAL = simplekml.Style() STYLE_NORMAL.linestyle.width = 3 STYLE_NORMAL.linestyle.color = simplekml.Color.white STYLE_HIGHLIGHT = simplekml.Style() STYLE_HIGHLIGHT.linestyle.width = 5 STYLE_HIGHLIGHT.linestyle.color = simplekml.Color.red STYLE_MAP = simplekml.StyleMap(normalstyle = STYLE_NORMAL, highlightstyle = STYLE_HIGHLIGHT) kml = simplekml.Kml() ls = kml.newlinestring(name = 'test' , coords = [[ 0 , 0 ], [ 1 , 1 ]]) ls.stylemap = STYLE_MAP kml.save( 'test.kml' ) |
保存時、save()
でなく savekmz()
を使用すると、kmlをzip圧縮した規格であるkmzファイルが生成され、容量の節約になる。
Point, LineString, Polygonなどについて、クリックすると開いてより詳細な情報を表示するバルーンを設定できる。
なんか方法が3つほどあるらしい。「ExtendedData」を使うのが簡単。「Scheme」を使うと決まった型を定義できてデータ的に扱いやすい?らしい。
ここではExtendedDataの方法を扱う。KMLを記述する方法とその結果は、上記のリンク先参照。
simplekmlでは以下のように記述すれば出来る。name
で項目名(str限定)、value
で任意の値を埋め込める。
1 2 3 4 5 6 7 8 9 10 11 12 |
# LineStringをクリックすると3つほどの要素を表示させる kml = simplekml.Kml() ls = kml.newlinestring(name = 'test' , coords = [[ 0 , 0 ], [ 1 , 1 ]]) ex_data = simplekml.ExtendedData() ex_data.newdata(name = 'item1' , value = 3.14 ) ex_data.newdata(name = 'item2' , value = 'ITEM2' ) ex_data.newdata(name = 'item3' , value = [ 0 , 1 , 2 ]) ls.extendeddata = ex_data kml.save( 'test.kml' ) |