天天看點

超實用,百行Python代碼制作動态樹地圖

今日表情?

超實用,百行Python代碼制作動态樹地圖

樹地圖(tree map)是一種适用于顯示大量分層結構的資料,它是餅狀圖的一種高次元替代者,可以用面積直覺顯示各個部分的占比。

先上圖檔:

超實用,百行Python代碼制作動态樹地圖

再上視訊:

最後上代碼:

import numpy as np 
import pandas as pd 
from matplotlib import pyplot as plt
import matplotlib.animation as  animation 

import imageio
import os 
import cv2
from PIL import Image
import squarify


cmap = [
'#2E91E5',
'#1CA71C',
'#DA16FF',
'#B68100',
'#EB663B',
'#00A08B',
'#FC0080',
'#6C7C32',
'#862A16',
'#620042',
'#DA60CA',
'#0D2A63']*100

plt.rcParams['animation.writer'] = 'html'
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

def html_to_gif(html_file, gif_file, duration=0.1):
    path = html_file.replace(".html","_frames")
    images = [os.path.join(path,x) for x in sorted(os.listdir(path))]
    frames = [imageio.imread(x) for x in images]
    imageio.mimsave(gif_file, frames, 'gif', duration=duration)
    return gif_file


df = pd.read_csv('./data/gdp_china_1993_2019.csv')
df["date"] = [str(x) for x in df["date"]]
df = df.set_index("date")
df.columns = [x if "自治區" not in x else x[0:2] for x in df.columns]
df = df.sort_values("2019",axis = 1,ascending=False)

figsize = (8,6)
dpi = 160
title = "中國大陸各省份曆年GDP"
n_visible = 31 

def treemap_dance(df,filename = None,
    title = "中國大陸各省份曆年GDP",figsize = (8,6),dpi = 120,duration = 2,n_visible= 31):
    
    assert filename is None or filename.endswith(".html"), "filename should like *.html!"
    
    fig,ax = plt.subplots(figsize=figsize,dpi=dpi)
    

    # 調整spines
    ax.spines["top"].set_visible(False)
    ax.spines["right"].set_visible(False)
    ax.spines["left"].set_visible(False)
    ax.spines["bottom"].set_visible(False)

    def plot_frame(i):
        
        ax.clear() 
        date = df.index[i]
        dfdata = pd.DataFrame(df.loc[date,:])
        dfdata.columns = ["values"]
        dfdata["color"] = [cmap[i] for i in range(len(dfdata))] 
        dfdata = dfdata.sort_values("values",ascending = True) 

        dfused = dfdata.iloc[n_visible::-1,:] 
        xdata = dfused.index.tolist()
        ydata = dfused["values"].tolist()
        colors = dfused["color"].tolist()

        #plt.rc('font', size=7,color = "white")
        squarify.plot(sizes = ydata, # 指定繪圖資料
             label = xdata, # 指定标簽
             color = colors, # 指定自定義顔色
             alpha = 0.5, # 指定透明度
             value = ydata, # 添加數值标簽
             edgecolor = 'white', # 設定邊界框為白色
             linewidth =3, # 設定邊框寬度為3
             ax = ax,
             text_kwargs = {"size":8,"color":"black"},
             zorder = 0
        )

        #輔助設定
        ax.set_title(title,color = "black",fontsize = 12)
        ax.text(0.08, 0.92, str(date), va="center", ha="center",
                alpha=1.0, color ="white", size = 20,transform = ax.transAxes)
        plt.axis('off')
        plt.tick_params(top = 'off', right = 'off')
        

    my_animation = animation.FuncAnimation(fig,plot_frame,frames = range(0,len(df)),interval = int(duration*1000))
    if filename is None:
        try:
            from IPython.display import HTML
            HTML(my_animation.to_jshtml())
            return HTML(my_animation.to_jshtml())
        except ImportError:
            pass
    else:
        my_animation.save(filename)
        return filename

treemap_dance(df)

html_file = "treemap_dance.html"
gif_file = "treemap_dance.gif"
treemap_dance(df, filename = html_file)

html_to_gif(html_file,gif_file,duration=1.0)
           

複制

主要原理是安裝并使用了squarify 庫來繪制樹地圖,并借助 matplotlib中的 animation制作動态圖。

收工。?