Chuyển đến nội dung chính

Cách tạo biểu đồ Gantt trong Python với Matplotlib

Tìm hiểu cách tạo biểu đồ Gantt trong Python với matplotlib và lý do các trực quan hóa này hữu ích.
· 10 phút đọc

Khám phá cùng AI

Trong hướng dẫn từng bước này, chúng ta sẽ bàn về biểu đồ Gantt là gì, vì sao và khi nào kiểu trực quan hóa này hữu ích, cách tạo biểu đồ Gantt trong Python với matplotlib, và cách tùy chỉnh thêm. Trong quá trình đó, chúng ta sẽ xây dựng một số ví dụ biểu đồ Gantt bằng matplotlib.

Biểu đồ Gantt là gì và vì sao nó hữu ích?

Biểu đồ Gantt là một dạng biểu đồ cột dùng để minh họa lịch trình lập kế hoạch và quản lý dự án hoàn chỉnh. Nó thường hiển thị các thông tin như tên nhiệm vụ của dự án, ngày bắt đầu và kết thúc, nhóm phụ trách nhiệm vụ, trạng thái hoàn thành dưới dạng phần trăm hoặc phân số, hiệu suất theo nhóm, và các cột mốc quan trọng của dự án.

Tên nhiệm vụ được sắp xếp dọc theo trục y của biểu đồ Gantt, thường được sắp theo thứ tự thời gian của ngày bắt đầu từ trên xuống dưới. Trục x dùng để hiển thị các khoảng thời gian, với độ rộng của mỗi thanh tương ứng với thời lượng thực hiện của từng nhiệm vụ.

Vì biểu đồ Gantt về bản chất là một dạng cụ thể của biểu đồ cột ngang, ta có thể tạo nó trong nhiều thư viện trực quan hóa dữ liệu của Python, gồm matplotlib, Plotly, Bokeh và Altair. Trong hướng dẫn này, chúng ta sẽ tập trung vào việc tạo biểu đồ Gantt trong thư viện phổ biến nhất – matplotlib.

Nếu bạn muốn khám phá các cách thay thế để tạo biểu đồ Gantt và các loại biểu đồ khác trong Python, hãy tham khảo khóa học Introduction to Data Visualization with Plotly in Python. Nếu bạn cần ôn lại hoặc nâng cao kỹ năng matplotlib, các khóa học này sẽ hữu ích: Introduction to Data Visualization with Matplotlib và Python for MATLAB Users.

Cách tạo biểu đồ Gantt trong Python với Matplotlib

Sử dụng barh()

Bắt đầu với việc dựng một biểu đồ Gantt cơ bản bằng matplotlib sử dụng phương thức barh() của matplotlib.pyplot.

Trước hết, ta cần tải các thư viện cần thiết:

import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import datetime as dt

Bước tiếp theo là tạo dữ liệu giả để thực hành:

df = pd.DataFrame({'task': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'],
                  'team': ['R&D', 'Accounting', 'Sales', 'Sales', 'IT', 'R&D', 'IT', 'Sales', 'Accounting', 'Accounting', 'Sales', 'IT'],
                  'start': pd.to_datetime(['20 Oct 2022', '24 Oct 2022', '26 Oct 2022', '31 Oct 2022', '3 Nov 2022', '7 Nov 2022', '10 Nov 2022', '14 Nov 2022', '18 Nov 2022', '23 Nov 2022', '28 Nov 2022', '30 Nov 2022']),
                  'end': pd.to_datetime(['31 Oct 2022', '28 Oct 2022', '31 Oct 2022', '8 Nov 2022', '9 Nov 2022', '18 Nov 2022', '17 Nov 2022', '22 Nov 2022', '23 Nov 2022', '1 Dec 2022', '5 Dec 2022', '5 Dec 2022']),
                  'completion_frac': [1, 1, 1, 1, 1, 0.95, 0.7, 0.35, 0.1, 0, 0, 0]})
print(df)

Kết quả:

  task        team      start        end  completion_frac
