# Quadrant charts

> Page: https://docs.plotwork.dev/quadrant-charts. Index of every page: https://docs.plotwork.dev/llms.txt

A quadrant chart places items on two axes and divides the plot into four zones, so the reader sees at a glance which items to do first, which to watch, and which to drop. Use it to rank ideas by impact and effort, to sort risks by likelihood and damage, or to compare build and buy options. It is for anyone who has to choose among a list, and for an agent that has been asked to prioritise one.

## TL;DR

| Question | Answer |
|---|---|
| What is it for? | A list of items that you want to place on two scales: impact against effort, risk against likelihood, value against cost. |
| How do I start one? | Write `quadrant "Title"`, an `x` and a `y` axis, optional `zone` names, and one `point` line for each item. |
| How is a point placed? | `x=` runs across and `y=` runs up, both from 0 to 1. Write `0.8`, not `80`. 0.5 is the dashed line and counts as the high side. |
| What does Mermaid convert? | `quadrantChart`. Axes, the four zone names, and points are read. Styles and classes are reported. See [From Mermaid](#from-mermaid). |
| How big can it be? | At most 120 points. Warnings start at 40 points, when two points touch, and when every point is in one zone. |
| How is it drawn? | A plot with four soft washes divided by dashed lines, a name in a corner tab for each zone you named, quiet arrows for the axes, and a chip or a dot for each point with its label beside it. |

## Ask your agent

```text
Use Plotwork to draw a quadrant chart of what to build next. Put effort across and impact up. Name the zones Quick wins, Big bets, Fill-ins and Time sinks, and highlight the quick wins. Place twelve ideas, with an icon on the ones that need a name to stand out.
```

```text
Use Plotwork to draw a risk register as a quadrant chart: likelihood across, impact up. Name the top right "Act now" in red and the top left "Watch" in amber, and place these risks: key engineer leaves, data breach, supplier misses delivery, scope creep.
```

## Example

Fourteen ideas, the four zones named and washed, the quick wins highlighted, and an icon on the ones that carry one. A point takes the tone of its zone, so each zone's items match its wash.

**Diagram source**

```diagram
quadrant "What to build next" highlight=top-left desc="Fourteen roadmap ideas placed by the effort they take and the impact they have on customers. The quick wins in the top left are the ones to start with."

x "Effort" low="Low effort" high="High effort"
y "Impact" low="Low impact" high="High impact"

zone top-left "Quick wins" tone=green icon=lucide:zap
zone top-right "Big bets" tone=blue icon=lucide:rocket
zone bottom-left "Fill-ins"
zone bottom-right "Time sinks" tone=red icon=lucide:hourglass

point "Saved filters" x=0.1 y=0.88 icon=lucide:funnel
point "Dark mode" x=0.26 y=0.7
point "Keyboard shortcuts" x=0.36 y=0.56
point "Email digest" x=0.4 y=0.86 icon=lucide:mail

point "Mobile app" x=0.88 y=0.9 icon=lucide:smartphone
point "Public API" x=0.68 y=0.78 icon=lucide:plug
point "SSO and SCIM" x=0.6 y=0.62 icon=lucide:key-round
point "Offline mode" x=0.84 y=0.62

point "Release notes page" x=0.2 y=0.24
point "Footer links" x=0.4 y=0.38
point "Favicon refresh" x=0.1 y=0.1

point "Rewrite in Rust" x=0.8 y=0.14
point "Custom themes" x=0.66 y=0.4
point "Plugin marketplace" x=0.58 y=0.22
```

*Picture: What to build next: 14 points placed by Effort and Impact. Fourteen roadmap ideas placed by the effort they take and the impact they have on customers. The quick wins in the top left are the ones to start with.*

**Text description**

**Horizontal axis: Effort, from Low effort to High effort.**

**Vertical axis: Impact, from Low impact to High impact.**

**Quick wins (top left, highlighted):**

- Saved filters: Effort 0.1, Impact 0.88
- Dark mode: Effort 0.26, Impact 0.7
- Keyboard shortcuts: Effort 0.36, Impact 0.56
- Email digest: Effort 0.4, Impact 0.86

**Big bets (top right):**

- Mobile app: Effort 0.88, Impact 0.9
- Public API: Effort 0.68, Impact 0.78
- SSO and SCIM: Effort 0.6, Impact 0.62
- Offline mode: Effort 0.84, Impact 0.62

**Fill-ins (bottom left):**

- Release notes page: Effort 0.2, Impact 0.24
- Footer links: Effort 0.4, Impact 0.38
- Favicon refresh: Effort 0.1, Impact 0.1

**Time sinks (bottom right):**

- Rewrite in Rust: Effort 0.8, Impact 0.14
- Custom themes: Effort 0.66, Impact 0.4
- Plugin marketplace: Effort 0.58, Impact 0.22

## The language

One statement to a line. Text is always in double quotes, options are `key=value`, and `#` starts a comment. A point is written with `x=` and `y=` and never with two bare numbers, so the two axes cannot be swapped by writing them in the other order.

| Statement | Meaning | Example |
|---|---|---|
| `quadrant "Title" highlight=<zone> desc="<text>"` | The header. Both options are optional, and so is the title. | `quadrant "Where to invest" highlight=top-left` |
| `x "<Title>" low="<text>" high="<text>"` | The horizontal axis. `low=` is the word at the left end, where the value is 0, and `high=` the word at the right end, where it is 1. With a title and no end labels, the ends read Low and High. An axis needs at least one of the three. | `x "Effort" low="Easy" high="Hard"` |
| `y "<Title>" low="<text>" high="<text>"` | The vertical axis. `low=` is the bottom and `high=` the top. | `y "Impact" low="Small" high="Large"` |
| `zone <position> "<Name>" tone=<tone> icon=<icon>` | Names one zone in a tab in its corner. Name each zone once. | `zone top-left "Quick wins" tone=green icon=lucide:zap` |
| `point "<Label>" x=<0 to 1> y=<0 to 1> tone=<tone> icon=<icon>` | An item. Labels are unique. | `point "Dark mode" x=0.2 y=0.8` |
| `desc "<text>"` | The plain-language description. The same as `desc=` on the header. | `desc "Ideas by effort and impact."` |

A point has no id, because a chart has no cross references. A habit from flow diagrams such as `point dark "Dark mode" x=0.2 y=0.8` is refused with `E100`, and the hint gives the form to write.

### Reading a point

The values run from 0 to 1 on both axes. A value on another scale is refused, and the hint gives the number it most likely meant.

| You write | You get |
|---|---|
| `x=0.8` | A point 80 percent of the way across. |
| `x=80` | `E136`, with the hint to write `x=0.8`. |
| `x=7` | `E136`, with the hint to write `x=0.7` for a score of 7 out of 10. |
| `x=0.5` | A point on the dashed line, which belongs to the high side: the right half for `x`, the top half for `y`. |
| `point "A" 0.2 0.8` | `E100`: write the position as `x=0.2 y=0.8`. |

### Zones and options

The four positions are `top-right`, `top-left`, `bottom-left`, and `bottom-right`. A zone you do not name is drawn with no name and a neutral wash.

| Option | On | Values | Default |
|---|---|---|---|
| `highlight=` | header | a zone position | none |
| `tone=` | zone | `neutral`, `blue`, `violet`, `aqua`, `orange`, `green`, `amber`, `red` | `neutral` |
| `icon=` | zone, point | any bundled icon, such as `lucide:zap`, or `none` | none |
| `tone=` | point | the same tones | the tone of the zone the point lies in |
| `low=`, `high=` | axis | quoted text, or `""` for no label at that end | Low and High, when the axis has a title |

### Colour

A zone with a tone mixes a tenth of it into the surface. The highlighted zone gets a sixth and an outline in its tone, so the zone to act on stands out. A neutral zone takes the quiet group colour, and a neutral zone that is highlighted is a little darker. A point takes the tone of its zone unless it chooses another with `tone=`, so a `tone=` on a point is a meaning, such as which team owns it. Nobody writes a colour value: the theme owns every colour, in light and in dark.

A risk register uses the tones for meaning, and the zones you do not tone stay plain plates that the dashed lines divide:

**Diagram source**

```diagram
quadrant "Risk register" highlight=top-right desc="Eight risks placed by how likely they are and how much damage they would do. The ones in the top right need an owner this week."

x "Likelihood" low="Unlikely" high="Almost certain"
y "Impact" low="Minor" high="Severe"

zone top-left "Watch" tone=amber icon=lucide:search
zone top-right "Act now" tone=red icon=lucide:triangle-alert
zone bottom-left "Accept"
zone bottom-right "Reduce" tone=blue icon=lucide:gauge

point "Key engineer leaves" x=0.34 y=0.84 icon=lucide:users
point "Cloud region outage" x=0.28 y=0.7
point "Data breach" x=0.2 y=0.94 icon=lucide:lock
point "Supplier misses delivery" x=0.78 y=0.82 icon=lucide:cable
point "Scope creep" x=0.9 y=0.58
point "Licence audit" x=0.4 y=0.2
point "Office move delay" x=0.64 y=0.28
point "Minor browser bugs" x=0.84 y=0.12
```

*Picture: Risk register: 8 points placed by Likelihood and Impact. Eight risks placed by how likely they are and how much damage they would do. The ones in the top right need an owner this week.*

**Text description**

**Horizontal axis: Likelihood, from Unlikely to Almost certain.**

**Vertical axis: Impact, from Minor to Severe.**

**Watch (top left):**

- Key engineer leaves: Likelihood 0.34, Impact 0.84
- Cloud region outage: Likelihood 0.28, Impact 0.7
- Data breach: Likelihood 0.2, Impact 0.94

**Act now (top right, highlighted):**

- Supplier misses delivery: Likelihood 0.78, Impact 0.82
- Scope creep: Likelihood 0.9, Impact 0.58

**Accept (bottom left):**

- Licence audit: Likelihood 0.4, Impact 0.2

**Reduce (bottom right):**

- Office move delay: Likelihood 0.64, Impact 0.28
- Minor browser bugs: Likelihood 0.84, Impact 0.12

### How it is laid out

The plot is a little under square. It is 600px wide for up to 12 points and grows by 12px for each point after that, up to 960px, so a crowded chart gets room for its labels. A point is a chip with its icon, or a dot, at the place its two values say, and the values 0 and 1 land a little inside the edges so that a point on an edge keeps its whole mark on the plot.

Each label goes beside its point, to the right when there is room, and then to the left, above, below, or off a corner. A label stays inside the zone of its point, and clears every mark, every zone name, and every other label. A zone name sits in its zone's top-left corner, and slides right along the edge when a point lies under it. A label that cannot be placed is left out of the picture and kept in the text description, and lint says so.

## Limits and warnings

| Limit | Value | What happens past it |
|---|---|---|
| Points | 120 | `E140` before any layout, with the advice to split the chart by theme or team. |
| Points before the density warning | 40 | `W200`. |
| Label width | 150px preferred, 220px hard, 2 lines | Text wraps at the preferred width, and a long word widens the label up to the hard width. Only past that is text cut with an ellipsis, with warning `W203`. |
| An axis end, and an axis title | A quarter, and a little over a third, of the axis | Cut with an ellipsis, with warning `W203`, so the line is never swallowed. |
| A zone name | The width of its zone less 24px | Cut with an ellipsis, with warning `W203`. |

Every mistake comes back as a result with a code, a line, a column, and a hint. Warnings never stop the drawing.

| Code | When it fires | Fix |
|---|---|---|
| `E100` | A position written as bare numbers, a point with no `x=` or `y=`, an axis with no name and no end labels, a name with no text, a chart with no points, or a point written with an id. | Read the hint, which names the line to write. |
| `E136` | A value outside 0 to 1 or not a number, or a zone that is none of the four. | Rescale the value to 0 to 1, as the hint says, or use one of the four positions. |
| `E130` | An axis described twice, a zone named twice, or a label used twice. | Say it once, or give the points different labels. |
| `E140` | More than 120 points. | Split the chart by theme or team. |
| `E101`, `E110`, `E121`, `E122`, `E135` | The shared codes: an unterminated string, an unknown statement (a line of Mermaid names the converter), an unknown tone or icon, and an unknown option. | Read the hint. |
| `W200` | More than 40 points, two points whose marks touch, a label with no free place, a zone name over a point it could not slide away from, or every point in one zone. | Spread the points, split the chart, or rescale the values so some fall on the other side of 0.5. |
| `W202` | The picture is wider than a Markdown column and its text would shrink. | Shorten the axis words and the labels, or split the chart. |
| `W203` | Text was cut with an ellipsis. | Shorten the label, the zone name, or the axis word. |

## From Mermaid

Mermaid `quadrantChart` converts to a quadrant chart. Ask your agent to convert it, or use the `convert_mermaid` tool. The [migration guide](https://docs.plotwork.dev/migrating-from-mermaid.md) covers the converter in full. Mermaid numbers its zones counter-clockwise from the top right, and the converter maps them to the four positions.

```mermaid-source
quadrantChart
    title Reach and engagement of campaigns
    x-axis Low Reach --> High Reach
    y-axis Low Engagement --> High Engagement
    quadrant-1 We should expand
    quadrant-2 Need to promote
    quadrant-3 Re-evaluate
    quadrant-4 May be improved
    Campaign A: [0.3, 0.6]
    Campaign B: [0.45, 0.23]
    Campaign C:::error: [0.57, 0.69] color: #ff3300, radius: 10
```

The converter reports the style it dropped (`M200`) and the tone it took from the class (`M207`):

```plotwork
quadrant "Reach and engagement of campaigns"

x low="Low Reach" high="High Reach"
y low="Low Engagement" high="High Engagement"

zone top-right "We should expand"
zone top-left "Need to promote"
zone bottom-left "Re-evaluate"
zone bottom-right "May be improved"

point "Campaign A" x=0.3 y=0.6
point "Campaign B" x=0.45 y=0.23
point "Campaign C" x=0.57 y=0.69 tone=red
```

| Mermaid | Plotwork | Report |
|---|---|---|
| `x-axis Low --> High` and `y-axis Low --> High` | `x low="Low" high="High"` | none |
| An axis with one end, or words in quotes | The one end, with the quotes removed | none |
| `quadrant-1` to `quadrant-4` | `zone top-right`, `top-left`, `bottom-left`, and `bottom-right` | none |
| `Name: [0.3, 0.6]` | `point "Name" x=0.3 y=0.6` | none |
| A value outside 0 to 1 | Moved to the nearest end | `M204` |
| Front matter `title:`, a `title` line, `accTitle:`, `accDescr:` | The title and `desc=`. The front matter wins over a `title` line. | none |
| `color:`, `radius:`, `stroke-color:`, `stroke-width:` after a point | Dropped. The theme owns every colour and every point has one size. | `M200` |
| `classDef`, and a class that names no tone | Dropped. | `M200` |
| `:::error` and the like | `tone=red` for a class that names a tone | `M207` |
| A second axis line, zone name, or point of the same name | The second is dropped. | `M209` |
| `<br/>`, other HTML, and entities in a name | Removed or decoded. | `M205` |
| Front matter `config:` and `%%{init}%%` | Dropped. | `M200` |
| A chart with no points | Nothing is converted. | `M103` |
| More than 120 points | Nothing is converted. | `M102` |
| A line that cannot be read | Nothing is converted, or the line is skipped when the conversion is lenient. | `M110`, or `M218` |

The converter sets a tone only from a class that names one. Choose a `tone=` on a point where its colour should mean something, and an `icon=` where a glyph helps.

## See also

| Doc | Why |
|---|---|
| [Writing diagrams](https://docs.plotwork.dev/writing-diagrams.md) | The flow, sequence and schema languages, and the rules every kind shares |
| [Examples to copy](https://docs.plotwork.dev/examples.md) | Finished diagrams with the prompt that gets an agent to write each one |
| [Migrating from Mermaid](https://docs.plotwork.dev/migrating-from-mermaid.md) | Convert existing Mermaid diagrams, and what is dropped |
| [Gantt charts](https://docs.plotwork.dev/gantt-charts.md) | A plan drawn as tasks along a calendar |
| [Mind maps](https://docs.plotwork.dev/mind-maps.md) | A central idea and the branches that grow from it |
| [Timelines](https://docs.plotwork.dev/timelines.md) | Events along a time axis, when the order matters more than the grouping |
| [Language reference](https://docs.plotwork.dev/reference/language.md) | Every kind, node type, option and diagnostic |
| [Diagram kinds](https://docs.plotwork.dev/reference/language/kinds.md) | The kinds Plotwork draws and the header of each |
