乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

地震

最近、やけに地震が多いので
気になって調べて
データを取って可視化してみました。


解説動画はこちら


 
今回のコードは
気象庁の地震データを取得して
そのデータを可視化するコードです。

先にデータが必要になるので
気になった人はコードを実行してみて下さい。

Jupyter Notebook や Google Colab で
実行できると思います。


地震データを取得する



気象庁から地震の観測データを取得して
データフレームにします。

やりたい人は、30分くらいかかるので
気をつけてやって下さい。

リンクを取得
import re
import time
import pandas as pd
import requests
from tqdm import tqdm
from bs4 import BeautifulSoup

domain = "https://www.data.jma.go.jp/"
index_url = "https://www.data.jma.go.jp/svd/eqev/data/daily_map/index.html"
res = requests.get(index_url)
soup = BeautifulSoup(res.content, "html.parser")
eq_link = [i.get("href") for i in soup.find_all("a") if len(i.get("href"))==13]
print(len(eq_link))

リンクからデータを取得する
# 地震データをテキストから取得
def data_pick(text):
    row_data = []
    for row in [i for i in text.split("\n") if len(i)>1][2:]:
        row = row.replace("° ","°")
        for i in range(7,1,-1):
            row = row.replace(" "*i, " ")
        row = row.replace(":"," ")
        tmp = row.split(" ")
        row_data.append(tmp[:-1])
    return row_data

all_data = []
for day in tqdm(eq_link):
    url = "https://www.data.jma.go.jp/svd/eqev/data/daily_map/" + day
    #print(url)
    res = requests.get(url)
    soup = BeautifulSoup(res.content, "html.parser")
    time.sleep(3.971)
    text_data = soup.pre.text
    all_data += data_pick(text_data)
    #break

print(len(all_data))


データを加工してデータフレームにする
columns=["年","月","日","時","分","秒","緯度","経度","深さ(km)","M","震央地名"]
df = pd.DataFrame(all_data,columns=columns)
df = df[df["M"] != "-"].reset_index(drop=True)
df = df.astype({"M": float , "深さ(km)":int, "年":int,"月":int,"日":int})
df["M2"] = df["M"]//1
df["年月日"] = df.apply(lambda x : "{0}{1:02}{2:02}".format(x["年"],x["月"],x["日"]),axis=1)

def lat_lon_10(x):
    tmp = x.split("°")
    degree = int(tmp[0])
    minute = int(tmp[1].split(".")[0])
    second = int(tmp[1].split(".")[1].split("'")[0])
    # 度、分、秒を10進法で表現
    decimal_degree = degree + minute/60 + second/3600
    return decimal_degree

df["緯度10"] = df["緯度"].map(lat_lon_10)
df["経度10"] = df["経度"].map(lat_lon_10)
df["size"] = df["M2"] ** 3

うまく実行できたら
df という変数にデータが格納されると思います。

エラーが出る人は
ライブラリが足りなかったり
通信がうまくいっていなかったり
色々な事象が起きると思いますが
全部は対応出来ませんので
がんばって解決して下さい。


データを見てみる


データを取得できたら
データを見てみましょう。

変数 df に対して
条件を指定すれば
絞り込みをしてみる事ができます。

マグニチュード別の地震回数
df[["M2","震央地名"]].groupby("M2").count().sort_index(ascending=False)
スクリーンショット 2024-03-02 16.29.41

日本地図にプロットする


日本地図にプロットするには
緯度と経度が必要です。

df 変数にはカラムとして
作成しているので
地図に表示する事ができます。

import plotly.express as px

fig = px.scatter_mapbox(
    data_frame=df[df["M2"]>=5],
    lat="緯度10",
    lon="経度10",
    hover_data=["年月日","深さ(km)"],
    color="M2",
    size="size",
    size_max=20,
    opacity=0.3,
    zoom=4,
    height=700,
    width=1500)

fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
fig.show()
output_88_0




千葉県だけにすると
こんな感じです。

output_106_0


色々な条件で絞り込んで
地図に反映させる事ができます。

最近は地震が多いので
何かが起きている可能性がありますね。

警戒を強める意味でも
データを見る価値はあるかもしれません。

今回は地震のデータを取得して
それを可視化するコードについてでした。

それでは。


先日結構大きな地震が有ったので
気になってしまいました。

地震のデータを集めてみたので
可視化することにしました。

解説動画はこちら



さて今回参考にしたのは
気象庁のデータです。

地震データベースがあるので
そこからCSVでダウンロードできるようです。

観測当時からのデータがありますが
震度1とかにしてしまうと
データが多すぎて全件は無理そうでした。

今回は震度5弱以上で抽出し
地震リスト.tsvに保存しています。

早速データを読み込みします。
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

data1_path = '地震リスト.tsv'
df1 = pd.read_table(data1_path)

中身はこんな感じになっています。

スクリーンショット 2021-10-09 16.57.00

つい最近までの震度5弱以上の震源地が記載されています。


これを可視化してみます。

可視化にはFoliumを使用します。
これはデータを地図上にプロットして
見やすくしてくれるものです。

マッピングには緯度経度を使用します。
データだと緯度経度の値などが
文字列かつ形式も違うので
そのままではマッピングに適していません。

