Python模組—製作新冠疫情世界地圖()

pyecharts模組

簡介

Echarts 是一個由百度開源的數據可視化,憑藉著良好的交互性,精巧的圖表設計,得到了眾多開發者的認可。而 Python 是一門富有表達力的語言,很適合用於數據處理。當數據分析遇上數據可視化時,pyecharts 誕生了。
如果想要掌握pyecharts,可以閱讀pyecharts中文文檔,裡面的圖表類型和配置項寫的非常詳細,我就不過多的贅述了

安裝pyecharts

安裝的命令也非常簡單:

pip install pyecharts

安裝成功:

測試pyecharts模組

我們可以嘗試運行官方文檔所給出的幾個小例子來測試一下pyecharts模組是否成功安裝
打開編輯器,輸入並運行以下程式碼:

from pyecharts.charts import Bar
from pyecharts import options as opts
# 內置主題類型可查看 pyecharts.globals.ThemeType
from pyecharts.globals import ThemeType

bar = (
    Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))
    .add_xaxis(["襯衫", "羊毛衫", "雪紡衫", "褲子", "高跟鞋", "襪子"])
    .add_yaxis("商家A", [5, 20, 36, 10, 75, 90])
    .add_yaxis("商家B", [15, 6, 45, 20, 35, 66])
    .set_global_opts(title_opts=opts.TitleOpts(title="主標題", subtitle="副標題"))
)
bar.render()   #保存為html文件

若此時在當前目錄下生成了一個名為render.html的文件

打開此文件,看到如下的圖片則證明安裝模組成功

pyecharts實戰:繪製新冠肺炎疫情地圖

需求分析

想要製作全球疫情的地圖(空氣品質圖,人口分布圖也是同理),首先需要的就是每個國家的疫情數據,比如人數,治癒數,增長數…… 那麼我們該如何獲取到這些資訊呢?

請求數據

我們發現很多app和網頁上都會有最新的疫情資訊公布,我選取的數據來源是騰訊地圖。
首先打開騰訊地圖的疫情資訊頁,可以發現疫情的資訊展現在這一頁中

獲取這些資訊的方法有很多種,可以是用表達式提取,也可以抓包分析,我更喜歡的一種方法是抓包分析。

右擊《檢查》,點擊《network》選項卡並刷新介面,看到載入出來很多數據包,找到裡面最像列表的一個list數據包

此時發現,這個list數據包正式我們要提取的數據列表,裡面的每個鍵值對都代表著相應的數據,提取到這些鍵值對就可以獲取到所有的數據資訊了,再次回到headers,選項卡下面對應的網址就是我們即將請求的網址,這裡我們需要注意的是,這個網址對應的請求是post而不是我們經常使用的get

向網頁請求數據:

import requests

url = '//api.inews.qq.com/newsqa/v1/automation/foreign/country/ranklist'
response = requests.post(url).text
print(response)

可以看到這個網頁並沒有設置反爬蟲,可以輕鬆的獲取到數據

提取數據

我們剛剛請求到的數據格式是字元格式,並不能被我們直接提取到,必須想將字元格式的數據轉換為字典格式才可以開始下一步的提取

resp = json.loads(response)   #使用變數resp來接收字典格式的數據

將變數轉化為字典格式後,就要開始提取數據了 提取json類型的數據可以使用取出列表元素的方法來提取,即先遍歷列表將每個國家的資訊提取出來,再分別從這些條資訊中提取到我們想要的數據

提取數據:

import json

resp = json.loads(response)   #使用變數resp來接收字典格式的數據
for data in resp['data']:  #遍歷提取每個國家的疫情數據
    name = data['name']   #國家名
    confirm = data['confirm']   #該國家疫情人數
    print(name,confirm)

列印數據:

處理數據

在得到了國家和人數資訊之後,還需要將數據存儲到字典中才能傳入圖表中,這就需要我們手動的轉換數據,並儲存到字典中

