🎨 Transform Figma mockups into production-ready Dash apps. Join us November 10. Save your spot.

Chris Parmer

Chris Parmer

October 24, 2026

Gantt Charts - A Complete Guide

TL;DR

  • A Gantt chart draws each task, phase or event as a horizontal bar from its start date to its end date, one row per task, on a shared time axis, so you can see when things happen, how long they take and what overlaps.
  • Use one for project plans, clinical trial programs, support windows, asset lifetimes and anything else where every item has a start and an end.
  • Use a sorted bar chart instead when only the durations matter, and a dot plot when each item has a single date.
  • Any coding agent can make one with Plotly in a minute. In Python it's px.timeline(df, x_start=..., x_end=..., y=...).

What is a Gantt chart?

Gantt charts look like this:

Gantt chart of 11 Eli Lilly tirzepatide trials grouped by program, with FDA approvals as diamonds: Mounjaro on May 13, 2022, 15 months after the last SURPASS readout; Zepbound on Nov 8, 2023, 6 months after SURMOUNT-4; and the sleep apnea indication on Dec 20, 2024, 9 months after SURMOUNT-OSA. An arrow links the Phase 2 readout to the first Phase 3 start

Data: ClinicalTrials.gov, Drugs@FDA.

How do you read a Gantt chart? In the example above, notice these things:

  • Each row is one of tirzepatide's trials, and its bar runs from the day the trial started to its primary completion, with a lighter extension to the end of follow-up.
  • The rows are grouped by program and sorted by start date within each group, and each program has its own color, so the blue SURPASS diabetes trials, which mostly ran at the same time, read as one block.
  • The black diamonds are FDA approvals, which happen on a single day, so they are drawn as points with their dates next to them instead of as bars.
  • The arrows show what came after what: the first Phase 3 trial started after the Phase 2 trial ended, and each approval came after the last readout of its program, with Mounjaro approved 15 months after the SURPASS-2 readout.
  • SURMOUNT-1's long pale tail is follow-up that ran into 2024, after Zepbound was already approved, so an approval can come before every bar in its program has ended.

It's often used for charts like these:

Gantt chart of Python 3.6 to 3.15, with a dark bugfix phase and a light security phase for each, faded after end of life. On Oct 24, 2026, versions 3.11 to 3.15 are supported and only 3.14 and 3.15 still get bugfix releases; 3.10 reached end of life in Oct 2026

Support windows. Five Python versions are supported today, only 3.14 and 3.15 still get bugfix releases, and every version since 3.8 gets about five years before end of life. Data: endoflife.date, from the Python developer guide.

Gantt chart of the 30 largest US coal generators with a planned retirement, from first operation (mostly the 1970s and 1980s) to planned retirement, gray until today and orange after, with bar thickness by capacity. J H Campbell 3 (791 MW) is first, in 2026; most close by 2034; 28.7 GW, 17% of coal capacity, has a date before 2031

Asset lifetimes. Owners have told EIA that 28.7 GW of US coal capacity, 17% of the 167.2 GW still running, will retire before 2031, and the 30 largest of those units have run for a median of 48 years. Data: EIA-860M, September 2026.

Swimlane Gantt chart above a step line of the federal funds target rate since 1988. Lanes show the Fed chairs from Greenspan to Warsh, hiking cycles in orange and cutting cycles in blue labeled in basis points: -681 from 1989, +425 from 2004, -500 from 2007, +525 from 2022

Terms and cycles. From March 2022 to July 2023 the Fed raised its target by 525 basis points in 16 months, its biggest hiking cycle since 1988, and the lanes show which chair ran each cycle above the rate itself. Data: FRED (DFEDTAR, DFEDTARU), Federal Reserve Board list of chairs.

A short history

Joseph Priestley drew the lifespans of famous people as bars on a time axis in his Chart of Biography in 1765, and this is the same idea redrawn with Plotly for 16 scientists and philosophers who died before then:

Lifespans of 16 scientists and philosophers who died before 1765 drawn as horizontal bars on a time axis from 1450 to 1770, colored by field, from Nicolaus Copernicus (1473 to 1543) to Edmond Halley (1656 to 1742), with Thomas Hobbes the longest at 91 years and Blaise Pascal the shortest at 39

