yamamoto-ryuzo / portal

Other
1 stars 0 forks source link

QGIS+LIZMAPと東京都オープンデータの統合によるデータ管理と可視化の強化 #9

Closed yamamoto-ryuzo closed 1 week ago

yamamoto-ryuzo commented 1 month ago

https://portal.data.metro.tokyo.lg.jp/ との統合の在り方を考えていきたい! とりあえずAPIがあるようなのでその接続の勉強。。。が、そもそもデータベースではないとおもうのでどうなるねん!?てかんじか???

yamamoto-ryuzo commented 1 month ago

テストデータは以下を利用 https://api.data.metro.tokyo.lg.jp/v1/Event?limit=2 を発見、、、とりあえずAPIがわからないので、事務局にRESTfulなのかを含めて、問い合わせ開始。 https://tokyo-odh-2024.slack.com/archives/C07AZF7DLH1/p1723282761174969

yamamoto-ryuzo commented 1 month ago

GISで表示する上でのカベ! とりあえず、JSON、CSVに位置情報を付与する必要がありそう。 おそらくすべてのデータにあるであろう市区町村のデータとリンクしてGIS化を図る。 市区町村データはオープンデータから  国土数値情報ダウンロードサイト:https://nlftp.mlit.go.jp/ksj/index.html  行政区域:https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html QGISポータブルには初期状態からインストール済みなのでこんな感じ image

yamamoto-ryuzo commented 1 month ago

後は、東京都がデータベースをRESTに公開しているかどうかがカギか??? 現在、問い合わせ中なのでしばし休憩。

yamamoto-ryuzo commented 1 month ago

CSV連携

テストデータは  http://www.opendata.metro.tokyo.jp/2018appcon/olympic/130001sports_facilities_barrierfree.csv 【課題】文字コードがShift-JISであるため、直接レイヤを構築で出来ていない。

import requests import csv from qgis.core import QgsVectorLayer, QgsField, QgsFeature, QgsGeometry, QgsPointXY, QgsProject from qgis.PyQt.QtCore import QVariant # APIからCSVデータを取得 url = "http://www.opendata.metro.tokyo.jp/2018appcon/olympic/130001sports_facilities_barrierfree.csv" response = requests.get(url) csv_data = response.content.decode("shift_jis") # メモリベースのレイヤを作成 layer = QgsVectorLayer("Point?crs=EPSG:4326", "API CSV Layer", "memory") pr = layer.dataProvider() # CSVデータを解析し、ヘッダーからフィールドを追加 reader = csv.reader(csv_data.splitlines()) headers = next(reader) fields = [] for header in headers: fields.append(QgsField(header, QVariant.String)) pr.addAttributes(fields) layer.updateFields() # CSVデータをレイヤに追加 for row in reader: feature = QgsFeature() feature.setAttributes(row) x = float(row[headers.index('経度')]) y = float(row[headers.index('緯度')]) feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y))) pr.addFeature(feature) layer.updateExtents() # レイヤをプロジェクトに追加 QgsProject.instance().addMapLayer(layer) print("Layer loaded successfully!")
import requests
import csv
from qgis.core import QgsVectorLayer, QgsField, QgsFeature, QgsGeometry, QgsPointXY, QgsProject
from qgis.PyQt.QtCore import QVariant

# APIからCSVデータを取得
url = "http://www.opendata.metro.tokyo.jp/2018appcon/olympic/130001sports_facilities_barrierfree.csv"
response = requests.get(url)
csv_data = response.content.decode("shift_jis")

# メモリベースのレイヤを作成
layer = QgsVectorLayer("Point?crs=EPSG:4326", "API CSV Layer", "memory")
pr = layer.dataProvider()

# CSVデータを解析し、ヘッダーからフィールドを追加
reader = csv.reader(csv_data.splitlines())
headers = next(reader)

fields = []
for header in headers:
    fields.append(QgsField(header, QVariant.String))
pr.addAttributes(fields)
layer.updateFields()

# CSVデータをレイヤに追加
for row in reader:
    feature = QgsFeature()
    feature.setAttributes(row)
    x = float(row[headers.index('経度')])
    y = float(row[headers.index('緯度')])
    feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
    pr.addFeature(feature)

layer.updateExtents()

# レイヤをプロジェクトに追加
QgsProject.instance().addMapLayer(layer)
print("Layer loaded successfully!")

image

yamamoto-ryuzo commented 1 month ago

API連携

