GIS奮闘記

元GISエンジニアの技術紹介ブログ。主にPythonを使用。

スポンサーリンク

Python3では SimpleHTTPServer ではなく http.server を使うべし

本日はちょっとローカルサーバーをたてたくて、あれっとなった時のお話です。

簡単にローカルサーバーをたてるならやっぱり SimpleHTTPServer かなと思い、

python -m SimpleHTTPServer 8080

を実行。しかし、

No module named SimpleHTTPServer

とでて、あれっ?となり調べてみると、Python2にはあった SimpleHTTPServer という標準ライブラリのモジュールが、Python3では http.server というモジュールに統合されていることがわかりました。

なので、Python3 では

python -m SimpleHTTPServer [ポート番号]

ではなく

python -m http.server [ポート番号]

としなければなりません。お気を付けください。

C# の WebRequest を使って標高API を使ってみる

さて、本日は C# のWebRequest を使って標高API を使ってみようと思います。最近はまっている標高APIですが、以下エントリーでは C# で作った画面から標高APIを呼び出している Python スクリプトを実行して、実行結果を画面に表示しました。今回はそれを C# オンリーで標高APIを使ってみたいと思います。

www.gis-py.com

今回実装するもの

簡単な画面を作りました。処理は以下のような流れです。

  • 作成した画面で緯度経度を入力し実行
  • 標高APIで標高値を取得し、それを標高のテキストボックスに表示

f:id:sanvarie:20190719232535p:plain

インストール

以下をNuget でインストールしてください。

  • System.Net.Http
  • Newtonsoft.Json

環境

Windows10(64bit)
Visual Studio2017
.NET Framework4.7.2

サンプルコード

実行ボタンの処理を記述します。

private async void BtnExecute_Click(object sender, RoutedEventArgs e)
{
    // パラメータ作成
    var parameters = new Dictionary<string, string>()
    {
        { "lon", LonText.Text },
        { "lat", LatText.Text },
        { "outtype", "JSON" },
    };

    // URL作成
    var url = $"http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?{await new FormUrlEncodedContent(parameters).ReadAsStringAsync()}";

    // 標高APIにリクエスト投げる
    WebRequest request = WebRequest.Create(url);

    using (Stream response_stream = request.GetResponse().GetResponseStream())
    {
        using (StreamReader reader = new StreamReader(response_stream))
        {
            // 標高取得
            var jObject = JObject.Parse(reader.ReadToEnd());
            ElevationText.Text = jObject.GetValue("elevation").ToString();
        }
    }
}

実行

このように入力し、実行を押します。
f:id:sanvarie:20190719232749p:plain

実行後、標高APIから取得した標高が表示されます。
f:id:sanvarie:20190719232801p:plain

この緯度経度の場所がどこか気になる方は以下エントリーを読んでみてください。

www.gis-py.com

簡単ですが、本日は以上です。

ArcGIS Pro SDK で開発を行うための重要な情報源

さて、本日はArcGIS Pro SDK について書いてみようと思います。

ArcGIS Pro SDK とは

ArcGIS Pro SDK とは ArcGIS Pro のアドイン開発、構成拡張をコンセプトにしたソフトウェア開発キットです。ArcGIS Pro SDK では、.NET Framework が提供する TAP(Task-based Asynchronous Pattern) による非同期プログラミング、統合言語クエリ (LINQ)、Windows Presentation Foundation (WPF)、MVVM などの最新の .NET 機能と Pro の API を使用してアドインが開発できます。

ArcGIS Pro SDK でできること

ArcGIS Pro SDK を利用することで ArcGIS Pro の画面上に表示されている既存のタブメニューを変更したり、独自のタブメニューを追加したりするなどの機能拡張を行うことができます。また、アドインとして独自のウィンドウ、外部の API を利用したデータの編集、保存などが可能です。アドインは、拡張したタブ内に設置したボタンから起動することができます。

※ Pro SDK は ArcGIS Pro の機能拡張とアドインのための開発環境であり、スタンドアロン アプリケーションのような独立したアプリケーションの開発はできません。

必要なライセンス

ADS(ArcGIS Developer Subscription)の Professional 以上が必要になります。

製品詳細 | ESRIジャパン

ArcGIS Pro SDK を扱う上で壁となりうるもの

ArcGIS Pro SDK は使いこなせたら非常に便利な反面・・・

  • 日本語での情報が少ない
  • 英語でも情報が多くない(日本語よりかは多いですが)
  • 非同期処理や MVVM など、とっつきにくい技術を使用しなければなく敬遠している

と思っている方は少なくないかと思います。そう思っている方は以下をご参照ください。ArcGIS Pro SDK で開発を行う上での重要なリソースを紹介します。

ArcGIS Pro SDK 開発をするためには

情報の取得 がキーになります。以下にキーとなる3つのサイトを紹介します。

  • ArcGIS Pro SDK for Microsoft .NET is the new .NET SDK for the ArcGIS Pro Application
    米国 Esri の Github です。ここにArcGIS Pro SDK を使って開発をするための基本的な情報が載っています。「Editing」や「Geodatabase」などといったカテゴリーに分かれており、それぞれのカテゴリーのコンセプトやスニペットを確認することができます(Geodatabase を扱うにはどういうクラスを使えばいいのかの情報を得ることができる)。

  • ArcGIS Pro SDK for Microsoft .NET Framework Community Samples
    米国 Esri の Github です。130個以上のサンプルツールが公開されています。作りたいものはあるけど、実現方法がわからないという場合はまずこのサンプルを確認してみるのがいいかと思います。

  • ArcGIS Pro 2.4 API Reference Guide
    API リファレンスです。

これらの三つの主要な情報源を活用することで効率の良い開発が望めるかと思います。ぜひ一度試してみてください。

C#からPythonスクリプトを実行する方法 ~標高APIを使用して緯度経度から標高を取得する~

さて、本日は C#からPythonを実行してみようと思います。先日、国土地理院の標高APIについて書いてみたのですが、これを生かして何かできないかと思い本エントリーを書くに至りました。国土地理院の標高API興味のある方はぜひ以下エントリーを読んでみてください。

www.gis-py.com

C# から Python スクリプトを実行する方法

C#の Process を使って、Pythonのスクリプトを実行し、printした値を受け取ることができます。そして、Pythonの戻り値そのものを取得することはできません。詳細は以下サイトに載っています。

code.msdn.microsoft.com

今回実装するもの

以下のような簡単な画面を作りました。処理は以下のような流れです。

  • C# で作成した画面で緯度経度を入力し実行(Pythonスクリプトを実行)
  • Pythonスクリプト側で緯度経度を受け取り、標高APIで標高値を取得し、それをprint
  • C# 側でPythonスクリプトがprintした値(標高)を受け取り、それを標高のテキストボックスに出力

f:id:sanvarie:20190714231700p:plain

環境

Windows10(64bit)
Python3.6.5
Visual Studio2017 .NET Framework4.7.2

サンプルコード

C#

実行ボタンを押した際の処理です。Pythonに渡す引数を作って、Process()を実行するだけですね。とてもシンプルにできます。

private void ExecuteClick(object sender, EventArgs e)
{
    // Pythonインタープリタのパス
    var pythonInterpreterPath = @"python.exe";

    // Pythonスクリプトのパス
    var pythonScriptPath = @"module.py";

    // Pythonスクリプトに渡す引数
    var arguments = new List<string>
    {
        pythonScriptPath ,
        LatText.Text, // 緯度
        LonText.Text  // 経度
    };

    var process = new Process()
    {
        StartInfo = new ProcessStartInfo(pythonInterpreterPath)
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
            Arguments = string.Join(" ", arguments),
        },
    };

    process.Start();

    //python側でprintした内容を取得
    var sr = process.StandardOutput;
    var result = sr.ReadLine();

    // 標高を取得
    ElevationText.Text = result;

    process.WaitForExit();
    process.Close();
}

Python

C# から受け取った緯度経度を使用して標高を取得し、それをprintします。printした結果がC#側に渡されます。

import sys
import requests

args = sys.argv

lat = args[1]
lon = args[2]

url = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php" \
       "?lon=%s&lat=%s&outtype=%s" %(lon, lat, "JSON")

resp = requests.get(url, timeout=10)
data = resp.json()

print(data["elevation"])

実行

このように入力し、実行を押します。
f:id:sanvarie:20190714232909p:plain

実行後、Pythonスクリプトで取得された標高が表示されます。
f:id:sanvarie:20190714232932p:plain

すごく簡単にできました。

Pythonのreturnを受け取れないのが少しもどかしいところですが、C# から Pythonスクリプト を実行するのは全然難しくないことがわかりました。Pytonで画面を作成するのは面倒なので、Pythonで作った処理結果を画面で表示したいという場合はこのような方法をとってもいいかもしれないですね。本日は以上です。

Pythonで国土地理院の標高API を使ってみよう!

さて、本日はPythonで国土地理院の標高API を使ってみようと思います。

標高API とは

緯度経度を送るとその地点の標高を返してくれるサービス。この仕組みを利用すれば、WEBサイト上の地図でクリックした地点の標高を取得したりすることができます。こんな便利なものを提供していただけるなんて、本当にありがたいですね。

仕様

地理院地図|標高APIをご参照ください。すごく簡単に使えますね。

例えば、このようなリクエストを投げると
http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=140.08531&lat=36.103543&outtype=JSON

このような結果が返ってきます。
f:id:sanvarie:20190713193538p:plain

「elevation」が標高ですね。

「hsrc」は標高データのデータソースみたいです。今回はこの値は無視します。

実行環境

Windows10(64bit)
Python3.6.5
Jupyter Notebook

使用する緯度経度

緯度: 35.678601
経度: 139.740286

ここがどこかといいますと永田町駅ですね。

f:id:sanvarie:20190713194234p:plain

サンプルコード

永田町駅の標高を取得するサンプルです。

import requests

lat = 35.678601  # 緯度
lon = 139.740286 # 経度

url = "http://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php" \
       "?lon=%s&lat=%s&outtype=%s" %(lon, lat, "JSON")

resp = requests.get(url, timeout=10)
data = resp.json()

print(data["elevation"])


ものすごく簡単にできました。結果は29.2m ですね。
f:id:sanvarie:20190713194753p:plain

取得結果が正しいか地理院地図を使用して確かめます。
f:id:sanvarie:20190713195814p:plain

29.2m としっかり表示されていますね。素晴らしい!
f:id:sanvarie:20190713195859p:plain

簡単に使用できてこんな有益な情報が取得できるなんて本当にうれしい限りです。ぜひこれを利用して何か便利なものを作ってみたいですね。

【Python と GIS】GDAL を使って ファイルジオデータベースを操作してみよう!

さて、本日も GDAL について書いてみようと思います。前回はGDAL で Shapeファイルの読み込みと属性検索について書きましたが、今回はGDAL でのファイルジオデータベースの操作について書いてみようと思います。興味のある方は前回のエントリーもぜひ読んでみてください。

www.gis-py.com

GDALとは

GDAL はフリーの GIS ライブラリです。GDAL — GDAL documentation
これがあればShapeの読み込みからジオメトリの作成まで基本的なことは何でもできるかと思います。

ファイルジオデータベースとは

以下エントリーでも紹介していますが、ファイルジオデータベースとは ArcGIS で使用されるデータフォーマットです。

www.gis-py.com

インストール

公式サイトの手順に従ってインストールをお願いします。https://gdal.org/download.html

実行環境

Windows10(64bit)
Python3.6.5
Jupyter Notebook

サンプルデータ

ArcMap で以下を作成しました。

  1. GDB・・・Sample.gdb
  2. フィーチャクラス・・・GDAL_TEST
  3. カラム・・・テスト1、テスト2

f:id:sanvarie:20190713163137p:plain

f:id:sanvarie:20190713163224p:plain

サンプルコード

GDAL_TEST フィーチャクラスのテスト1、テスト2カラムの値を取得するサンプルです。

from osgeo import ogr

# GDBオープン
driver = ogr.GetDriverByName("OpenFileGDB")
gdb = driver.Open(r"D:\python\data\Sample.gdb", 0)

list1, list2 = [], []

# GDBに格納されているフィーチャクラス数分ループ
for featsClass_idx in range(gdb.GetLayerCount()):

    # フィーチャクラスを取得
    featureClass = gdb.GetLayerByIndex(featsClass_idx)

    layerDefinition = featureClass.GetLayerDefn()

    # GDAL_TESTフィーチャクラスの場合のみ処理を実行
    if featureClass.GetName() == "GDAL_TEST":

        while featureClass:

            feat = featureClass.GetNextFeature()

            if feat is None:
                break

            else:
                for column_num in range(layerDefinition.GetFieldCount()):

                    # カラム名取得
                    column_name = layerDefinition.GetFieldDefn(column_num).GetName()

                    #テスト1、テスト2カラムのときのみ属性を取得する
                    if column_name == "テスト1":
                        list1.append(feat.GetField(column_name))
                    elif column_name == "テスト2":
                        list2.append(feat.GetField(column_name))

print(list1)
print(list2)

del gdb


結果を見ると、想定通りテスト1、テスト2カラムの値を取得できたことがわかりました。
f:id:sanvarie:20190713163525p:plain

処理のポイント

以下にポイントとなる箇所を記述します。

GDBオープン
# GDBオープン
driver = ogr.GetDriverByName("OpenFileGDB")
gdb = driver.Open(r"D:\python\data\Sample.gdb", 0)
フィーチャクラス取得

GetLayerByIndex(index) を使用することでフィーチャクラスを取得することができます。

