|
|
# 导入必要的库
|
|
|
import requests
|
|
|
import pandas as pd
|
|
|
import matplotlib.pyplot as plt
|
|
|
import seaborn as sns
|
|
|
import folium
|
|
|
from folium.plugins import HeatMap
|
|
|
import streamlit as st
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
|
|
|
|
# 第一步:数据收集
|
|
|
def fetch_earthquake_data(min_magnitude=4.5, start_time=None, end_time=None):
|
|
|
url = 'https://earthquake.usgs.gov/fdsnws/event/1/query'
|
|
|
if not start_time:
|
|
|
start_time = (datetime.utcnow() - timedelta(days=30)).strftime("%Y-%m-%d")
|
|
|
if not end_time:
|
|
|
end_time = datetime.utcnow().strftime("%Y-%m-%d")
|
|
|
params = {
|
|
|
'format': 'geojson',
|
|
|
'starttime': start_time,
|
|
|
'endtime': end_time,
|
|
|
'minmagnitude': min_magnitude
|
|
|
}
|
|
|
response = requests.get(url, params=params)
|
|
|
data = response.json()
|
|
|
features = data['features']
|
|
|
# 提取所需信息
|
|
|
earthquakes = []
|
|
|
for feature in features:
|
|
|
properties = feature['properties']
|
|
|
geometry = feature['geometry']
|
|
|
earthquakes.append({
|
|
|
'time': pd.to_datetime(properties['time'], unit='ms'),
|
|
|
'place': properties['place'],
|
|
|
'magnitude': properties['mag'],
|
|
|
'depth': geometry['coordinates'][2],
|
|
|
'latitude': geometry['coordinates'][1],
|
|
|
'longitude': geometry['coordinates'][0]
|
|
|
})
|
|
|
return pd.DataFrame(earthquakes)
|
|
|
|
|
|
|
|
|
# 第二步:数据分析和可视化函数
|
|
|
def plot_magnitude_distribution(df):
|
|
|
plt.figure(figsize=(10, 6))
|
|
|
sns.histplot(df['magnitude'], bins=20, kde=True)
|
|
|
plt.title('magnitude distribution histogram')
|
|
|
plt.xlabel('magnitude')
|
|
|
plt.ylabel('frequency')
|
|
|
st.pyplot(plt)
|
|
|
|
|
|
|
|
|
def plot_time_series(df):
|
|
|
df_time = df.set_index('time').resample('D').count()
|
|
|
plt.figure(figsize=(10, 6))
|
|
|
plt.plot(df_time.index, df_time['magnitude'])
|
|
|
plt.title('daily earthquake count time series')
|
|
|
plt.xlabel('date')
|
|
|
plt.ylabel('number of earthquakes')
|
|
|
st.pyplot(plt)
|
|
|
|
|
|
|
|
|
def create_interactive_map(df):
|
|
|
map_center = [df['latitude'].mean(), df['longitude'].mean()]
|
|
|
base_map = folium.Map(location=map_center, zoom_start=2)
|
|
|
# 添加地震位置点
|
|
|
for _, row in df.iterrows():
|
|
|
folium.CircleMarker(
|
|
|
location=[row['latitude'], row['longitude']],
|
|
|
radius=row['magnitude'] * 1.5,
|
|
|
popup=f"Magnitude: {row['magnitude']}, Depth: {row['depth']} km",
|
|
|
color='red',
|
|
|
fill=True,
|
|
|
fill_color='red'
|
|
|
).add_to(base_map)
|
|
|
# 添加热力图
|
|
|
heat_data = [[row['latitude'], row['longitude']] for _, row in df.iterrows()]
|
|
|
HeatMap(heat_data).add_to(base_map)
|
|
|
return base_map
|
|
|
|
|
|
|
|
|
# 第三步:制作Streamlit应用
|
|
|
def main(streamlit_folium=None):
|
|
|
st.title("全球地震数据分析与可视化")
|
|
|
|
|
|
# 侧边栏参数选择
|
|
|
st.sidebar.header("参数设置")
|
|
|
min_magnitude = st.sidebar.slider("最小震级", 0.0, 10.0, 4.5, 0.1)
|
|
|
days = st.sidebar.slider("过去多少天的数据", 1, 90, 30)
|
|
|
|
|
|
# 获取数据
|
|
|
start_time = (datetime.utcnow() - timedelta(days=days)).strftime("%Y-%m-%d")
|
|
|
end_time = datetime.utcnow().strftime("%Y-%m-%d")
|
|
|
df = fetch_earthquake_data(min_magnitude=min_magnitude, start_time=start_time, end_time=end_time)
|
|
|
|
|
|
st.subheader(f"从{start_time}到{end_time},震级大于{min_magnitude}的地震数据,共{len(df)}条")
|
|
|
st.map(df[['latitude', 'longitude']])
|
|
|
|
|
|
# 显示数据表
|
|
|
if st.checkbox("显示原始数据表"):
|
|
|
st.write(df)
|
|
|
|
|
|
# 震级分布直方图
|
|
|
st.subheader("震级分布直方图")
|
|
|
plot_magnitude_distribution(df)
|
|
|
|
|
|
# 时间序列图
|
|
|
st.subheader("每日地震数量时间序列")
|
|
|
plot_time_series(df)
|
|
|
|
|
|
# 交互式地图
|
|
|
st.subheader("地震分布交互式地图")
|
|
|
folium_map = create_interactive_map(df)
|
|
|
# 将Folium地图嵌入Streamlit
|
|
|
from streamlit_folium import st_folium
|
|
|
st_data = st_folium(folium_map, width=700)
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
main()
|