さて、本日は久しぶりに GIS に関するエントリーを書いてみようと思います。PyShp を使って CSV をシェープファイルに変換してみます。
PyShp とは
Shape ファイルを読み書きするためのライブラリです。
使用するデータ
ESRIジャパンさんが主催した「ArcGIS 開発者のための最新アプリ開発塾 2020」で使用された 各店舗売上.csvを使用します。
CSV の中身はこんな感じになっています。
使用するライブラリ
PyShp と Pandas を使用するのでインストールをお願いします。
実行環境
Windows 10 64bit
Python 3.6.10
Pandas 1.1.2
PyShp 2.1.2
ArcGIS Pro 2.6(作成した Shape ファイルの確認用に使用)
サンプルコード
PyShp を使って CSV をシェープファイルに変換するサンプルです
# -*- coding: utf-8 -*- import shapefile import pandas as pd # 読み込むCSV input_file = r"D:\python\data\csv\各店舗売上.csv" # CSV 読込 df = pd.read_csv(input_file, encoding="SHIFT-JIS") # CSV のカラムを取得 column_list = df.columns.values def create_shape(): with shapefile.Writer(r'D:\python\data\pyshp\各店舗売上.shp') as w: # Shape のフィールドを作成 for column in column_list: if column == "緯度": w.field(column, "F", 12, 6) elif column == "経度": w.field(column, "F", 12, 6) else: w.field(column, "C", 50) for _, row in df.iterrows(): lat = 0 lon = 0 attributes = [] for column in column_list: if column == "緯度": lat = row[column] attributes.append(lat) elif column == "経度": lon = row[column] attributes.append(lon) else: attributes.append(row[column]) # ポイントを作成 w.point(lon, lat) w.record(attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]) # プロジェクションファイル作成 with open("%s.prj" % r'D:\python\data\pyshp\各店舗売上', "w") as prj: epsg = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]' prj.write(epsg) if __name__ == '__main__': create_shape()
結果をみるとばっちりシェープファイルが作成されたことがわかります。属性もしっかり付与されてますね。
PyShp のいいところ
GDAL や Fiona などで同じことをやろうとすると以下エントリーのように日本語でひっかかるのですが、PyShp の場合はその問題は起きないのが素晴らしいですね。
PyShp のいまいちなところ
属性を作成する際に、w.record(attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]) のようにしなければならないのがいまいちかなと思います(他のやり方があるのかもしれませんが・・・)。この仕様だと汎用的には使えないですね。
解決策
コメント欄参照
最後に
ArcGIS のような商用 GIS を使用すればシェープファイルの作成なんて簡単にできてしまいますが、高価な製品なので簡単には購入できません。シェープファイルが欲しいけど、フリーのライブラリで何とかしたいという方はぜひ PyShp を使ってみてください。本日は以上です。