map_version = {}  #定義空字典
for data in resp['data']:  #遍歷提取每個國家的疫情數據
    name = data['name']   #國家名
    confirm = data['confirm']   #該國家疫情人數
    map_version[name] = int(confirm)  #將國家和人數以鍵值對的形式傳入字典

輸出字典:

此時列印出來的字典是標準的字典格式,但是這種格式並不是pyecharts所要求的格式,所以還需要一行程式碼來進行轉換

element = list(map_version.items())

然後就可以輸出傳入數據的標準格式:

製作可視化地圖

在將數據爬取、變換、整理後,所有準備工作都已經做完,下面我們來調用數據實現數據可視化

先寫出一個初步的框架來接收內容

from pyecharts.charts import Map,Geo

map = Map().add(series_name="世界疫情分布圖",  #名稱
                data_pair=element,   #傳入數據
                maptype='world',   #地圖類型
                )
map.render('map.html')  #命名並保存

運行程式碼,發現當前文件夾下出現了一個map.html文件,雙擊運行

看到這個圖表之後,發現程式碼的運行並沒有問題,但是數據卻沒有傳到地圖中,這是由於pyecharts默認的世界地圖中的國家名是英文,所以我們就要傳入一個字典來替代掉這些英文

設置可視化地圖

生成了地圖之後,接下來就是要保證地圖的正確性和美觀,所以我們要來設置世界地圖

地圖上顯示國家名太多,影響可讀性,所以設置為不顯示國家名

from pyecharts import options

map.set_series_opts(label_opts=options.LabelOpts(is_show=False))  #不顯示國家名

按照感染人數的不同,給地圖添加不同的顏色

#設置全局配置項
map.set_global_opts(visualmap_opts=options.VisualMapOpts(max_=1100000,is_piecewise=True,pieces=[
                 {"min": 500000},
                 {"min": 200000, "max": 499999},
                 {"min": 100000, "max": 199999},
                 {"min": 50000, "max": 99999},
                 {"min": 10000, "max": 49999},
                 {"max": 9999},]))

代表國家首都的圓點不美觀,去掉紅點:

map = Map().add(
                                    is_map_symbol_show=False,  #不顯示標記
                                    )

設置背景顏色並為網頁取名:

map = Map(options.InitOpts(bg_color="#87CEFA",page_title='世界疫情分布')).add()

到了現在所有的配置已經完成,但是圖表要想顯示數據還需要傳入一個字典來替換掉默認的英文名,具體實現請看下面的完整程式碼。

完整程式碼

import requests
import json
from pyecharts.charts import Map
from pyecharts import options

url = '//api.inews.qq.com/newsqa/v1/automation/foreign/country/ranklist'
response = requests.post(url).text
resp = json.loads(response)   #使用變數resp來接收字典格式的數據
map_version = {}  #定義空字典
for data in resp['data']:  #遍歷提取每個國家的疫情數據
    name = data['name']   #國家名
    confirm = data['confirm']   #該國家疫情人數
    map_version[name] = int(confirm)  #將國家和人數以鍵值對的形式傳入字典
