rosswang35 downloadsDraw labelled N x M quadrant charts with free-floating text, stored as plain-YAML .mdx files you can also edit by hand or with a script.
Draw labelled quadrant charts in Obsidian, with free-floating text placed anywhere on the plot.
Charts live in .mdx files as plain YAML frontmatter, so they stay readable, hand-editable, and
diff-friendly.
.mdx, so it travels with
the chart and can be generated by a script..mdx file.Create a chart — command palette → Create a blank chart. Pick a name and it opens straight into the editor.
Start from an example — command palette → Create from a worked example → SWOT or talent nine-box. You get the cells, colours, labels and an explanatory body to edit.
Add text — double-click anywhere on the plot, or use the Add label button. With nothing pointed at, a new label lands in the middle of the cell you last clicked. A label wider than the configured share of the plot (80% by default, see Maximum label width in the settings) wraps onto another line.
Move text — drag it.
Edit text — double-click it, or select it and use the Label button → Edit text…. Clearing the text deletes the label.
Delete text — right-click it, or select it and use the Label button → Delete label.
Select a label or a cell — click it. A click on a label selects the label, never the cell underneath; a click on empty space selects the cell. Both draw a dashed box.
Style a label — select it, then Label → background colour, Draw a box around it, or a text size. Default clears the size override so the label follows the chart again.
Reach a label under another — click the same spot repeatedly to step down the stack, or use Send to back / Bring to front. Order is stored in the file, so it survives a reload.
Name a cell — click the cell, then the Cell button.
Change the grid — the Grid N×M button. Columns and rows are independent, and the button always shows the current size. You can also drag a dashed split line on the canvas.
Name the axes / set the range — Axes button, or click the X or Y caption on the canvas.
Add an axis note — Axes → Note under the X axis… / Note beside the Y axis…. The X note is drawn below its caption and the Y note up the left gutter, each in smaller muted text; writing one reserves room for it, and clearing it gives the room back. A cell note says what is in a cell — an axis note says what the whole scale means, which is the one thing a quadrant chart cannot leave implicit.
Export an image — the Export button, or the command palette → Export as an image.
| Option | Notes |
|---|---|
| JPG | Smallest file. Always opaque — JPEG has no alpha channel. |
| PNG | Lossless, sharper text. |
| PNG, transparent | For slides and documents that supply their own background. |
| SVG | Vector — scales to any size without blurring, and diffable in git. |
| SVG, transparent | Same, with no background rectangle. |
The file is written beside the .mdx and never overwrites an existing one.
Everything you do is written straight to the file, so you can also just edit the YAML.
A label is a label, not a paragraph. Free text wraps, but only at the configured width — see Maximum label width in the settings, 80% of the plot area by default. A 91-character Chinese label at the default 14px needs 1180px, so it wraps onto two lines. Push past a few hundred characters and you get a tall stack of lines rather than a readable block.
Two things follow:
One halo colour per line. The outline that keeps a label readable where it crosses a grid line is coloured to match the cell that line sits in, so it is invisible against its own background. A label that overhangs a differently tinted cell still shows the ring on the overhanging part.
No multi-select. One label at a time — no marquee, no group operations.
| Shortcut | Action |
|---|---|
| Ctrl/Cmd+Z | Undo the last change to this chart |
| Ctrl/Cmd+Shift+Z | Redo |
| Ctrl+Y | Redo (Windows convention) |
A new change after an undo discards the redo branch, so redo can only replay something you have not since replaced.
.mdx formatA chart is a YAML frontmatter block. The body after it is yours and is never modified.
---
quadrant-chart: 1
title: Q1 Priorities
x:
label: Impact
min: 0
max: 10
y:
label: Urgency
min: 0
max: 10
grid:
columns: 2
rows: 2
cells:
- col: 1
row: 1
label: Do now
color: "#d93025"
note: Anything blocking a release
items:
- id: a1
text: Rework the sync engine
x: 8.2
y: 9
background: "#fdd663" # optional plate behind the text
box: true # optional outline around it
---
Notes go here. The plugin never rewrites anything below the frontmatter.
Coordinates are stored in data space — the axis min/max range — not in pixels. Resizing the
pane or changing the range never rewrites your numbers, which is what lets a chart saved on a phone
land in the same logical spot on a desktop.
quadrant-chart: 1 is what marks the file as a chart. Without it, a .mdx file is left alone.
A damaged file still opens: missing fields fall back to defaults, a reversed axis range is repaired, and out-of-range cells are dropped. The point is that you can always see the file to fix it.
One trap worth writing down, because it is not visible from the format:
row 0is the bottom band. Rows are counted along Y from the minimum, and columns along X from the minimum. Get it backwards and a SWOT silently swaps "helpful" with "harmful" — the chart still renders, it is just wrong. The same applies to a nine-box, where it inverts high and low potential.
Because a chart is plain YAML, you do not need the plugin to create one. Anything that can write YAML can produce a chart; the plugin only has to render it. That includes an LLM, a cron job, a spreadsheet export, or another plugin.
A reference implementation ships with this workspace:
python3 /home/wang/wk/Script/mdx_chart.py --help
import sys; sys.path.insert(0, "/home/wang/wk/Script")
from mdx_chart import Chart, Axis
chart = Chart(
title="SWOT",
x=Axis("Internal ——— External", -5, 5),
y=Axis("Harmful ——— Helpful", -5, 5),
columns=2, rows=2,
)
chart.add_cell(0, 1, "Strengths", color="green", note="Internal · helpful")
chart.add_cell(0, 0, "Weaknesses", color="red", note="Internal · harmful")
chart.add_cell(1, 1, "Opportunities", color="blue", note="External · helpful")
chart.add_cell(1, 0, "Threats", color="orange", note="External · harmful")
chart.add_item("Plain-text format — git-diffable", x=-3.4, y=4.2, item_id="s1")
chart.save("SWOT.mdx", body="# Notes\n\nThis body is never rewritten.\n")
The same operations from the command line:
python3 Script/mdx_chart.py create --path Q1.mdx --title "Q1 Priorities" --columns 2 --rows 2
python3 Script/mdx_chart.py set-cell --path Q1.mdx --col 1 --row 1 --label "Do now" --color red
python3 Script/mdx_chart.py add-item --path Q1.mdx --text "Rework sync engine" --x 8.2 --y 9
python3 Script/mdx_chart.py show --path Q1.mdx # JSON, for an agent to read
It edits in place: load() returns the chart and the body, and save() rewrites only the
frontmatter, so notes written under a chart survive. It refuses to overwrite on create without
--force, and refuses to touch a file that is not a chart at all.
Full reference — docs/API.md. It is written to be read by an agent: the field
table, the complete API surface, the CLI, worked recipes for SWOT and the talent nine-box, the
colour palette, a pre-write checklist, and the processFrontMatter warning below.
Worked examples, both generated through that API:
/home/wang/wk/wk/SWOT-插件价值.mdx/home/wang/wk/wk/人才九宫格-示例.mdx.mdxUse app.vault.process(file, fn) for the atomic read-modify-write.
Do not use
fileManager.processFrontMatteron a.mdxfile. Measured on a live vault, it resolves successfully and writes nothing — the file stays byte-identical. It is a silent no-op, which is why it cost several rounds to track down. Its callback also takes(frontmatter) => void, so a returned object is discarded.
.mdx is also React's component-file suffix. There is no conflict inside Obsidian, which has no MDX
pipeline of its own, but be aware of it if a vault ever gains a real MDX toolchain.
npm install
npm run build # typecheck + production bundle -> main.js
npm test # 377 tests: format, geometry, hit-testing, undo, image export, the
# save path, and interoperability with Script/mdx_chart.py
To build straight into a vault's plugin folder:
OUTDIR=~/vault/.obsidian/plugins/quadrant-chart npm run build