天天看點

Python 資料可視化:Stack Graph 堆疊圖,标準化堆疊柱形圖,标準化的同時還能反應資料量大小的堆疊圖(放入自寫庫,一行代碼搞定複雜細節繪圖)

Python 資料可視化:Stack Graph 堆疊圖,标準化堆疊柱形圖,标準化的同時還能反應資料量大小的堆疊圖(放入自寫庫,一行代碼搞定複雜細節繪圖)
本文已在公衆号 “ 資料分析與商業實踐 ” 首發。關注一下~,更多商業資料分析案例源碼等你來撩。背景回複 “堆疊圖” ,即可擷取本文的案例示範與包含詳細注釋的源資料與源代碼!

  這是一個自寫庫系列,即筆者在資料可視化路上踩過的坑的彙總,并自定義函數和傳入參數來實作快速避坑 + 快速繪制出複雜精美的圖檔。

引言

  Python 的繪圖功能非常強大,如果能将已有的繪圖庫和各種複雜操作彙總在一個自己寫的庫/包中,并實作一行代碼就調用并實作複雜的繪圖功能,那就更強大了。是以本博文隻強調繪圖代碼的實作,繪圖中的統計學知識(名義變量,數值變量,xx圖與xx圖的差別等等)與 Python 基礎庫操作(seaborn,matplotlib)并不會提及,不過也歡迎關注,後續會有更多更廣更豐富的知識瘋狂輸出。

業務需求 & 使用效果

  老闆:我有一份北京地區二手房房價的資料,幫我按照地區分一下類,每類的學區房與非學區房的占比情況彙報一下。

  先看一下筆者的産圖過程(逐漸去殺馬特化)

Step1: 預覽資料,餅圖柱形圖試一下

Python 資料可視化:Stack Graph 堆疊圖,标準化堆疊柱形圖,标準化的同時還能反應資料量大小的堆疊圖(放入自寫庫,一行代碼搞定複雜細節繪圖)

Step2:畫出堆疊圖,各種标準化

Python 資料可視化:Stack Graph 堆疊圖,标準化堆疊柱形圖,标準化的同時還能反應資料量大小的堆疊圖(放入自寫庫,一行代碼搞定複雜細節繪圖)

  筋疲力盡的一波看似挺騷的操作後,才發現其實有輪子可以通過短短的幾行代碼完成,真的又浪費了不少青春,不過這個輪子似乎不好找,是自己以前無意間儲存下來的。

Python 資料可視化:Stack Graph 堆疊圖,标準化堆疊柱形圖,标準化的同時還能反應資料量大小的堆疊圖(放入自寫庫,一行代碼搞定複雜細節繪圖)

代碼展示!!

  代碼中的注釋已經非常非常詳細了!希望能夠幫你規避畫圖中的各種坑。繪圖代碼并不是自己創作的,而是從前人(創造繪圖庫的人)和各種大神的代碼中學習并積累下來的,為了畫出一幅還比較完美的圖,已經踩過無數的坑了,最終通過自己設定函數和函數中的參數來進行自定義的傳參繪制,真的太難了

# 基礎繪圖庫
import matplotlib.pyplot as plt
import seaborn as sns
# %matplotlib inline
# 各種細節配置如 文字大小,圖例文字等雜項
large = 22; med = 16; small = 12
params = {'axes.titlesize': large,
          'legend.fontsize': med,
          'figure.figsize': (16, 10),
          'axes.labelsize': med,
          'axes.titlesize': med,
          'xtick.labelsize': med,
          'ytick.labelsize': med,
          'figure.titlesize': large}
plt.rcParams.update(params)
plt.style.use('seaborn-whitegrid')
sns.set_style("white")
plt.rc('font', **{'family': 'Microsoft YaHei, SimHei'})  # 設定中文字型的支援
# sns.set(font='SimHei')  # 解決Seaborn中文顯示問題,但會自動添加背景灰色網格
plt.rcParams['axes.unicode_minus'] = False  # 解決儲存圖像是負号'-'顯示為方塊的問題