Karol Adamiecki, a Polish engineer, developed a scheduling chart he called the "harmonogram" in 1896 but published it only in 1931, in Polish, so it stayed little known in the West (Marsh, 1975). Henry Gantt developed his charts in the 1910s to schedule production and track progress against plan, and they spread through US industry and government during and after the First World War (Wilson, 2003); the dependency arrows that project software draws today came later, with the critical path method of the late 1950s.

Alternatives to a Gantt chart

Here's the same set of 11 trials drawn six ways. Some are better for the question, some worse, some just different:

The same 11 tirzepatide trials drawn six ways: a Gantt chart, a dumbbell chart, a sorted bar chart of months to primary completion (from 14 for the Phase 2 trial to 28 for SURMOUNT-1), a dot plot of primary completion dates, a step line of how many trials were under way at once (up to 6, from December 2019) and a table of start and primary completion dates
  • Sorted bar chart of durations (better when only the length matters). Bars that share a baseline are easier to compare than bars that start on different dates, so this shows at once that SURMOUNT-1 took longest (28 months). You lose the calendar and the overlap.
  • Dumbbell chart (works too). The two dates as dots joined by a line carry the same information with less ink, which helps when there are many rows and the overlap matters less than the dates themselves. See our dumbbell chart guide.
  • Dot plot (different). One date per item, for deadlines, launches or readouts that have no duration.
  • Step line of tasks under way (different). Counts how many tasks were running at each moment, here up to six trials at once from December 2019, which answers a capacity question but no longer says which tasks they were.
  • Table (better for looking things up). Exact dates for each row, and the right choice for hundreds of tasks that each need a label, but the pattern over time disappears.

How to make a Gantt chart

With AI

ChatGPT, Claude Code, GitHub Copilot, Cursor and other AI tools are excellent at writing Plotly code. Name Plotly in the prompt, describe the rows, the dates and what color means, and list the details you want:

Make a plotly Gantt chart from trials.csv (columns: trial, program, start, primary_completion, status).
- One row per trial, a bar from start to primary_completion on a date axis.
- Rows sorted by program, then start date, first row on top (yaxis autorange="reversed").
- One color per program; hatch the part of each bar after today with marker.pattern.
- Dashed vertical line labeled "Today"; print the end month after each bar.
- Parse month-only dates ("2027-10") as the 1st of the month and say so in the subtitle.
- Inter font, white background, a title that states the takeaway with a number,
muted subtitle with the source. Save as gantt.html and a PNG at 2x scale.

With Plotly Studio

Plotly Studio is a desktop app where you point an AI at a dataset and it builds charts and a Dash app around your questions. Ask for a Gantt chart the same way:

Show a Gantt chart of our clinical trials, one row per trial from start date to primary completion, grouped and colored by indication. Hatch the part after today, mark FDA approvals as diamonds, and add a dropdown to filter by sponsor.

Make a Gantt chart in Python or JavaScript

This is the code AI tools write under the hood. In Python, px.timeline makes a Gantt chart from a table with a task, a start and an end column:

import pandas as pd
import plotly.express as px
df = pd.DataFrame({
"version": ["Python 3.12", "Python 3.13", "Python 3.14"],
"release": ["2023-10-02", "2024-10-07", "2025-10-07"],
"end_of_life": ["2028-10-31", "2029-10-31", "2030-10-31"],
})
fig = px.timeline(df, x_start="release", x_end="end_of_life", y="version")
fig.update_yaxes(autorange="reversed")
fig.show()

Under the hood that's a horizontal bar trace whose base is each start date and whose length is the duration in milliseconds, on a date axis. In JavaScript, plotly.js builds the same chart from that bar trace:

<div id="chart"></div>
<script src="https://cdn.plot.ly/plotly-4.1.1.min.js"></script>
<script>
const rows = [
["Python 3.12", "2023-10-02", "2028-10-31"],
["Python 3.13", "2024-10-07", "2029-10-31"],
["Python 3.14", "2025-10-07", "2030-10-31"],
];
Plotly.newPlot("chart", [{
type: "bar",
orientation: "h",
y: rows.map(r => r[0]),
base: rows.map(r => r[1]),
x: rows.map(r => new Date(r[2]) - new Date(r[1])), // duration in ms
}], {
xaxis: {type: "date"},
yaxis: {autorange: "reversed"},
});
</script>

The same go.Bar(orientation="h", base=start, x=duration_ms) in Python gives you full control, for several phases in one row, a today line or milestones, which is how every example in this guide is built.

Share it

Every Plotly chart has a Share chart button (the cloud icon in its toolbar) that uploads it to Plotly Cloud and gives you a link. Only you can see it until you change its visibility.

For a live app, put the chart in a Dash app and publish it with the Plotly Cloud CLI. Coding agents can run these commands for you:

pip install "dash[cloud]"
plotly user login
plotly app publish

If your data has to stay in your own cloud or data center, publish to Dash Enterprise instead.

Dos and don'ts

A Gantt chart is easy to get roughly right and easy to make hard to read. Most of the work for a published chart is ordering the rows and choosing what to print on the bars. Here are the 11 tirzepatide trials both ways.

Don't leave the rows in alphabetical order with the first row at the bottom, which scrambles the programs and the sequence, or force full date ranges into every bar, where most of them get cut off:

Gantt chart of the 11 tirzepatide trials in the same program colors, but with alphabetical rows from the bottom up, so the Phase 2 trial is at the bottom and SURMOUNT-OSA sits between the SURPASS and SURMOUNT trials, and with start and end dates like 2019-04-01 to 2020-12-11 squeezed inside every bar and clipped at both ends

Do sort the rows by program and start date with the first on top, keep the same colors, name the programs next to their first bar and print the number that matters (here the primary completion month) after each bar:

The same 11 trials sorted by program and start date, with the Phase 2 trial in gray, the SURPASS diabetes trials in blue, the SURMOUNT obesity trials in orange and SURMOUNT-OSA in green, the program names next to the first bar of each and the primary completion month after every bar

Use color for one thing

Bar length already shows duration, so color is free to say something else. Here are four options on the same 13 obesity drug programs in Phase 3, each drawn from its first trial start to its last expected readout.

By group. One color per sponsor shows who is behind each program, and it's a good default when there are fewer than about eight groups.

Gantt chart of 13 obesity drug programs colored by sponsor, with a legend for Eli Lilly, Novo Nordisk, Amgen, Boehringer Ingelheim, Innovent, Viking Therapeutics, Roche and Pfizer and a dashed today line

Highlight one story. Eli Lilly's three programs (orforglipron, retatrutide and eloralintide) are blue and the rest are gray, which works when the chart is about one sponsor.

The same 13 programs with Eli Lilly's orforglipron, retatrutide and eloralintide in blue and every other program in gray

By status. Each bar is solid up to today and hatched after, so the chart separates what has happened from what is planned.

The same 13 programs with each bar solid blue up to today and hatched after it; the programs that started in late 2026 are almost entirely hatched

By a measure. A blue scale by the number of Phase 3 trials shows that orforglipron has the most (18), at the cost of a colorbar the reader has to look up.

The same 13 programs shaded from light to dark blue by their number of Phase 3 trials, with orforglipron darkest at 18 and a colorbar from 0 to 18

Checklist

Do

  • Sort the rows by start date, by group or by end date, depending on the question, and set yaxis.autorange="reversed" so the first task is on top.
  • Color by group, status or a measure.
  • Draw a today line whenever the chart mixes past and future, and hatch the planned part with marker.pattern.
  • Mark milestones with diamonds and label them directly.
  • Print the number that matters at the end of each bar: an end date, a duration or a count.
  • Write a title that states the takeaway, with the source in a muted subtitle.

Don't

  • Give every task its own color, which makes an unreadable legend and slows the chart down (see the FAQ).
  • Leave rows in alphabetical order unless readers will look tasks up by name.
  • Squeeze long labels such as full date ranges inside the bars, where they get clipped. Print one short number after each bar instead.
  • Draw hundreds of dependency arrows. Draw the few that explain the schedule.
  • Label every row of a chart with 100 or more rows. Hide the tick labels and annotate the outliers instead.

