如何用Python繪製堆疊直條圖(以2022年直轄市市長選舉政治獻金為例)

更新於 2024/05/30閱讀時間約 16 分鐘

首先,這是我們的資料

raw-image

共有5份檔案,每份檔案的內容大致如下

raw-image

所以我們要先把我們所需的資料彙整到同一個檔案中

import pandas as pd
import os

#建立所在之資料夾路徑
path = r"D:\Desktop\@PROJECT\Python\111年直轄市市長選舉政治獻金會計報告書\incomes"

#建立資料夾內所有檔案名稱的list
data_name_list = os.listdir(path)

#建立存放所有檔案的list
data_file_list = []

#利用迴圈將所有檔案存入data_file_list
for i in  data_name_list:
    pure_name = i.split(".")[0]
    globals()[f"data_{pure_name}"] = pd.read_csv(f"{path}/{i}")
    data_file_list.append(globals()[f"data_{pure_name}"])

#將data_file_list中的檔案,彙整成一個檔案(data_all)
data_all = pd.concat(data_file_list,ignore_index=True)

接著我們要整理我們想要的資訊

#利用pvt_table計算各候選人,各收支科目的總金額
data_pvt =  pd.pivot_table(data=data_all,
                           index=["擬參選人/政黨","選舉名稱","收支科目"],
                           values="收入金額",
                           aggfunc="sum").reset_index()

#更改欄位名稱
data_pvt.rename(columns={"擬參選人/政黨":"參選人"},inplace=True)

#擷取出參選市成一欄
data_pvt["參選市"] = list(map(lambda x: x[4:7] ,data_pvt["選舉名稱"]))
raw-image

總共有6種收支科目,我們希望繪圖的表中有每個候選人在這幾項收支科目的金額(就算金額為0),以利我們作圖,所以:

#先建一個空list
data_file_list = []

#接著我們要建立一個包含所有參選人X收支科目,且每個金額皆為0的表
for i in data_pvt["參選人"].unique():
    globals()[f"data_in_loop_{i}"] = pd.DataFrame()
    globals()[f"data_in_loop_{i}"]["參選人"] = [i]*6
    globals()[f"data_in_loop_{i}"]["收支科目"] = data_pvt["收支科目"].unique().tolist()
    globals()[f"data_in_loop_{i}"]["金額0"] = [0]*6
    data_file_list.append(globals()[f"data_in_loop_{i}"])

data_temp = pd.concat(data_file_list)
raw-image
#將兩個表做outer join合併成一個合併表(data_merge)
data_merge = pd.merge(left = data_pvt[["參選人","收支科目","收入金額"]],
                      right = data_temp,
                      how = "outer",
                      on = ["參選人","收支科目"]
                      )

data_merge["收入金額"].fillna(0,inplace=True)
raw-image

接著我們還需要每個候選人的參選市的資料,所以:

#接著建立包含參選人與參選市的表(data_candidate_city)
data_candidate_city = data_pvt[["參選人","參選市"]].drop_duplicates()
raw-image
#將參選市的資料串入合併表(data_merge)
data_merge = pd.merge(left = data_merge[["參選人","收支科目","收入金額"]],
                      right = data_candidate_city,
                      how = "left",
                      on = "參選人")

data_merge.sort_values(by=["參選市","參選人","收支科目"],inplace=True)

data_merge.reset_index(drop=True,inplace=True)
raw-image

接著我們還需要每個候選人的收入總額的資料,所以:

#接著建立包含參選人與收入總額的表(data_candidate_city)
data_sum = pd.pivot_table(data=data_merge,index="參選人",values="收入金額",aggfunc="sum").rename(columns={"收入金額":"收入總額"}).reset_index()

#將收入總額的資料串入合併表(data_merge)
data_merge = pd.merge(left=data_merge,right=data_sum,on="參選人",how="left")

#篩選收入總額大於一千萬的候選人
data_merge = data_merge[data_merge["收入總額"]>=10000000]
raw-image

以上就是我們要拿來繪圖的資料,繪圖方法如下:

import matplotlib

#設定中文字型
matplotlib.rc("font",family="Microsoft Yahei")

from matplotlib import pyplot as plt

#設定圖表大小
plt.figure(figsize=(18,12))

#以每一個參選市作為一個子圖
for i,p in zip(data_merge["參選市"].unique(),range(0,6)):

    data_city = data_merge[data_merge["參選市"] == i]

    #設定子圖位置
    globals()[f"ax_{i}"] = plt.subplot2grid((1,5),(0,p))

    #設定x值位置(每次重跑新的參選市時,x值便從0開始)
    x_value = 0

    #建立該參選市的參選人list
    xticklabels_list = data_city["參選人"].unique().tolist()

    #在各子圖內,為每個參選人繪製一根bar
    for j in data_city["參選人"].unique():

        data_city_person = data_city[data_city["參選人"] == j]

        #設定bar的起始位置(每次重跑參選人時,bar的高度起始位置便從0開始)
        y_bottom = 0

        #建立colorlist
        colorlist = ["lightcoral","royalblue","springgreen","lightgray","gold","orchid"]

        #在每個參選人內,為每個收支科目畫上不同的bar
        for k,c in zip(data_city_person["收支科目"].unique(),colorlist):

            data_city_person_item = data_city_person[data_city_person["收支科目"] == k]

            data_city_person_item.reset_index(drop=True,inplace=True)

            #設定參選人的bar的x位置順序的參數
            person_position = xticklabels_list.index(j)

            #設定該參選市有多少參選人的參數
            how_many_person = len(xticklabels_list)

            #建立x值資料
            #如果是該市的第一個參選人的話:
            if person_position == 0 :
                #且如果該市有2個參選人,那x軸起始位置設定為4/3
                if how_many_person == 2:
                    ax_x = 4/3
​                #且如果該市有3個參選人,那x軸起始位置設定為4/4
                elif how_many_person == 3:
                    ax_x = 4/4
            #其他狀況:
            else: ax_x = x_value

            #建立y值資料(每個收支科目bar的長度)
            ax_y = data_city_person_item["收入金額"][0]

            #繪製各收支科目的bar
            globals()[f"ax_{i}"].bar(ax_x,
                                     ax_y,
                                     bottom = y_bottom,
                                     width = 0.5,
                                     color = c,
                                     label = k)

            #疊代收支科目bar的起始位置
            y_bottom = y_bottom + ax_y

            #設定X軸標籤的位置
            #如果該市有2個參選人
            if how_many_person == 2:
                globals()[f"ax_{i}"].set_xticks([4/3,(4/3)*2])
            #如果該市有3個參選人
            elif how_many_person == 3:
                globals()[f"ax_{i}"].set_xticks([4/4,(4/4)*2,(4/4)*3])  

            #設定X軸標籤(參選人名稱)
            globals()[f"ax_{i}"].set_xticklabels(xticklabels_list)
            #設定X軸最大最小值
            globals()[f"ax_{i}"].set_xlim(0,4)

            #設定Y軸最大最小值
            globals()[f"ax_{i}"].set_ylim(0,120000000)

            #如果是第一張子圖的話,設定Y軸標籤位置與標籤如下
            if p == 0 :    
                globals()[f"ax_{i}"].set_yticks([20000000,40000000,60000000,80000000,100000000,120000000])
                globals()[f"ax_{i}"].set_yticklabels(["2千萬","4千萬","6千萬","8千萬","1億","1.2億"])
            #如果是其他張子圖的話,設定Y軸標籤位置與標籤為空值
            else :    
                globals()[f"ax_{i}"].set_yticks([])
                globals()[f"ax_{i}"].set_yticklabels([])

        #設定下一張子圖的X軸的值
        #如果該市有2個參選人
        if how_many_person == 2:
            #x軸的值增加4/3
            x_value = ax_x + 4/3
        #如果該市有3個參選人
        elif how_many_person == 3:
            #x軸的值增加4/4
            x_value = ax_x + 4/4

        #如果是第一章子圖中的第一位參選者,設定圖例如下:
        if (p == 0) & (person_position == 0) :
            globals()[f"ax_{i}"].legend(bbox_to_anchor=(4.8,-0.05),ncols=6)

        #設定各子圖的標題
        globals()[f"ax_{i}"].set_title(f"{i}")

