どこから対応する？～全国道路施設点検データベース・道路交通センサス①～

本記事は[国土交通データプラットフォームアドベントカレンダー](https://qiita.com/advent-calendar/2023/mlit-dpf)15日目の記事です。

### はじめに
みなさん　こんにちは

突然ですが[全国道路施設点検データベース～　損傷マップ　～](https://road-structures-map.mlit.go.jp/Map.aspx)をご覧になったことはありますでしょうか？

道路橋やトンネルなどの道路施設の点検結果について「健全性」「措置状況」のどちらかで絞り込みして該当する施設を地図上に表示することができます。

![road-structures-map.mlit.go.jp_Map.aspx(iPad Pro) (2) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/c565fe4a-4897-3c01-f862-f22a9f6b5476.png)

![road-structures-map.mlit.go.jp_Map.aspx(iPad Pro) (1) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/ee8e5233-e2a1-25c7-5792-2e8f2515f0cb.png)

ですが「措置状況」が「措置未着手」かつ「健全性」が「Ⅳ（緊急措置）」または「Ⅲ（早期措置）」の施設を全て表示したいといったことは残念ながらできません。。。

そこで国交DPFのAPIの出番です。上記のようなAND/ORの条件を組み合わせてデータを取得することができますよ！

早速Pythonでやってみましょう。

### ライブラリの読み込み
まず必要なライブラリを読み込みます。
```python
import json

import folium
import pandas as pd
import requests
```

### データを取得する関数の作成
次に国土交通データプラットフォームにリクエストを送信する関数を定義します。
リクエストボディに設定するGraphQLを引数で受け取り、結果を辞書型で返します。
（13日目で使用したものと同じですね！）

```python
def send_request(query: str) -> dict:
    """_summary_

    Args:
        query (str): QraphQL query string

    Returns:
        dict: MLIT DPF API response
    """
    END_POINT: str = "https://www.mlit-data.jp/api/v1/"
    API_KEY: str = "enter your api key"

    response: requests.models.Response = requests.post(
        END_POINT,
        headers={
            "Content-type": "application/json",
            "apikey": API_KEY,
        },
        json={"query": query},
    )
    result: dict = json.loads(response.content)["data"]
    return result
```

### リクエストボディの定義
検索APIのクエリ内容を定義します。
データカタログに「全国道路施設点検データベース」のIDを指定し、措置状況```RSDB:tenken.syuzen.sochi_joukyou```が「1:措置未着手」、健全性```RSDB:tenken.kiroku.hantei_kubun```が「3:早期措置」または「4:緊急措置」の施設を取得します。また今回は東京都のデータを取得するように```DPF:prefecture_code```が```13```のデータのみとしています。

```python
graphql_query: str = """
{
  search(
    term: "",
    phraseMatch: true,
    first: 0,
    size: 10000,
    attributeFilter: {
      AND: [
        {
          attributeName: "DPF:catalog_id",
          is: "rsdb"
        },
        {
          attributeName: "DPF:prefecture_code",
          is: "13"
        },
        {
          attributeName: "RSDB:tenken.syuzen.sochi_joukyou",
          is: "1"
        },
        {
          OR:[
            {
              attributeName: "RSDB:tenken.kiroku.hantei_kubun",
              is: "3"
            },
            {
              attributeName: "RSDB:tenken.kiroku.hantei_kubun",
              is: "4"
            },
          ]
        }
      ]
    }
  ) {
    totalNumber
    searchResults {
      title
      lat
      lon
      metadata
    }
  }
}
"""
```

### 全国道路施設点検データベースデータの取得
準備ができたのでリクエストを送信します。
結果はJSONで返ってくるためDataFrameに変換します。

```python
data: dict = send_request(query=graphql_query)
df: pd.DataFrame = pd.json_normalize(data["search"]["searchResults"])
```

不要な項目が多く、列名も長いので必要な項目に列名も変えます。

```python
selected_columns: list = [
    "title",
    "lat",
    "lon",
    "metadata.RSDB:shisetsu_id",
    "metadata.DPF:object_category",
    "metadata.RSDB:shisetsu_kubun",
    "metadata.RSDB:tenken.nendo",
    "metadata.RSDB:tenken.kiroku.hantei_kubun",
    "metadata.RSDB:tenken.syuzen.sochi_joukyou",
]
renamed_data = df[selected_columns].rename(
    columns={
        "metadata.RSDB:shisetsu_id": "id",
        "metadata.DPF:object_category": "object_category",
        "metadata.RSDB:shisetsu_kubun": "shisetsu_kubun",
        "metadata.RSDB:tenken.nendo": "nendo",
        "metadata.RSDB:tenken.kiroku.hantei_kubun": "hantei_kubun",
        "metadata.RSDB:tenken.syuzen.sochi_joukyou": "sochi_joukyou",
    }
)
renamed_data.head()
```

|    | title          |     lat |     lon | id                 | object_category   |   shisetsu_kubun |   nendo |   hantei_kubun |   sochi_joukyou |
|---:|:---------------|--------:|--------:|:-------------------|:------------------|-----------------:|--------:|---------------:|----------------:|
|  0 | 亀戸駅前歩道橋 | 35.6966 | 139.825 | 35.69658,139.82548 | 横断歩道橋        |                5 |    2022 |              4 |               1 |
|  1 | 栄町横断歩道橋 | 35.7479 | 139.475 | 35.74792,139.47456 | 横断歩道橋        |                5 |    2022 |              4 |               1 |
|  2 | 湯の浜橋       | 34.747  | 139.354 | 34.74699,139.35408 | 道路橋            |                1 |    2018 |              4 |               1 |
|  3 | 和泉橋         | 35.6971 | 139.775 | 35.69710,139.77548 | 道路橋            |                1 |    2020 |              4 |               1 |
|  4 | 西国分寺人道橋 | 35.7009 | 139.466 | 35.70086,139.46581 | 道路橋            |                1 |    2014 |              4 |               1 |

すっきりしました！

### 地図表示

では地図に表示してみましょう。

```python
m = folium.Map(tiles="http://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png", attr="地理院タイル")
for i, row in renamed_data.iterrows():
    folium.CircleMarker(
        location=[row["lat"], row["lon"]], fill=True, radius=5, color="black", fill_opacity=1, fill_color="white"
    ).add_to(m)
m
```

![folium (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629590/2b399336-b0b9-361e-6fb8-838ec0abe70f.png)

できました！

### まとめ

本家の全国道路施設点検データベース 損傷マップでは確認が難しい複雑な条件でのデータの可視化について国交DPFのAPIを活用することで実現することができました。

今回取得した条件でも施設数が840件あり、どこから着手すべきかこれだけだと判断が難しいです。

そこで次回は道路交通センサスと組み合わせて交通量が多い施設を特定したいと思います。
それではまた明日！