Options to customize

These are the options that matter most for a Gantt chart built from go.Bar (or px.timeline) and the layout. The full list is in the Plotly Gantt chart documentation and the bar reference.

  1. px.timeline(x_start=, x_end=, y=, color=): builds the bars from start and end columns; color by a group, not by task.
  2. go.Bar(orientation="h", base=start, x=duration_ms): a bar from the start date with the duration in milliseconds, for full control and several phases per row.
  3. xaxis.type="date": a date axis for the bars, needed when you build them by hand.
  4. yaxis.autorange="reversed": puts the first task on top, which you almost always want.
  5. yaxis.categoryorder="array", categoryarray: fixes the row order, by start, group or end.
  6. barmode="overlay": keeps several segments of one task on the same row.
  7. width: bar thickness, one value per bar if you pass a list, so it can carry a measure such as capacity.
  8. marker.pattern.shape: hatching for planned or estimated parts.
  9. marker.opacity: per-bar transparency, to fade finished or expired rows.
  10. go.Scatter(marker_symbol="diamond"): milestone markers for approvals, launches and deadlines.
  11. fig.add_vline or fig.add_shape(type="line", yref="paper"): a today line or a deadline across the chart.
  12. fig.add_annotation(ax=, ay=, axref="x", ayref="y"): an arrow between two points in data coordinates, for dependencies.
  13. fig.add_vrect: a shaded band across all rows, for recessions, freezes or holidays.
  14. make_subplots(shared_xaxes=True): a Gantt chart and a line chart on one time axis.
  15. textposition, insidetextanchor: labels inside or after the bars.
  16. hovertemplate, customdata: hover content such as exact dates, counts and IDs.

More Gantt chart examples

Eight more Gantt charts built from real public data, each with its source, the technique that makes it work and a prompt to rebuild it.

1. The race for the next obesity drug

Gantt chart of 13 obesity drugs in Phase 3, one row per drug from the first trial start to the last expected readout, solid before today and hatched after, with dots for each of 107 trials' primary completions. CagriSema, mazdutide, orforglipron, retatrutide and survodutide started first; 81 trials have yet to read out

Thirteen obesity drugs other than semaglutide and tirzepatide have 107 industry Phase 3 trials registered since 2020, and 81 of them have yet to reach their primary completion. Lilly's orforglipron has the most trials (18), and readouts run into 2030. Data: ClinicalTrials.gov, October 2026 (grouping by drug is ours).

Tip: roll many tasks up into one bar per program and keep the detail as dots, filled when done and hollow when expected.

Get the data from the ClinicalTrials.gov API v2: industry-sponsored Phase 3 trials with condition
"obesity OR overweight" that started in 2020 or later, and shape it into a table
(columns: drug, sponsor, nct, acronym, start, primary_completion, status).
Assign trials to drugs by intervention name; leave out semaglutide and tirzepatide.
Build a plotly Gantt chart with one row per drug, from first start to last primary completion.
- Color by sponsor; solid up to today, hatched after (marker.pattern shape "/").
- A dot per trial at its primary completion: filled if in the past, hollow if expected.
- Dashed today line; "N trials" after each bar; rows sorted by first start.

2. When Medicare's top drugs lose patent protection

Gantt chart of the 15 brand drugs with the most Medicare Part D spending that have Orange Book patents, from FDA approval to the last listed patent, gray before today and blue after, with diamonds for the last drug-substance patent. Eliquis ($20.8B) loses its molecule patent on Nov 21, 2026 and its last listed patent in Aug 2031; Mounjaro's last listed patent runs to Dec 2041

Eliquis cost Medicare Part D $20.8 billion in 2024, more than any other drug, and its last patent on the molecule itself expires on November 21, 2026. Later patents run to 2031, and for Ozempic, Farxiga and Mounjaro they reach 2041. Data: FDA Orange Book (October 2026), Drugs@FDA, CMS Part D Spending by Drug.

Tip: sort by the end date so the chart reads as a calendar of patent cliffs, and put the spending in the row label.

