Python繪製新冠肺炎疫情圖

寫在前面的話

       在《詩經·秦風》中有一篇叫做《無衣》的詩歌,其中這樣寫道:豈曰無衣?與子同袍,與子同仇!豈曰無衣?與子同澤,與子偕作!豈曰無衣?與子同裳,與子偕行!這句話的意思就是:誰說沒有衣裳?和你穿同樣的戰袍,和你同仇敵愾!誰說沒有衣裳?和你穿同樣的內衣,和你共同作準備!誰說沒有衣裳?和你穿同樣的戰裙,和你共同上前線!

       新型冠狀病毒感染引發肺炎疫情,各地物資緊急調配馳援武漢,全力以赴,堅決打贏疫情防控的阻擊戰。豈曰無衣?與子同袍、與子同澤、與子同裳!我們的故事便從這裏開始說起……


目錄

一、數據分析

二、獲取數據

三、繪製疫情圖

四、測試

五、完整代碼地址


一、數據分析

       首先我們需要找到新冠肺炎的實時數據,類似於支付寶上每天更新的實時數據(由於沒有找到支付寶的實時更新數據,這裏使用騰訊網的實時更新數據,也可以使用其他網站數據)。

       下面便以谷歌瀏覽器爲例進行說明,使用快捷鍵“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,詳情請點擊此處~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章