說起折線圖,很多人都覺得非常簡單,不就是一些點連成的線嗎?用 Excel 幾秒鐘就能畫出一張折線圖。
真的就這么簡單嗎?
想一想:在普通的折線圖中,如何自動地添加一條代表平均值的橫線?如何添加一條帶箭頭的趨勢線?如何快速地標(biāo)注最大值和最小值?如何標(biāo)注特殊事件?如何對折線圖進(jìn)行數(shù)據(jù)分析?
下面我們用一個具體的案例,演示折線圖的分析過程和畫圖的方法。
一個案例
根據(jù)某公司 2019 年 9 月份每天的銷量數(shù)據(jù),畫出如下一張折線圖:

通過觀察可以看到,銷量每隔幾天就有一個波谷,對照日歷,發(fā)現(xiàn)一個規(guī)律:這些銷量比較低的日期,都是周末或節(jié)假日。
如果理解了業(yè)務(wù)的周期性,那么在分析數(shù)據(jù)時,就能排除一些干擾,更快地找到對業(yè)務(wù)真正有價值的信息。
排除周期性的因素之后,我們觀察折線圖中的最大值和最小值,看看它們是否在正常范圍以內(nèi),如果不是的話,那么要分析背后的原因。
比如說,9 月 30 日的銷量最高,明顯高于平時的正常水平,經(jīng)過與業(yè)務(wù)溝通和分析發(fā)現(xiàn),是因為這一天做了打折促銷的運營活動。
在折線圖中,有一條代表平均值的橫線,以及一條帶箭頭的趨勢線,它們有助于對數(shù)據(jù)整體趨勢的把握。
從上面的圖中可以看出,中秋節(jié)放假之后,銷量有所上升,結(jié)合廣告費的投入數(shù)據(jù)進(jìn)行分析,計算它們相關(guān)系數(shù),發(fā)現(xiàn)銷量與廣告費之間具有比較強(qiáng)的正相關(guān)性,也就是說,中秋節(jié)之后,銷量上升的主要原因,是公司加大了廣告費的投入。
通過上面的分析解讀,我們知道,折線圖能直觀地反映出數(shù)據(jù)隨著時間變化的趨勢,讓數(shù)據(jù)更容易進(jìn)行對比,發(fā)現(xiàn)數(shù)據(jù)背后規(guī)律性的知識,從而幫助管理者更好地做出決策。
畫圖不是為了炫技,而是為了提高信息傳遞的效率。你不妨反思一下自己畫過的圖,是不是提高了信息傳遞的效率呢?
畫圖方法
能畫折線圖的軟件工具有很多,本文采用的是
Python中的matplotlib庫。
在
Jupyter Lab中運行以下Python代碼,就可以畫出上面那張折線圖。
讀取數(shù)據(jù)
# 讀取每日銷售數(shù)據(jù)
df = pd.read_excel('2019年9月每日銷售.xlsx')
df
日期 實際銷量
0 2019-09-01 7
1 2019-09-02 16
2 2019-09-03 18
3 2019-09-04 16
4 2019-09-05 18
5 2019-09-06 16
6 2019-09-07 9
7 2019-09-08 7
8 2019-09-09 16
9 2019-09-10 15
10 2019-09-11 17
11 2019-09-12 16
12 2019-09-13 3
13 2019-09-14 6
14 2019-09-15 7
15 2019-09-16 25
16 2019-09-17 23
17 2019-09-18 22
18 2019-09-19 23
19 2019-09-20 21
20 2019-09-21 13
21 2019-09-22 12
22 2019-09-23 22
23 2019-09-24 23
24 2019-09-25 23
25 2019-09-26 22
26 2019-09-27 24
27 2019-09-28 13
28 2019-09-29 12
29 2019-09-30 29
開始分析和畫圖
# 定義畫圖的數(shù)據(jù)
x = df.日期
y = df.實際銷量
# 定義顏色
color1 = '#0085c3'
color2 = '#7ab800'
color3 = '#dc5034'
# 設(shè)置圖像大小
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111)
# 繪制折線圖
ax.plot(x, y, marker='o', color=color1)
fig

# 標(biāo)注最大值
ax.text(x[y.idxmax()]+timedelta(hours=-12),
y.max()+1, y.max(),
color=color1, fontsize=15)
# 標(biāo)注最小值
ax.text(x[y.idxmin()]+timedelta(hours=-9),
y.min()-2, y.min(),
color=color1, fontsize=15)
fig

# 計算 7 天移動平均
y2 = y.rolling(7).mean()
# 繪制趨勢線
ax.plot(x, y2, ls='--', color=color2, label='7 天移動平均')
fig