0     A         R&D 2022-10-20 2022-10-31             1.00
1     B  Accounting 2022-10-24 2022-10-28             1.00
2     C       Sales 2022-10-26 2022-10-31             1.00
3     D       Sales 2022-10-31 2022-11-08             1.00
4     E          IT 2022-11-03 2022-11-09             1.00
5     F         R&D 2022-11-07 2022-11-18             0.95
6     G          IT 2022-11-10 2022-11-17             0.70
7     H       Sales 2022-11-14 2022-11-22             0.35
8     I  Accounting 2022-11-18 2022-11-23             0.10
9     J  Accounting 2022-11-23 2022-12-01             0.00
10    K       Sales 2022-11-28 2022-12-05             0.00
11    L          IT 2022-11-30 2022-12-05             0.00

Để thuận tiện cho việc dựng biểu đồ Gantt cho dữ liệu này, chúng ta cần tính thêm bốn cột đại diện cho các thông tin sau:

  1. Số ngày đã/sẽ trôi qua từ lúc dự án bắt đầu tới ngày bắt đầu của mỗi nhiệm vụ:
df['days_to_start'] = (df['start'] - df['start'].min()).dt.days
  1. Số ngày đã/sẽ trôi qua từ lúc dự án bắt đầu tới ngày kết thúc của mỗi nhiệm vụ:
df['days_to_end'] = (df['end'] - df['start'].min()).dt.days
  1. Thời lượng của mỗi nhiệm vụ, bao gồm cả ngày bắt đầu và ngày kết thúc:
df['task_duration'] = df['days_to_end'] - df['days_to_start'] + 1  # to include also the end date
  1. Trạng thái hoàn thành của mỗi nhiệm vụ chuyển từ phân số sang số ngày phân bổ cho nhiệm vụ đó:
df['completion_days'] = df['completion_frac'] * df['task_duration']

Hãy kiểm tra kết quả thu được:

print(df)

Kết quả:

  task        team      start        end  completion_frac  days_to_start  \
0     A         R&D 2022-10-20 2022-10-31             1.00              0  
1     B  Accounting 2022-10-24 2022-10-28             1.00              4  
2     C       Sales 2022-10-26 2022-10-31             1.00              6  
3     D       Sales 2022-10-31 2022-11-08             1.00             11  
4     E          IT 2022-11-03 2022-11-09             1.00             14  
5     F         R&D 2022-11-07 2022-11-18             0.95             18  
6     G          IT 2022-11-10 2022-11-17             0.70             21  
7     H       Sales 2022-11-14 2022-11-22             0.35             25  
8     I  Accounting 2022-11-18 2022-11-23             0.10             29  
9     J  Accounting 2022-11-23 2022-12-01             0.00             34  
10    K       Sales 2022-11-28 2022-12-05             0.00             39  
11    L          IT 2022-11-30 2022-12-05             0.00             41  

    days_to_end  task_duration  completion_days 
0            11             12            12.00 
1             8              5             5.00 
2            11              6             6.00 
3            19              9             9.00 
4            20              7             7.00 
5            29             12            11.40 
6            28              8             5.60 
7            33              9             3.15 
8            34              6             0.60 
9            42              9             0.00 
10           46              8             0.00 
11           46              6             0.00 

Bây giờ, chúng ta sẵn sàng tạo một biểu đồ Gantt cơ bản trong matplotlib:

plt.barh(y=df['task'], width=df['task_duration'], left=df['days_to_start'])
plt.show()

Kết quả:

Biểu đồ Gantt trong Matplotlib

Biểu đồ trên cần khá nhiều điều chỉnh để chúng ta có thể rút trích tối đa thông tin từ đó:

  • Thêm tiêu đề ý nghĩa và nhãn trục x (các ngày)
  • Đảo ngược trục y để các nhiệm vụ theo thứ tự thời gian từ trên xuống dưới
  • Thêm lưới
  • Tô màu nhiệm vụ theo nhóm
  • Hiển thị chú giải
  • Thêm trạng thái hoàn thành nhiệm vụ

Chúng ta sẽ sớm triển khai tất cả những tinh chỉnh đó. Tuy nhiên, trước khi làm vậy, hãy xem cách xử lý việc tạo biểu đồ Gantt cơ bản.

Sử dụng broken_barh()

Khi một số nhiệm vụ có hai hoặc nhiều phân nhiệm trải dài theo thời gian, chúng ta nên dùng một phương thức khác của matplotlib – broken_barh().

Để có dữ liệu giả để thử cách tiếp cận này, hãy làm như sau:

  1. Lấy từ dataframe ban đầu những nhiệm vụ được giao cho nhóm Sales (tạm thời bỏ qua cột completion_frac).
  2. Đổi tên cột start và end thành start_1 và end_1 tương ứng (cho tiện).
  3. Thêm nhiều phân nhiệm cho một số nhiệm vụ hiện có.
  4. Với mỗi phân nhiệm, tính ba cột như trên, biểu diễn các thông tin sau:
    • Số ngày đã/sẽ trôi qua từ lúc dự án bắt đầu tới ngày bắt đầu của từng phân nhiệm.
    • Số ngày đã/sẽ trôi qua từ lúc dự án bắt đầu tới ngày kết thúc của từng phân nhiệm.
    • Thời lượng của từng phân nhiệm, bao gồm cả ngày bắt đầu và ngày kết thúc.
# 1
df2 = df[df['team']=='Sales'][['task', 'team', 'start', 'end']]

# 2
df2.rename(columns={'start': 'start_1', 'end': 'end_1'}, inplace=True)
df2.reset_index(drop=True, inplace=True)

# 3
df2['start_2'] = pd.to_datetime([None, '10 Nov 2022', '25 Nov 2022', None])
df2['end_2'] = pd.to_datetime([None, '14 Nov 2022', '28 Nov 2022', None])
df2['start_3'] = pd.to_datetime([None, None, '1 Dec 2022', None])
df2['end_3'] = pd.to_datetime([None, None, '5 Dec 2022', None])

# 4
for i in [1, 2, 3]:
    suffix = '_' + str(i)
    df2['days_to_start' + suffix] = (df2['start' + suffix] - df2['start_1'].min()).dt.days
    df2['days_to_end' + suffix] = (df2['end' + suffix] - df2['start_1'].min()).dt.days
    df2['task_duration' + suffix] = df2['days_to_end' + suffix] - df2['days_to_start' + suffix] + 1


print(df2)

Kết quả:

task   team    start_1      end_1    start_2      end_2    start_3  \
0    C  Sales 2022-10-26 2022-10-31        NaT        NaT        NaT  
1    D  Sales 2022-10-31 2022-11-08 2022-11-10 2022-11-14        NaT  
2    H  Sales 2022-11-14 2022-11-22 2022-11-25 2022-11-28 2022-12-01  
3    K  Sales 2022-11-28 2022-12-05        NaT        NaT        NaT  

      end_3  days_to_start_1  days_to_end_1  task_duration_1  \
0        NaT                0              5                6  
1        NaT                5             13                9  
2 2022-12-05               19             27                9  
3        NaT               33             40                8  

  days_to_start_2  days_to_end_2  task_duration_2  days_to_start_3  \
0              NaN            NaN              NaN              NaN  
1             15.0           19.0              5.0              NaN  
2             30.0           33.0              4.0             36.0  
3              NaN            NaN              NaN              NaN  

  days_to_end_3  task_duration_3 
0            NaN              NaN 
1            NaN              NaN 
2           40.0              5.0 
3            NaN              NaN 

