gantt charts

This section describes various options available for gantt charts in fivecentplots

See the full API

Setup

Import packages:


%load_ext autoreload
%autoreload 2
import fivecentplots as fcp
import pandas as pd
from pathlib import Path
import datetime
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

Read some made-up Gantt chart data for the recording schedule of one of the greatest albums of one of the greatest bands:

[275]:
df = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_gantt.csv')
df.head()
[275]:
Task Assigned Start Stop Category
0 Record drums Taylor 2010-09-01 2010-09-05 Recording
1 Record bass Nate 2010-09-04 2010-09-06 Recording
2 Record rhythm guitar Pat 2010-09-06 2010-09-08 Recording
3 Record rhythm guitar Dave 2010-09-06 2010-09-08 Recording
4 Record lead guitar Chris 2010-09-07 2010-09-09 Recording

Optionally set the design theme (skipping here and using default):

[276]:
#fcp.set_theme('gray')
#fcp.set_theme('white')

Basic chart

We create a basic Gantt chart showing tasks across a time axis specified by start and stop column containing Datetime values:

[277]:
fcp.gantt(df, x=['Start', 'Stop'], y='Task', ax_size=[600, 400])
_images/gantt_12_0.png

As with other plots, tick label fonts, sizes, and rotations can all be controlled using the correct kwarg. See Grids and ticks for more details.

Grouping

Like all other plots in fivecentplots, Gantt charts can grouped in various ways to provide further insight into the data set. This includes:

  • legend

  • row

  • col

  • wrap

keyword options. A couple of examples are shown below.

Legends

Legends can be used to further distinguish various tasks by assignee or other factors. If the same task has multiple assignees, they will be split into two different bars in the chart.


fcp.gantt(df, x=['Start', 'Stop'], y='Task', legend='Assigned', ax_size=[600, 400], gantt_tick_labels_x_rotation=45)
_images/gantt_18_0.png

When using a legend, we can also sort the y-axis values based on the order in the legend using keyword order_by_legend=True:


fcp.gantt(df, x=['Start', 'Stop'], y='Task', legend='Assigned', ax_size=[600, 400], gantt_tick_labels_x_rotation=45, order_by_legend=True)
_images/gantt_20_0.png

Row/column plot

Row grouping (share_y is automatically disabled):

[418]:
fcp.gantt(df, x=['Start', 'Stop'], y='Task', row='Category', ax_size=[400, 240])
Text(0, 0, 'Category=Post')
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/mpl.py(3350)set_axes_rc_labels()
   3348 
   3349         # Col/wrap labels
-> 3350         if (ir == 0 and self.label_col.on) or self.label_wrap.on:
   3351             if self.label_wrap.on:
   3352                 if not self.label_wrap.values_only:

Text(0, 0, 'Category=Recording')
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/mpl.py(3350)set_axes_rc_labels()
   3348 
   3349         # Col/wrap labels
-> 3350         if (ir == 0 and self.label_col.on) or self.label_wrap.on:
   3351             if self.label_wrap.on:
   3352                 if not self.label_wrap.values_only:

_images/gantt_23_1.png

Column grouping (share_y is automatically disabled):


fcp.gantt(df, x=['Start', 'Stop'], y='Task', col='Category', ax_size=[400, 240])
_images/gantt_25_0.png

Wrap plot

Notice that share_y is enabled for this type of grouping:


fcp.gantt(df, x=['Start', 'Stop'], y='Task', wrap='Category', ax_size=[400, 240])
_images/gantt_28_0.png

Styling

Default style:


fcp.gantt(df, x=['Start', 'Stop'], y='Task', ax_size=[600, 400])
_images/gantt_31_0.png

Now with various style modifications:


fcp.gantt(df, x=['Start', 'Stop'], y='Task', ax_size=[600, 400], color_by_bar=True,
          gantt_edge_width=2, gantt_edge_color='#555555', gantt_height=0.2, gantt_fill_alpha=1)
_images/gantt_33_0.png

Sorting

By default, the sorting order of tasks is “descending” from top to bottom by date. We can flip that behavior with the keyword sort='ascending':


fcp.gantt(df, x=['Start', 'Stop'], y='Task', sort='ascending', ax_size=[600, 400])
_images/gantt_36_0.png

df = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_gantt_milestone.csv')
df

Quarter Priority Workstream Description Owner Start date End date Duration Milestone Dependency
0 2025-Q1 P0 Design Pixel layout Gary Garrison 01-01-2025 NaN 2w NaN NaN
1 2025-Q1 P0 Design Periphery circuits Andy Anderson 01-20-2025 03-31-2025 NaN NaN Pixel layout
2 2025-Q1 P1 Design TCAD simulation Sam Samuelson 02-22-2025 NaN 10d NaN NaN
3 2025-Q1 P2 Design Initial tape out Amber Amberly 02-22-2025 03-15-2025 NaN NaN NaN
4 2025-Q2 P0 Design Finalize tape out Amber Amberly NaN NaN 1.5m NaN Pixel layout; Periphery circuits
5 2025-Q2 P0 Design Deliver tape out Amber Amberly 05-30-2025 NaN NaN NaN Finalize tape out
6 2025-Q2 P1 Fab Test chip Karthik Sweeny 03-01-2025 04-15-2025 NaN NaN NaN
7 2025-Q3 P0 Fab Alpha samples Karthik Sweeny 06-30-2025 09-15-2025 NaN NaN Deliver tape out
8 2025-Q3 P0 Fab Beta samples Karthik Sweeny 10-01-2025 02-15-2026 NaN NaN Alpha samples
9 2025-Q2 P0 Test Test chip eval Denvyr Loud 04-15-2025 05-15-2025 NaN NaN NaN
10 2025-Q2 P0 Test Test chip eval Denvyr Loud 05-15-2025 NaN NaN Decide pixel NaN
11 2025-Q4 P0 Test Alpha sample testing Denvyr Loud 09-15-2025 12-15-2025 NaN NaN NaN
12 2025-Q2 P4 Marketing Lie about performance Harry Harrison 05-15-2025 06-30-2025 NaN NaN NaN
13 2025-Q3 P4 Marketing Lie about schedule Harry Harrison 07-15-2025 12-30-2025 NaN NaN NaN
14 2025-Q4 P4 Marketing Stress engineers about schedule Harry Harrison 01-15-2026 12-20-2026 NaN NaN NaN
15 2025-Q4 P4 Marketing Deliver beta samples Harry Harrison 12-30-2026 NaN NaN NaN Beta samples
[566]:
fcp.gantt(df, x=['Start date', 'End date'], y='Description', #legend='Owner',
          ax_size=[600, 400], date_type='quarter', workstreams='Workstream',
          labels_as_yticks=False, #workstreams_title=False,
          show=True, workstreams_label_font_size=12)#, today=False)

> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/mpl.py(1248)add_text()
   1246 
   1247             # Update element with the actual object reference
-> 1248             if element and track_element:
   1249                 if el.obj is None:
   1250                     el.obj = text_obj

'Alpha sample testing'
(np.datetime64('2025-12-15T00:00:00.000000000'), 0)
(np.datetime64('2025-12-15T00:00:00.000000000'), 0)
datetime.timedelta(days=1)
*** TypeError: unsupported operand type(s) for +: 'int' and 'datetime.timedelta'
np.datetime64('2025-12-15T00:00:00.000000000')
np.datetime64('2025-12-15T00:00:00.000000000')
datetime.timedelta(days=1)
*** TypeError: unsupported operand type(s) for +: 'int' and 'datetime.timedelta'
_images/gantt_38_1.png
[113]:
fcp.gantt(df, x=['Start date', 'End date'], y='Description', #legend='Owner',
          ax_size=[600, 400], date_type='quarter', workstreams='Workstream',
          #workstreams_title=False,
          show=True, workstreams_label_font_size=12)#, today=False)

Warning: the following kwargs are not supported:
    - date_type
    - workstreams
    - workstreams_label_font_size

legend position is wrong period. but tick size doesn’t fully translate when moved to the top, must be some other tick_param


df = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_gantt_milestone.csv')
fcp.gantt(df, x=['Start date', 'End date'], y='Description',
          ax_size=[900, 400],
          # legend='Owner',
          date_type='quarter',
          workstreams='Workstream',
          # bar_labels='Owner',
          # today=datetime.datetime(2026, 3, 6),
          # today_text='Start',
          #xmin=datetime.datetime(2025, 6, 15),
          show=True,
          xmax=datetime.datetime(2027, 3, 1),
          workstreams_label_font_size=12,
          milestone_text_location='right',
          workstreams_match_bar_color=True
          )
# XMAX NOT WORKING MANUALLY OR WITH

Warning: The following kwargs are not supported:
    - milestone_text_location
    - workstreams_match_bar_color
[514]:
df.loc[9, 'Milestone']
[514]:
'Decide\\npixel'