def stack2dim(raw, i, j, rotation=0, location='best'):
    '''
    此函數是為了畫兩個次元标準化的堆積柱狀圖
    raw為pandas的DataFrame資料框
    i、j為兩個分類變量的變量名稱,要求帶引号,比如"school"
    rotation:水準标簽旋轉角度,預設水準方向,如标簽過長,可設定一定角度,比如設定rotation = 40
    location:分類标簽的位置,如果被主體圖形擋住,可更改為'upper left'
    '''
    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    import math

    data_raw = pd.crosstab(raw[i], raw[j])
    data = data_raw.div(data_raw.sum(1), axis=0)  # 交叉表轉換成比率,為得到标準化堆積柱狀圖

    # 計算x坐标,及bar寬度
    createVar = locals()
    x = [0]  # 每個bar的中心x軸坐标
    width = []  # bar的寬度
    k = 0
    for n in range(len(data)):
        # 根據頻數計算每一列bar的寬度
        createVar['width' + str(n)] = list(data_raw.sum(axis=1))[n] / sum(data_raw.sum(axis=1))
        width.append(createVar['width' + str(n)])
        if n == 0:
            continue
        else:
            k += createVar['width' + str(n - 1)] / 2 + createVar['width' + str(n)] / 2 + 0.05
            x.append(k)

    # 以下是通過頻率交叉表矩陣生成一串對應堆積圖每一塊位置資料的數組,再把數組轉化為矩陣
    y_mat = []
    n = 0
    y_level = len(data.columns)
    for p in range(data.shape[0]):
        for q in range(data.shape[1]):
            n += 1
            y_mat.append(data.iloc[p, q])
            if n == data.shape[0] * data.shape[1]:
                break
            elif n % y_level != 0:
                y_mat.extend([0] * (len(data) - 1))
            elif n % y_level == 0:
                y_mat.extend([0] * len(data))

    y_mat = np.array(y_mat).reshape(-1, len(data))
    y_mat = pd.DataFrame(y_mat)  # bar圖中的y變量矩陣,每一行是一個y變量

    # 通過x,y_mat中的每一行y,依次繪制每一塊堆積圖中的每一塊圖

    from matplotlib import cm
    cm_subsection = [level for level in range(y_level)]
    colors = [cm.Pastel1(color) for color in cm_subsection]

    bottom = [0] * y_mat.shape[1]
    createVar = locals()
    for row in range(len(y_mat)):
        createVar['a' + str(row)] = y_mat.iloc[row, :]
        color = colors[row % y_level]

        if row % y_level == 0:
            bottom = bottom = [0] * y_mat.shape[1]
            if math.floor(row / y_level) == 0:
                label = data.columns.name + ': ' + str(data.columns[row])
                plt.bar(x, createVar['a' + str(row)],
                        width=width[math.floor(row / y_level)], label=label, color=color)
            else:
                plt.bar(x, createVar['a' + str(row)],
                        width=width[math.floor(row / y_level)], color=color)
        else:
            if math.floor(row / y_level) == 0:
                label = data.columns.name + ': ' + str(data.columns[row])
                plt.bar(x, createVar['a' + str(row)], bottom=bottom,
                        width=width[math.floor(row / y_level)], label=label, color=color)
            else:
                plt.bar(x, createVar['a' + str(row)], bottom=bottom,
                        width=width[math.floor(row / y_level)], color=color)

        bottom += createVar['a' + str(row)]

    plt.title(j + ' vs ' + i)
    group_labels = [str(name) for name in data.index]
    plt.xticks(x, group_labels, rotation=rotation)
    plt.ylabel(j)
    plt.legend(shadow=True, loc=location)
    plt.show()

           
本文已在公衆号 “ 資料分析與商業實踐 ” 首發。關注一下~,更多商業資料分析案例源碼等你來撩。背景回複 “堆疊圖” ,即可擷取本文的案例示範與包含詳細注釋的源資料與源代碼!

後記

  資料分析,商業實踐,資料可視化,網絡爬蟲,統計學,Excel,Word, 社會心理學,認知心理學,行為科學,民族意志學 各種專欄後續瘋狂補充。

  歡迎評論與私信交流!

推薦你看

  • Python 資料可視化:seaborn displot 正态分布曲線拟合圖代碼注釋超詳解(放入自寫庫,一行代碼搞定複雜細節繪圖)
  • Python 繪制正态曲線:linespace 組合 matplotlib(放入自寫庫,一行代碼實作複雜繪圖)
  • Python 資料可視化:treemap 樹形圖 餅圖更新版超詳解,展現占比的同時顯示出數量(放入自寫庫,一行代碼搞定複雜細節繪圖)

繼續閱讀