Metadata-Version: 2.4
Name: jsonantt
Version: 2026.28
Summary: Generate Gantt charts from JSON descriptions using matplotlib
Project-URL: Homepage, https://jsonantt.readthedocs.io/en/latest/
Project-URL: Documentation, https://jsonantt.readthedocs.io/en/latest/
Project-URL: Repository, https://github.com/briday1/jsonantt
Project-URL: Issues, https://github.com/briday1/jsonantt/issues
Keywords: gantt,chart,matplotlib,project-management,visualization
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: matplotlib>=3.5

# jsonantt

[![Documentation](https://readthedocs.org/projects/jsonantt/badge/?version=latest)](https://jsonantt.readthedocs.io/en/latest/) [![PyPI](https://img.shields.io/pypi/v/jsonantt)](https://pypi.org/project/jsonantt/)

**jsonantt** generates beautiful Gantt chart images from a simple JSON description.  
Charts are rendered with [matplotlib](https://matplotlib.org/) so they can be saved as `.png`, `.pdf`, `.svg`, and more.

📖 **Full documentation:** https://jsonantt.readthedocs.io

---

## Features

- **Infinitely nestable tasks** — define sub-tasks, sub-sub-tasks, etc., using either `tasks` or legacy `children`.
- **Composable task files** — import task trees from other JSON files with `filename`, either inline or nested under a wrapper task.
- **Auto date computation** — parent task start/end are derived automatically from children when not specified.
- **Milestone markers** — easy `"milestone": true` flag with chart-level defaults and per-milestone marker overrides, including milestone chains on one row via a `date` list.
- **Major milestones, rollups, and numbering** — distinguish major milestones from regular milestones, optionally roll only major milestones up onto summary bars, add milestone edge colours, and label milestones as `M1`, `M2`, ... in markers and tables.
- **Optional task descriptions and extra fields** — add long-form context per task, plus arbitrary metadata like assignee or cost for table output.
- **Fully colourable** — set colours per-task; children inherit their parent's colour.
- **Recursive child colour lightening** — inherited subtask colours can optionally lighten at each nested level.
- **Clean, indented y-axis labels** — task names are left-aligned with proper indentation per depth level.
- **Table output mode** — render a task summary table with the same hierarchy and colour cues.
- **Funded burn output** — render cost-over-time charts and period matrix tables from numeric task fields.
- **PNG / PDF / SVG output** — whatever matplotlib supports.

---

## Installation

```bash
pip install jsonantt
```

Or, directly from source:

```bash
git clone https://github.com/briday1/jsonantt.git
cd jsonantt
pip install -e .
```

---

## Quick start

### 1. Create a JSON description

```json
{
  "title": "My Project",
  "dateformat": "%Y-%m-%d",
  "style": {
    "milestone_color": "#FFD700",
    "milestone_marker": "D"
  },
  "tasks": [
    {
      "name": "Phase 1 – Planning",
      "tasks": [
        { "name": "Requirements", "start": "2024-01-08", "end": "2024-01-19" },
        { "name": "Architecture",  "start": "2024-01-15", "end": "2024-01-31" }
      ]
    },
    { "name": "Planning done", "milestone": true, "date": ["2024-01-24", "2024-01-31"] },
    {
      "name": "Phase 2 – Build",
      "color": "#70AD47",
      "children": [
        { "name": "Backend",  "start": "2024-02-01", "end": "2024-03-01" },
        { "name": "Frontend", "start": "2024-02-12", "end": "2024-03-08" }
      ]
    },
    { "name": "Launch", "milestone": true, "date": "2024-04-01", "color": "#FF5757" }
  ]
}
```

### 2. Generate the chart or table

**CLI:**

```bash
jsonantt project.json project.png
jsonantt project.json project.pdf   # vector PDF
jsonantt project.json project.svg   # scalable SVG
jsonantt --dpi 300 project.json project.png   # high-resolution PNG
jsonantt -r 1 project.json project.png   # top-level tasks only
jsonantt --renderdepth 2 project.json project.png   # include one child level
jsonantt -t project.json project-table.png   # task name / description table
jsonantt -t project.json project-table.csv   # CSV table export
jsonantt agreed.json compare.png --compare actual.json   # outline vs actual compare chart
jsonantt -t agreed.json compare-table.csv --compare actual.json   # compare table with signed offsets
jsonantt --burn project.json burn.png --burn-field cost --burn-period month --burn-group 0
jsonantt --burn-table project.json burn-table.csv --burn-field cost --burn-period quarter --burn-group 0
jsonantt project.json project.png --date-line today --date-line-color "#C00000"   # single target line
```

**Python API:**

```python
from jsonantt import load_chart, render_burn_chart, render_burn_table, render_chart, render_compare_chart, render_compare_table, render_table

config = load_chart("project.json")
actual = load_chart("actual.json")
render_chart(config, "project.png", dpi=150)
render_chart(config, "summary.png", dpi=150, render_depth=1)
render_table(config, "project-table.png", dpi=150)
render_compare_chart(config, actual, "compare.png", dpi=150)
render_compare_table(config, actual, "compare-table.csv", dpi=150)
render_burn_chart(config, "burn.png", dpi=150, field="cost", period="month", group_by=0)
render_burn_table(config, "burn-table.csv", dpi=150, field="cost", period="quarter", group_by=0)
```

`render_depth=0` renders all nested levels. `1` renders only top-level tasks, `2` includes one level of children, and so on.

`--table` / `-t` switches the output to a table view. By default it renders `Task`, `Name`, and `Description`. The `Task` column keeps hierarchy numbering, the `Name` column stays unindented, `style.table_colorize` controls the side color accent, and `style.table_show_markers` controls whether milestone rows use a diamond marker in that gutter.

You can customize the table columns with `style.table_columns`. Each entry can be either a string field name or an object with `field` and optional `title`. The special fields `task`, `name`, and `description` preserve the existing behavior; any other field is read from the task object, including extra task keys like `assignee`, `cost`, or `fte`.

Column objects can also opt into numeric aggregation. Use `rollup: "sum"` to show a recursively summed value on parent rows, `total: true` to add a footer total for that column, and `total_level` to control which task depth contributes to that footer. When `rollup` is enabled, totals default to depth `0` so parent rollups are not double-counted.

For display-only unit conversion, set `display_factor` on the column. This multiplies the numeric value one time at render/export time, after the raw value has been read and after any rollup sum has been calculated. That makes it suitable both for converting FTE into annual dollars and for showing large values in `k` or `M` units by pairing a factor with a custom header title.

```json
{
  "style": {
    "table_columns": [
      "task",
      "name",
      { "field": "assignee", "title": "Owner" },
      { "field": "fte", "title": "Annual Cost ($)", "rollup": "sum", "total": true, "total_level": 0, "display_factor": 250000 },
      "description"
    ]
  },
  "tasks": [
    {
      "name": "API Design",
      "start": "2024-01-01",
      "end": "2024-01-10",
      "assignee": "Morgan",
      "fte": 1.2,
      "description": "Finalize endpoints and review contracts."
    }
  ]
}
```

Examples:

- FTE to annualized dollars: `{ "field": "fte", "title": "Annual Cost ($)", "display_factor": 250000 }`
- Dollars to thousands: `{ "field": "cost", "title": "Cost (k$)", "display_factor": 0.001 }`
- Dollars to millions: `{ "field": "cost", "title": "Cost ($M)", "display_factor": 0.000001 }`

Description and Name cells wrap to the measured rendered width of the column, and the row height expands to fit the wrapped lines. Very long unbroken tokens are not split mid-word, so they can still clip horizontally.

`--milestones-only` works with `--table` to render only milestone rows in a dedicated milestone table. `--no-milestones` does the opposite and excludes milestones.

If the table output path ends in `.csv`, `jsonantt` writes CSV instead of an image.

`--compare` turns the first JSON input into the planned/agreed baseline and overlays the second JSON as the updated/actual state. In compare charts, planned bars are drawn as slightly larger unfilled outlines, actual bars are drawn normally, removed planned tasks are struck through with no actual bar, and actual-only tasks render as normal filled bars. In compare tables and CSV output, the `Offset` column shows signed duration changes like `+2d`, `-1w`, `+3mo`, or `+1y`; milestones use the signed date shift instead.

`--burn` renders a funded burn chart from a numeric task field such as `cost`. Burn output always allocates from the lowest tasks that actually carry a numeric value, spreads each task uniformly over its duration, and only then groups the result. That means collapsing to top-level or total views does not lose deeper task spend.

Use `--burn-period` to choose `day`, `week`, `month`, `quarter`, or `year`. Use `--burn-group total` for one overall series, `--burn-group leaf` for the lowest direct-cost tasks, or a depth integer where `0` is top-level, `1` is subtasks, `2` is sub-subtasks, and so on. `--burn-table` renders the same burn data as a matrix with one row per grouped task and one column per time bucket. `--burn-display-factor` applies a display-only multiplier once, after burn allocation, so the same scaling rules used for cost tables also work here.

Use `--date-line` to draw a single vertical reference line on chart outputs. It accepts either a date in the input file's `dateformat` or the special value `today`. Use `--date-line-color` to control its color.

---

## JSON reference

| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Optional chart title shown at the top |
| `dateformat` | string | `strptime` format string (default: `"%Y-%m-%d"`) |
| `start` | date string | Optional chart x-axis start date (overrides task dates) |
| `end` | date string | Optional chart x-axis end date |
| `style` | object | Visual style overrides (see below) |
| `tasks` | array | Top-level list of task objects |
| `children` | array | Legacy alias for top-level `tasks` |

### Task object

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | **Required.** Task label |
| `description` | string | Optional long-form text used by table output |
| any other key | any JSON value | Preserved on the task and available to `style.table_columns` for table output |
| `id` | string | Unique identifier used for `not_before` references |
| `start` | date string | Bar start date |
| `end` | date string | Bar end date |
| `duration` | string or int | Duration from `start` (or resolved `not_before` end): `"14d"`, `"2w"`, `"3m"`, `"2y"`, or a plain integer (days) |
| `not_before` | string | `id` of another task — this task starts immediately after that task ends |
| `color` | CSS hex string | Bar colour, or milestone colour override for an individual milestone (e.g. `"#4472C4"`) |
| `edge_color` | CSS hex string | Optional milestone outline colour override for an individual milestone |
| `milestone` | boolean | Render as a diamond milestone instead of a bar |
| `major_milestone` | boolean | Mark this milestone as a major milestone; it still behaves like a milestone but can use separate default styling and rollup rules |
| `date` | date string or array of date strings | Milestone date, or a list of milestone dates to draw multiple markers on the same row when `milestone: true` |
| `marker` | string | Milestone marker override for an individual milestone (matplotlib marker symbol such as `"D"`, `"o"`, `"s"`, `"*"`) |
| `marker_size` | number | Override milestone diamond size in points |
| `bold` | boolean | Render label in bold (top-level tasks are auto-bolded by default) |
| `filename` | string | Path to another JSON file whose task tree should be imported at this location |
| `tasks` | array | Nested sub-tasks (preferred key, infinitely nestable) |
| `children` | array | Legacy alias for nested sub-tasks |

> **Auto date computation:** When a task has `children` but no explicit `start`/`end`, the dates are computed automatically as the earliest child start and latest child end, recursively.

> **Milestone chains:** When `milestone: true`, `date` may be either one date string or a list of date strings. A list draws multiple milestone markers on the same task row while keeping the same label, description, color, and marker settings.

> **Milestone numbering:** When `style.number_milestones` is `true`, milestones are numbered `M1`, `M2`, ... in tree order. The marker keeps its configured shape and the `M` label is drawn inside it. Tables use the same `M` labels in the `Task` column instead of hierarchy numbers for milestone rows.

> **Milestone rollup:** When `style.rollup_milestones` is `true` and deeper rows are hidden by `render_depth`, descendant milestones are not listed as separate rows. Instead their milestone markers are drawn on top of the visible ancestor bar they roll up into. This happens recursively, so deeply nested hidden milestones keep rolling up until they land on a visible row.

> **Major milestone styling:** `major_milestone: true` implies `milestone: true`. Major milestones can have a separate default fill, edge colour, marker, and size through the `style.major_milestone_*` fields. Task-level `color`, `edge_color`, `marker`, and `marker_size` still override both milestone and major milestone defaults.

> **Major-only rollup:** When both `style.rollup_milestones` and `style.rollup_major_milestones_only` are `true`, hidden regular milestones stay hidden while hidden major milestones roll up onto the visible ancestor bar.

```json
{
  "title": "Release Gates",
  "tasks": [
    {
      "name": "Release Track",
      "tasks": [
        {
          "name": "Gate Reviews",
          "description": "Same milestone row, repeated checkpoints.",
          "milestone": true,
          "date": ["2024-06-01", "2024-06-15", "2024-07-01"],
          "marker": "D",
          "color": "#C0504D"
        },
        {
          "name": "Executive Approval",
          "major_milestone": true,
          "date": "2024-07-08"
        }
      ]
    }
  ]
}
```

`tasks` and `children` are interchangeable at both the chart root and inside nested task objects. If both are present on the same object, jsonantt reads both lists in order.

`filename` lets you build a larger plan from smaller task files. A task entry that is only `{ "filename": "phase.json" }` inlines the referenced file's tasks at that position. When `filename` appears alongside normal task fields like `name` or `description`, the referenced file's tasks are imported as that task's children. The included file's `style`, `title`, chart `start`/`end`, and `arrows` are ignored during inclusion; only its task tree is used.

```json
{
  "title": "Combined Plan",
  "tasks": [
    { "filename": "composed-discovery.json" },
    {
      "name": "Delivery Program",
      "filename": "composed-delivery.json"
    }
  ]
}
```

> **Duration formats:** `d`/`day`/`days`, `w`/`week`/`weeks`, `m`/`month`/`months`, `y`/`year`/`years` — e.g. `"14d"`, `"2w"`, `"3m"`, `"1y"`.

### Style object

| Field | Default | Description |
|-------|---------|-------------|
| `width` | `14` | Figure width in inches |
| `row_height` | `0.3` | Height of each task row in inches |
| `bar_height` | `0.5` | Bar height as a fraction of `row_height` |
| `font_size` | `12` | Base font size in points |
| `indent_size` | `3` | Spaces added per depth level in labels |
| `label_fraction` | `0.0` | Fraction of figure width used for labels; `0` means auto-size from measured text width |
| `subtask_lightening_pct` | `0.0` | Percentage to lighten inherited subtask colours at each nested level; `20` means each inherited step moves 20% toward white |
| `colors` | palette | Array of default hex colours cycled per top-level task |
| `background` | `"#FFFFFF"` | Figure background colour |
| `grid_color` | `"#E0E0E0"` | Vertical gridline colour |
| `row_band_color` | `"#F5F5F5"` | Alternating row band colour |
| `milestone_color` | `"#FFD700"` | Default milestone colour |
| `milestone_edge_color` | `null` | Optional default milestone outline colour |
| `milestone_marker` | `"D"` | Default milestone marker symbol |
| `milestone_size` | `14` | Default milestone marker size in points |
| `rollup_milestones` | `false` | When rows are hidden by `render_depth`, draw descendant milestone markers on the visible ancestor bar instead of dropping them |
| `rollup_major_milestones_only` | `false` | When milestone rollup is enabled, restrict rolled-up overlays to hidden major milestones |
| `number_milestones` | `false` | Number milestones as `M1`, `M2`, ... inside their markers and in table `Task` cells |
| `major_milestone_color` | `null` | Optional default fill colour for major milestones |
| `major_milestone_edge_color` | `null` | Optional default outline colour for major milestones |
| `major_milestone_marker` | `null` | Optional default marker symbol for major milestones |
| `major_milestone_size` | `null` | Optional default marker size in points for major milestones |
| `major_tick` | `null` | Major tick unit: `"year"`, `"quarter"`, `"month"`, `"week"` |
| `minor_tick` | `null` | Minor tick unit: `"quarter"`, `"month"`, `"week"`, `"day"` |
| `major_grid_width` | `2.0` | Major gridline linewidth |
| `minor_grid_width` | `1.5` | Minor gridline linewidth |
| `tick_position` | `"top"` | X-axis label position: `"top"`, `"bottom"`, or `"both"` |
| `bold_tasks` | `true` | Auto-bold top-level (depth 0) task labels |
| `number_tasks` | `true` | Prefix task labels with hierarchy numbers like `1`, `1.1`, `1.2` |
| `table_colorize` | `true` | Show a task-coloured accent bar in table output; when `false`, both accent bars and milestone markers are suppressed |
| `table_show_markers` | `true` | Replace the accent bar with a milestone diamond for milestone rows in table output when table colours are enabled |
| `table_columns` | `[]` | Ordered table column definitions. Empty means the default `Task`, `Name`, `Description` columns. Entries can be field-name strings or objects like `{ "field": "cost", "title": "Cost (k$)", "rollup": "sum", "total": true, "total_level": 0, "display_factor": 0.001 }` |

---

## Examples

See the [examples/](https://github.com/briday1/jsonantt/tree/main/examples) folder for ready-to-run JSON files.

### Simple project

[examples/simple.json](https://github.com/briday1/jsonantt/blob/main/examples/simple.json) — a five-phase project with milestones

![simple](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/simple.png)

### Dependencies

[examples/dependencies.json](https://github.com/briday1/jsonantt/blob/main/examples/dependencies.json) — `id`, `duration`, and `not_before`

![dependencies](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/dependencies.png)

### Render depth

[examples/renderdepth.json](https://github.com/briday1/jsonantt/blob/main/examples/renderdepth.json) — nested tasks that are useful with `-r` / `--renderdepth`

Full depth, `render_depth=0`:

![render depth all](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth.png)

One child level, `-r 2`:

![render depth mid](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth-mid.png)

Top level only, `-r 1`:

### Chained milestones

[examples/chained-milestones.json](https://github.com/briday1/jsonantt/blob/main/examples/chained-milestones.json) — nested `tasks` with multiple milestone dates on one row

### Composed plans

[examples/composed-plan.json](https://github.com/briday1/jsonantt/blob/main/examples/composed-plan.json) — combines multiple task files with `filename`, including nested chained milestones

### Major milestone rollup

[examples/major-milestones.json](https://github.com/briday1/jsonantt/blob/main/examples/major-milestones.json) — distinguishes regular vs major milestones, numbers them, and rolls up only hidden major milestones

![render depth top](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth-top.png)

Table output, `-t`:

![render depth table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth-table.png)

Milestones only, `-t --milestones-only`:

![render depth milestones table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth-milestones.png)

No milestones, `-t --no-milestones`:

![render depth no milestones table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/renderdepth-no-milestones.png)

Try the same file with different depth limits:

```bash
jsonantt examples/renderdepth.json examples/renderdepth-all.png      # full depth
jsonantt -r 1 examples/renderdepth.json examples/renderdepth-top.png # top-level only
jsonantt -r 2 examples/renderdepth.json examples/renderdepth-mid.png # one child level
jsonantt -t examples/renderdepth.json examples/renderdepth-table.png # task table view
jsonantt -t --milestones-only examples/renderdepth.json examples/renderdepth-milestones.png # milestones only
jsonantt -t --no-milestones examples/renderdepth.json examples/renderdepth-no-milestones.png # exclude milestones
jsonantt -t examples/renderdepth.json examples/renderdepth-table.csv # CSV table export
```

### Funding burn

[examples/funding.json](https://github.com/briday1/jsonantt/blob/main/examples/funding.json) — direct task costs allocated uniformly over time, then grouped into top-level burn output

Monthly burn chart, `--burn --burn-period month --burn-group 0`:

![funding burn](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/funding-burn.png)

Quarter burn table, `--burn-table --burn-period quarter --burn-group 0`:

![funding burn table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/funding-burn-table.png)

### Color schemes

[examples/colors.json](https://github.com/briday1/jsonantt/blob/main/examples/colors.json) — custom palette, background, grid, row band, milestone colours, and custom milestone markers

![color schemes](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/colors.png)

### Compare mode

[examples/compare-planned.json](https://github.com/briday1/jsonantt/blob/main/examples/compare-planned.json) and [examples/compare-actual.json](https://github.com/briday1/jsonantt/blob/main/examples/compare-actual.json) — planned vs actual comparison with a CLI date line

Compare chart:

![compare chart](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/compare.png)

Compare table image:

![compare table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/compare-table.png)

CSV export:

[examples/compare-table.csv](https://github.com/briday1/jsonantt/blob/main/examples/compare-table.csv)

### Description wrapping

[examples/description-wrap.json](https://github.com/briday1/jsonantt/blob/main/examples/description-wrap.json) — demonstrates normal word wrapping in table output and the edge case where a single unbroken token will not wrap

Table output, `-t`:

![description wrap table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/description-wrap-table.png)

CSV export:

[examples/description-wrap-table.csv](https://github.com/briday1/jsonantt/blob/main/examples/description-wrap-table.csv)

### Custom table fields

[examples/costs.json](https://github.com/briday1/jsonantt/blob/main/examples/costs.json) — shows `style.table_columns` with custom `Owner` and `Cost` columns sourced from task fields like `assignee` and `cost`

CSV export:

[examples/costs-table.csv](https://github.com/briday1/jsonantt/blob/main/examples/costs-table.csv)

### Overlapping cost plan

[examples/costs-overlap.json](https://github.com/briday1/jsonantt/blob/main/examples/costs-overlap.json) — a more realistic cost plan with overlapping workstreams, nested tasks, milestones, and rolled-up `Cost (k$)` values

Chart output:

![overlapping cost chart](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/costs-overlap.png)

Table output, `-t`:

![overlapping cost table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/costs-overlap-table.png)

CSV export:

[examples/costs-overlap-table.csv](https://github.com/briday1/jsonantt/blob/main/examples/costs-overlap-table.csv)

Monthly burn chart, `--burn --burn-period month --burn-group 0 --burn-display-factor 0.001`:

![overlapping cost burn](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/costs-overlap-burn.png)

Monthly burn matrix, `--burn-table --burn-period month --burn-group 0 --burn-display-factor 0.001`:

![overlapping cost burn table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/costs-overlap-burn-table.png)

Burn CSV export:

[examples/costs-overlap-burn-table.csv](https://github.com/briday1/jsonantt/blob/main/examples/costs-overlap-burn-table.csv)

### Complex roadmap

[examples/complex.json](https://github.com/briday1/jsonantt/blob/main/examples/complex.json) — a multi-year roadmap with deep nesting, task descriptions, and custom colours

![complex](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/complex.png)

Table output, `-t`:

![complex table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/complex-table.png)

Milestones only, `-t --milestones-only`:

![complex milestones table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/complex-milestones.png)

No milestones, `-t --no-milestones`:

![complex no milestones table](https://raw.githubusercontent.com/briday1/jsonantt/main/examples/complex-no-milestones.png)


## How to Run

```bash
jsonantt examples/simple.json examples/simple.png                    # basic milestones
jsonantt examples/dependencies.json examples/dependencies.png        # not_before scheduling
jsonantt examples/renderdepth.json examples/renderdepth.png          # full nested view
jsonantt -r 1 examples/renderdepth.json examples/renderdepth-top.png # top-level only
jsonantt -r 2 examples/renderdepth.json examples/renderdepth-mid.png # one child level
jsonantt -t examples/renderdepth.json examples/renderdepth-table.png # task table with descriptions
jsonantt -t --milestones-only examples/renderdepth.json examples/renderdepth-milestones.png # milestone table
jsonantt -t --no-milestones examples/renderdepth.json examples/renderdepth-no-milestones.png # table without milestones
jsonantt -t examples/renderdepth.json examples/renderdepth-table.csv # CSV export
jsonantt examples/colors.json examples/colors.png                    # custom palette and background
jsonantt examples/compare-planned.json examples/compare.png --compare examples/compare-actual.json --date-line 2024-03-01 --date-line-color "#C00000" # compare chart with target line
jsonantt -t examples/compare-planned.json examples/compare-table.png --compare examples/compare-actual.json # compare table image
jsonantt -t examples/compare-planned.json examples/compare-table.csv --compare examples/compare-actual.json # compare table CSV
jsonantt -t examples/description-wrap.json examples/description-wrap-table.png # wrapped descriptions table image
jsonantt -t examples/description-wrap.json examples/description-wrap-table.csv # wrapped descriptions CSV
jsonantt -t examples/costs.json examples/costs-table.csv                # custom cost/owner columns CSV
jsonantt examples/complex.json examples/complex.png                  # deep roadmap example
jsonantt -t examples/complex.json examples/complex-table.png         # full complex table
jsonantt -t --milestones-only examples/complex.json examples/complex-milestones.png # complex milestones only
jsonantt -t --no-milestones examples/complex.json examples/complex-no-milestones.png # complex without milestones
```

