寫在前面的話
在《詩經·秦風》中有一篇叫做《無衣》的詩歌,其中這樣寫道:豈曰無衣?與子同袍,與子同仇!豈曰無衣?與子同澤,與子偕作!豈曰無衣?與子同裳,與子偕行!這句話的意思就是:誰說沒有衣裳?和你穿同樣的戰袍,和你同仇敵愾!誰說沒有衣裳?和你穿同樣的內衣,和你共同作準備!誰說沒有衣裳?和你穿同樣的戰裙,和你共同上前線!
新型冠狀病毒感染引發肺炎疫情,各地物資緊急調配馳援武漢,全力以赴,堅決打贏疫情防控的阻擊戰。豈曰無衣?與子同袍、與子同澤、與子同裳!我們的故事便從這裏開始說起……
目錄
一、數據分析
首先我們需要找到新冠肺炎的實時數據,類似於支付寶上每天更新的實時數據(由於沒有找到支付寶的實時更新數據,這裏使用騰訊網的實時更新數據,也可以使用其他網站數據)。
下面便以谷歌瀏覽器爲例進行說明,使用快捷鍵“F12”之後刷新頁面,出現如下界面。
通過分析發現,以下的兩部分爲需要的數據。
於是我們得到了需要的url等基本信息,根據獲得的信息,我們可以先打印出數據進行查看。
import time
import json
import requests
ts = int(time.time()*1000) # 時間戳
data_url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=&_=%d'%ts
print("url:" + data_url)
data = json.loads(requests.get(url=data_url).json()['data']) # requests庫獲取數據
data = data['areaTree'][0]['children']
print(data)
部分結果如下:
url:https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=&_=1583757380728
[{'name': '湖北', 'today': {'confirm': 36, 'confirmCuts': 0, 'isUpdated': True, 'tip': ''}, 'total': {'confirm': 67743, 'suspect': 0, 'dead': 3007, 'deadRate': '4.44', 'showRate': False, 'heal': 46433, 'healRate': '68.54', 'showHeal': True}, 'children': [{'name': '武漢', 'today': {'confirm': 36, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 49948, 'suspect': 0, 'dead': 2388, 'deadRate': '4.78', 'showRate': False, 'heal': 30933, 'healRate': '61.93', 'showHeal': True}}, {'name': '孝感', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 3518, 'suspect': 0, 'dead': 126, 'deadRate': '3.58', 'showRate': False, 'heal': 3057, 'healRate': '86.90', 'showHeal': True}}, {'name': '黃岡', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 2907, 'suspect': 0, 'dead': 125, 'deadRate': '4.30', 'showRate': False, 'heal': 2641, 'healRate': '90.85', 'showHeal': True}}, {'name': '荊州', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 1580, 'suspect': 0, 'dead': 49, 'deadRate': '3.10', 'showRate': False, 'heal': 1410, 'healRate': '89.24', 'showHeal': True}}, {'name': '鄂州', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 1394, 'suspect': 0, 'dead': 54, 'deadRate': '3.87', 'showRate': False, 'heal': 1030, 'healRate': '73.89', 'showHeal': True}}, {'name': '隨州', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 1307, 'suspect': 0, 'dead': 44, 'deadRate': '3.37', 'showRate': False, 'heal': 1104, 'healRate': '84.47', 'showHeal': True}}, {'name': '襄陽', 'today': {'confirm': 0, 'confirmCuts': 0, 'isUpdated': True}, 'total': {'confirm': 1175, 'suspect': 0, 'dead': 38, 'deadRate': '3.23', 'showRate': False, 'heal': 1064, 'healRate': '90.55', 'showHeal': True}},...
二、獲取數據
既然可以通過如此簡單的方法獲取數據,我們接下來就需要獲取我們需要的數據。
1、首先需要獲取每天的數據。
def get_everyday_data(everyday_data_url):
'''
獲取每天的數據
:param everyday_data_url: 存放每天數據的路徑
:return: 返回每天的數據列表,分確診、疑似、死亡和治癒
'''
data = json.loads(requests.get(url=everyday_data_url).json()['data']) # 獲取數據
data.sort(key=lambda x: x['date']) # 將數據按照時間升序排序
# 定義相關數據列表:日期列表、確診列表、疑似列表、死亡列表、治癒列表
date_list, confirm_list, suspect_list, dead_list, heal_list = list(), list(), list(), list(), list()
# 迭代數據,得到需要的數據
for item in data:
month, day = item['date'].split('/')
date_list.append(datetime.strptime('2020-%s-%s' % (month, day), '%Y-%m-%d')) # 格式化日期
confirm_list.append(int(item['confirm']))
suspect_list.append(int(item['suspect']))
dead_list.append(int(item['dead']))
heal_list.append(int(item['heal']))
return date_list, confirm_list, suspect_list, dead_list, heal_list
2、獲取各區域確診分佈數據。
def get_area_distribution_data(area_distribution_data_url):
'''
獲取各區域確診分佈數據
:param area_distribution_data_url: 存放區域分佈數據的路徑
:return: 返回各區域確診的字典數據
'''
result_data = {} # 存儲結果數據的字典
data = json.loads(requests.get(url=area_distribution_data_url).json()['data'])['areaTree'][0]['children'] # 獲取數據
# 迭代數據,獲取需要的數據
for item in data:
if item['name'] not in result_data: # 將區域名稱設置爲字典的key
result_data.update({item['name']: 0})
for city_data in item['children']: # 將確診數據作爲字典的value
result_data[item['name']] += int(city_data['total']['confirm'])
return result_data
三、繪製疫情圖
使用matplotlib庫進行疫情圖的繪製,主代碼如下:
1、繪製每日疫情曲線圖
def plot_curve_graph():
'''
繪製每日疫情曲線圖
:return:
'''
date_list, confirm_list, suspect_list, dead_list, heal_list = get_everyday_data(everyday_data_url) # 獲取每天的數據
# 設置標題等相關參數
plt.figure('2019-nCoV疫情統計圖表', facecolor='#f4f4f4', figsize=(10, 8))
plt.title('2019-nCoV疫情曲線', fontsize=20)
# 畫圖
plt.plot(date_list, confirm_list, label='確診')
plt.plot(date_list, suspect_list, label='疑似')
plt.plot(date_list, heal_list, label='治癒')
plt.plot(date_list, dead_list, label='死亡')
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m-%d')) # 格式化時間
plt.gcf().autofmt_xdate() # 優化標註,添加自動傾斜功能
plt.grid(linestyle=':') # 顯示網格
plt.legend() # 顯示圖例
plt.savefig('2019-nCoV疫情曲線.png') # 保存爲文件
2、繪製各區域確診分佈圖
def plot_distribution_graph(province_positions):
'''
繪製各區域確診分佈圖
:param province_positions: 各省位置
:return:
'''
data = get_area_distribution_data(area_distribution_data_url) # 獲取各區域確診分佈數據
# 相關參數設置
width, height, rect, lat_min, lat_max, lon_min, lon_max = 1600, 800, [0.1, 0.12, 0.8, 0.8], 0, 60, 77, 140
# 經緯投影替換爲如下設置
# width, height, rect, lat_min, lat_max, lon_min, lon_max = 3000, 1500, [0, 0, 1, 1], -90, 90, 0, 360
# 匹配圖例顏色
handles = [
matplotlib.patches.Patch(color='#ffaa85', alpha=1, linewidth=0),
matplotlib.patches.Patch(color='#ff7b69', alpha=1, linewidth=0),
matplotlib.patches.Patch(color='#bf2121', alpha=1, linewidth=0),
matplotlib.patches.Patch(color='#7f1818', alpha=1, linewidth=0),
]
# 設置圖例標籤
labels = ['1-9人', '10-99人', '100-999人', '>1000人']
fig = matplotlib.figure.Figure()
# 設置繪圖板尺寸
fig.set_size_inches(width / 100, height / 100)
axes = fig.add_axes(rect)
# 局部蘭博託投影
# m = Basemap(projection='lcc', llcrnrlon=77, llcrnrlat=14, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45,
# lon_0=100, ax=axes)
# 全局蘭博託投影
# m = Basemap(projection='lcc', llcrnrlon=80, llcrnrlat=0, urcrnrlon=140, urcrnrlat=51, lat_1=33, lat_2=45,
# lon_0=100, ax=axes)
# 局部圓柱投影
# m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes)
# 正射投影
# m = Basemap(projection='ortho', lat_0=36, lon_0=102, resolution='l', ax=axes)
# 經緯投影
m = Basemap(llcrnrlon=lon_min, urcrnrlon=lon_max, llcrnrlat=lat_min, urcrnrlat=lat_max, resolution='l', ax=axes)
m.etopo()
# 讀取shape文件,shape文件主要的作用是:畫海陸分界線、國界線、行政分界線。
m.readshapefile('files/shapefiles/china', 'province', drawbounds=True)
m.readshapefile('files/shapefiles/china_nine_dotted_line', 'section', drawbounds=True)
m.drawcoastlines(color='black') # 洲際線
m.drawcountries(color='black') # 國界線
m.drawparallels(np.arange(lat_min, lat_max, 10), labels=[1, 0, 0, 0]) # 畫經度線
m.drawmeridians(np.arange(lon_min, lon_max, 10), labels=[0, 0, 0, 1]) # 畫緯度線
for p_info, p_shape in zip(m.province_info, m.province): # 分析shape文件,得到相關省數據
p_name = p_info['OWNER'].strip('\x00')
f_cname = p_info['FCNAME'].strip('\x00')
if p_name != f_cname: # 不繪製海島
continue
for key in data.keys(): # 設置不同數據範圍區域的顏色
if key in p_name:
if data[key] == 0:
color = '#f0f0f0'
elif data[key] < 10:
color = '#ffaa85'
elif data[key] < 100:
color = '#ff7b69'
elif data[key] < 1000:
color = '#bf2121'
else:
color = '#7f1818'
break
# 添加設置的顏色至地圖中
poly = Polygon(p_shape, facecolor=color, edgecolor=color)
axes.add_patch(poly)
pos = province_positions[p_name]
text = p_name.replace("自治區", "").replace("特別行政區", "").replace("壯族", "").replace("維吾爾", "")\
.replace("回族", "").replace("省", "").replace("市", "") # 替換省級名稱
# 指定字庫並設置字體大小
font15 = FontProperties(fname='files/fonts/simsun.ttf', size=15)
font10 = FontProperties(fname='files/fonts/simsun.ttf', size=10)
pset = set()
if text not in pset:
x, y = m(pos[0], pos[1])
axes.text(x, y, text, fontproperties=font10, color='#00FFFF')
pset.add(text)
axes.legend(handles, labels, bbox_to_anchor=(0.5, -0.11), loc='lower center', ncol=4, prop=font15)
axes.set_title("2019-nCoV疫情地圖", fontproperties=font15)
FigureCanvasAgg(fig)
fig.savefig('2019-nCoV疫情地圖.png')
四、測試
1、主函數如下:
if __name__ == '__main__':
ts = int(time.time() * 1000) # 時間戳
# 存放每天數據的路徑
everyday_data_url = 'https://view.inews.qq.com/g2/getOnsInfo?name=wuwei_ww_cn_day_counts&callback=&_=%d' % ts
# 存放區域分佈數據的路徑
area_distribution_data_url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5&callback=&_=%d' % ts
# 各省位置
province_positions = {
"遼寧省": [121.7, 40.9],
"吉林省": [124.5, 43.5],
"黑龍江省": [125.6, 46.5],
"北京市": [116.0, 39.9],
"天津市": [117.0, 38.7],
"內蒙古自治區": [110.0, 41.5],
"寧夏回族自治區": [105.2, 37.0],
"山西省": [111.0, 37.0],
"河北省": [114.0, 37.8],
"山東省": [116.5, 36.0],
"河南省": [111.8, 33.5],
"陝西省": [107.5, 33.5],
"湖北省": [111.0, 30.5],
"江蘇省": [119.2, 32.5],
"安徽省": [115.5, 31.8],
"上海市": [121.0, 31.0],
"湖南省": [110.3, 27.0],
"江西省": [114.0, 27.0],
"浙江省": [118.8, 28.5],
"福建省": [116.2, 25.5],
"廣東省": [113.2, 23.1],
"臺灣省": [120.5, 23.5],
"海南省": [108.0, 19.0],
"廣西壯族自治區": [107.3, 23.0],
"重慶市": [106.5, 29.5],
"雲南省": [101.0, 24.0],
"貴州省": [106.0, 26.5],
"四川省": [102.0, 30.5],
"甘肅省": [103.0, 35.0],
"青海省": [95.0, 35.0],
"新疆維吾爾自治區": [85.5, 42.5],
"西藏自治區": [85.0, 31.5],
"香港特別行政區": [115.1, 21.2],
"澳門特別行政區": [112.5, 21.2]
}
plot_curve_graph() # 繪製每日疫情曲線圖
plot_distribution_graph(province_positions) # 繪製各區域確診分佈數據
2、測試結果如下:
(1)疫情曲線
(2)局部蘭博託投影
(3)全局蘭博託投影
(4)局部圓柱投影
(5)正射投影
(6)局部經緯投影
(7)全局經緯投影
五、完整代碼地址
本文代碼已上傳至GitHub,詳情請點擊此處~