Looker Studioのバブルマップを利用した震度情報の可視化

弊社がサービス提供しておりますKCCS APIデータ配信サービスでは、震度データなど災害データを取り扱っています。

今回は、「地震震度データPUSH配信機能」で配信された震度情報をGoogle Cloud Looker Studioのバブルマップで可視化してみたいと思います。

「地震震度データPUSH配信機能」では、震度観測所ごとに観測した震度データを取得することができます。震度観測所ごとに観測した震度データを、震度観測所の緯度経度にプロットしてみます。

### 「地震震度データPUSH配信機能」で配信されるデータ
KCCS APIデータ配信サービスのGoogle Cloud Pub/Subで、気象庁からのデータ受信をトリガーとしJSON形式としてプッシュ配信されます。

サンプルデータは、KCCS APIデータ配信サービスのホームページからサンプルデータのダウンロードからご確認ください。

https://www.energy-cloud.jp/specification/#disaster-push-seismic-intensities

今回は2022/11/14 22:27に石川県で発生した地震をピックアップし、見える化してみます。
JSONファイルでは、下記のように地震に対する最大震度、都道府県ごとの最大震度、細分区域ごとの最大震度、市町村ごとの最大震度、震度観測点ごとの観測した震度が取得できます。
今回は震度観測点ごとに観測した震度をつかって、マップに表示をしてみます。
つまり、「/body/intensity/observation/pref[n]/area[n]/city[n]/intensity_station[n]」配下のデータを利用します。
```json
		"intensity": {
			"observation": {
				"max_int": "4",
				"max_int_code": "40",
				"pref": [
					{
						"name": "石川県",
						"code": "17",
						"max_int": "4",
						"max_int_code": "40",
						"revise": null,
						"area": [
							{
								"name": "石川県能登",
								"code": "390",
								"max_int": "4",
								"max_int_code": "40",
								"revise": null,
								"city": [
									{
										"name": "珠洲市",
										"code": "1720500",
										"max_int": "4",
										"max_int_code": "40",
										"revise": null,
										"intensity_station": [
											{
												"name": "珠洲市正院町＊",
												"code": "1720520",
												"int": "4",
												"int_code": "40",
												"revise": null
											},
```

### 震度観測所マスタの取得
震度観測所の緯度経度をつかって、マップにプロットするため、震度観測所の緯度経度が必要となります。
最新の震度観測所マスタをgithubで公開しています。
下記URLの「01-07_PointSeismicIntensity.csv」となります。

https://github.com/kccs-api/code-list


#### Jupyter NotebookでJSONファイルを分解し、震度観測所マスタと統合する


```py
import json
import pandas as pd
 
json_file = open('seismic.json', 'r')
json_object = json.load(json_file)

dict = {}

#震度情報のJSONファイルから震度観測所と震度情報をあるだけ抜き出す
for i in range(len(json_object["body"]["intensity"]["observation"]["pref"])):
    for j in range(len(json_object["body"]["intensity"]["observation"]["pref"][i]["area"])):
        for k in range(len(json_object["body"]["intensity"]["observation"]["pref"][i]["area"][j]["city"])):
            for l in range(len(json_object["body"]["intensity"]["observation"]["pref"][i]["area"][j]["city"][k]["intensity_station"])):                

                dict[str(json_object["body"]["intensity"]["observation"]["pref"][i]["area"][j]["city"][k]["intensity_station"][l]["code"])]\
                = json_object["body"]["intensity"]["observation"]["pref"][i]["area"][j]["city"][k]["intensity_station"][l]["int"]

df = pd.DataFrame(list(dict.items()),columns=['code', 'int'])

#地震発生時刻をすべての行に挿入する
df["origin_time"] = json_object["body"]["earthquake"]["origin_time"]
df = df.set_index('origin_time')
df.index = pd.to_datetime(df.index, format='%Y/%m/%d %H:%M:%S').tz_localize(None).astype(str)
df = df.reset_index()

seismic = df.copy()

#震度観測所マスタから必要情報を抜き出す
seismic_master = pd.read_csv("seismic_master.csv", dtype={'震度観測点番号(XML)':str})
seismic_master = seismic_master[["震度観測点番号(XML)","震度観測点名称","北緯","東経"]]

# ヘッダの和名を英名に
seismic_master = seismic_master.rename(columns={
"震度観測点番号(XML)":"code",
"震度観測点名称":"seismic_name",
"北緯":"lat",
"東経":"lon",
})

seismic = pd.merge(seismic, seismic_master, on="code", how="left")
seismic.to_csv("seismic.csv", index = False)
```

#### Jupyter NotebookでBigQueryにデータを挿入する

```py
#挿入先のBigQueryのテーブルを一度削除する
!bq rm -f -t <PJ名>:<DataSet名>.<table名>
!echo '[{"name":"origin_time","type":"TIMESTAMP","mode":"NULLABLE","description":"地震発生時刻"},{"name":"code","type":"INTEGER","mode":"NULLABLE","description":"震度観測点コード"},{"name":"int","type":"INTEGER","mode":"NULLABLE","description":"震度"},{"name":"seismic_name","type":"STRING","mode":"NULLABLE","description":"震度観測点名"},{"name":"lat","type":"FLOAT","mode":"NULLABLE","description":"緯度"},{"name":"lon","type":"FLOAT","mode":"NULLABLE","description":"経度"}]' > schema.json ;bq mk --table --schema schema.json --description "地震発生データ" <PJ名>:<DataSet名>.<table名>

#BigQueryのテーブルにデータを挿入する
!bq load \
--skip_leading_rows 1 \
--schema schema.json \
<PJ名>:<DataSet名>.<table名> seismic.csv
```
### Looker StudioにBigQueryをデータソースとして追加する
Looker StudioからBigQueryの対象のテーブルを参照できるようにします。

レポート上で「データを追加」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/ba2873c0-443d-0b98-4e8c-dcdde46a9a8d.png)

「BigQuery」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/84ed6b6a-a490-1224-ba3d-a6f091741ef1.png)

対象の「プロジェクト」「データセット」「データステージ」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/3c8daded-4d75-6845-d1ff-d9ce2a3785eb.png)


### Looker Studioで緯度経度を使って表示する

まずは表をつかって、発生日時と震度観測所点名と震度情報を表示してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/52cbb51b-62fb-a868-208f-94d44a668666.png)


そのつぎに、マップに震度情報をマッピングしてみます。
マップのバブルマップを挿入します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/494ad664-abf4-4f8b-57ec-039380525f35.png)


フィールドの位置を緯度経度とし、CONCAT(lat,",",lon)でデータを結合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/12693498-7b4f-b521-09c5-4b611b7b97c1.png)
<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/d810fe93-e84b-5db2-bf42-1a0e2e997ff2.png">

色ディメンションは震度を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/550f5b7a-8075-8918-1d56-bee3a8b01acd.png)

地図にマッピングができました。
緯度経度が分かれば、簡単に地図にプロットができますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/d15e0ed8-bdcb-5b6f-37fa-dba1c8da6ae2.png)

### まとめ

実は、気象庁のホームページでも同じものが表示されています。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1194651/1c700aba-d244-88e1-7e68-017e1134e282.png">

震度情報のJSONファイルから県を抜き出し、必要な情報のみLooker Studioで表示させるなど、ピンポイントでの確認にも活用いただけるのではないかと思います。
また、今回はJupyter Notebookで分解してみましたが、Pub/Subを使ったプッシュ配信を活用し例えばCloud Functionsをつかって、常に最新の情報をLooker Studioで表示させることも可能です。