制作全球地震散点图:JSON格式

发布于 2022-04-07  508 次阅读


Plotly提供了根据位置绘制地图的工具。将使用它来使用它来进行可视化并指出全球地震分布情况。

地震数据

地震是一里氏震级度量的,而该文件记录了最近24小时内全球发生所有不低于1级的地震。

查看json数据

模块json提供各种探索和处理JSON数据的工具,其中有一些助于重新设置这个文件的格式,让我们能够清楚地查看原始数据,继而决定如何以编程的方式来处理。
先加载这个些数据并将其以易于阅读的方式显示出来。这个数据文件很长,因此不打印出来,而是将数据写入另一个文件,再打开该文件并轻松地再数据中导航:

import json

# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

reader_file = 'readable_eq_data.json'
with open(reader_file,'w') as f:
    json.dump(all_eq_data,f,indent=4)

file
导入json以便恰当的加载文件中的数据。并将其存储到all_eq_data中.函数json.load()将数据转换成为Python能够处理的格式,这里是一个庞大的字典。后创建一个文件,以便将这些易于阅读的方式写入其中。函数json.dump()接受一个JSON数据对象和一个文件对象,并将数据写入这个文件中,参数indent=4让dump()使用与数据结构匹配的缩进来设置数据格式。
file
这个文件的开头是一个键为“metadata”的片段,指出了这个数据文件是什么时候生成的,以及能够在网上什么地方找到,它还包括适合人类阅读的标题以及文件中记录了多少次地震:在过去24小时内,发生了158次地震。
这个geoJSON文件的结构适合存储基于位置的数据。数据存储在一个与键"features"相关联的列表中。这个文件包含的是地震数据。因此列表的每个元素都对应于一次地震。这种结构很有用,让地质学家能够将有关每次地震的任意数量信息存储在一个字典中,在将这些字典放在一个大型列表中。
表示地政的字典:

{
            "type": "Feature",
            "properties": {
                "mag": 0.96,
                "place": "8km NE of Aguanga, CA",
                "time": 1550360775470,
                "updated": 1550360993593,
                "tz": -480,
                "url": "https://earthquake.usgs.gov/earthquakes/eventpage/ci37532978",
                "detail": "https://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/ci37532978.geojson",
                "felt": null,
                "cdi": null,
                "mmi": null,
                "alert": null,
                "status": "automatic",
                "tsunami": 0,
                "sig": 14,
                "net": "ci",
                "code": "37532978",
                "ids": ",ci37532978,",
                "sources": ",ci,",
                "types": ",geoserve,nearby-cities,origin,phase-data,",
                "nst": 32,
                "dmin": 0.02648,
                "rms": 0.15,
                "gap": 37,
                "magType": "ml",
                "type": "earthquake",
                "title": "M 1.0 - 8km NE of Aguanga, CA"
            },
            "geometry": {
                "type": "Point",
                "coordinates": [
                    -116.7941667,
                    33.4863333,
                    3.22
                ]
            },
            "id": "ci37532978"
        },

键"properties"关联到了与特定地震相关的大量信息。主要关心键"mag"相关联的地震震级以及地震的标题,因为后者很好地概述了地震的震级和位置。
键"geometry"指出了地震发生在什么地方,我们需要根据这项信息将地震在散点图上标出来,在与键"conordinates"相关联的列表中,可以找出地震发生位置的经度和纬度。
首先提取过去24小时内发生的每次地震对应的字典:

创建地震列表

首先创建一个列表,其中包含所有地震的各种信息:

import json

# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']
print(len(all_eq_dicts))

file
提取与键'features'相关联的数据,并将其存储到all_eq_dicts中。

提取震级

有了包含所有地震数据的列表之后,就可以遍历这个列表,从中提取所需的数据。下面提取每次地震的震级:

import json

# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags = []
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    mags.append(mag)

print(mags[:10])

file

每次地震的震级都存储在相应字典‘properties’部分的‘mag’键下,依次将地震震级赋给遍历mag,再将这个变量附加到列表mags末尾。

提取位置数据

位置数据存储在了“geometry”键下。在“geometry”键关联的字典中,有一个“coordinates”键,它关联到了一个列表,而列表中的前两个值为经度和纬度。

import json

# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

print(mags[:10])
print(titles[:2])
print(lons[:5])
print(lats[:5])

file

绘制震级散点图

在确保显示的信息正确无误后,可以将注意力转向样式和外观:

import json

import plotly.express as px
# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

fig = px.scatter(
    x=lons,
    y=lats,
    labels= {'x':'经度','y':'纬度'},
    range_x=[-200,200],
    range_y=[-90,90],
    width=800,
    height=800,
    title='全球地震散点图',
)
fig.write_html('global_earthquakes.html')
fig.show()

