Python使用Matplotlib繪制甘特圖的實(shí)踐
1.引言
甘特圖已經(jīng)擁有 100 多年的歷史,這種可視化圖表對(duì)項(xiàng)目管理非常有用。

Henry Gantt 為了分析已經(jīng)完成的項(xiàng)目創(chuàng)建了甘特圖,他最初設(shè)計(jì)這個(gè)可視化工具主要用來(lái)衡量員工的工作效率并從中識(shí)別表現(xiàn)不佳的員工。經(jīng)過(guò)多年的發(fā)展,甘特圖已經(jīng)發(fā)展成項(xiàng)目規(guī)劃和跟蹤的必備工具。
本文主要介紹如何使用Matplotlib來(lái)繪制甘特圖,并不斷優(yōu)化我們的可視化效果。
閑話少說(shuō),我們直接開(kāi)始吧。 :)
2.舉個(gè)栗子
首先我們導(dǎo)入Pandas和Numpy庫(kù),這兩個(gè)庫(kù)可以幫助我們進(jìn)行數(shù)據(jù)預(yù)處理。
import pandas as pd import matplotlib.pyplot as plt import numpy as np
為了舉例,這里采用一個(gè)項(xiàng)目管理的數(shù)據(jù)集,如下所示為對(duì)應(yīng)的讀取代碼:
df = pd.read_excel('../data/plan.xlsx')
df
結(jié)果如下:

上圖所示,我們一共有14個(gè)Task,從TaskA到TaskM。其中每一行依次表示編號(hào),Task名字,Task所屬部門,Task開(kāi)始日期,Task結(jié)束日期,以及已經(jīng)完成了多少。
3.數(shù)據(jù)預(yù)處理
為了使我們的繪圖變得更加容易,我們需要增加一些變量。
首先我們需要設(shè)置整個(gè)項(xiàng)目開(kāi)始日期,接著,我們將添加一列,用于表示從項(xiàng)目開(kāi)始日期到每個(gè)子任務(wù)開(kāi)始的天數(shù);這將有助于在 x 方向上定位每個(gè)子任務(wù)的位置。
同理,我們對(duì)從項(xiàng)目開(kāi)始日期到子任務(wù)結(jié)束的天數(shù)也增加一列,這將有助于計(jì)算完成子任務(wù)所需的總的天數(shù)。
編寫代碼如下:
# project start date proj_start = df.Start.min() # number of days from project start to task start df['start_num'] = (df.Start - proj_start).dt.days # number of days from project start to end of tasks df['end_num'] = (df.End - proj_start).dt.days # days between start and end of each task df['days_start_to_end'] = df.end_num - df.start_num
運(yùn)行結(jié)果如下:

如上圖所示,我們?cè)O(shè)置整個(gè)項(xiàng)目的開(kāi)始日期為2022-02-15,我們?cè)黾恿?列,依次為start_num用于表示子任務(wù)開(kāi)始日期到整個(gè)項(xiàng)目開(kāi)始日期的天數(shù),end_num用于表示子任務(wù)結(jié)束日期到整個(gè)項(xiàng)目開(kāi)始日期的天數(shù),days_start_to_end用于表示完成子任務(wù)所需要的天數(shù)。
4.繪制甘特圖
做好上述準(zhǔn)備,我們就可以繪制我們的甘特圖了。這里我們使用Matplotlib中的條形圖進(jìn)行繪制。
Y軸表示任務(wù)名稱,每個(gè)子項(xiàng)的寬度表示子任務(wù)開(kāi)始和結(jié)束之間的天數(shù),子項(xiàng)的起始位置為從項(xiàng)目開(kāi)始到子任務(wù)開(kāi)始之間的天數(shù)。
繪制代碼如下:
fig, ax = plt.subplots(1, figsize=(16,6)) ax.barh(df.Task, df.days_start_to_end, left=df.start_num) plt.show()
運(yùn)行結(jié)果如下:

5.添加顏色
觀察上圖,我們繪制了最簡(jiǎn)單的條形圖用來(lái)表示項(xiàng)目管理。但是太粗糙了,接著我們來(lái)一步一步進(jìn)行改進(jìn)吧。。。
首先我們觀察上圖,條形圖中的子項(xiàng)都是同一顏色,區(qū)分度不明顯,但是我們數(shù)據(jù)中每項(xiàng)任務(wù)都有歸屬部門,我們可以對(duì)不同部門設(shè)置不同顏色。代碼如下:
# create a column with the color for each department
def color(row):
c_dict = {'MKT':'#E64646', 'FIN':'#E69646', 'ENG':'#34D05C', 'PROD':'#34D0C3', 'IT':'#3475D0'}
return c_dict[row['Department']]
df['color'] = df.apply(color, axis=1)
同時(shí)我們觀察到上圖中x軸為數(shù)字,所代表的含義并不直觀,我們將其轉(zhuǎn)化為日期每隔三天進(jìn)行一次顯示。這樣我們優(yōu)化后x軸日期顯示代碼如下:
from matplotlib.patches import Patch
fig, ax = plt.subplots(1, figsize=(16,6))
ax.barh(df.Task, df.days_start_to_end, left=df.start_num, color=df.color)
##### LEGENDS #####
c_dict = {'MKT':'#E64646', 'FIN':'#E69646', 'ENG':'#34D05C',
'PROD':'#34D0C3', 'IT':'#3475D0'}
legend_elements = [Patch(facecolor=c_dict[i], label=i) for i in c_dict]
plt.legend(handles=legend_elements)
##### TICKS #####
xticks = np.arange(0, df.end_num.max()+1, 3)
xticks_labels = pd.date_range(proj_start, end=df.End.max()).strftime("%m/%d")
xticks_minor = np.arange(0, df.end_num.max()+1, 1)
ax.set_xticks(xticks)
ax.set_xticks(xticks_minor, minor=True)
ax.set_xticklabels(xticks_labels[::3])
plt.show()
運(yùn)行結(jié)果如下:

6.添加透明度
仔細(xì)觀察上圖,是不是比第一版美觀很多。我們觀察我們的數(shù)據(jù),發(fā)現(xiàn)我們還有一列Completeness沒(méi)有進(jìn)行可視化,我們知道它代表每項(xiàng)子任務(wù)的完成度。接著我們來(lái)對(duì)齊進(jìn)行可視化。
# days between start and current progression of each task df['current_num'] = (df.days_start_to_end * df.Completion)
我們將新創(chuàng)建一個(gè)條形圖,子項(xiàng)為上述每項(xiàng)子任務(wù)的完成度。同時(shí)我們將在子項(xiàng)的末尾寫上完成度的百分比。
為了區(qū)分已完成和未完成,我們可以使用參數(shù)alpha將未完成部分設(shè)置成透明效果。
代碼如下:
from matplotlib.patches import Patch
fig, ax = plt.subplots(1, figsize=(16,6))
# bars
ax.barh(df.Task, df.current_num, left=df.start_num, color=df.color)
ax.barh(df.Task, df.days_start_to_end, left=df.start_num, color=df.color, alpha=0.5)
# texts
for idx, row in df.iterrows():
ax.text(row.end_num+0.1, idx,
f"{int(row.Completion*100)}%",
va='center', alpha=0.8)
##### LEGENDS #####
c_dict = {'MKT':'#E64646', 'FIN':'#E69646', 'ENG':'#34D05C', 'PROD':'#34D0C3', 'IT':'#3475D0'}
legend_elements = [Patch(facecolor=c_dict[i], label=i) for i in c_dict]
plt.legend(handles=legend_elements)
##### TICKS #####
xticks = np.arange(0, df.end_num.max()+1, 3)
xticks_labels = pd.date_range(proj_start, end=df.End.max()).strftime("%m/%d")
xticks_minor = np.arange(0, df.end_num.max()+1, 1)
ax.set_xticks(xticks)
ax.set_xticks(xticks_minor, minor=True)
ax.set_xticklabels(xticks_labels[::3])
plt.show()
運(yùn)行結(jié)果如下:

7.再優(yōu)化
最后,為了讓我們的甘特圖更具有吸引力。我們可以繪制網(wǎng)格線,添加我們的標(biāo)題說(shuō)明圖表用途。
代碼較長(zhǎng),不在粘貼。后文有完整代碼獲取方式。
最后的可視化結(jié)果如下:

當(dāng)然也可以設(shè)置背景色,以突出前景條目。效果如下所示:

Wow,果真逼格滿滿。。。。
8. 總結(jié)
本文介紹了如何用Matplotlib使用條形圖繪制甘特圖來(lái)進(jìn)行項(xiàng)目管理可視化,并不斷改進(jìn)以提升最終顯示效果。
到此這篇關(guān)于Python使用Matplotlib繪制甘特圖的實(shí)踐的文章就介紹到這了,更多相關(guān)Matplotlib 甘特圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python中pathlib 面向?qū)ο蟮奈募到y(tǒng)路徑
文章介紹了Python 3.4+內(nèi)置的標(biāo)準(zhǔn)庫(kù)pathlib,該庫(kù)提供面向?qū)ο蟮奈募到y(tǒng)路徑處理,通過(guò)pathlib,可以更方便地進(jìn)行路徑操作,感興趣的朋友一起看看吧2024-12-12
梯度下降法介紹及利用Python實(shí)現(xiàn)的方法示例
梯度下降算法是一個(gè)很基本的算法,在機(jī)器學(xué)習(xí)和優(yōu)化中有著非常重要的作用,下面這篇文章主要給大家介紹了關(guān)于利用Python實(shí)現(xiàn)梯度下降法的相關(guān)資料,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-07-07
Python Flask token身份認(rèn)證的示例代碼(附完整代碼)
在Web應(yīng)用中,經(jīng)常需要進(jìn)行身份認(rèn)證,以確保只有授權(quán)用戶才能訪問(wèn)某些資源,本文主要介紹了Python Flask token身份認(rèn)證的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
Virtualenv 搭建 Py項(xiàng)目運(yùn)行環(huán)境的教程詳解
這篇文章主要介紹了Virtualenv 搭建 Py項(xiàng)目運(yùn)行環(huán)境的詳細(xì)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Python通用函數(shù)實(shí)現(xiàn)數(shù)組計(jì)算的方法
數(shù)組的運(yùn)算可以進(jìn)行加減乘除,同時(shí)也可以將這些算數(shù)運(yùn)算符進(jìn)行任意的組合已達(dá)到效果。這篇文章主要介紹了Python通用函數(shù)實(shí)現(xiàn)數(shù)組計(jì)算的代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-06-06
在pandas多重索引multiIndex中選定指定索引的行方法
今天小編就為大家分享一篇在pandas多重索引multiIndex中選定指定索引的行方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
基于python if 判斷選擇結(jié)構(gòu)的實(shí)例詳解
代碼執(zhí)行結(jié)構(gòu)為順序結(jié)構(gòu)、選擇結(jié)構(gòu)、循環(huán)結(jié)構(gòu)。這篇文章主要介紹了python if 判斷選擇結(jié)構(gòu)的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
python調(diào)用xlsxwriter創(chuàng)建xlsx的方法
今天小編就為大家分享一篇python調(diào)用xlsxwriter創(chuàng)建xlsx的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