Get the data from CMS Medicare Part D Spending by Drug (2024 total spending per brand), the FDA
Orange Book data files (products and patents) and Drugs@FDA (original NDA approval dates), and
shape it into a table (columns: brand, nda, spend_2024_bn, approved, last_substance_patent,
last_patent). Keep the 15 highest-spending brands with Orange Book patents.
Build a plotly Gantt chart sorted by last_patent: gray bar from approval to today, blue from
today to the last listed patent, a black diamond at the last drug-substance patent.
Row labels "Brand $X.XB"; end month printed after each bar; dashed today line.
Subtitle: listed patents are not generic launch dates.

3. How long it took to build every US nuclear reactor

Dense Gantt chart of 135 US commercial reactors, one thin row each sorted by construction start, blue for construction and gray for operation. Build phases lengthen through the 1970s; Watts Bar 2 took 42.8 years, Watts Bar 1 22.9 years, and Vogtle 3 and 4, the only reactors started after 1978, 10.4 years each

US reactors started in the 1960s took a median 5.8 years to build, and those started in the 1970s took 11. Watts Bar 2 took 42.8 years, and Vogtle 3 and 4, the only reactors started after 1978, took 10.4 years each. Data: IAEA PRIS via Wikipedia's list of commercial nuclear reactors.

Tip: for 100+ rows, set bargap=0, hide the tick labels and annotate only the outliers.

