100行程式碼實現疫情地圖視覺化,原理是什麼?

個推2018發表於2020-05-08

前言

2020年,大家都在密切關注著疫情的進展。不少人每天醒來開啟手機的第一件事,便是檢視各地的疫情圖。你所看到的可能是這樣的:

武漢
又或者是這樣的:

丁香園
疫情進展牽動著我們的心。作為一名開發者,我們閉門在為抗擊疫情做貢獻的同時,也可以繼續深耕自己的技術。此文章旨在向大家介紹疫情地圖視覺化的原理,幫助大家深入理解echart。

核心思路

疫情圖的核心在於疫情資料整理以及疫情資料視覺化。

疫情資料整理

本文疫情資料是由網易新聞的公開資料整理而成,僅用於demo 展示。資料的具體地址已在程式碼中說明:此地址是一個 Get 請求,大家可以先複製地址到瀏覽器中檢視資料格式。請求成功後服務端響應的資料格式如下(文中僅羅列出我們需要的資料

引數 型別 備註
code int
msg String
data Object

data 裡面的引數

引數 型別 備註
list List 各地級市確診人數

Object 裡面的引數

引數 型別 備註
name String 地級市名(簡稱)
province String 省份
confirm int 確診人數

疫情資料視覺化

地圖是資料視覺化的一種常用工具,我們用地圖來展示疫情的具體分佈。本文采用的是開源的   專案,方便開發者用於地圖展示。其中,pyecharts 是一個幫助生成 Echarts 圖表的類庫;而 Echarts 則是百度開源的資料視覺化 JS 庫,支援折線圖、柱狀圖、散點圖、K線圖、餅圖、雷達圖、和絃圖、力導向佈局圖、地圖、儀表盤、漏斗圖、事件河流圖等12類圖表,並可以在 PC 和移動裝置上流暢地執行,相容當前絕大部分瀏覽器。pyecharts 是在 Python 的基礎上對 Echarts 所進行的擴充套件。

原理詳解

接下來,本文將為大家詳細說明如何搭建環境、整合資料、使用 pyecharts 來做資料視覺化以及如何除錯專案。

環境搭建

為了快速開發此功能並且儘可能地縮減程式碼量,此 demo 選擇使用 Python 來進行開發。為此,我們應該準備好Python 的開發環境並匯入python 基礎庫。

安裝 Python 環境

Mac 上面自帶了 Python2.7 ,其他機型的電腦可以參考網上相關的

安裝 pip

pip 是 Python 包管理工具,使用該工具可以快速地對Python 包予以查詢、下載、安裝、解除安裝等。如果你是在 python.org上下載的最新版本的安裝包,則系統已經自帶該工具。此外, Python 2.7.9 + 和 Python 3.4+ 以上版本都自帶 pip 工具。可以使用“pip –version”命令列來檢視當前 pip 的版本。

如果本機沒有 配置Python 環境的,我們可以線上安裝,只需要在終端輸入以下 2 行命令即可

$ curl 
$ sudo python get-pip.py

安裝工程所需要的外掛

在程式碼中大家不難發現我們匯入了一些開源的庫:

import math
import time
from fake_useragent import UserAgent 
from pyecharts.charts import Map
from pyecharts import options as opts
import requests
import json
import sys

請求網路資料需要用到的外掛:

pip install fake_useragent # 偽裝請求,隨機生成UserAgent
pip install requests # HTTP請求庫。

地圖展示需要用到的外掛:

pip install echarts-countries-pypkg  # 世界地圖
pip install echarts-china-provinces-pypkg  # 中國省級地圖
pip install echarts-china-cities-pypkg  # 中國城市地圖

我們把上述的命令列復制到終端,逐行執行即可。

資料整合& 過濾

程式碼依然簡潔明瞭,我們可以直接使用 requests 庫構建一個 GET 請求,伺服器響應的資料即為“ 全國所有城市的疫情情況”。

ua = UserAgent(verify_ssl=False)
headers = {'User-Agent': ua.random}
url = "
def getEpidemicInfo(url):
    try:
        response = requests.get(url, headers=headers)
        print(response.status_code)
        if response.status_code == 200:
            content_field = json.loads(response.text)
            epidemicInfo = content_field['data']['list']
            return epidemicInfo
        else:
            print('請求錯誤碼:' + response.status_code)
            return None
    except Exception as e:
        print('此頁有問題!', e)
        return None

請求地址裡面的 t 代表時間戳。我們輸入上述程式碼,計算機便會輸出前文所提及格式的資料。注意:拿到資料後還要進行過濾,我們僅需獲得某個省份、自治州所包含的地級市或者是某個直轄市所包含的下屬區縣的疫情資訊即可。
透過以下程式碼,我們對有關資料予以篩選:

# 生成本省疫情列表
def makedict(list):
    cityList = {}
    for item in list:
        for k, v in item.items():
        # 1
            if v == sys.argv[1]:
            #2
                if str(item["confirm"]).isdigit():
                # 3
                    if v == "北京" or v == "上海" or v == "天津":
                        cityList[item['name'] + '區'] = int(item["confirm"])
                    elif "自治州" in v:
                        continue
                    else:
                        cityList[item['name'] + '市'] = int(item["confirm"])
    return cityList
  1. sys.argv[1] 是一個傳參,代表我們手動輸入的省份、自治區、直轄市或特別行政區,比如浙江、新疆、北京、香港等;
  2. “confirm” 關鍵字用於匹配響應結果的 value 值,在上文疫情資料整合裡有提及,代表當前城市的疫情人數;
  3. pyecharts 是根據城市的全稱來適配的,此處需對資料格式中的地級市或者是下屬區縣進行排查,如果有城市採用簡稱的,需要進行除錯,(如介面返回的城市名是恩施,我們則需要適配成恩施土家族苗族自治州),從而防止地圖展示異常。

舉例來講,當我們輸入浙江時,計算機最後輸出的資料格式為:

{'湖州市': 9, '麗水市': 16, '舟山市': 7, '衢州市': 15, '金華市': 47, '嘉興市': 30, '紹興市': 33, '寧波市': 126, '台州市': 124, '杭州市': 151, '溫州市': 396}

資料視覺化

這是最核心的一步。makeEpidemicInfoMap方法裡面的 dict 對應我們過濾得到的資料:

def makeEpidemicInfoMap(dict):
    # 省和直轄市
    province_distribution = dict
    value = province_distribution.values()
    print(province_distribution)
    title = str(int(time.strftime("%Y%m%d")) - 1) + sys.argv[1] + "疫情地圖"
    epidemicCount = []
    for k, v in dict.items():
        epidemicCount.append(v)
    # 1
    epidemicCount.sort(reverse=True)
    maxEpidemic = handle(epidemicCount.pop(0))
    maxEpidemic = int(maxEpidemic)
    # 2
    map = Map()
    # 3
    map.set_global_opts(
        title_opts=opts.TitleOpts(title=title),
        visualmap_opts=opts.VisualMapOpts(max_=200, is_piecewise=True,
                                          pieces=[
                                              {"max": 9999999, "min": maxEpidemic, "label": ">" + str(maxEpidemic),
                                               "color": "#780707"},  # 資料範圍分段,分顏色,可以根據資料大小具體分配大小
                                              {"max": int(maxEpidemic), "min": int(maxEpidemic / 8) * 7,
                                               "label": str(int(maxEpidemic / 8) * 7) + "-" + str(int(maxEpidemic)),
                                               "color": "#B40404"},
                                              {"max": int(maxEpidemic / 8) * 7, "min": int(maxEpidemic / 8) * 4,
                                               "label": str(int(maxEpidemic / 8) * 4) + "-" + str(
                                                   int(maxEpidemic / 8) * 7 - 1), "color": "#CD1111"},
                                              {"max": int(maxEpidemic / 8) * 4, "min": int(maxEpidemic / 8),
                                               "label": str(int(maxEpidemic / 8)) + "-" + str(
                                                   int(maxEpidemic / 8) * 4 - 1), "color": "#F68181"},
                                              {"max": int(maxEpidemic / 8), "min": 1,
                                               "label": "1-" + str(int(maxEpidemic / 8)), "color": "#F5A9A9"},
                                              {"max": 0, "min": 0, "label": "0", "color": "#FFFFFF"},
                                          ], )  # 最大資料範圍,分段
    )
    # 4
    map.add(title, data_pair=province_distribution.items(), maptype=sys.argv[1], is_roam=True)
    map.render(sys.argv[1] + '疫情地圖.html')
  1. 根據所選省份各城市的確診人數對所有城市進行降序並得到當前省份確診人數最多的城市名稱。maxEpidemic 是最接近該城市確診人數的高位數,比如當前省份疫情最為嚴重的城市的確診數量為“357”,則 maxEpidemic=300 ,引入此引數的目的是讓地圖呈現效果更加清晰直觀。
  2. 用PyEcharts繪製地圖需要對Map物件進行初始化,以用於地理區域資料的視覺化。
  3. 以建造者模式對 map 進行設值,其中,VisualMapOpts 是 PyEcharts 的視覺對映配置項。
    # 指定 visualMapPiecewise 元件的最大值。
    max =100
    # 是否為分段型
    is_piecewise: bool = False,
 
    # 自定義的每一段的範圍,以及每一段的文字,以及每一段的特別的樣式。例如:
    # pieces: [
    #   {"min": 1500}, // 不指定 max,表示 max 為無限大(Infinity)。
    #   {"min": 900, "max": 1500},
    #   {"min": 310, "max": 1000},
    #   {"min": 200, "max": 300},
    #   {"min": 10, "max": 200, "label": '10 到 200(自定義label)'},
    #   {"value": 123, "label": '123(自定義特殊顏色)', "color": 'grey'}, //表示 value 等於 123 的情況
    #   {"max": 5}     // 不指定 min,表示 min 為無限大(-Infinity)。
    # ]

詳細配置可以見 PyEcharts 官網。此處的範圍分為6 段,每一段的範圍均是根據上述計算出來的 maxEpidemic 進行動態調整的,目的是為了保證疫情圖的視覺效果,這 裡面我僅是做了非常簡略的範圍模型,僅供參考
4. 使用 PyEcharts 在當前目錄下面生成一個網頁

除錯

執行 python map.py [省份],如:

python /Users/xxx/map.py 浙江

會在當前目錄下面得到一份名字為  浙江疫情地圖.html 的檔案,直接使用瀏覽器開啟即可,最後的展示效果是不是很酷
浙江

福建
廣東

總結

讀完此篇文章,希望大家可以對資料視覺化有個初步的瞭解。全民戰“疫”期間,個推服務的腳步不會停歇,我們將一如既往地為開發者提供技術支援。此外,個推“防災速報”小程式還上線了 “新型肺炎疫情實時動態”新功能,為大家進行疫情防護提供可靠的資料支援。

在這裡插入圖片描述


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556026/viewspace-2690759/,如需轉載,請註明出處,否則將追究法律責任。

相關文章