最近要做一个中国地图,以前用pyecharts,最近接触了geopandas 觉得很强大,改用geopandas作图。比如我制作一个疫情分布地图,效果应该是这样的。最终效果。
首先导入需要用的库:
import pandas as pd
import matplotlib.pyplot as plt
import requests
import geopandas as gpd
plt.rcParams['font.family'] = 'SimHei'
然后使用爬虫把疫情数据怕取下来,我使用的是 手机端的网易数据接口,地址是,
实时更新|新冠肺炎疫情动态地图https://wp.m.163.com/163/page/news/virus_report/index.html用浏览器打开是这样的。
打开检查工具,找到XHR,看请求的内容。
第一个地址就是,
可以看一下它的相应,
是json数据,没有问题,还是选择用curl工具生成,直接生成的代码是这样的。
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Origin': 'https://wp.m.163.com',
'Connection': 'keep-alive',
'Referer': 'https://wp.m.163.com/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-site',
'TE': 'trailers',
}
params = (
('t', '326609897543'),
)
response = requests.get('https://c.m.163.com/ug/api/wuhan/app/data/list-total', headers=headers, params=params)
然后就是数据提取。
使用这个网站,解析一下json数据。
这个网站对json的解析比较鲁棒。
可以看到,我们需要省:每个省的确诊数。
接下来,代码提取。
rj = response.json()
rj.keys()
rj
data = rj['data']
data.keys()
areaTree = data['areaTree']
areaTree.keys()
chinaData = areaTree[2]
chinaData.keys()
children = chinaData['children']
len(children)
#用一个试试
c1 = children[0]
c1.keys()
c1['name']
prov = [c['name'] for c in children]
print(prov)
c1['total']['confirm']
confirm = [c['total']['confirm'] for c in children]
print(confirm)
做成一个dataframe,以便后面使用
china_prov = pd.DataFrame({
"prov":prov,
"confirm":confirm
})
china_prov
geopandas使用
接下来,使用geopandas,看了一个大神的博客,写得很详细了。
这里是网址:
(数据科学学习手札74)基于geopandas的空间数据分析——数据结构篇 - 费弗里 - 博客园
https://www.cnblogs.com/feffery/p/11898190.html
这位高人,介绍很系统了。分成好几篇博客,看完对geo的理解更深刻一些。
这里我直接读取中国地图的数据,
china = gpd.read_file("region_map/MLgis/feifuli3_geometry/china_provinces/china_provinces.shp")
fig, ax = plt.subplots(figsize=(12, 8))
ax = china.geometry.plot(ax = ax )
这个地图做出来,是不太常见的投影方式或者坐标系,因此不好看,所以把投影方式改成:
albers_proj = '+proj=aea +lat_1=25 +lat_2=47 +lon_0=105'
fig, ax = plt.subplots(figsize=(12, 8))
ax = china.geometry.to_crs(albers_proj).plot(ax=ax)
fig, ax = plt.subplots(figsize=(12, 8))
ax = china.geometry.to_crs(albers_proj).plot(ax=ax,
facecolor = 'grey',
edgecolor = 'whit
这样基本就得到了中国地图。
其中 shp文件,我从网上下载的。如有必要可以上传。
另外 各地区的疫情数据为了防止边,转成json格式的。贴上无所谓:
china_prov
china_prov.to_json()
china_prov2 = pd.read_json('{"prov":{"0":"\\u6e56\\u5317","1":"\\u53f0\\u6e7e","2":"\\u9999\\u6e2f","3":"\\u5e7f\\u4e1c","4":"\\u4e0a\\u6d77","5":"\\u9ed1\\u9f99\\u6c5f","6":"\\u6c5f\\u82cf","7":"\\u6cb3\\u5357","8":"\\u6d59\\u6c5f","9":"\\u4e91\\u5357","10":"\\u6cb3\\u5317","11":"\\u798f\\u5efa","12":"\\u56db\\u5ddd","13":"\\u6e56\\u5357","14":"\\u5317\\u4eac","15":"\\u5b89\\u5fbd","16":"\\u65b0\\u7586","17":"\\u6c5f\\u897f","18":"\\u5c71\\u4e1c","19":"\\u9655\\u897f","20":"\\u91cd\\u5e86","21":"\\u5409\\u6797","22":"\\u5929\\u6d25","23":"\\u8fbd\\u5b81","24":"\\u5185\\u8499\\u53e4","25":"\\u5e7f\\u897f","26":"\\u5c71\\u897f","27":"\\u7518\\u8083","28":"\\u6d77\\u5357","29":"\\u8d35\\u5dde","30":"\\u5b81\\u590f","31":"\\u6fb3\\u95e8","32":"\\u9752\\u6d77","33":"\\u897f\\u85cf"},"confirm":{"0":68298,"1":16223,"2":12217,"3":3177,"4":2603,"5":1702,"6":1599,"7":1540,"8":1448,"9":1424,"10":1317,"11":1282,"12":1208,"13":1182,"14":1124,"15":1008,"16":980,"17":937,"18":933,"19":671,"20":603,"21":574,"22":487,"23":455,"24":419,"25":298,"26":260,"27":199,"28":190,"29":147,"30":77,"31":71,"32":18,"33":1}}')
china_prov2
然后接下来就是合并数据了。
使用geopandas读入的china 是一个geoDataFrame格式的。
但是可以当做普通数据表对待,直接合并就可以。
合并之前注意到,china 的 NAME 是各省名字,和我们原有的疫情数据的prov 不一样。
所以要先处理成统一昂的数据。
china['prov_name'] = china['NAME'].str.replace('省', '')
china['prov_name'] = china['prov_name'].str.replace('市', '')
china['prov_name'] = china['prov_name'].str.replace('自治区', '')
china['prov_name'] = china['prov_name'].str.replace(r'壮族|回族|维吾尔', '')
china['prov_name']
生成一个“prov_name”,和疫情数据中“prov”对应。这样合并。
data_with_geometry = pd.merge(left = china_prov,
right = china,
left_on='prov',
right_on = 'prov_name',
how = 'left')
合并之后,还要改变投影方式,
data_with_geometry = gpd.GeoDataFrame(data_with_geometry, crs = 'EPSG:4326')
接下来就可以作图了。
fig, ax =plt.subplots(figsize=(12, 8))
ax = data_with_geometry.to_crs(albers_proj).plot(ax=ax,
column = 'confirm',
cmap = 'Reds',
missing_kwds = {
"color":"lightgrey",
"edgecolor":"black",
"hatch":"///"
})
只不过这样的作图方式,湖北省颜色唯一最深的,其他地区都一样,没有层次。
所以设置一下scheme。
fig, ax = plt.subplots(figsize=(12, 8))
ax = data_with_geometry.to_crs(albers_proj).plot(ax=ax,
column = 'confirm',
cmap = 'Reds',
legend = True,
scheme = 'NaturalBreaks',
k = 5 ,
legend_kwds = {
"loc":"lower left",
"title":'确诊数量分级',
"shadow":True
})
这样就ok了。
这个过程关键就是合并地图数据和分析数据。geopandas就是强,直接和。非常方便。