DMS形式の緯度経度を
Degree形式の緯度経度に直します。

その他数値であるデータもデータ型を直す
前処理を行うコードがこれです。

# 不明データの削除
df1 = df1[~(df1['緯度']=='不明') | ~(df1['経度']=='不明')]
df1 = df1[~(df1['M']=='不明')]
df1 = df1.reset_index(drop = True)

# 震度データの整理
df1['最大震度'][df1['最大震度']=='震度5'] = '震度5弱'
df1['最大震度'][df1['最大震度']=='震度6'] = '震度6弱'

# 数値データの整形
df1['緯度2'] = df1['緯度'].str.replace('′N','').str.replace('°','.').str.split('.')
df1['経度2'] = df1['経度'].str.replace('′E','').str.replace('°','.').str.split('.')
df1['深さ'] = df1['深さ'].str.replace(' km','')

# 緯度経度をDegree形式へ変換
import math
from decimal import Decimal, ROUND_HALF_UP

# DMS形(度分秒)からDegree形式(度)への変換
def dms_to_degree(d):
    h,m,s = int(d[0]),int(d[1]),int(d[1])
    return Decimal(str(h + (m / 60) + (s / 3600))).quantize(Decimal('0.0001'), rounding=ROUND_HALF_UP)
    
# 緯度経度の変換
df1['longitude'] = df1['緯度2'].apply(dms_to_degree)
df1['latitude'] = df1['経度2'].apply(dms_to_degree)

# データ型変換
df1['longitude'] = df1['longitude'].astype('float')
df1['latitude'] = df1['latitude'].astype('float')
df1['M'] = df1['M'].astype('float')
df1['深さ'] = df1['深さ'].astype('int')

これで下処理ができました。
出来上がりはこんな感じです。

スクリーンショット 2021-10-09 16.58.15


早速このデータを使って
Foliumでマッピングしたいと思います。

今回は震度別で色で分けられるように
マッピングしました。

データは前処理したdf1をそのまま使用します。

import folium
from folium.features import CustomIcon
import pandas as pd

# マーカーの指定
def make_maker(r,color):
    rad = r['M'] * 1000
    name = r['地震の発生日'] + ' ' + r['地震の発生時刻'] +' : ' + r['震央地名']
    tmp = folium.Circle(
        location = [r['longitude'],r['latitude']], 
        popup    = name ,
        tooltip  = '{0} , 深さ : {1}km , M{2} , {3}'.format(name,r['深さ'],r['M'],r['最大震度']),
        radius = rad , color     = color , fill = True )
    return tmp
    
plot_map = folium.Map(location=[適当な緯度,適当な経度] ,  zoom_start=5)
s5j_group = folium.FeatureGroup(name="震度5弱").add_to(plot_map)
s5k_group = folium.FeatureGroup(name="震度5強").add_to(plot_map)
s6j_group = folium.FeatureGroup(name="震度6弱").add_to(plot_map)
s6k_group = folium.FeatureGroup(name="震度6強").add_to(plot_map)
s7_group = folium.FeatureGroup(name="震度7").add_to(plot_map)

for i, r in df1[df1['最大震度']=='震度5弱'].iterrows():
    s5j_group.add_child(make_maker(r,'#99FFFF'))
for i, r in df1[df1['最大震度']=='震度5強'].iterrows():
    s5k_group.add_child(make_maker(r,'#66FF00'))
for i, r in df1[df1['最大震度']=='震度6弱'].iterrows():
    s6j_group.add_child(make_maker(r,'#FFFF00'))
for i, r in df1[df1['最大震度']=='震度6強'].iterrows():
    s6k_group.add_child(make_maker(r,'#FF00FF'))
for i, r in df1[df1['最大震度']=='震度7'].iterrows():
    s7_group.add_child(make_maker(r,'#FF0000'))
folium.LayerControl().add_to(plot_map)
plot_map.save("HTMLファイル名")

実行するとHTMLファイルが出来上がります。
それを開くとこんな感じです。

スクリーンショット 2021-10-09 16.52.44


地図の右上から震度別で
表示を切り替えできるようになっています。

スクリーンショット 2021-10-09 16.54.24

震度6以上だとこんな感じに

スクリーンショット 2021-10-09 16.54.51

震度7だけだとこうなります。
スクリーンショット 2021-10-09 16.55.15


先日地震のあった場所は
千葉県の北西部で震度5強を観測しています。

スクリーンショット 2021-10-09 17.05.12


こんな感じでうまくマッピング出来て
いろいろ切り替えながら眺められるので
面白いと思います。

50年以上の観測データのようですが
関東圏では震度6強より大きな地震の発生がなさそうですね。

ただ、ここ最近の大地震を線で結ぶと
スクリーンショット 2021-10-09 16.54.51のコピー

きれいに一直線でつながるのが
少し怖いですねーー

無理くりつなげてみましたが
このライン上には何か有るのかも・・・

いつ地震が来ても良いような
備は考えておくべきですね!!!!

今回は地震データを
Folium可視化してみました。

やりたい方はコピペして
試してみてくださいね。

それでは。

このページのトップヘ