Get the data from the IAEA Power Reactor Information System (or the United States table of
Wikipedia's "List of commercial nuclear reactors"), and shape it into a table
(columns: reactor, capacity_mw, start, commercial, closed, build_years).
Keep reactors with both a construction start and a commercial operation date.
Build a plotly Gantt chart with one thin row per reactor sorted by start, no tick labels.
- Blue from construction start to commercial operation; gray from then to closure or today
(light gray if closed).
- Label only Watts Bar 1 and 2, Shippingport 1 and Vogtle 3 and 4 with their build years.
- Title compares the median build time of 1960s and 1970s starts.

Another way to see it: a scatter of build time against construction start shows the same jump as two medians, but loses the operating lives.

Scatter of build years against construction start for 135 US reactors, with medians of 5.8 years for 1960s starts and 11.0 for 1970s starts, and Watts Bar 2 at 42.8 years as the outlier

4. Every S&P 500 bear market since 1950, side by side

Gantt chart of 11 S&P 500 bear markets aligned at their peak, with red bars for the fall and gray for the recovery to the old peak. The 1973 bear market took 7.5 years in all, 2000 took 7.2 and 2007 5.5, while 2020 fell 34% and recovered in 0.5 years

Aligned at the peak, the 11 bear markets since 1950 range from 6 months peak to peak (2020) to 7.5 years (1973). The 2000 and 2007 falls took 7.2 and 5.5 years to win back. Data: Yahoo Finance, S&P 500 daily closes (price only).

Tip: a Gantt chart doesn't need dates: use base=0 and lengths in years to compare episodes from different decades.

Get the data from Yahoo Finance, daily closes of the S&P 500 (^GSPC) since 1950, and shape it into
a table of bear markets (falls of 20% or more from a record close) with columns peak, trough,
recovery, drawdown_pct, days_down, days_to_recover.
Build a plotly Gantt chart on a numeric axis "years since the peak", one row per bear market:
red bar from 0 to the trough, gray from the trough to the recovery. Row labels "Mon YYYY peak -NN%",
total years printed after each bar, rows in date order.

Another way to see it: a scatter of the fall against the recovery time shows that depth predicts duration loosely: 1987 fell 34% and recovered in 1.9 years.

Scatter of 11 bear markets, fall from the peak against years from peak back to peak: 1973, 2000 and 2007 fell 48% to 57% and took 5.5 to 7.5 years, while 1987 and 2020 fell about 34% and took 1.9 and 0.5 years

5. Presidents and recessions on one timeline

Two-row timeline since 1929: presidents as blocks colored by party with their names, and the 15 NBER recessions as dark bars with their length in months, also shaded across the chart: 43 months from 1929, 18 months in 2008-09 and 2 months in 2020

The US has had 15 recessions since 1929, and the 13 since 1945 lasted a median 10 months. The longest since then ran 18 months (2008-09) and the shortest 2 months (2020). Data: Wikidata (presidential terms), NBER recession dates via FRED (USREC).

Tip: a one-row Gantt chart is a timeline; fig.add_vrect shades each event across every row.

Get the data from Wikidata (holders of "President of the United States" with term start, end and
party) and FRED's USREC (NBER recession indicator, monthly), and shape it into two tables:
presidents (president, party, start, end) and recessions (start, end, months).
Build a plotly timeline since 1929 with two rows: presidents as blocks colored by party with the
name inside, and recessions as dark bars with their length in months below. Shade every recession
across the chart with fig.add_vrect.

6. Who has lived on the International Space Station

Gantt chart of 51 crew stays on the ISS since January 2023, one row per person sorted by arrival, colored by the spacecraft they arrived on. Crew Dragon and Soyuz crews overlap at each handover; Barry Wilmore and Sunita Williams arrived on Boeing's first crewed Starliner flight and stayed 285 days, leaving on SpaceX Crew-9; seven people are on board today

Barry Wilmore and Sunita Williams arrived on Boeing's first crewed Starliner flight in June 2024 and left 285 days later on SpaceX Crew-9. Seven people are on board today. Data: Wikipedia, List of International Space Station expeditions.

Tip: sort by arrival so each crew forms a block, and end open stays at today with an arrow marker.

Get the data from Wikipedia's "List of International Space Station expeditions" table and shape it
into a table of stays (columns: person, arrival, arrival_flight, departure, departure_flight, vehicle).
Build a plotly Gantt chart of stays since January 2023, one row per person and stay, sorted by
arrival. Color by arrival vehicle (Crew Dragon, Soyuz, Starliner); end current stays at today
with a triangle marker; annotate the Starliner crew's stay in days.

7. Every plotly.py release, by major version

Gantt chart of the plotly Python package with one lane per major version from v0 to v7 and a tick for each of 272 releases. Version 5 lasted 3.6 years and 34 releases, version 1 2.7 years and 129 releases, and version 7 started in August 2026

plotly.py has shipped 272 releases since 2013, and version 5 stayed current for 3.6 years and 34 releases, longer than any other major version. Version 7 came out in August 2026. Data: PyPI (pypi.org/project/plotly).

Tip: marker.symbol="line-ns" draws events as ticks on a lane, a light way to show many milestones.

Get the data from the PyPI JSON API for the plotly package (pypi.org/pypi/plotly/json), first upload
date of each release, and shape it into a table (columns: version, major, minor, patch, date).
Drop pre-releases.
Build a plotly Gantt chart with one lane per major version from its first release to the next
major's, and a tick (marker symbol "line-ns") per release, darker for x.y.0 releases.
Print "N yrs · N releases" after each lane.

8. Every team's run at the 2026 World Cup

Gantt chart of all 48 teams at the 2026 World Cup, from first to last match, sorted by the round each reached and shaded from gray to dark blue, with a dot per match colored by result. Spain won the final against Argentina 1-0 after extra time, conceding one goal in eight matches

Sorted by how far each team went, the 48 bars step down like a bracket. Spain won 7 of 8 matches and conceded once, beating Argentina 1-0 after extra time in the final. Data: openfootball worldcup.json (all 104 matches).

Tip: sort rows by outcome and put each event on its bar as a colored dot, so one chart shows schedule and results.

Get the data from openfootball's worldcup.json for 2026 (all 104 matches with round, date, teams
and score) and shape it into two tables: matches (date, round, team, opponent, goals_for,
goals_against, result) and teams (team, first, last, matches, out_in).
Build a plotly Gantt chart with one row per team from first to last match, sorted by the round
reached, bars shaded by that round, a dot per match colored win/draw/loss, and dotted lines at
the start of each knockout round.

FAQ

bluesly
x
instagram
youtube
medium
fcaebook

Product

© 2026
Plotly. All rights reserved.
Cookie Preferences
aicpa/soc2