【小ネタ】Windows の位置情報 API を利用して現在地から一番近いアメダス観測所を探す

2024/09/27に公開

概要

https://zenn.dev/sharl/articles/8dd5fffb369f02

でおおよその現在地の緯度経度が取れるようになったので、現在地から一番近いアメダス観測所を探してみたいと思います。

上記の記事から現在地の緯度経度を取得する部分をコピってきて、アメダス観測所テーブルの JSON から各観測地点の緯度経度との距離が一番近いものを取得してみます。

現在地の緯度経度を取得

lat, lng = getLocation()

それぞれ十進数で返ってきます。

JSON 構造

アメダス観測所テーブルの JSON は https://www.jma.go.jp/bosai/amedas/const/amedastable.json です。

この JSON は以下のような構造になっています。

{
    "観測所番号": {
        "type": "観測地点の種類",
        "elems": "観測要素",
        "lat": [
            北緯(度),
            北緯(分)
        ],
        "lon": [
            東経(度),
            東経(分)
        ],
        "alt": 標高(m),
        "kjName": "観測所名",
        "knName": "カタカナ表記",
        "enName": "英語表記"
    },
    ...
}

例として帯広観測所は次のようなデータになっています。

{
    "20432": {
        "type": "B",
        "elems": "11111111",
        "lat": [
            42,
            55.3
        ],
        "lon": [
            143,
            12.7
        ],
        "alt": 38,
        "kjName": "帯広",
        "knName": "オビヒロ",
        "enName": "Obihiro"
    },
}

緯度経度を十進数に変換

観測地点の緯度経度は「度」「分」に分かれているので十進数に変換します。

def deg2dec(deg):
    degree, minute = deg
    return degree + minute / 60


_lat = deg2dec(data[key]['lat'])
_lng = deg2dec(data[key]['lon'])

現在地と観測所の距離を算出

現在地の緯度経度と観測地点の緯度経度との距離を math.dist を使って算出します。
平面として計算しているので近似値となります。

dist = math.dist((lat, lng), (_lat, _lng))

観測要素から「気温」が有効な観測所を抽出

観測要素はそれぞれ「気温 降水量 風向 風速 日照時間 積雪深 湿度 気圧」の順で (無効: 0, 有効: 1, 日照時間タイプ: 2) の順だと思われるので(詳しくは調査していません)、気温を観測している地点のみを抽出してみます。
降水量だけの観測地点がけっこうあるので、それを省く感じです。

elem[0] == '1'

まとめ

以上をまとめた一番近い観測所を探すコードが以下のソースになります。

sample.py
import asyncio
import math

import winsdk.windows.devices.geolocation as wdg
import requests


async def getCoords():
    locator = wdg.Geolocator()
    pos = await locator.get_geoposition_async()
    return [pos.coordinate.latitude, pos.coordinate.longitude]


def getLocation():
    try:
        return asyncio.run(getCoords())
    except Exception as e:
        print(e)


def deg2dec(deg):
    degree, minute = deg
    return degree + minute / 60


def getNearAmedas(lat, lng):
    r = requests.get('https://www.jma.go.jp/bosai/amedas/const/amedastable.json')
    if r and r.status_code == 200:
        lines = []
        data = r.json()
        for key in data:
            name = data[key]['kjName']
            elem = data[key]['elems']
            _lat = deg2dec(data[key]['lat'])
            _lng = deg2dec(data[key]['lon'])
            dist = math.dist((lat, lng), (_lat, _lng))
            if elem[0] == '1':
                lines.append([key, name, dist])

        return sorted(lines, key=lambda x: x[2])[0]

    return []


if __name__ == '__main__':
    lat, lng = getLocation()
    code, name, _ = getNearAmedas(lat, lng)
    print(f'現在地から一番近いアメダス観測所は {code} {name} です')

実行例

PS C:\Users\sharl\Downloads\sample> python -m venv .venv
PS C:\Users\sharl\Downloads\sample> .\.venv\Scripts\activate
(.venv) PS C:\Users\sharl\Downloads\sample> pip install winsdk requests
(.venv) PS C:\Users\sharl\Downloads\sample> python .\sample.py
現在地から一番近いアメダス観測所は 20432 帯広 です

おまけ

一番近い観測所のコードがわかれば

https://zenn.dev/sharl/articles/6e5eff90d70071

と組み合わせてみるのもよいでしょう。

Enjoy!!

参考資料

https://www.dpac.dpri.kyoto-u.ac.jp/enomoto/pymetds/JSON.html

Discussion