# 繪制平均值線
ax.hlines(y.mean(), x[0], x[-1:],
linestyles='-.', colors=color3)
# 標(biāo)注平均值
ax.text(x[-1:]+timedelta(days=-7.5), y.mean()-2,
'平均值: ' + str(round(y.mean(),1)),
color=color3, fontsize=15)
fig

# 繪制箭頭
plt.annotate('', xy=(x[-1:], y2[-1:]),
xytext=(x[-2:-1], y2[-2:-1]),
arrowprops=dict(arrowstyle='->',
color=color2,
shrinkB=0))
# 標(biāo)注特殊事件
ax.annotate('中秋節(jié)', xy=(x[y.idxmin()], y.min()), color=color1,
xytext=(x[y.idxmin()]+timedelta(days=1.5), y.min()-2),
arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)
ax.annotate('打折促銷', xy=(x[y.idxmax()], y.max()), color=color1,
xytext=(x[y.idxmax()]+timedelta(days=-5), y.max()+2),
arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)
fig

# 設(shè)置網(wǎng)格線
ax.grid(ls=':', color='gray', alpha=0.6)
# 設(shè)置圖例的位置和大小
ax.legend(loc='upper left', fontsize=12)
# 設(shè)置坐標(biāo)軸標(biāo)簽的角度和大小
plt.xticks(rotation=90, fontsize=12)
plt.yticks(fontsize=12)
# 設(shè)置 y 軸的刻度范圍
ax.set_ylim(0, y.max()+5)
# 設(shè)置圖表標(biāo)題
_ = ax.set_title('2019年9月每日銷量變化趨勢', fontsize=25)
fig

補充
Series.idxmax(self,axis = 0,skipna = True,* args,** kwargs )返回最大值的行標(biāo)簽
代碼合集
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import timedelta
# 正常顯示中文標(biāo)簽
plt.rcParams['font.sans-serif'] = ['SimHei']
# 正常顯示負(fù)號
plt.rcParams['axes.unicode_minus'] = False
# 讀取每日銷售數(shù)據(jù)
df = pd.read_excel('./data/2019年9月每日銷售.xlsx')
# 定義畫圖的數(shù)據(jù)
x = df.日期
y = df.實際銷量
# 定義顏色
color1 = '#0085c3'
color2 = '#7ab800'
color3 = '#dc5034'
# 設(shè)置圖像大小
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111)
# 繪制折線圖
ax.plot(x, y, marker='o', color=color1)
# 標(biāo)注最大值
ax.text(x[y.idxmax()]+timedelta(hours=-12),
y.max()+1, y.max(),
color=color1, fontsize=15)
# 標(biāo)注最小值
ax.text(x[y.idxmin()]+timedelta(hours=-9),
y.min()-2, y.min(),
color=color1, fontsize=15)
# 計算 7 天移動平均
y2 = y.rolling(7).mean()
# 繪制趨勢線
ax.plot(x, y2, ls='--', color=color2, label='7 天移動平均')
# 繪制箭頭
plt.annotate('', xy=(x[-1:], y2[-1:]),
xytext=(x[-2:-1], y2[-2:-1]),
arrowprops=dict(arrowstyle='->',
color=color2,
shrinkB=0))
# 繪制平均值線
ax.hlines(y.mean(), x[0], x[-1:],
linestyles='-.', colors=color3)
# 標(biāo)注平均值
ax.text(x[-1:]+timedelta(days=-7.5), y.mean()-2,
'平均值: ' + str(round(y.mean(),1)),
color=color3, fontsize=15)
# 標(biāo)注特殊事件
ax.annotate('中秋節(jié)', xy=(x[y.idxmin()], y.min()), color=color1,
xytext=(x[y.idxmin()]+timedelta(days=1.5), y.min()-2),
arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)
ax.annotate('打折促銷', xy=(x[y.idxmax()], y.max()), color=color1,
xytext=(x[y.idxmax()]+timedelta(days=-5), y.max()+2),
arrowprops=dict(arrowstyle='->', color=color1), fontsize=15)
# 設(shè)置網(wǎng)格線
ax.grid(ls=':', color='gray', alpha=0.6)
# 設(shè)置圖例的位置和大小
ax.legend(loc='upper left', fontsize=12)
# 設(shè)置坐標(biāo)軸標(biāo)簽的角度和大小
plt.xticks(rotation=90, fontsize=12)
plt.yticks(fontsize=12)
# 設(shè)置 y 軸的刻度范圍
ax.set_ylim(0, y.max()+5)
# 設(shè)置圖表標(biāo)題
_ = ax.set_title('2019年9月每日銷量變化趨勢', fontsize=25)