element = list(map_version.items())   #將字典值調整為可以傳入地圖的格式
name_map = {
    'Singapore Rep.': '新加坡',
    'Dominican Rep.': '多米尼加',
    'Palestine': '巴勒斯坦',
    'Bahamas': '巴哈馬',
    'Timor-Leste': '東帝汶',
    'Afghanistan': '阿富汗',
    'Guinea-Bissau': '幾內亞比索',
    "Côte d'Ivoire": '象牙海岸',
    'Siachen Glacier': '錫亞琴冰川',
    "Br. Indian Ocean Ter.": '英屬印度洋領土',
    'Angola': '安哥拉',
    'Albania': '阿爾巴尼亞',
    'United Arab Emirates': '阿聯酋',
    'Argentina': '阿根廷',
    'Armenia': '亞美尼亞',
    'French Southern and Antarctic Lands': '法屬南半球和南極領地',
    'Australia': '澳大利亞',
    'Austria': '奧地利',
    'Azerbaijan': '亞塞拜然',
    'Burundi': '蒲隆地',
    'Belgium': '比利時',
    'Benin': '貝南',
    'Burkina Faso': '布吉納法索',
    'Bangladesh': '孟加拉國',
    'Bulgaria': '保加利亞',
    'The Bahamas': '巴哈馬',
    'Bosnia and Herz.': '波士尼亞赫塞哥維納',
    'Belarus': '白俄羅斯',
    'Belize': '貝里斯',
    'Bermuda': '百慕大',
    'Bolivia': '玻利維亞',
    'Brazil': '巴西',
    'Brunei': '汶萊',
    'Bhutan': '不丹',
    'Botswana': '波札那',
    'Central African Rep.': '中非',
    'Canada': '加拿大',
    'Switzerland': '瑞士',
    'Chile': '智利',
    'China': '中國',
    'Ivory Coast': '象牙海岸',
    'Cameroon': '喀麥隆',
    'Dem. Rep. Congo': '剛果民主共和國',
    'Congo': '剛果',
    'Colombia': '哥倫比亞',
    'Costa Rica': '哥斯大黎加',
    'Cuba': '古巴',
    'N. Cyprus': '北塞普勒斯',
    'Cyprus': '塞普勒斯',
    'Czech Rep.': '捷克',
    'Germany': '德國',
    'Djibouti': '吉布地',
    'Denmark': '丹麥',
    'Algeria': '阿爾及利亞',
    'Ecuador': '厄瓜多',
    'Egypt': '埃及',
    'Eritrea': '厄利垂亞',
    'Spain': '西班牙',
    'Estonia': '愛沙尼亞',
    'Ethiopia': '衣索比亞',
    'Finland': '芬蘭',
    'Fiji': '斐',
    'Falkland Islands': '福克蘭群島',
    'France': '法國',
    'Gabon': '加彭',
    'United Kingdom': '英國',
    'Georgia': '喬治亞',
    'Ghana': '迦納',
    'Guinea': '幾內亞',
    'Gambia': '甘比亞',
    'Guinea Bissau': '幾內亞比索',
    'Eq. Guinea': '赤道幾內亞',
    'Greece': '希臘',
    'Greenland': '格陵蘭',
    'Guatemala': '瓜地馬拉',
    'French Guiana': '法屬蓋亞那',
    'Guyana': '蓋亞那',
    'Honduras': '宏都拉斯',
    'Croatia': '克羅埃西亞',
    'Haiti': '海地',
    'Hungary': '匈牙利',
    'Indonesia': '印度尼西亞',
    'India': '印度',
    'Ireland': '愛爾蘭',
    'Iran': '伊朗',
    'Iraq': '伊拉克',
    'Iceland': '冰島',
    'Israel': '以色列',
    'Italy': '義大利',
    'Jamaica': '牙買加',
    'Jordan': '約旦',
    'Japan': '日本',
    'Kazakhstan': '哈薩克',
    'Kenya': '肯亞',
    'Kyrgyzstan': '吉爾吉斯斯坦',
    'Cambodia': '柬埔寨',
    'Korea': '韓國',
    'Kosovo': '科索沃',
    'Kuwait': '科威特',
    'Lao PDR': '寮國',
    'Lebanon': '黎巴嫩',
    'Liberia': '賴比瑞亞',
    'Libya': '利比亞',
    'Sri Lanka': '斯里蘭卡',
    'Lesotho': '賴索托',
    'Lithuania': '立陶宛',
    'Luxembourg': '盧森堡',
    'Latvia': '拉脫維亞',
    'Morocco': '摩洛哥',
    'Moldova': '摩爾多瓦',
    'Madagascar': '馬達加斯加',
    'Mexico': '墨西哥',
    'Macedonia': '馬其頓',
    'Mali': '馬里',
    'Myanmar': '緬甸',
    'Montenegro': '黑山',
    'Mongolia': '蒙古',
    'Mozambique': '莫三比克',
    'Mauritania': '茅利塔尼亞',
    'Malawi': '馬拉維',
    'Malaysia': '馬來西亞',
    'Namibia': '納米比亞',
    'New Caledonia': '新喀里多尼亞',
    'Niger': '尼日',
    'Nigeria': '奈及利亞',
    'Nicaragua': '尼加拉瓜',
    'Netherlands': '荷蘭',
    'Norway': '挪威',
    'Nepal': '尼泊爾',
    'New Zealand': '紐西蘭',
    'Oman': '阿曼',
    'Pakistan': '巴基斯坦',
    'Panama': '巴拿馬',
    'Peru': '秘魯',
    'Philippines': '菲律賓',
    'Papua New Guinea': '巴布亞紐幾內亞',
    'Poland': '波蘭',
    'Puerto Rico': '波多黎各',
    'Dem. Rep. Korea': '朝鮮',
    'Portugal': '葡萄牙',
    'Paraguay': '巴拉圭',
    'Qatar': '卡達',
    'Romania': '羅馬尼亞',
    'Russia': '俄羅斯',
    'Rwanda': '盧安達',
    'W. Sahara': '西撒哈拉',
    'Saudi Arabia': '沙烏地阿拉伯',
    'Sudan': '蘇丹',
    'S. Sudan': '南蘇丹',
    'Senegal': '塞內加爾',
    'Solomon Is.': '索羅門群島',
    'Sierra Leone': '獅子山',
    'El Salvador': '薩爾瓦多',
    'Somaliland': '索馬利亞蘭',
    'Somalia': '索馬利亞',
    'Serbia': '塞爾維亞',
    'Suriname': '蘇利南',
    'Slovakia': '斯洛伐克',
    'Slovenia': '斯洛維尼亞',
    'Sweden': '瑞典',
    'Swaziland': '史瓦濟蘭',
    'Syria': '敘利亞',
    'Chad': '查德',
    'Togo': '多哥',
    'Thailand': '泰國',
    'Tajikistan': '塔吉克',
    'Turkmenistan': '土庫曼',
    'East Timor': '東帝汶',
    'Trinidad and Tobago': '特里尼達和多巴哥',
    'Tunisia': '突尼西亞',
    'Turkey': '土耳其',
    'Tanzania': '坦尚尼亞',
    'Uganda': '烏干達',
    'Ukraine': '烏克蘭',
    'Uruguay': '烏拉圭',
    'United States': '美國',
    'Uzbekistan': '烏茲別克',
    'Venezuela': '委內瑞拉',
    'Vietnam': '越南',
    'Vanuatu': '萬那杜',
    'West Bank': '西岸',
    'Yemen': '葉門',
    'South Africa': '南非',
    'Zambia': '尚比亞',
    'Zimbabwe': '辛巴威',
    'Comoros': '葛摩'
}

map = Map(options.InitOpts(bg_color="#87CEFA",page_title='世界疫情分布')).\
    add(series_name="世界疫情分布圖",  #名稱
        data_pair=element,   #傳入數據
        is_map_symbol_show=False,  #不顯示標記
        maptype='world',   #地圖類型
        name_map=name_map,
        )
#設置全局配置項
map.set_global_opts(visualmap_opts=options.VisualMapOpts(max_=1100000,is_piecewise=True,pieces=[
                 {"min": 500000},
                 {"min": 200000, "max": 499999},
                 {"min": 100000, "max": 199999},
                 {"min": 50000, "max": 99999},
                 {"min": 10000, "max": 49999},
                 {"max": 9999},]))
#設置系列配置項
map.set_series_opts(label_opts=options.LabelOpts(is_show=False))  #不顯示國家名
map.render('map.html')  #命名並保存

實現結果

這個結果可以動態的顯示在網頁中,可以根據人數來篩選地圖的板塊,而且方便縮放