经常看人家用basemap做热力图,不过basemap也比较旧了。 试试用folium。
步骤
- 通过API获取当前最新信息
- 根据城市编码查找城市的经纬度数据
- 记录城市的经纬度和对应的数值生成数据集
- 通过工具生成地图
1、获取数据:
这里我选用的是新浪的API:
https://interface.sina.cn/news/wap/fymap2020_data.d.json
可以看到data中第一级参数有 times, mtime, gntotal. list 等等表示数据时间患病人数之类的。 这里我们先只做国内的热力图。
先看看数据内容的结构是怎么样的,list中显示各个省份/直辖市,下一级city显示有各省/直辖市的城市/市区的数据,这里我们取econNum查看当前确诊人数和citycode城市编号。
首先将返回的数据转换成JSON。由于本身就是JSON字符串,转换起来也相较简单。
r = requests.get(url_str, timeout=5)
r.json()
url_str就是填新浪的API.
2、查找数据:
刚才说了选择国内的信息,也就是要用‘list’这一列数据,这里我使用pandas:
import pandas as pd
df = pd.DataFrame(r.json())
# find 'list'
province_data_list = df.loc['list', 'data']
从第一张截图里你可以看到第一级是省/直辖市,第二级才是我们要的城市(city)。这里我们简单地用for去循环读取每个城市的数据。
在city里有‘citycode’这一个数据。通过这个城市编号在数据库中查找相应的经纬度,我下载的数据库是Excel格式。那我们依然用pandas获取这一列数据。
geo_df = pd.read_excel("./area.xlsx")
for index, row in geo_df.iterrows():
print( str(row['area_code']) )
pandas可以使用 iterrows()对dataframe进行遍历。iterrows()返回值为元组,(index,row)
上面的代码里,for循环定义了两个变量 index,row,那么返回的元组,index=index,row=row.
我这里只需要row。里面就是具体城市的地理数据了。
3、生成folium数据集:
在新浪的接口里返回的citycode显示着各个省/城市/地区的编号,只不过开头是大写的CN,而且后面是以0填充到一定长度。那只需忽略开头的CN并且只匹配开头。如果匹配成功,获取Excel中的对应经度纬度。和患病人数一起组成列表,跳出循环。
这个数组是给folium 的 Heatmap函数使用的。Heatmap的第一个参数为数值集合,类型是列表 list,集合中每个子元素也是一个list。格式为:[经度, 纬度, 范围]
def get_fymap_data(url_str):
r = requests.get(url_str, timeout=5)
""" to pandas dataframe """
# load json
df = pd.DataFrame(r.json())
# find 'list'
province_data_list = df.loc['list', 'data']
heatmap_list = []
# load xlsx
geo_df = pd.read_excel("./area.xlsx")
for data_list in province_data_list:
# ignore empty list
if len(data_list['city']) != 0:
for city_dict in data_list['city']:
# find city/area
if city_dict['citycode'] != "" and city_dict['conNum'] != "0":
for index, row in geo_df.iterrows():
a = str(city_dict['citycode'])
b = str(row['area_code'])
if a.startswith('CN' + b):
# heatmap data : [lat, lon, range]
heat_data = [round(row['lat'], 3), round(row['lon'], 3), float(city_dict['econNum'])]
heatmap_list.append( heat_data )
break
return heatmap_list
这里就返回了相应的列表。
map_data = get_fymap_data("https://interface.sina.cn/news/wap/fymap2020_data.d.json")
map_osm = folium.Map(location=[35,110],zoom_start=5)
HeatMap(map_data, name="coronavirus", min_opacity=0.8).add_to(map_osm)
file_path = r"./test.html"
map_osm.save(file_path)
将地图坐标定位到中国,这样一打开就可以定位到我们想到的地方:
map_osm = folium.Map(location=[35,110],zoom_start=5)
加载数据:
HeatMap(map_data, name="coronavirus", min_opacity=0.8).add_to(map_osm)
最后生成html文件。
源文件:
https://github.com/elihe999/Eli_observations/blob/master/python/c19map/download_map.py