# Gantt Chart
A Gantt chart displays tasks as horizontal bars spanning a time range, making it easy to see schedule, duration, sequence, and overlap at a glance. Tasks can be organized into named phases or groups, which receive colored header rows and distinct bar colors drawn from the category10 palette.
kuva's `GanttPlot` adds three features beyond basic scheduling:
- **Progress fill** — a darker inner region shows completion fraction; tasks not yet started are shown at full opacity without a progress fill.
- **Milestone diamonds** — single-point events (deadlines, sign-offs, launches) render as ◆ markers rather than bars.
- **Now line** — a dashed vertical reference line marks the current date or time.
**Import path:** `kuva::plot::GanttPlot`
---
## Basic usage
Add tasks with `.with_task(label, start, end)`. Without groups, all bars share the default color and appear in insertion order.
```rust,no_run
use kuva::plot::GanttPlot;
use kuva::backend::svg::SvgBackend;
use kuva::render::render::render_multiple;
use kuva::render::layout::Layout;
use kuva::render::plots::Plot;
let gantt = GanttPlot::new()
.with_task("Literature review", 0.0, 4.0)
.with_task("Data collection", 2.0, 8.0)
.with_task("Analysis", 7.0, 12.0)
.with_task("Write-up", 11.0, 16.0);
let plots = vec![Plot::Gantt(gantt)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Research Project")
.with_x_label("Week");
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write("gantt.svg", svg).unwrap();
```
<img src="../assets/gantt/basic.svg" alt="Basic Gantt chart of four research tasks" width="600">
Labels are drawn inside the bar when there is enough room; otherwise they appear to the right of the bar. The right margin is automatically expanded so outside labels are never clipped.
---
## Groups and phases
Use `.with_task_group(group, label, start, end)` to assign tasks to named groups. Each group gets a shaded header row and a distinct bar color from the category10 palette. Tasks within a group appear in insertion order immediately below their header.
```rust,no_run
use kuva::plot::GanttPlot;
use kuva::render::plots::Plot;
# use kuva::backend::svg::SvgBackend;
# use kuva::render::render::render_multiple;
# use kuva::render::layout::Layout;
let gantt = GanttPlot::new()
.with_task_group("Discovery", "User research", 0.0, 3.0)
.with_task_group("Discovery", "Competitive audit",1.0, 4.0)
.with_task_group("Design", "Wireframes", 3.5, 6.0)
.with_task_group("Design", "Prototyping", 5.0, 8.0)
.with_task_group("Build", "Frontend", 7.0, 12.0)
.with_task_group("Build", "Backend", 6.0, 11.0);
let plots = vec![Plot::Gantt(gantt)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Product Development")
.with_x_label("Week");
```
<img src="../assets/gantt/grouped.svg" alt="Gantt chart with three grouped phases" width="620">
Use `.with_group_order(groups)` to control phase order explicitly. Groups not listed follow in insertion order.
```rust,no_run
# use kuva::plot::GanttPlot;
# use kuva::render::plots::Plot;
let gantt = GanttPlot::new()
.with_group_order(["Build", "Discovery", "Design"]) // Build appears first
.with_task_group("Discovery", "Research", 0.0, 3.0)
.with_task_group("Design", "Wireframes", 2.0, 5.0)
.with_task_group("Build", "Dev", 4.0, 9.0);
```
---
## Progress fills and the now line
`.with_task_group_progress(group, label, start, end, fraction)` draws a darker inner fill showing how much of the task is complete. The fraction is clamped to `[0.0, 1.0]`.
`.with_now_line(value)` draws a dashed red vertical reference line at the given x position — useful for marking today's date.
```rust,no_run
use kuva::plot::GanttPlot;
use kuva::render::plots::Plot;
# use kuva::backend::svg::SvgBackend;
# use kuva::render::render::render_multiple;
# use kuva::render::layout::Layout;
let gantt = GanttPlot::new()
.with_task_group_progress("Q1", "API design", 0.0, 3.0, 1.0) // done
.with_task_group_progress("Q1", "Auth service", 1.0, 4.0, 1.0) // done
.with_task_group_progress("Q2", "Dashboard", 3.0, 7.0, 0.65) // in progress
.with_task_group_progress("Q2", "Reporting", 4.0, 8.0, 0.25) // early
.with_task_group("Q3", "Mobile app", 7.0, 11.0) // not started
.with_task_group("Q3", "Performance", 8.0, 12.0)
.with_now_line(5.5);
let plots = vec![Plot::Gantt(gantt)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Engineering Roadmap — progress at week 5.5")
.with_x_label("Week");
```
<img src="../assets/gantt/progress.svg" alt="Gantt chart with progress fills and a now line" width="650">
---
## Milestones
`.with_milestone(label, at)` and `.with_milestone_group(group, label, at)` add diamond markers at a single point in time. Milestone labels are always drawn to the right of the diamond in bold, and the right margin is automatically widened to fit them.
```rust,no_run
use kuva::plot::GanttPlot;
use kuva::render::plots::Plot;
# use kuva::backend::svg::SvgBackend;
# use kuva::render::render::render_multiple;
# use kuva::render::layout::Layout;
let gantt = GanttPlot::new()
.with_task_group("Planning", "Requirements", 0.0, 2.0)
.with_task_group("Planning", "Architecture", 1.0, 3.0)
.with_milestone_group("Planning", "Sign-off", 3.0)
.with_task_group("Execution", "Core build", 3.0, 9.0)
.with_task_group("Execution", "Integration", 7.0, 11.0)
.with_milestone_group("Execution", "Code freeze", 11.0)
.with_task_group("Launch", "Testing", 10.0, 13.0)
.with_milestone("Public launch", 14.0)
.with_now_line(7.0);
let plots = vec![Plot::Gantt(gantt)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Software Release Plan")
.with_x_label("Week");
```
<img src="../assets/gantt/milestones.svg" alt="Gantt chart with milestone diamonds" width="680">
---
## Showcase — clinical trial timeline
The example below uses every major feature: explicit `group_order`, progress fills on pre-trial tasks, in-progress recruitment bars, ungrouped treatment arms, per-group and free-floating milestones, and a now line marking the current month.
```rust,no_run
use kuva::plot::GanttPlot;
use kuva::render::plots::Plot;
use kuva::backend::svg::SvgBackend;
use kuva::render::render::render_multiple;
use kuva::render::layout::Layout;
let gantt = GanttPlot::new()
.with_group_order(["Pre-trial", "Recruitment", "Treatment", "Analysis"])
.with_task_group_progress("Pre-trial", "Protocol writing", 0.0, 3.0, 1.0)
.with_task_group_progress("Pre-trial", "IRB approval", 2.0, 5.0, 1.0)
.with_task_group_progress("Pre-trial", "Site selection", 3.0, 6.0, 1.0)
.with_milestone_group("Pre-trial", "Trial start", 6.0)
.with_task_group_progress("Recruitment", "Screening", 6.0, 12.0, 0.75)
.with_task_group_progress("Recruitment", "Enrollment", 7.0, 14.0, 0.45)
.with_task_group("Treatment", "Arm A (n=150)", 12.0, 24.0)
.with_task_group("Treatment", "Arm B (n=150)", 12.0, 24.0)
.with_milestone_group("Treatment", "Interim analysis", 18.0)
.with_task_group("Analysis", "Data lock", 23.0, 26.0)
.with_task_group("Analysis", "Statistical analysis",25.0, 30.0)
.with_task_group("Analysis", "Report writing", 28.0, 34.0)
.with_milestone("Primary endpoint", 24.0)
.with_milestone("Submission", 35.0)
.with_now_line(16.0)
.with_bar_height(0.55);
let plots = vec![Plot::Gantt(gantt)];
let layout = Layout::auto_from_plots(&plots)
.with_title("Phase III Clinical Trial Timeline")
.with_x_label("Month")
.with_width(800.0)
.with_height(520.0);
let svg = SvgBackend.render_scene(&render_multiple(plots, layout));
std::fs::write("trial.svg", svg).unwrap();
```
<img src="../assets/gantt/showcase.svg" alt="Full-featured clinical trial Gantt chart" width="800">
---
## GanttPlot API reference
### Task builders
| `.with_task(label, start, end)` | Ungrouped task bar |
| `.with_task_group(group, label, start, end)` | Task assigned to a named group/phase |
| `.with_task_progress(label, start, end, frac)` | Ungrouped task with progress fill (`0.0`–`1.0`) |
| `.with_task_group_progress(group, label, start, end, frac)` | Grouped task with progress fill |
| `.with_colored_task(label, start, end, color)` | Task with a per-task CSS color override |
| `.with_milestone(label, at)` | Ungrouped milestone diamond at position `at` |
| `.with_milestone_group(group, label, at)` | Grouped milestone diamond |
### Display builders
| `GanttPlot::new()` | — | Create a Gantt chart with defaults |
| `.with_group_order(groups)` | insertion order | Explicit display order for groups; unlisted groups follow in insertion order |
| `.with_now_line(value)` | none | Dashed red vertical line at `value` (the current time) |
| `.with_bar_height(frac)` | `0.6` | Bar height as fraction of row height |
| `.with_milestone_size(px)` | `7.0` | Diamond half-size in pixels |
| `.with_show_labels(bool)` | `true` | Draw task and milestone labels |
| `.with_color(css)` | `"steelblue"` | Default bar color when no groups are present |
| `.with_group_bg(css)` | `"#ebebeb"` | Background color for group header rows |
| `.with_legend(label)` | none | Add a legend entry |