Quadrant charts
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. |
| 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
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.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.
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:zapzone top-right "Big bets" tone=blue icon=lucide:rocketzone 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:funnelpoint "Dark mode" x=0.26 y=0.7point "Keyboard shortcuts" x=0.36 y=0.56point "Email digest" x=0.4 y=0.86 icon=lucide:mail
point "Mobile app" x=0.88 y=0.9 icon=lucide:smartphonepoint "Public API" x=0.68 y=0.78 icon=lucide:plugpoint "SSO and SCIM" x=0.6 y=0.62 icon=lucide:key-roundpoint "Offline mode" x=0.84 y=0.62
point "Release notes page" x=0.2 y=0.24point "Footer links" x=0.4 y=0.38point "Favicon refresh" x=0.1 y=0.1
point "Rewrite in Rust" x=0.8 y=0.14point "Custom themes" x=0.66 y=0.4point "Plugin marketplace" x=0.58 y=0.22Horizontal 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:
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:searchzone top-right "Act now" tone=red icon=lucide:triangle-alertzone bottom-left "Accept"zone bottom-right "Reduce" tone=blue icon=lucide:gauge
point "Key engineer leaves" x=0.34 y=0.84 icon=lucide:userspoint "Cloud region outage" x=0.28 y=0.7point "Data breach" x=0.2 y=0.94 icon=lucide:lockpoint "Supplier misses delivery" x=0.78 y=0.82 icon=lucide:cablepoint "Scope creep" x=0.9 y=0.58point "Licence audit" x=0.4 y=0.2point "Office move delay" x=0.64 y=0.28point "Minor browser bugs" x=0.84 y=0.12Horizontal 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 covers the converter in full. Mermaid numbers its zones counter-clockwise from the top right, and the converter maps them to the four positions.
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: 10The converter reports the style it dropped (M200) and the tone it took from the class (M207):
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.6point "Campaign B" x=0.45 y=0.23point "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 | The flow, sequence and schema languages, and the rules every kind shares |
| Examples to copy | Finished diagrams with the prompt that gets an agent to write each one |
| Migrating from Mermaid | Convert existing Mermaid diagrams, and what is dropped |
| Gantt charts | A plan drawn as tasks along a calendar |
| Mind maps | A central idea and the branches that grow from it |
| Timelines | Events along a time axis, when the order matters more than the grouping |
| Language reference | Every kind, node type, option and diagnostic |
| Diagram kinds | The kinds Plotwork draws and the header of each |