plt.tight_layout()

#設定總標題
plt.suptitle("111年直轄市市長選舉政治獻金")
raw-image




avatar-img
4會員
60內容數
我是果農,這裡有我的人資職涯經驗分享,與我菜鳥般的Python資料分析筆記,還有一些讀書心得,希望對大家有幫助。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
果農的沙龍 的其他內容
你可能也想看
Google News 追蹤
Thumbnail
本文探討了複利效應的重要性,並藉由巴菲特的投資理念,說明如何選擇穩定產生正報酬的資產及長期持有的核心理念。透過定期定額的投資方式,不僅能減少情緒影響,還能持續參與全球股市的發展。此外,文中介紹了使用國泰 Cube App 的便利性及低手續費,幫助投資者簡化投資流程,達成長期穩定增長的財務目標。
學習如何使用讀心術,以影響孩子的思想和行為。這篇文章介紹了《心控》一書中的三個技巧,包括把否定詞換成共鳴詞、壓低期待值以獲得好印象、引導對方說出「對呀」的會話術。
Thumbnail
房地產市場投資的一個關鍵就是善用房市景氣和房市指標來把握投資時機。這篇文章聚焦在住宅市場,透過介紹不同房市指標的含義和解讀方式,希望幫助讀者更深入地瞭解房市景氣和相關房市指標,進而對市場動態有更深入的認識。
Thumbnail
# 如何用[55688 APP]在台灣大車隊享受更便捷的出行體驗? 台灣大車隊的55688 APP帶來了一系列革命性的功能,為用戶提供了前所未有的便捷出行體驗。以下是如何利用這款應用程序享受更加輕鬆、安全的乘車體驗的幾個關鍵點: 固定車資功能:此新功能允許乘客在預訂車輛前,即知道具體的車資,這樣
台灣的科技公司會發放股票,美國科技公司發放的則是RSU (Restricted Stock Unit), 通常會分成數年慢慢發放。跟股票或選擇權不同的地方是,RSU 在發放的時候,會納入當年的所得,所以員工需要先繳一筆所得稅,之後買賣股票的時候,如果有賺的話,又會再產生資本利得稅。
Thumbnail
設計完一覽表之後,如果會寫程式的人可以每天用這種方法去抓資料放到Excel. 那不會寫程式的人呢? 這裡教你一個稍微要花點時間的輸出Excel的方法。 在上禮拜完成的自選裡。   一、  你先依下圖,在“功能”中找到”輸出到Excel”,按下報價精靈 二、  選擇全部加入,按下全部加
Thumbnail
根據RFM的資料來分成8種類型的客戶,1.重要價值客戶2.重要保持客戶3.重要發展客戶4.一般發展客戶5.重要挽留客戶6.一般價值客戶7.一般保持客戶8.一般挽留客戶
Thumbnail
RFM模型是最基本的分析,可以讓你知道哪些是常客、哪些人是偶爾來一次,或是根本不常來,藉此針對不同的客群去做不同的策略,達到提升業績的方法。接下來就讓我教你如何運用PYTHON快速做出RFM分析
Thumbnail
你也曾想過用直式的編排,在方格子寫下自己的新詩與散文嗎?古板的我,明知道閱讀的是網路文章,還是有想要閱讀直式排版的時候。尤其是讀到很棒的詩與散文,會開始意淫如果是直式排版(像看書本一樣),那會是什麼樣的氣質?閒人如我,在使用方格子編輯器一年多後,試著將不輕不重的小文字,編排成直式閱讀的文章。
Thumbnail
幾年前,偶然的在某社群聽見 Robot Framework 這套開源框架,起初抱持著好奇的心情簡單的玩了一下,不過當時完全不理解,用這種 Keyword 方式去撰寫自動化測試的好處在哪? ( 不過就是…我知識不足罷了XD ) 。 接下來,我就可以跑測試拉~! 接著看 log.html:
Thumbnail
本文探討了複利效應的重要性,並藉由巴菲特的投資理念,說明如何選擇穩定產生正報酬的資產及長期持有的核心理念。透過定期定額的投資方式,不僅能減少情緒影響,還能持續參與全球股市的發展。此外,文中介紹了使用國泰 Cube App 的便利性及低手續費,幫助投資者簡化投資流程,達成長期穩定增長的財務目標。
學習如何使用讀心術,以影響孩子的思想和行為。這篇文章介紹了《心控》一書中的三個技巧,包括把否定詞換成共鳴詞、壓低期待值以獲得好印象、引導對方說出「對呀」的會話術。
Thumbnail
房地產市場投資的一個關鍵就是善用房市景氣和房市指標來把握投資時機。這篇文章聚焦在住宅市場,透過介紹不同房市指標的含義和解讀方式,希望幫助讀者更深入地瞭解房市景氣和相關房市指標,進而對市場動態有更深入的認識。
Thumbnail
# 如何用[55688 APP]在台灣大車隊享受更便捷的出行體驗? 台灣大車隊的55688 APP帶來了一系列革命性的功能,為用戶提供了前所未有的便捷出行體驗。以下是如何利用這款應用程序享受更加輕鬆、安全的乘車體驗的幾個關鍵點: 固定車資功能:此新功能允許乘客在預訂車輛前,即知道具體的車資,這樣
台灣的科技公司會發放股票,美國科技公司發放的則是RSU (Restricted Stock Unit), 通常會分成數年慢慢發放。跟股票或選擇權不同的地方是,RSU 在發放的時候,會納入當年的所得,所以員工需要先繳一筆所得稅,之後買賣股票的時候,如果有賺的話,又會再產生資本利得稅。
Thumbnail
設計完一覽表之後,如果會寫程式的人可以每天用這種方法去抓資料放到Excel. 那不會寫程式的人呢? 這裡教你一個稍微要花點時間的輸出Excel的方法。 在上禮拜完成的自選裡。   一、  你先依下圖,在“功能”中找到”輸出到Excel”,按下報價精靈 二、  選擇全部加入,按下全部加
Thumbnail
根據RFM的資料來分成8種類型的客戶,1.重要價值客戶2.重要保持客戶3.重要發展客戶4.一般發展客戶5.重要挽留客戶6.一般價值客戶7.一般保持客戶8.一般挽留客戶
Thumbnail
RFM模型是最基本的分析,可以讓你知道哪些是常客、哪些人是偶爾來一次,或是根本不常來,藉此針對不同的客群去做不同的策略,達到提升業績的方法。接下來就讓我教你如何運用PYTHON快速做出RFM分析
Thumbnail
你也曾想過用直式的編排,在方格子寫下自己的新詩與散文嗎?古板的我,明知道閱讀的是網路文章,還是有想要閱讀直式排版的時候。尤其是讀到很棒的詩與散文,會開始意淫如果是直式排版(像看書本一樣),那會是什麼樣的氣質?閒人如我,在使用方格子編輯器一年多後,試著將不輕不重的小文字,編排成直式閱讀的文章。
Thumbnail
幾年前,偶然的在某社群聽見 Robot Framework 這套開源框架,起初抱持著好奇的心情簡單的玩了一下,不過當時完全不理解,用這種 Keyword 方式去撰寫自動化測試的好處在哪? ( 不過就是…我知識不足罷了XD ) 。 接下來,我就可以跑測試拉~! 接著看 log.html: