Skip to content

Instantly share code, notes, and snippets.

@Thiagobc23
Created August 30, 2021 02:46
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0 to your computer and use it in GitHub Desktop.
Save Thiagobc23/ad0f228dd8a6b1c9a9e148f17de5b4b0 to your computer and use it in GitHub Desktop.
Gantt chart with Matplotlib
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from pandas import Timestamp
##### DATA #####
data = {'Task': {0: 'TSK M',
1: 'TSK N',
2: 'TSK L',
3: 'TSK K',
4: 'TSK J',
5: 'TSK H',
6: 'TSK I',
7: 'TSK G',
8: 'TSK F',
9: 'TSK E',
10: 'TSK D',
11: 'TSK C',
12: 'TSK B',
13: 'TSK A'},
'Department': {0: 'IT',
1: 'MKT',
2: 'ENG',
3: 'PROD',
4: 'PROD',
5: 'FIN',
6: 'MKT',
7: 'FIN',
8: 'MKT',
9: 'ENG',
10: 'FIN',
11: 'IT',
12: 'MKT',
13: 'MKT'},
'Start': {0: Timestamp('2022-03-17 00:00:00'),
1: Timestamp('2022-03-17 00:00:00'),
2: Timestamp('2022-03-10 00:00:00'),
3: Timestamp('2022-03-09 00:00:00'),
4: Timestamp('2022-03-04 00:00:00'),
5: Timestamp('2022-02-28 00:00:00'),
6: Timestamp('2022-02-28 00:00:00'),
7: Timestamp('2022-02-27 00:00:00'),
8: Timestamp('2022-02-26 00:00:00'),
9: Timestamp('2022-02-23 00:00:00'),
10: Timestamp('2022-02-22 00:00:00'),
11: Timestamp('2022-02-21 00:00:00'),
12: Timestamp('2022-02-19 00:00:00'),
13: Timestamp('2022-02-15 00:00:00')},
'End': {0: Timestamp('2022-03-20 00:00:00'),
1: Timestamp('2022-03-19 00:00:00'),
2: Timestamp('2022-03-13 00:00:00'),
3: Timestamp('2022-03-13 00:00:00'),
4: Timestamp('2022-03-17 00:00:00'),
5: Timestamp('2022-03-02 00:00:00'),
6: Timestamp('2022-03-05 00:00:00'),
7: Timestamp('2022-03-03 00:00:00'),
8: Timestamp('2022-02-27 00:00:00'),
9: Timestamp('2022-03-09 00:00:00'),
10: Timestamp('2022-03-01 00:00:00'),
11: Timestamp('2022-03-03 00:00:00'),
12: Timestamp('2022-02-24 00:00:00'),
13: Timestamp('2022-02-20 00:00:00')},
'Completion': {0: 0.0,
1: 0.0,
2: 0.0,
3: 0.0,
4: 0.0,
5: 1.0,
6: 0.4,
7: 0.7,
8: 1.0,
9: 0.5,
10: 1.0,
11: 0.9,
12: 1.0,
13: 1.0}}
##### DATA PREP #####
df = pd.DataFrame(data)
# 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
# days between start and current progression of each task
df['current_num'] = (df.days_start_to_end * df.Completion)
# 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)
##### PLOT #####
fig, (ax, ax1) = plt.subplots(2, figsize=(16,6), gridspec_kw={'height_ratios':[6, 1]})
# 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)
for idx, row in df.iterrows():
ax.text(row.end_num+0.1, idx, f"{int(row.Completion*100)}%", va='center', alpha=0.8)
ax.text(row.start_num-0.1, idx, row.Task, va='center', ha='right', alpha=0.8)
# grid lines
ax.set_axisbelow(True)
ax.xaxis.grid(color='gray', linestyle='dashed', alpha=0.2, which='both')
# 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])
ax.set_yticks([])
# ticks top
# create a new axis with the same y
ax_top = ax.twiny()
# align x axis
ax.set_xlim(0, df.end_num.max())
ax_top.set_xlim(0, df.end_num.max())
# top ticks (markings)
xticks_top_minor = np.arange(0, df.end_num.max()+1, 7)
ax_top.set_xticks(xticks_top_minor, minor=True)
# top ticks (label)
xticks_top_major = np.arange(3.5, df.end_num.max()+1, 7)
ax_top.set_xticks(xticks_top_major, minor=False)
# week labels
xticks_top_labels = [f"Week {i}"for i in np.arange(1, len(xticks_top_major)+1, 1)]
ax_top.set_xticklabels(xticks_top_labels, ha='center', minor=False)
# hide major tick (we only want the label)
ax_top.tick_params(which='major', color='w')
# increase minor ticks (to marks the weeks start and end)
ax_top.tick_params(which='minor', length=8, color='k')
# remove spines
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['left'].set_position(('outward', 10))
ax.spines['top'].set_visible(False)
ax_top.spines['right'].set_visible(False)
ax_top.spines['left'].set_visible(False)
ax_top.spines['top'].set_visible(False)
plt.suptitle('PROJECT XYZ')
##### LEGENDS #####
legend_elements = [Patch(facecolor='#E64646', label='Marketing'),
Patch(facecolor='#E69646', label='Finance'),
Patch(facecolor='#34D05C', label='Engineering'),
Patch(facecolor='#34D0C3', label='Production'),
Patch(facecolor='#3475D0', label='IT')]
ax1.legend(handles=legend_elements, loc='upper center', ncol=5, frameon=False)
# clean second axis
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.spines['bottom'].set_visible(False)
ax1.set_xticks([])
ax1.set_yticks([])
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment