Draw a Gantt chart¶
gantt() draws a table with a row per task: a lane per task in the order of the table, a bar
from each task's start to its end, dependencies as arrows, progress as a fill, and milestones
(a start equal to the end) as diamonds.
import numpy as np
from anytimeline import gantt
plan = {
"task": ["Requirements", "Design", "Prototype", "Review", "Build backend",
"Build frontend", "Write docs", "Test", "Release"],
"start": np.array(["2026-09-01", "2026-09-08", "2026-09-15", "2026-09-29", "2026-09-30",
"2026-10-02", "2026-10-05", "2026-10-20", "2026-11-02"],
dtype="datetime64[D]"),
"days": [7, 9, 14, 0, 18, 16, 20, 13, 0],
"after": [None, "Requirements", "Design", "Prototype", "Review", "Review", "Design",
"Build backend, Build frontend", "Test, Write docs"],
"done": [1.0, 1.0, 1.0, 1.0, 0.6, 0.4, 0.3, 0.0, 0.0],
"phase": ["plan", "plan", "plan", "plan", "build", "build", "build", "ship", "ship"],
}
chart = gantt(
plan, end=None, duration="days", duration_unit="d",
depends="after", progress="done", color="phase", text="{task}",
palette={"plan": "#4c78a8", "build": "#f58518", "ship": "#54a24b"},
title="Project plan", today="2026-10-12",
)
chart
The columns¶
| Argument | The column | Default |
|---|---|---|
task= |
the task's name: its lane, and how other tasks refer to it | "task" |
start= |
when it starts | "start" |
end= |
when it ends; or end=None with duration= |
"end" |
duration=, duration_unit= |
how long it takes: durations, or numbers in "d", "h", "min", ... |
— |
depends= |
the tasks it follows: a name, a list of names, or names separated by commas | — |
parent= |
the task it is part of (missing for a top task) | — |
progress= |
how far it is done, 0 to 1 | — |
color= |
a category to color it by (a phase, a team), or one color | the theme's color |
palette= given as a dict sets the colors and the order of the legend. text= writes in
each bar where it fits (here the task's name again). today= draws a line labelled "today";
give it datetime.now() for a live plan.
Read it¶
- Hover over a task for its start, end, duration and progress.
- Arrows run from the end of a task to the start of each task that follows it; when the next task starts before this one ends, the arrow goes around.
- Switch to Order in the toolbar: every start and end gets the same width, so short tasks and long waits take the same room and the sequence of steps stands out.
Sub-tasks¶
parent= names the task each task is part of: sub-tasks go under their task, which you can
fold (click its name; double-click to zoom to it).
work = {
"task": ["Backend", "API", "Database", "Frontend", "Pages", "Styles", "Release"],
"part of": [None, "Backend", "Backend", None, "Frontend", "Frontend", None],
"start": np.array(["2026-10-01", "2026-10-01", "2026-10-06", "2026-10-05", "2026-10-05",
"2026-10-12", "2026-10-23"], dtype="datetime64[D]"),
"end": np.array(["2026-10-20", "2026-10-14", "2026-10-20", "2026-10-22", "2026-10-16",
"2026-10-22", "2026-10-23"], dtype="datetime64[D]"),
"after": [None, None, None, None, None, None, "Backend, Frontend"],
}
chart = gantt(work, parent="part of", depends="after", color="#4c78a8", title="Work breakdown")
print(chart._embed_html())
More than gantt() gives¶
gantt() returns a Timeline, so everything else works on it:
chart.marker("2026-10-30", "code freeze", color="#d62728") # more lines
chart.events(meetings, time="time", lane="task", symbol="x") # events on the tasks' lanes
chart.selection # selected tasks, as rows
For bars on lanes that are not tasks (machines, people, services), with several bars per lane, see schedules and spans.