首先,這是我們的資料
共有5份檔案,每份檔案的內容大致如下
所以我們要先把我們所需的資料彙整到同一個檔案中
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["選舉名稱"]))
總共有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)
#將兩個表做outer join合併成一個合併表(data_merge)
data_merge = pd.merge(left = data_pvt[["參選人","收支科目","收入金額"]],
right = data_temp,
how = "outer",
on = ["參選人","收支科目"]
)
data_merge["收入金額"].fillna(0,inplace=True)
接著我們還需要每個候選人的參選市的資料,所以:
#接著建立包含參選人與參選市的表(data_candidate_city)
data_candidate_city = data_pvt[["參選人","參選市"]].drop_duplicates()
#將參選市的資料串入合併表(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)
接著我們還需要每個候選人的收入總額的資料,所以:
#接著建立包含參選人與收入總額的表(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]
以上就是我們要拿來繪圖的資料,繪圖方法如下:
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年直轄市市長選舉政治獻金")