COVID19 data 數據集分析 (4) --Bar Race (python製做動態排名視頻)

前言

上一篇咱們對數據進行了從新佈局,佈局後的數據結構方便咱們進行柱狀圖可視化以及彈道分析。html

今天咱們來學習使用該數據集執着更酷炫的動態排名視頻。python

先看效果:api

一如既往,直奔代碼。

準備數據源

數據源就是咱們一直分析的COVID19 data 數據,能夠去kaggle 下載。數組

導入咱們所需的庫,相比於以前的文章,咱們本次分析會用到animation模塊,重點是裏面會提供FuncAnimation 類,幫助咱們實現動態圖。bash

# coding: utf-8
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.animation as animation
from datetime import datetime, timedelta
import numpy as np
複製代碼

pandas 讀取數據,這是每篇分析的第一步操做。 簡單處理數據,採用groupby 函數將一些國家的各個省份信息合併成該國家的總和。 前一篇文章有詳細介紹,此處再也不說明。數據結構

# read data
covid19_data_file = 'data/COVID_19_data.csv'
covid19_data_df = pd.read_csv(covid19_data_file)
# handle the countries data
df_country = covid19_data_df.groupby(
    ['ObservationDate', 'Country/Region']).sum()
df_country.reset_index(inplace=True)
複製代碼

動態視頻思路-FuncAnimation

你們都知道,視頻就是一堆堆圖像(或者稱爲幀 frame)在時間軸上連續起來造成的。因此咱們的思路也很簡單,製做一個畫面,改變畫面的內容,重複製做這個畫面。ide

matplotlib 已經有這個類:FuncAnimation,它用來重複調用一個函數進行畫圖。咱們來研究一下它的主要參數,更詳細的請參考官方文檔。函數

class matplotlib.animation.FuncAnimation(fig, func, frames=None, init_func=None, fargs=None, save_count=None, *, cache_frame_data=True, **kwargs)[source複製代碼

其中主要的參數:佈局

  • fig: 就是matplotlib的Figure 對象。
  • func: 就是須要重複調用的函數。對於咱們這個案例來講,須要重複的事情就是「畫(水平)柱狀圖」。因此咱們須要定義個畫水平柱狀圖的函數。這也是本文的重點。
  • frames: 就是可迭代的對象,假如咱們賦值爲整數n,就是用range(n)來創造迭代對象
  • init_func: 相似於func,若是你的第一幀畫面須要調用不一樣的函數,可選此參數
  • fargs: func 函數的其餘參數(除去frames 必須做爲第一個位置參數)
  • 其餘參數:略

爲了調用這個函數,咱們須要準備好各個參數。post

  • 採用subplots 建立Figure 對象,命名爲fig。
  • 調用datetime,設置須要動態顯示的起止日期,而且計算出delta 時間。該值咱們將做爲frames 參數傳遞給FuncAnimation函數。
  • 剩下就是重中之重,func 函數以及fargs 參數
fig, ax = plt.subplots(figsize=(15, 8))
start_date = datetime(2020, 1, 22)
end_date = datetime(2020, 5, 13)
dates_delta = (end_date - start_date).days
複製代碼

每一幀畫面的繪製函數func

先上代碼,再作解釋。

def mini_bar_chart_frame(
        delta,
        df=None,
        start_date=None,
        date_col=None,
        cat_col=None,
        observe_col=None,
        top_k=10,
        ax=None):
    if start_date is None:
        start_date = datetime(2020, 2, 22)
    date_show = timedelta(days=delta) + start_date
    date_str = date_show.strftime('%m/%d/%Y')
    top_k_df = df[df[date_col].eq(date_str)].sort_values(
        by=observe_col, ascending=False).head(top_k)
    ax.clear()
    # plot horizon bar
    ax.barh(
        top_k_df[cat_col],
        top_k_df[observe_col],
        log=False)
    ax.invert_yaxis()  # to make the biggest in the top
    #dx = np.log(top_k_df[observe_col].max()) / 200
    for i, (value, name) in enumerate(
            zip(top_k_df[observe_col], top_k_df[cat_col])):
        ax.text(
            value - 20,
            i,
            name,
            size=10,
            weight=600,
            ha='right',
            va='center')
        ax.text(
            value + 0.1,
            i,
            f'{value:,.0f}',
            size=10,
            ha='left',
            va='center')
    ax.text(
        1,
        0.1,
        date_str,
        transform=ax.transAxes,
        size=40,
        ha='right',
        weight=800)
    ax.set_yticks([])  # we have label on the top of bar
複製代碼

代碼中咱們主要實現一下內容:

  • 整理數據,選出天天top10的國家,而且降序排列
  • 繪製barh,水平繪製時,須要反轉y軸,使得最大值排在第一位。也就是上圖中第1部份內容繪製完畢
  • 添加國家名稱以及對應的確診數據。也就是上圖中第2 和第3部份內容
  • 添加大寫的日期,放在右下角,也就是圖中第4部分
  • 裏面還有一些細節,好比取消掉y軸的標籤

函數準備好了,下面咱們就將函數的對應的參數傳遞給FuncAnimation。

fargs = (df_country,
         start_date,
         'ObservationDate',
         'Country/Region',
         'Confirmed',
         10,
         ax)
animator = animation.FuncAnimation(
    fig,
    mini_bar_chart_frame,
    frames=dates_delta,
    fargs=fargs,
    interval=1000,
    repeat=False)
複製代碼

咱們也可使用如下代碼將其保存爲本地mp4格式。

writer = animation.writers['ffmpeg']
writer = writer(fps=1)
animator.save('mini_covid_bar_race.mp4', writer=writer)
複製代碼

咱們看一下上述代碼的輸出結果,這裏我將視頻轉成gif以作演示。基本效果已經成型,應該算是很經典的動態排名了。

來點更炫的(彩色+動態文字+xkcd)

彩色柱狀圖

給柱狀圖添加顏色,應該很好處理。barh 函數帶有color 參數,這裏僅僅須要注意傳入的顏色須要是類數組的格式。 小技巧:

  • 因爲咱們沒法爲全部的國家定義顏色,所以這裏咱們採用定義一個dict顏色集,裏面定義主要國家的顏色,而後對於沒有定義在dict中的國家,顏色採用默認。顏色代碼的獲取能夠從不少網站查詢和複製。
color_dict = {'Mainland China': '#e63946',
              'US': '#ff006e',
              'Italy': '#02c39a',
              'Span': '#f4a261',
              'UK': '#3a86ff',
              'Germany': '#370617',
              'France': '#3a86ff',
              'Japan': '#d8e2dc',
              'Iran': '#fec89a',
              'Russia': '#dc2f02'}
# barh 中的color 參數爲:
# color=[
# color_dict.get(
# x,
# "#f8edeb") for x in top_k_df[cat_col]],
複製代碼

添加動態文字

這裏我添加了一些文字來給視頻作註釋。好比3月15日,中國捐給西班牙50萬個口罩。

  • 之因此用英文,是由於最初這個視頻是我放在facebook上給老外看的。

  • 第二個緣由,是由於中文須要一些字體支持。

實現動態文字添加的思路很簡單,就是ax.text 函數。實現方法相似於咱們的國家標籤以及確診數的標籤。

timeline_event = {
    '01/30/2020': 'WuHan declared lockdown.',
    '01/31/2020': 'Italian suspended all flights from China',
    '02/02/2020': 'Trump restricts on any foreigners from entering the U.S',
    '03/13/2020': 'China sent medical supplies to Italy',
    '03/15/2020': 'China donated 500,000 facemasks to Spain',
    '03/19/2020': 'USA suspended visa services worldwide.',
    '05/12/2020': 'America first(LOL).'
}
複製代碼

添加xkcd 效果

xkcd 是啥? 只不過一個漫畫名稱而已,很差發音,也不是縮寫。對於matplotlib 來講,xkcd 就指的相似於漫畫的的效果。通俗講就是「線條抖啊抖啊抖~~~~」 代碼很簡單就一行:

with plt.xkcd():
        把全部plt相關的代碼放在這個with 裏面
複製代碼

完整的func 函數

除了添加顏色,動態文字以及「抖啊抖」的效果,咱們還作了一些細節處理,好比調整字體顏色,字號等小細節。

def xkcd_bar_chart_frame(
        delta,
        df=None,
        start_date=None,
        date_col=None,
        cat_col=None,
        observe_col=None,
        top_k=10,
        color_dict=None,
        ax=None):

    if start_date is None:
        start_date = datetime(2020, 2, 22)
    date_show = timedelta(days=delta) + start_date
    date_str = date_show.strftime('%m/%d/%Y')
    top_k_df = df[df[date_col].eq(date_str)].sort_values(
        by=observe_col, ascending=False).head(top_k)
    with plt.xkcd():
        ax.clear()
        # plot horizon bar
        ax.barh(
            top_k_df[cat_col],
            top_k_df[observe_col],
            color=[
                color_dict.get(
                    x,
                    "#f8edeb") for x in top_k_df[cat_col]],
            log=False,
            left=1)
        ax.invert_yaxis()  # to make the biggest in the top
        #dx = np.log(top_k_df[observe_col].max()) / 200
        for i, (value, name) in enumerate(
                zip(top_k_df[observe_col], top_k_df[cat_col])):
            ax.text(
                value - 20,
                i,
                name,
                size=10,
                weight=600,
                ha='right',
                va='center')
            ax.text(
                value + 0.1,
                i,
                f'{value:,.0f}',
                size=10,
                ha='left',
                va='center')
        ax.text(
            1,
            0.1,
            date_str,
            transform=ax.transAxes,
            color='#f8edeb',
            size=40,
            ha='right',
            weight=800)
        ax.text(
            0.5,
            1.1,
            'Covid-19',
            transform=ax.transAxes,
            size=14,
            color='#f8edeb')
        ax.text(
            0.2,
            0.05,
            timeline_event.get(date_str, ''),
            transform=ax.transAxes,
            size=20,
            color='#06d6a0')
        ax.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
        ax.xaxis.set_ticks_position('top')
        ax.tick_params(axis='x', colors='#777777', labelsize=12)
        ax.set_yticks([])
        ax.margins(0, 0.01)
        ax.grid(which='major', axis='x', linestyle='-')
        ax.set_axisbelow(True)
        plt.box(False)
複製代碼

從新調用這個新的func來製做動畫。

fargs = (df_country,
         start_date,
         'ObservationDate',
         'Country/Region',
         'Confirmed',
         10,
         color_dict,
         ax)
animator = animation.FuncAnimation(
    fig,
    xkcd_bar_chart_frame,
    frames=dates_delta,
    fargs=fargs,
    interval=1000,
    repeat=False)
複製代碼

最後咱們來看一下咱們更新後的動畫效果。ps. 眼看着中國從top10中消失,眼看着America First。

Tips

保存爲MP4格式須要電腦安裝ffmep 編碼/解碼器,安裝好的ffmpeg_path須要添加到matplotlibrc 參數下。

# add ffmpeg path to matplotlibrc
plt.rcParams['animation.ffmpeg_path'] = r'your_path\ffmpeg-20200323-ba698a2-win64-static\ffmpeg-20200323-ba698a2-win64-static\bin\ffmpeg.exe'

複製代碼

總結

本文中咱們繼續使用covid19的數據來進行可視化分析。咱們採用python 製做了酷炫的動態排名。 定義的函數能夠套用在其餘數據集中用於製做動態排名。 經過本文咱們能夠學會:

  • 如何製做動態排名(barh race) 圖,以及保存爲視頻
  • 如何給bar 不一樣類別賦予不一樣的顏色
  • 若是給畫面添加文字
  • 如何是畫面顯得「抖一抖」

八卦

據說Youtuber 使用Bar race 製做視頻,月入50萬。

相關文章
相關標籤/搜索