Print

Gantt chart / Timeline in matplotlib

In this tutorial I will show you how to create Gantt charts using Python and Matplotlib. For more matplotlib charts, check out the gallery:

1 dataset 100 matplotlib visualizations
Python dataviz gallery, matplotlib viz gallery

Important notes:

1. This are my personal notes, so apologies if some explanations and notations are missing.

Gantt charts in matplotlib

This is what we will be creating:

Import the packages

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

Create the data

data = {
    "war": ['World War I','World War II','Korea','Vietnam','Guf War','Iraq','Afghanistan'],
    "start" : [1914,1939,1950,1965,1990,2003,2001],
    "end" : [1918,1945,1953,1973,1991,2011,2020]
}

#convert array to pandas dataframe
df = pd.DataFrame(data)
#convert array to pandas dataframe
df['start'] = df['start'].astype(int)
df['end'] = df['end'].astype(int)  #change the type to number
df['year_Diff'] = df['end'] - df['start']
warstartendyear_Diff
0World War I191419184
1World War II193919456
2Korea195019533
3Vietnam196519738
4Guf War199019911
5Iraq200320118
6Afghanistan2001202019

Define variables

#convert the columns into numpy 2D array
x_coord = df[['start','year_Diff']].to_numpy()

#array for the range annotation
arrow = df[['start','end']].to_numpy()

Plot the chart

fig, ax = plt.subplots(figsize=(18, 4), facecolor="white")

#add the timeline
ax.broken_barh([(1905, 117)], (20, 5), color = "#eeeeee")


#add a for afgahnistan for each event
for st, ed, text, arr, xcoord in zip(start[-1:],end[-1:], war[-1:], arrow[-1:], x_coord[-1:]): #remove afghanistan
#the max and min for the line is specified in percentage
    ax.broken_barh([xcoord], (20, 5), color=['#dbdbdb'], alpha=0.7, 
                linewidth=2, 
                edgecolor=['#E82E22'], 
                linestyle='dashed', hatch='xx' )
    #the max and min for the line is specified in percentage
    ax.axvline(x=st, ymin = 0.17, ymax = 0.42, color='#000', linestyle= "-") 
    ax.axvline(x=ed, ymin = 0.34, ymax = 0.42, color='#000', linestyle= "-") 
    ax.annotate(text, (st , 15),xytext=(4, -3), textcoords='offset points', ha='left', va='bottom')
    ax.annotate(str(st) + " - " + str(ed), (st , 12),xytext=(4, -3), textcoords='offset points', ha='left', va='bottom')
    ax.annotate('', xy = (arr[0],17), xycoords='data', xytext=(arr[1],17),
                 arrowprops=dict(arrowstyle='-',  lw=1, shrinkA=0, shrinkB=0,  color = "#000",))

#add a line for each event
for st, ed, text, arr, xcoord in zip(start[:-1],end[:-1], war[:-1], arrow[:-1], x_coord[:-1]): #remove afghanistan
#the max and min for the line is specified in percentage
    ax.broken_barh([xcoord], (20, 5), color = "#E82E22", hatch='/')
    #the max and min for the line is specified in percentage
    ax.axvline(x=st, ymin = 0.57, ymax = 0.8, color='#000', linestyle= "-") 
    ax.axvline(x=ed, ymin = 0.57, ymax = 0.62, color='#000', linestyle= "-") 
    ax.annotate(text, (st , 32),xytext=(4, -3), textcoords='offset points', ha='left', va='bottom')
    ax.annotate(str(st) + " - " + str(ed), (st , 29),xytext=(4, -3), textcoords='offset points', ha='left', va='bottom')
    ax.annotate('', xy = (arr[0],27), xycoords='data', xytext=(arr[1],27),
                 arrowprops=dict(arrowstyle='-',  lw=1, shrinkA=0, shrinkB=0,  color = "#000",))

    
ax.set_ylim(5, 40)
ax.set_xlim(1905, 2022)

# Hide grid lines
plt.box(False) #remove box

# Hide axes ticks
plt.axis('off') #turn all axis off
plt.yticks([])
Was this helpful?

Reader Interactions

Leave a Reply

Your email address will not be published. Required fields are marked *

Table of Contents