# 導入所需的庫
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 設置正常顯示中文標籤
plt.rcParams['font.sans-serif'] = ['SimHei']
########## 準備繪圖數據 ###############
# 從 Excel 文件中讀取數據,第一列設置為索引
sale = pd.read_excel('data/不同地區的銷售額變化.xlsx', index_col=0)
sale
########## 處理數據 ###############
# 計算銷售額的變化
sale['銷售變化'] = sale.iloc[:, 1] - sale.iloc[:, 0]
# 把銷售匯總作為第一行
change = pd.concat([pd.DataFrame(sale.sum()).T, sale])
# 修改第一行的索引名稱:上個月
change.rename(index={0: sale.columns[0]}, inplace=True)
# 設置瀑布圖的第一個數值
change.iloc[0, 2] = change.iloc[0, 0]
# 排除沒有變化的項目
change = change[abs(change.銷售變化) > 0]
# 降序排列
change = change.sort_values('銷售變化', ascending=False)
# 不要包含匯總,後面會自動計算
index = change.index
data = change.銷售變化
trans = pd.DataFrame(data=data, index=index)
# 為瀑布圖創建空白序列,用於把柱子撐起來
blank = trans.銷售變化.cumsum().shift(1).fillna(0)
# 計算瀑布圖的最後一個數值:當月收入
thismonth = sale.columns[1]
total = trans.sum().銷售變化
# 設置瀑布圖中每個項目的變化
step = blank.reset_index(drop=True).repeat(3).shift(-1)
step[1::3] = np.nan
# 最後一根柱子是從 0 開始
blank.loc[thismonth] = 0
trans.loc[thismonth] = total
trans
########## 開始畫圖 ###############
# 設置標題
title = '\n各地區銷售額變化瀑布圖\n'
# 使用 Pandas 中的畫圖函數
waterfall = trans.plot(kind='bar', stacked=True, bottom=blank, legend=None, figsize=(16, 8), fontsize=20, width=0.8)
# 設置 x 軸標籤
waterfall.set_xlabel("")
# 計算標籤位置的偏移量
max = trans.max()
neg_offset = max / 25
pos_offset = max / 50
plot_offset = int(max / 10)
# 獲取標籤的高度位置
y_height = trans.銷售變化.cumsum().shift(1).fillna(0)
# 循環設置標籤
loop = 0
for index, row in trans.iterrows():
x = row['銷售變化']
# 最後一個標籤的位置不要雙倍
if x == total:
y = y_height[loop]
else:
y = y_height[loop] + x
# 決定向上還是向下偏移
if x > 0:
y += pos_offset
else:
y -= neg_offset
# 添加數字標籤,負數用紅色
waterfall.annotate("{:.1f}".format(x), (loop, y), ha="center", fontsize=20, color=('k' if x>0 else 'r'))
loop+=1
# 設置 y 軸的偏移量
waterfall.set_ylim(0, blank.max()+int(plot_offset))
# 設置 x 軸標籤的角度
waterfall.set_xticklabels(trans.index, rotation=0)
# 設置標題並顯示圖片
plt.title(title, fontsize=36, loc='center', color='k')
plt.show()