Lưu ý rằng giờ đây nhiệm vụ D có hai phân nhiệm, nhiệm vụ H có ba phân nhiệm, còn C và K mỗi nhiệm vụ có một phân nhiệm. Vì vậy, D và H là những nhiệm vụ mà chúng ta sẽ áp dụng phương thức broken_barh(). Do cú pháp của phương thức này kém trực quan hơn barh(), hãy xem các tham số chính và định dạng của chúng. Các tham số bắt buộc của broken_barh() là:

  • xranges – một dãy các bộ giá trị theo định dạng (xmin, xwidth) để chỉ điểm bắt đầu và độ dài của mỗi thanh. Tại đây, mỗi thanh đại diện cho một phân nhiệm. Vậy tham số này hiển thị ngày bắt đầu và thời lượng của mỗi phân nhiệm.
  • yrange – một bộ giá trị theo định dạng (ymin, yheight) để chỉ vị trí y và chiều cao cho mỗi thanh.

Bây giờ, hãy vẽ biểu đồ Gantt "gãy đoạn" của chúng ta. Thuật toán như sau:

  1. Tạo một figure với các subplot.
  2. Lặp qua các hàng của dataframe và kiểm tra nhiệm vụ có một, hai hay ba phân nhiệm. Dựa vào đó, thực hiện:
    • Một phân nhiệm: vẽ một thanh bằng phương thức barh() như trước.
    • Hai phân nhiệm: vẽ hai thanh bằng phương thức broken_barh().
    • Ba phân nhiệm: vẽ ba thanh bằng phương thức broken_barh().
  3. Thêm điều chỉnh cơ bản: đặt và gán nhãn các tick của trục y.
# 1
fig, ax = plt.subplots()

# 2
for index, row in df2.iterrows():
    if row['start_2'] is None:
        ax.barh(y=df2['task'], width=df2['task_duration_1'], left=df2['days_to_start_1'])
    elif row['start_2'] is not None and row['start_3'] is None:
        ax.broken_barh(xranges=[(row['days_to_start_1'], row['task_duration_1']), (row['days_to_start_2'], row['task_duration_2'])], yrange=(index + 1, 0.5))
    else:
        ax.broken_barh(xranges=[(row['days_to_start_1'], row['task_duration_1']), (row['days_to_start_2'], row['task_duration_2']), (row['days_to_start_3'], row['task_duration_3'])], yrange=(index + 1, 0.5))

# 3
ax.set_yticks([1.25, 2.25, 3.25, 4.25])
ax.set_yticklabels(df2['task'])

plt.show()

Kết quả:

Biểu đồ Gantt broken_barh()

Trong đoạn mã trên, thực ra chúng ta có thể dùng phương thức broken_barh() để vẽ các thanh cả cho những nhiệm vụ chỉ có một phân nhiệm. Khi đó, cần thay dòng:

ax.barh(y=df2['task'], width=df2['task_duration_1'], left=df2['days_to_start_1'])

bằng dòng này:

ax.broken_barh(xranges=[(row['days_to_start_1'], row['task_duration_1'])], yrange=(index + 1, 0.5))

Cách này cũng giúp mã của chúng ta đồng nhất và dễ đọc hơn.

Cách tùy chỉnh biểu đồ Gantt trong Matplotlib

Quay lại dataframe ban đầu của chúng ta:

print(df)

Kết quả:

  task        team      start        end  completion_frac  days_to_start  \
0     A         R&D 2022-10-20 2022-10-31             1.00              0  
1     B  Accounting 2022-10-24 2022-10-28             1.00              4  
2     C       Sales 2022-10-26 2022-10-31             1.00              6  
3     D       Sales 2022-10-31 2022-11-08             1.00             11  
4     E          IT 2022-11-03 2022-11-09             1.00             14  
5     F         R&D 2022-11-07 2022-11-18             0.95             18  
6     G          IT 2022-11-10 2022-11-17             0.70             21  
7     H       Sales 2022-11-14 2022-11-22             0.35             25  
8     I  Accounting 2022-11-18 2022-11-23             0.10             29  
9     J  Accounting 2022-11-23 2022-12-01             0.00             34  
10    K       Sales 2022-11-28 2022-12-05             0.00             39  
11    L          IT 2022-11-30 2022-12-05             0.00             41  

    days_to_end  task_duration  completion_days 
0            11             12            12.00 
1             8              5             5.00 
2            11              6             6.00 
3            19              9             9.00 
4            20              7             7.00 
5            29             12            11.40 
6            28              8             5.60 
7            33              9             3.15 
8            34              6             0.60 
9            42              9             0.00 
10           46              8             0.00 
11           46              6             0.00 

và biểu đồ Gantt đầu tiên của chúng ta:

plt.barh(y=df['task'], width=df['task_duration'], left=df['days_to_start'])
plt.show()

Kết quả:

Biểu đồ Gantt trong Matplotlib

Cụ thể, chúng ta muốn thêm một số tùy chỉnh vào biểu đồ này để nó giàu thông tin hơn.

Để đào sâu hơn vào việc tùy chỉnh biểu đồ với matplotlib, hãy tham khảo các tài nguyên sau: Matplotlib Tutorial: Python Plotting và Matplotlib Cheat Sheet: Plotting in Python.

Các điều chỉnh cơ bản cho biểu đồ Gantt

Gồm có:

  • Thêm tiêu đề biểu đồ
  • Điều chỉnh và tùy biến các trục
  • Thêm lưới

Thêm tiêu đề biểu đồ

Có tiêu đề ý nghĩa là điều bắt buộc với bất kỳ biểu đồ nào, kể cả biểu đồ Gantt. Giả sử dự án của chúng ta tên là Project X:

plt.barh(y=df['task'], width=df['task_duration'], left=df['days_to_start'])
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.show()

Kết quả:

Tiêu đề biểu đồ Matplotlib cho biểu đồ Gantt

Điều chỉnh và tùy biến các trục và thêm lưới

Ở bước này, chúng ta sẽ xây dựng tiếp trên đoạn mã trước và thực hiện các thao tác sau:

  1. Tạo figure với subplot để có thể làm việc với đối tượng ax.
  2. Đảo trục y để các nhiệm vụ theo thứ tự thời gian từ trên xuống dưới.
  3. Xác định vị trí tối ưu của các tick trên trục x.
    • Giả sử chúng ta muốn đặt tick trục x vào mỗi thứ Hai, lưu ý rằng Project X bắt đầu vào thứ Năm.
    • Chúng ta chỉ dùng tick chính để tránh rối biểu đồ.
  4. Xác định nhãn tick trục x phù hợp và định dạng hợp lý.
    • Một lần nữa, lưu ý rằng Project X bắt đầu vào thứ Năm, và chúng ta chỉ cần gắn nhãn cho các thứ Hai.
    • Vì Project X hoàn toàn diễn ra trong năm 2022, nên không cần ghi năm cho mỗi ngày.
    • Điều quan trọng là số tick trục x phải bằng số nhãn tick trục x.
  5. Thêm tick và nhãn tick cho trục x.
  6. Thêm lưới dọc.
# 1
fig, ax = plt.subplots()

plt.barh(y=df['task'], width=df['task_duration'], left=df['days_to_start'] + 1)
plt.title('Project Management Schedule of Project X', fontsize=15)

# 2
plt.gca().invert_yaxis()

# 3
xticks = np.arange(5, df['days_to_end'].max() + 2, 7)

# 4
xticklabels = pd.date_range(start=df['start'].min() + dt.timedelta(days=4), end=df['end'].max()).strftime("%d/%m")
# 5
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])

# 6
ax.xaxis.grid(True, alpha=0.5)

plt.show()

Kết quả:

Tùy chỉnh trục cho biểu đồ Gantt

Nếu bạn cần thực hành Python nhiều hơn để viết và đọc mã Python dễ dàng, khóa học Intermediate Python của chúng tôi là điểm tham chiếu tốt.

Tô màu nhiệm vụ theo nhóm

Bây giờ, hãy mã hóa màu cho mỗi thanh (đại diện cho một nhiệm vụ cụ thể) theo nhóm phụ trách nhiệm vụ đó. Để làm vậy, chúng ta sẽ:

  1. Tạo một từ điển với tên nhóm là khóa và màu cơ bản của matplotlib là giá trị.
  2. Tạo figure với subplot.
  3. Lặp qua các hàng của dataframe, tạo một thanh cho mỗi hàng và thêm màu tương ứng với nhóm.
  4. Thêm tất cả các điều chỉnh cơ bản như trước.
# 1
team_colors = {'R&D': 'c', 'Accounting': 'm', 'Sales': 'y', 'IT': 'b'}

# 2
fig, ax = plt.subplots()

# 3
for index, row in df.iterrows():
    plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start'] + 1, color=team_colors[row['team']])

# 4
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)
plt.show()

Kết quả:

Biểu đồ Gantt với nhiệm vụ được tô màu theo nhóm

Thêm chú giải

Một điều còn thiếu trong ví dụ biểu đồ Gantt trên là chú giải thể hiện màu nào ứng với nhóm nào. Để khắc phục, hãy tạo các patch – đối tượng đồ họa 2D của matplotlib được tô bằng một màu xác định trước. Chúng ta sẽ dùng lớp matplotlib.patches.Patch để tạo danh sách patch, mỗi nhóm một patch, tô màu tương ứng:

patches = []
for team in team_colors:
    patches.append(matplotlib.patches.Patch(color=team_colors[team]))

Giờ chúng ta sẵn sàng thêm chú giải vào biểu đồ:

fig, ax = plt.subplots()
for index, row in df.iterrows():
    plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start'] + 1, color=team_colors[row['team']])
plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)

# Adding a legend
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)

plt.show()

Kết quả:

Biểu đồ Gantt với chú giải

Ví dụ biểu đồ Gantt trên trông nhiều thông tin hơn hẳn.

Bạn sẽ tìm thấy thêm nhiều kỹ thuật để cải thiện thẩm mỹ và khả năng đọc của biểu đồ trong khóa học Improving Your Data Visualizations in Python.

Thêm trạng thái hoàn thành

Cho đến giờ, chúng ta vẫn chưa dùng cột completion_days đã tính ở đầu hướng dẫn. Bây giờ, chúng ta sẽ dùng nó để làm cho biểu đồ Gantt mang nhiều thông tin hơn bằng cách hiển thị giai đoạn hoàn thành của mỗi nhiệm vụ.

Về kỹ thuật, chúng ta sẽ thêm một thanh nữa chồng lên mỗi thanh đã vẽ. Thanh dưới biểu diễn tổng thời lượng của mỗi nhiệm vụ theo số ngày được phân bổ, trong khi thanh trên biểu diễn trạng thái hoàn thành của nhiệm vụ đó theo số ngày được phân bổ. 

Với mỗi nhiệm vụ, cả hai thanh sẽ có cùng một màu theo nhóm tương ứng, nhưng thanh dưới sẽ nhạt màu hơn thanh trên để dễ phân biệt.

Nói cách khác, nếu một nhóm đang vượt tiến độ ở một nhiệm vụ, sự kết hợp của hai thanh sẽ cho thấy như thể nhóm đã làm nhiều ngày cho nhiệm vụ đó hơn dự kiến (nghĩa là nhiệm vụ có khả năng hoàn thành trước hạn). 

Ở chiều ngược lại, nếu một nhóm đang chậm tiến độ ở một nhiệm vụ, sự kết hợp các thanh tương ứng sẽ cho thấy như thể nhóm làm ít ngày hơn dự kiến (nghĩa là nhiệm vụ có khả năng hoàn thành sau hạn).

fig, ax = plt.subplots()

for index, row in df.iterrows():

    # Adding a lower bar - for the overall task duration
    plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start'] + 1, color=team_colors[row['team']], alpha=0.4)

    # Adding an upper bar - for the status of completion
    plt.barh(y=row['task'], width=row['completion_days'], left=row['days_to_start'] + 1, color=team_colors[row['team']])

plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)
plt.show()

Kết quả:

Biểu đồ Gantt với trạng thái hoàn thành

Từ biểu đồ trên, ta thấy các nhóm không có cùng nhịp độ hoàn thành nhiệm vụ, điều khá phổ biến trong nhiều dự án thực tế. Để rút thêm thông tin, giả sử ngày hiện tại là 17/11/2022 và đánh dấu ngày này trên biểu đồ:

fig, ax = plt.subplots()
for index, row in df.iterrows():
    plt.barh(y=row['task'], width=row['task_duration'], left=row['days_to_start'] + 1, color=team_colors[row['team']], alpha=0.4)
    plt.barh(y=row['task'], width=row['completion_days'], left=row['days_to_start'] + 1, color=team_colors[row['team']])

plt.title('Project Management Schedule of Project X', fontsize=15)
plt.gca().invert_yaxis()
ax.set_xticks(xticks)
ax.set_xticklabels(xticklabels[::7])
ax.xaxis.grid(True, alpha=0.5)
ax.legend(handles=patches, labels=team_colors.keys(), fontsize=11)

# Marking the current date on the chart
ax.axvline(x=29, color='r', linestyle='dashed')
ax.text(x=29.5, y=11.5, s='17/11', color='r')

plt.show()

Kết quả:

Biểu đồ Gantt với ngày hiện tại

Chúng ta có thể đưa ra các nhận xét sau về trạng thái hiện tại của Project X:

  • Nhóm R&D đang vượt tiến độ ở Nhiệm vụ F và có thể sẽ hoàn thành trước hạn.
  • Nhóm IT đang chậm ở Nhiệm vụ G và có lẽ cần được hỗ trợ.
  • Nhóm Sales đang thực hiện đúng lịch ở Nhiệm vụ H.
  • Nhóm Accounting đã bắt đầu Nhiệm vụ I sớm hơn lịch dự án.

Những nhận xét như vậy có thể giúp các trưởng nhóm và quản lý dự án điều chỉnh lịch trình phù hợp và phân bổ nguồn lực kịp thời để tránh chậm trễ các hạng mục bàn giao.

Các điều chỉnh khác có thể thực hiện

Chúng ta có thể bổ sung thêm chi tiết cho biểu đồ Gantt bằng matplotlib. Ví dụ:

  • Thêm tỷ lệ phần trăm hoàn thành trên mỗi thanh.
  • Chia nhỏ một số nhiệm vụ thành các phân nhiệm (chúng ta đã bàn cách thực hiện ở phần trước).
  • Chú thích các nhiệm vụ có liên quan.
  • Đánh dấu các cột mốc và thời hạn quan trọng.
  • Làm nổi bật cuối tuần và ngày nghỉ.
  • Sắp xếp các thanh theo nhóm hoặc loại nhiệm vụ.
  • Thêm các tick phụ trên trục x để tăng độ chi tiết thông tin.
  • Cải thiện định dạng và bố cục tổng thể của biểu đồ.

Tuy nhiên, điều quan trọng là giữ cho biểu đồ Gantt gọn gàng và tránh chất quá nhiều chi tiết. Cũng như mọi loại trực quan hóa dữ liệu khác, chúng ta cần duy trì cân bằng giữa dung lượng thông tin và khả năng đọc của biểu đồ, cũng như khả năng đọc của mã dùng để tạo biểu đồ đó.

Bắt đầu tự tạo biểu đồ Gantt trong Python với Matplotlib

Tóm lại, trong hướng dẫn này, chúng ta đã khám phá:

  • biểu đồ Gantt là gì
  • nó hiển thị kiểu thông tin nào
  • khi nào được dùng
  • các cách và lưu ý khi tạo biểu đồ Gantt với matplotlib
  • cách tạo biểu đồ Gantt trong Python với matplotlib 
  • cách điều chỉnh thêm để biểu đồ giàu thông tin hơn
  • cách diễn giải kết quả cuối cùng. 

Ngoài ra, chúng ta đã xem nhiều ví dụ biểu đồ Gantt và quy trình xây dựng từng bước.

Để có cách tiếp cận tích hợp hơn trong việc học cách tạo các biểu đồ hấp dẫn và nhiều thông tin trong Python, hãy xem lộ trình kỹ năng Data Visualization with Python của chúng tôi.

Chủ đề

Liên quan