file
Plotly Express 是Plotly 的高级接口。语法与Matplotlib类似。
fig.write_html方法可以将可视化图保存为html文件,在文件夹中找到global_earthquakes.html文件,用浏览器打开即可。
如果使用Jupyter Notebook,可以直接使用fig.show方法在notebook单元格显示散点图。

另一种指定图表数据的方式

当前,经纬度数据是手动配置的:

--skip--
    x=lons,
    y=lats,
     labels= {'x':'经度','y':'纬度'},

这是在Plotly Express中给图表定义数据的最简单方式之一,但在数据处理中并不是最佳的。
下面是另一种给图表定义数据的等效方式,需要使用pandas数据分析工具,首先创建一个DateFrame,将需要的数据封装起来:

import json
import pandas as pd
import plotly.express as px
# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

data = pd.DataFrame(
    data=zip(lons,lats,titles,mags),columns=['经度','纬度','位置','震级']
)
data.head()
fig = px.scatter(
    data,
    x='经度',
    y='纬度',
    labels= {'x':'经度','y':'纬度'},
    range_x=[-200,200],
    range_y=[-90,90],
    width=800,
    height=800,
    title='全球地震散点图',
)
fig.write_html('global_earthquakes.html')
fig.show()

在这种方式中,所有有关数据的信息都以键值对的形式放在一个字典中。相比于前一种格式,这种格式让我们能够无缝衔接数据分析,并且更轻松的进行定制。

定制标记的尺寸

确定如何改进散点图的样式时,应着重于让要传达的信息更清晰,当前的散点图显示了每次地震的位置,但没有指出震级,我们让观察者迅速获悉最严重的地震发生在什么地方。

import json
import pandas as pd
import plotly.express as px
# 探索数据的结构。
filename = './eq_data_1_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

data = pd.DataFrame(
    data=zip(lons,lats,titles,mags),columns=['经度','纬度','位置','震级']
)
data.head()
fig = px.scatter(
    data,
    x='经度',
    y='纬度',
    range_x=[-200,200],
    range_y=[-90,90],
    width=800,
    height=800,
    title='全球地震散点图',
    size='震级',
    size_max=10,
)
fig.write_html('global_earthquakes.html')
fig.show()

file
Plotly Express支持对数据系列进行定制,这些定制都以参数表示,这里使用了size参数来指定散点图中每个标记的尺寸,我们只需要将前面data中的'震级'字段提供给size参数即可,另外,标记尺寸默认为20像素,还可以通过size_max=10将最大显示尺寸缩放到10.

定制标记的颜色

还可以定制标记的颜色,以呈现地震的严重程度。

import json
import pandas as pd
import plotly.express as px
# 探索数据的结构。
filename = './eq_data_30_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

data = pd.DataFrame(
    data=zip(lons,lats,titles,mags),columns=['经度','纬度','位置','震级']
)
data.head()
fig = px.scatter(
    data,
    x='经度',
    y='纬度',
    range_x=[-200,200],
    range_y=[-90,90],
    width=800,
    height=800,
    title='全球地震散点图',
    size='震级',
    size_max=10,
    color='震级'
)
fig.write_html('global_earthquakes.html')
fig.show()

file
默认的实觉映射的图例渐变色范围是从蓝到红再到黄,数值越小则标记越蓝,而数值越大则标记越黄。
file

其他渐变

Plotly Express有大量渐变可供选择。要获悉有哪些渐变可供使用。

import plotly.express as px

for key in px.colors.named_colorscales():
    print(key)

file
这些渐变其实映射到一个个配色列表,使用px.colors.driverging.RdY1Gn[::1]可以将对应颜色的配色列表反转。

添加鼠标指向时显示的文本

import json
import pandas as pd
import plotly.express as px
# 探索数据的结构。
filename = './eq_data_30_day_m1.json'
with open(filename) as f:
    all_eq_data = json.load(f)

# reader_file = 'readable_eq_data.json'
# with open(reader_file,'w') as f:
#     json.dump(all_eq_data,f,indent=4)

all_eq_dicts = all_eq_data['features']

mags,titles,lons,lats = [],[],[],[]
for eq_dict in all_eq_dicts:
    mag = eq_dict['properties']['mag']
    title = eq_dict['properties']['title']
    lon = eq_dict['geometry']['coordinates'][0]
    lat = eq_dict['geometry']['coordinates'][1]
    mags.append(mag)
    titles.append(title)
    lons.append(lon)
    lats.append(lat)

data = pd.DataFrame(
    data=zip(lons,lats,titles,mags),columns=['经度','纬度','位置','震级']
)
data.head()
fig = px.scatter(
    data,
    x='经度',
    y='纬度',
    range_x=[-200,200],
    range_y=[-90,90],
    width=800,
    height=800,
    title='全球地震散点图',
    size='震级',
    size_max=10,
    color='震级',
    hover_name='位置',
)
fig.write_html('global_earthquakes.html')
fig.show()

file

小结

学习了如何使用现实世界中的数据集,如何处理CSV和JSON文件。
。。。


擦肩而过的概率