元データがCSVなのにJSONにする必要あるのか疑問なのでこっちはボツかも?シンプルISベストでは?

【課題】メモリにいったん取り込んでしまい直接レイヤを構築出来ていない。 テストデータはJSON形式 ガイド:  https://portal.data.metro.tokyo.lg.jp/opendata-api/ 実際のデータ:  https://api.data.metro.tokyo.lg.jp/v1/PublicFacility?limit=1000 どうも、データベースをRESTFullに公開している雰囲気のデータ  https://github.com/yamamoto-ryuzo/portal/issues/9#issuecomment-2282309835 基本構成は以下の通り

import requests
from qgis.core import QgsVectorLayer, QgsField, QgsFeature, QgsGeometry, QgsPointXY, QgsProject
from PyQt5.QtCore import QVariant

# APIエンドポイント
url = 'https://api.data.metro.tokyo.lg.jp/v1/PublicFacility?limit=10'

# GETリクエストを送信してデータを取得
response = requests.get(url)
response.raise_for_status()  # リクエストが失敗した場合に例外を投げる

# JSONレスポンスを解析
response_json = response.json()

# データ部分を取得
data = response_json[0]  # 最初のリストを取得

# QGISで新しいレイヤーとしてレスポンスを追加する
layer = QgsVectorLayer("Point?crs=EPSG:4326", "API Response", "memory")
provider = layer.dataProvider()

# 属性フィールドを追加(JSONデータに合わせて調整)
provider.addAttributes([QgsField("name", QVariant.String)])
layer.updateFields()

# フィーチャーを作成して追加
for item in data:
    try:
        lon = float(item['地理座標']['経度'])
        lat = float(item['地理座標']['緯度'])
        name = item['名称']['表記']

        feature = QgsFeature()
        feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(lon, lat)))
        feature.setAttributes([name])
        provider.addFeature(feature)
    except (KeyError, ValueError) as e:
        print(f"データ処理エラー: {e}")

layer.updateExtents()
QgsProject.instance().addMapLayer(layer)

  image

 

yamamoto-ryuzo commented 1 month ago

時点での結論

2024/08/11 結構一度仮想メモリに読み込まないとレイヤ構築ができていない

結果/的には、POSTGISに読み込んだほうがましな状態。。。なんとか、APIから直接レイヤを構築したい。

2024/08/12 東京都オープンデータのGEOJSONは、定義がメチャクチャ

期待通りに表示されない。。。データを確認。。。 GEOJSON勝手にポイントを3D表現して、さらい、拡張子JSON。。。これGEOJSONって言わない。。。なぜこんなことに?

yamamoto-ryuzo commented 4 weeks ago

質問の回答が来た!

結論

 今回の私のしたいことに都の公開しているAPIは、利用目的が違いよう???たぶん?
 が、リンク先一覧が簡単に取得できるだけでも助かる!
 今後の作業手順は
 ・とりあえず最大勢力のCSVに着目
 ・CSVのうち、座標のあるものを、「データ一覧」の属性として、属性「位置情報」として付加
    位置情報の整理方法は
     緯度・経度 (十進度(DD)形式:例: 35.6895, 139.6917)      市区町村名
 ・あとはとにかく一度GISで表示してみて、次のステップを検討。   以前作っていたGIF_downloderを思い出して、それを改造が早そうなので、以下で改造!
 https://github.com/yamamoto-ryuzo/TokyoOD_downloader/

質問

APIについて、こちらのページ ( https://portal.data.metro.tokyo.lg.jp/opendata-api/ )見つけました。
RestFull APIで公開している一覧はないのでしょうか。データベース一覧と属性を希望です。
以下のようなページ
https://postgrest.org/en/stable/references/api/tables_views.html
教えてもらえるのがベストです。よろしくお願いいたします。

回答

データ一覧を取得するためのAPI一覧等は公開していません。
データ一覧については下記の手順でCSVとして取得可能です。
①カタログサイトのトップページにて左上にある「一覧からデータを探す」をクリックする。
②データセット一覧の画面に切り替わると「xxxx件のデータセットが見つかりました」のメッセージが表示される。
③ ②の画面にて「検索結果を出力」ボタン(検索キーワード入力用のテキストボックス上方に配置されている)をクリック するとメッセージの対象となった件数に該当するデータ一覧をCSVとして取得可能

yamamoto-ryuzo commented 1 week ago

ファーストステージも終わり、 https://github.com/yamamoto-ryuzo/TokyoOD_downloader もそこそこ動くようになったので、いったんクローズ!