# GDBに格納されているフィーチャクラス数分ループ
for featsClass_idx in range(gdb.GetLayerCount()):

    # フィーチャクラスを取得
    featureClass = gdb.GetLayerByIndex(featsClass_idx)
フィーチャクラスの走査

GetNextFeature() を使用することで、フィーチャクラス内のフィーチャにアクセスできます。

while featureClass:
    feat = featureClass.GetNextFeature()
属性の取得

基本的には前回のエントリー(https://www.gis-py.com/entry/gdal-shape)と同じですが、今回はリスト内包表記は使用していません。ぱっと見はこちらの方がわかりやすいかもしれないですね。

for column_num in range(layerDefinition.GetFieldCount()):

    # カラム名取得
    column_name = layerDefinition.GetFieldDefn(column_num).GetName()

    #テスト1、テスト2カラムのときのみ属性を取得する
    if column_name == "テスト1":
        list1.append(feat.GetField(column_name))
    elif column_name == "テスト2":
        list2.append(feat.GetField(column_name))


本日は以上になります。また GDAL について書いてみようと思いますが、今度はもう少し突っ込んだ内容にしてみようかと思います。

【Python と GIS】 GDAL を使って Shapeファイルを読み込んで属性検索してみよう!

さて、本日は GDAL について書いてみようと思います。GDAL については以下のように以前に何個か記事を書いているのですが、紹介していない機能がまだまだたくさん残っています。今回は属性検索について紹介します。

www.gis-py.com

www.gis-py.com

www.gis-py.com

www.gis-py.com

GDALとは

GDAL はフリーの GIS ライブラリです。GDAL — GDAL documentation
これがあればShapeの読み込みからジオメトリの作成まで基本的なことは何でもできるかと思います。

インストール

公式サイトの手順に従ってインストールをお願いします。https://gdal.org/download.html

サンプルデータ

以下エントリーで紹介した全国市区町村界データを使用します。

www.gis-py.com

サンプルデータの属性情報

フィールド名

  • JCODE・・・市区町村コード
  • KEN・・・都道府県名
  • SICHO ・・・支庁名・振興局名
  • GUN・・・郡名(町村部のみ)
  • SEIREI・・・政令指定都市の市名
  • SIKUCHOSON・・・市区町村名
  • CITY_ENG・・・市区町村名(英語)
  • P_NUM・・・人口
  • H_NUM・・・世帯数

実行環境

Windows10(64bit)
Python3.6.5
Jupyter Notebook

GDAL で属性検索をするには

以下のような手順を踏む必要があります。

  1. Shape ファイルの読み込み
  2. レイヤの取得
  3. フィルター設定
  4. 属性の取得

サンプルコード

KEN = '神奈川県'のフィーチャを属性検索するサンプルです。

from osgeo import ogr

daShapefile = r"D:\data\japan_ver81.shp"
dataSource = ogr.Open(daShapefile)
layer = dataSource.GetLayer(0)
layerDefinition = layer.GetLayerDefn()
layer.SetAttributeFilter("KEN = '神奈川県'")

for feature in layer:
    attribute_list = [feature.GetField(layerDefinition.GetFieldDefn(column).GetName()) for column in range(layerDefinition.GetFieldCount())]
    print(attribute_list)


結果を見ると、想定通り神奈川県のデータを取得できたことがわかりました。
f:id:sanvarie:20190713143258p:plain

処理のポイント

サンプルコードの処理を重要なポイントごとに分けると以下のようになります。

Shapeファイルの読み込み
daShapefile = r"D:\data\japan_ver81.shp"
dataSource = ogr.Open(daShapefile)
レイヤーの取得
layer = dataSource.GetLayer(0)
フィルター設定
layer.SetAttributeFilter("KEN = '神奈川県'")
属性の取得
attribute_list = [feature.GetField(layerDefinition.GetFieldDefn(column).GetName()) for column in range(layerDefinition.GetFieldCount())]


ここが少し複雑なので、この部分の処理を分解して解説します。

  • レイヤーのフィールド数の取得
for column in range(layerDefinition.GetFieldCount())
  • フィールド名の取得

上記の「レイヤーのフィールド数の取得」で取得した要素を引数にします。

layerDefinition.GetFieldDefn(column).GetName()
  • 属性の取得
feature.GetField("フィールド名")

でそのフィールドの属性を取得することができます。

なので、上記の「フィールド名の取得」で取得した要素、つまり、フィールド名を引数にしています。

feature.GetField(layerDefinition.GetFieldDefn(column).GetName())

少し長いのですが、上記の処理をリスト内包表記にしたものをサンプルコードに載せました。

本日は以上になりますが、まだまだ紹介しきれていない使い方がたくさんあるので、 また GDAL について書いてみようと思います。