月次、四半期など報告書のための図表作りを少しでも楽にしたい。その一念のみです。
より良い方法があればぜひご教示ください。
#課題
最近、本社上層部が入れ替わり、ウォーターフォールで売上増減要因を明確化せよ、とのお達し。
エクセルでも出来るが、ひとつひとつ作るのは邪魔くさい!
#元データ
こればっかりは自分で作らなきゃいけない。
data.dat
2018, 1000
Factor A, 200
Factor B, -70
Factor C, 50
Factor D, 100
Factor E, -500
Factor F, 200
2019, 980
#データを読み込んで整形
とりあえず、pandasで読む。indexとか面倒なので敢えて無視。
waterfall.py前半
import matplotlib.pyplot as plt
import pandas as pd
# Read File
df = pd.read_csv("./data.dat", header=None)
# Data Preparation
df[2]=df[1]
for i in range(len(df)):
if i==0 or i==len(df)-1:
df.iloc[i,2] = 0
else:
df.iloc[i,1] = df.iat[i-1,1] + df.iat[i-1,2]
#いざプロット
waterfall.py後半
# Plot parameter
graphTitle = "Waterfall"
ylabel = "Turnover [mil. JPY]"
barWidth = 0.5
clrLeft = "lightgray"
clrRight = "gray"
clrPos = "lightgreen"
clrNeg = "red"
# Plot
fig = plt.figure(figsize=(10,5))
fig.suptitle(graphTitle)
ax = fig.add_subplot()
ax.grid(which="major", axis="y", linestyle="--")
bottomBar = ax.bar(df[0], df[1], width=barWidth, linewidth=0, color="white")
upperBar = ax.bar(df[0],df[2], width=barWidth, linewidth=0, bottom=df[1])
# Colour
for i in range(len(df)):
if df.iat[i,2] < 0.0:
upperBar[i].set_color(clrNeg)
else:
upperBar[i].set_color(clrPos)
bottomBar[0].set_color(clrLeft)
bottomBar[len(df)-1].set_color(clrRight)
fig.savefig("Waterfall.png")
#売上は悪くとも、せめて見栄え良く
###カラーパレット
本当はもう少し色に気を配りたいところ。カンパニーカラーなどのカラーパレットがあるのであれば、他にも共通で使えるように別のファイルにリストしておいてimportすると便利。
CompanyColour.py
# Company Colour
MyCompanyColour = "#3F48CC"
MyPalette1 = "#211A1D"
MyPalette2 = "#8075FF"
MyPalette3 = "#F8F0FB"
MyPalette4 = "#CAD5CA"
# Gray Colour
GrayScaleBlack = "#000000"
GrayScale90 = "#1A1A1A"
GrayScale80 = "#333333"
GrayScale70 = "#4D4D4D"
GrayScale60 = "#666666"
GrayScale50 = "#7F7F7F"
GrayScale40 = "#9A9A9A"
GrayScale30 = "#B3B3B3"
GrayScale20 = "#CCCCCC"
GrayScale10 = "#E6E6E6"
グレースケールは結構大事!。
###増減のラベル
# Label for increments
for i in range(len(upperBar)):
if i!=0 and i!=len(upperBar)-1:
height = upperBar[i].get_height()
if df.iat[i,2]<0:
ax.annotate("{}".format(height),
xy=(upperBar[i].get_x()+upperBar[i].get_width()/2, upperBar[i].get_y()),
xytext=(0,3),textcoords="offset points", ha="center", va="bottom")
else:
ax.annotate("{}".format(height),
xy=(upperBar[i].get_x()+upperBar[i].get_width()/2, upperBar[i].get_y()+height),
xytext=(0,3),textcoords="offset points", ha="center", va="bottom")
###矢印の追加
# additional arrow
for i in range(len(upperBar)):
if i!=0 and i!=len(upperBar)-1:
length = upperBar[i].get_height()
x = upperBar[i].get_x() + upperBar[i].get_width()/2
ys = upperBar[i].get_y()
ye = ys+length
ax.annotate("", xy=(x,ye), xytext=(x,ys),
arrowprops=dict(arrowstyle="-|>"))
なんだかんだ書きましたが、図表に時間をかける前に上層部を説得できる言い訳説明を考えよう。