# A Gantt chart in Power BI, from portfolio to critical path

> Get started with Gantt Plume: turn a task table into a collapsible project › phase › task plan with milestones and a status date, in 15 minutes.

- Language: English
- Web page: https://plumevisuals.com/en/tutorials/diagramme-de-gantt-power-bi
- Published: 2026-10-13
- Visual: Gantt Plume, technical reference: https://plumevisuals.com/ai/visuals/gantt-chart.md
- If an option name in this tutorial differs from the technical reference, the reference is right (it is generated from the visual's code).

## In short

**What the visual does.** Gantt Plume turns a simple list of tasks into a project plan. On the left, a **task grid** (owner, dates, progress…). On the right, a **timeline** where each task is a bar, from its start date to its end date. Think of a site manager's wall planner: projects fold like folders, and the reader zooms in and out on their own, from hours to years.

**When to use it:**
- track one or more projects broken down into phases and tasks;
- show what blocks what (dependencies) and which tasks must not slip (critical path);
- compare the actual plan with the plan agreed at the start;
- see each person's workload (time off, job sites, machines).

**When to use something else:** for a simple task list with no dates to visualize, a table is enough (Table Plume). The visual does not move tasks with the mouse and does not reschedule the plan: it displays the dates in your data, without changing the source.

**By the end, you will know how to:**
- prepare a task table and turn it into a collapsible project › phase › task plan;
- enter dependencies in MS Project format (English or French notation) and show the critical path;
- compare actuals with the baseline and color tasks by status;
- switch to the Resources view to spot overloads;
- export the whole plan to PDF on a single page.

**What you need:**
- Power BI Desktop (a recent version);
- the Gantt Plume visual installed (see [the common basics](/en/tutorials/bien-demarrer-visuels-plume), "Install a Plume visual");
- a table with one row per task, containing at least a task name and a start date.

## The data to provide

### The expected shape

Gantt Plume expects **one row per task** (or per bar). Each piece of information is a **column** (a column is a field in your table, with one value per row: name, date, owner…):

- the task name and its start date, at a minimum;
- the end date (or a duration);
- the **groups**: one column per hierarchy level (project, then phase). No "parent" column needed: the visual builds the tree from these columns;
- a unique ID per task, if you want dependencies.

Only four fields expect a **measure** (a calculation written in DAX, Power BI's formula language, that returns a value depending on the context): duration, progress, bar color and tooltips. Why a measure for progress? Because it lets the visual compute the progress of a task, and also that of each group (an average weighted by task duration).

### The sample dataset

A home goods retailer is tracking two projects: opening a store in Bordeaux and launching an online store. Fictitious data, as of Oct 15, 2026.

| ID | Project | Phase | Task | Start | End | Planned start | Planned end | Owner | Team | Milestone | Predecessors | % complete | Rank | Note | Budget €k |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A1 | Bordeaux store | Feasibility | Market study | 2026-04-07 | 2026-05-15 | 2026-04-07 | 2026-05-15 | Claire Dubois | Management | No | | 1 | 2 | | 18 |
| A2 | Bordeaux store | Feasibility | Lease signed | 2026-05-18 | 2026-05-18 | 2026-05-18 | 2026-05-18 | Hugo Lambert | Management | Yes | A1 | 1 | 2 | | 0 |
| A3 | Bordeaux store | Feasibility | Building permit | 2026-05-19 | 2026-07-31 | 2026-05-19 | 2026-07-10 | Paul Martin | Construction | No | A2 | 1 | 2 | Neighbor's appeal | 6 |
| A4 | Bordeaux store | Construction | Structural work | 2026-08-03 | 2026-09-25 | 2026-07-20 | 2026-09-11 | Paul Martin | Construction | No | A3 | 1 | 2 | | 240 |
| A5 | Bordeaux store | Construction | Electrical and lighting | 2026-08-24 | 2026-10-09 | 2026-08-10 | 2026-09-25 | Karim Haddad | Construction | No | A4SS+15 | 0.7 | 2 | Waiting for equipment | 85 |
| A6 | Bordeaux store | Construction | Interior fit-out | 2026-10-12 | 2026-11-13 | 2026-09-28 | 2026-10-30 | Léa Moreau | Construction | No | A5 | 0 | 2 | | 120 |
| A7 | Bordeaux store | Opening | Team hiring | 2026-09-14 | 2026-11-06 | 2026-09-14 | 2026-11-06 | Sophie Bernard | HR | No | A3 | 0.55 | 2 | | 12 |
| A8 | Bordeaux store | Opening | Grand opening | 2026-11-16 | 2026-11-16 | 2026-11-02 | 2026-11-02 | Hugo Lambert | Management | Yes | A6;A7 | 0 | 2 | | 15 |
| B1 | Online store | Design | Mockups | 2026-06-01 | 2026-06-26 | 2026-06-01 | 2026-06-26 | Inès Garcia | Digital | No | | 1 | 1 | | 20 |
| B2 | Online store | Development | Site development | 2026-06-29 | 2026-10-02 | 2026-06-29 | 2026-10-02 | Thomas Petit | Digital | No | B1 | 1 | 1 | | 95 |
| B3 | Online store | Launch | Sales staff training | 2026-10-05 | 2026-10-23 | 2026-10-05 | 2026-10-23 | Sophie Bernard | HR | No | B2 | 0.6 | 1 | | 10 |
| B4 | Online store | Launch | Go-live | 2026-10-26 | 2026-10-26 | 2026-10-26 | 2026-10-26 | Hugo Lambert | Management | Yes | B3 | 0 | 1 | | 5 |

How to read a few rows:
- **A2** and **A8** are **milestones** (a milestone is a one-off event with no duration: a signing, a grand opening). They are drawn as diamonds.
- **A5** has `A4SS+15` as its predecessor: electrical work starts 15 business days after the **s**tart of structural work (a **S**tart → **S**tart link). The format is detailed in ["The visual's fields"](/en/tutorials/gantt-plume-champs-et-reglages#the-visual-s-fields).
- **Planned start** and **Planned end** keep the original plan: they feed the baseline (★).
- **Rank** sets the order of the projects: the online store (1) comes before the Bordeaux store (2).

### The same dataset, ready to paste

In Power BI Desktop, on the **Modeling** tab › **New table**, paste this code. It creates a **calculated table** (a table produced by a DAX formula, with no source file) named `Tasks`.

```dax
Tasks =
DATATABLE (
    "ID", STRING,
    "Project", STRING,
    "Phase", STRING,
    "Task", STRING,
    "Start", DATETIME,
    "End", DATETIME,
    "Planned start", DATETIME,
    "Planned end", DATETIME,
    "Owner", STRING,
    "Team", STRING,
    "Milestone", STRING,
    "Predecessors", STRING,
    "% complete", DOUBLE,
    "Rank", INTEGER,
    "Note", STRING,
    "Budget €k", DOUBLE,
    {
        { "A1", "Bordeaux store", "Feasibility", "Market study", "2026-04-07", "2026-05-15", "2026-04-07", "2026-05-15", "Claire Dubois", "Management", "No", "", 1, 2, "", 18 },
        { "A2", "Bordeaux store", "Feasibility", "Lease signed", "2026-05-18", "2026-05-18", "2026-05-18", "2026-05-18", "Hugo Lambert", "Management", "Yes", "A1", 1, 2, "", 0 },
        { "A3", "Bordeaux store", "Feasibility", "Building permit", "2026-05-19", "2026-07-31", "2026-05-19", "2026-07-10", "Paul Martin", "Construction", "No", "A2", 1, 2, "Neighbor's appeal", 6 },
        { "A4", "Bordeaux store", "Construction", "Structural work", "2026-08-03", "2026-09-25", "2026-07-20", "2026-09-11", "Paul Martin", "Construction", "No", "A3", 1, 2, "", 240 },
        { "A5", "Bordeaux store", "Construction", "Electrical and lighting", "2026-08-24", "2026-10-09", "2026-08-10", "2026-09-25", "Karim Haddad", "Construction", "No", "A4SS+15", 0.7, 2, "Waiting for equipment", 85 },
        { "A6", "Bordeaux store", "Construction", "Interior fit-out", "2026-10-12", "2026-11-13", "2026-09-28", "2026-10-30", "Léa Moreau", "Construction", "No", "A5", 0, 2, "", 120 },
        { "A7", "Bordeaux store", "Opening", "Team hiring", "2026-09-14", "2026-11-06", "2026-09-14", "2026-11-06", "Sophie Bernard", "HR", "No", "A3", 0.55, 2, "", 12 },
        { "A8", "Bordeaux store", "Opening", "Grand opening", "2026-11-16", "2026-11-16", "2026-11-02", "2026-11-02", "Hugo Lambert", "Management", "Yes", "A6;A7", 0, 2, "", 15 },
        { "B1", "Online store", "Design", "Mockups", "2026-06-01", "2026-06-26", "2026-06-01", "2026-06-26", "Inès Garcia", "Digital", "No", "", 1, 1, "", 20 },
        { "B2", "Online store", "Development", "Site development", "2026-06-29", "2026-10-02", "2026-06-29", "2026-10-02", "Thomas Petit", "Digital", "No", "B1", 1, 1, "", 95 },
        { "B3", "Online store", "Launch", "Sales staff training", "2026-10-05", "2026-10-23", "2026-10-05", "2026-10-23", "Sophie Bernard", "HR", "No", "B2", 0.6, 1, "", 10 },
        { "B4", "Online store", "Launch", "Go-live", "2026-10-26", "2026-10-26", "2026-10-26", "2026-10-26", "Hugo Lambert", "Management", "Yes", "B3", 0, 1, "", 5 }
    }
)
```

> **Tip:** **Tip**: once the table is created, select the `Start`, `End`, `Planned start` and `Planned end` columns and set their type to **Date** (**Column tools** tab › **Data type**). The "00:00:00" times disappear from the task grid.

### The DAX measures to create

Select the `Tasks` table, then **Home** › **New measure**, and paste each measure separately.

```dax
// Task progress, between 0 and 1 (0% to 100%)
Progress =
AVERAGE ( Tasks[% complete] )   // one row per task: the average simply returns its value
```

```dax
// ★ Alert color: red for a task whose end date has passed without being finished
Alert color =
IF (
    MAX ( Tasks[% complete] ) < 1                     // the task is not finished…
        && MAX ( Tasks[End] ) < DATE ( 2026, 10, 15 ), // …and it ends before the status date
    "#C0392B"                                         // then: red
)                                                     // otherwise: blank = the bar keeps its usual color
```

The second measure is only used by the **Bar color (measure) ★** field ([how-to guide "How do I color tasks by status?"](/en/tutorials/gantt-plume-cas-pratiques#how-do-i-color-tasks-by-status-late-at-risk)). In a real report, replace `DATE ( 2026, 10, 15 )` with `TODAY ()`.

### Data preparation pitfalls

- **Dates**: `Start` and `End` must be real dates (Date or Date/time type). ISO text (`2026-05-19`, with or without a time, time zone or "Z") and `dd/mm/yyyy hh:mm:ss` are read too. A date outside 1900–2200 (for example 12/31/9999 for "no end") is ignored and flagged in edit mode.
- **Date Hierarchy**: when you drag a date, Power BI often replaces it with a "Date Hierarchy" (Year › Quarter › Month › Day). Gantt Plume needs the date itself (see step 6 of the walkthrough).
- **IDs**: one ID per task, no duplicates. The comparison ignores case (`a3` = `A3`).
- **Same task name in the same group**: by default, two rows with the same name in the same phase share a single row of the plan (several bars). Give different tasks different names, or turn off **Rows and hierarchy › Same task = same row (several bars)**.
- **Progress**: 0 to 1 or 0 to 100, both are understood. Stay consistent across the whole column.
- **Volume**: 30,000 rows are loaded at once, then the visual automatically fetches more, up to 100,000. Beyond that, it stops and says so: filter the page (project, period).

## Step by step: your first Gantt Plume in 15 minutes

1. In **Modeling** › **New table**, paste the `DATATABLE` code from ["The data to provide"](#the-data-to-provide) and confirm.
   The `Tasks` table appears in the **Data** pane with 12 rows.
2. With the `Tasks` table selected, click **Home** › **New measure** and paste the `Progress` measure.
   The `Progress` measure (calculator icon) appears in the table.
3. In the **Visualizations** pane, click the **Gantt Plume** icon, then enlarge the visual to cover almost the whole page.
   The visual shows a welcome screen that lists the fields to fill in.
4. Drag `Project`, then `Phase`, into the **Groups (project, phase…)** well, in that order.
   The order matters: the first field is the broadest level.
5. Drag `Task` into the **Task** well.
6. Drag `Start` into the **Start** well. If the well shows **Date Hierarchy**, click the arrow next to the field and choose `Start`.
   Each task appears, for now as a diamond: without an end, a task is a milestone.
7. Drag `End` into the **End** well.
   The diamonds become bars, except **Lease signed**, **Grand opening** and **Go-live** (start = end).
8. Fill in the other wells according to this table:

   | Visual well | Field |
   |---|---|
   | Progress (%) | `Progress` measure |
   | Owner / resource | `Owner` |
   | Color (team, type…) | `Team` |
   | Milestone (yes / no) | `Milestone` |
   | Task ID (for dependencies) | `ID` |
   | Sort order | `Rank` |

   The bars take one color per team, progress fills each bar, and the online store comes before the Bordeaux store.
9. In the **Format** pane, **Layout** card, type `2026-10-15` in **Status date (empty = today)**.
   The "today" line moves to Oct 15, 2026: the report is "frozen" at that date.
10. In the same **Layout** card, set **Initial position** to *Start of the plan*.
    The plan opens on the first task (Apr 7, 2026) instead of today.
11. In the **Time axis** card, set **Initial scale** to *Months*.
    The header shows months; each bar can be read to the nearest week.
12. In the **Time axis** card, **Calendar** group, paste these 2026 French public holidays into **Holidays (yyyy-mm-dd; …)**:
    `2026-01-01; 2026-04-06; 2026-05-01; 2026-05-08; 2026-05-14; 2026-05-25; 2026-07-14; 2026-08-15; 2026-11-01; 2026-11-11; 2026-12-25`
    Holidays are shaded like weekends and no longer count in business-day durations.

**Expected result**: a plan with two collapsible projects (**Online store**, then **Bordeaux store**), each broken down into phases. Each project and each phase has a **summary bar** that spans its tasks. The task grid shows the owner, start, end and progress; three milestones as diamonds; a vertical line at Oct 15, 2026.

> **Tip:** **Tip**: to read the plan, the reader has the **toolbar** at the top of the visual (search for a task, scales, **Fit**, expand / collapse all, "Today" button). **Ctrl + mouse wheel** zooms around the pointer, and dragging the background scrolls through time. The chevrons to the left of the groups collapse them. Clicking a bar filters the other visuals on the page (**cross-filter**, see the [glossary](/en/tutorials/bien-demarrer-visuels-plume#glossary)); Ctrl or Shift + click selects several. With the keyboard: ↑ ↓ to move, ← → to collapse or expand, Enter to select, Esc to clear the selection, + / − to change the scale.

## Troubleshooting

| What you see | Likely cause | Solution |
|---|---|---|
| No bars, a message about the "Date Hierarchy" | The date arrived as a Year › Quarter › Month › Day hierarchy. | In the **Start** (and **End**) well, click the field's arrow and choose the column itself. |
| A task is drawn as a diamond | It has neither an end nor a duration, or the **Milestone (yes / no)** field is Yes (or any non-empty text). | Add an end or a duration; clear the **Milestone** cell, or set it to "No". |
| A task looks longer than expected | **Durations counted in** is set to *Business days*: weekends and holidays are skipped; **End date included** counts the last day. | Choose *Calendar days*, or turn off **End date included**. |
| A date is ignored and flagged in edit mode | Date outside 1900–2200 (12/31/9999 for "no end", for example). | Replace these values with a real date or leave the cell empty. |
| "Unknown predecessor" in edit mode | The ID is not in the **Task ID (for dependencies)** field, or the task is filtered out of the page. | Check the spelling of the IDs and the page filters. The critical path stops at that link. |
| No critical path | **Critical path ★ › Show** is off by default, or the **Predecessors ★** field is empty. | Turn on **Show** and fill in **Predecessors ★**. |
| The plan does not open at the level you set | **Save the state in the report (edit mode)** kept the groups you expanded by hand. | Change **Levels expanded at start** or turn off this option. |
| The plan opens on today, an empty area | **Initial position** is *Today (status date)* by default. | Choose *Start of the plan*, *End of the plan* or *Chosen date*. |
| The Resources view is empty | The **Owner / resource** field is not filled in. | Drag the owner column into this field. |
| Two different tasks end up on the same row | Same task name in the same group, with **Same task = same row (several bars)** turned on. | Give them different names, or turn off this setting. |
| The visual stops and reports too many rows | More than 100,000 rows. | Filter the page (project, period). |
| "Premium preview" watermark | A ★ feature is used without a license key. | Paste a key in **Plume Studio License › License key**, or turn off the ★ feature (see ["Premium ★ features"](/en/tutorials/gantt-plume-champs-et-reglages)). |

## Key takeaways

- One row per task: **Task** and **Start** are enough, **End** (or **Duration**) draws the bar, and each level of **Groups** becomes a collapsible level.
- Always drag the date column itself, never its **Date Hierarchy**.
- **Predecessors ★** follow the MS Project format (`A3`, `A4SS+15`, `A6;A7`, in English or French notation) and drive the arrows, the conflicts and the critical path; the visual never moves your dates.
- The **Status date** freezes the report: the "today" line, the computed status and the expected progress all refer to it.
- To share: the **Resources ★** view for workload, collapsed groups ★ for a portfolio, **Whole plan in the frame (PDF export) ★** for a printable page.

## Learn more

- [Gantt Plume: 10 how-to guides (dependencies, critical path, PDF…)](/en/tutorials/gantt-plume-cas-pratiques): recipes for everyday needs.
- [Gantt Plume: every field and setting explained](/en/tutorials/gantt-plume-champs-et-reglages): each field well and each setting.
- [Getting started with Plume visuals](/en/tutorials/bien-demarrer-visuels-plume): installation, license, styles and settings shared by all visuals.
- The visual's page: [Gantt Plume](/en/visuals/gantt-chart). A question? [Support](/en/support).
