D2 XY Annotation
Write your own grid headers when the plot won't
- x / y_annotation
D2 XY Annotation is a tiny node with one job: build the header data that D2 XY Grid Image draws across your comparison grid. It takes a title and a list, and turns them into an annotation object. When you're using D2 XY Plot or D2 XY Plot Easy, the plots generate their own annotations and you never touch this node. You reach for it in the edge cases - manual plots, custom grids, or when you want headers that say something the plot's axis values don't.
How it works
You give it a title and a list (multiline, one value per line). It packs them into an annotation - essentially "here's the axis label, and here are the N values that row/column represents" - and outputs x / y_annotation, the same custom socket type that D2 XY Plot and D2 XY Grid Image use. Wire that into the x_annotation or y_annotation input of D2 XY Grid Image and your grid gets a proper labeled axis.
The catch is that annotations are only as good as the list you feed them. D2 XY Grid Image computes the grid's dimensions from the annotations - it expects the number of entries to match the number of cells in that row/column. So if your plot produces 4 columns but you hand the grid an annotation with 5 values, the layout goes sideways. When the plot is driving, it computes these itself and stays in sync automatically; when you hand-wire an annotation, you're taking over that responsibility.
Inputs
title- the axis header text (e.g. "CFG scale" or "Hair color").list- the values, one per line, matching the grid's rows or columns.
One output: x / y_annotation.
When you'd actually use it
Three scenarios, honestly. First, when you're building a plot without the D2 XY Plot nodes - say you're running your own loop or batching images manually, and you want the grid to still carry labels. Second, when the auto-generated header would be misleading: the plot labels each axis with its type, but if you're comparing "which prompt reads best," a custom title like "Prompt variant" beats "STRING." Third, for partial or curated grids where you're showing a subset of a larger run and the titles need to reflect what's actually shown.
It also composes with D2 XY Prompt SR: build your replacement list there, feed the same values to this node as the annotation list, and the grid labels will match the prompt rows exactly - which is the difference between a readable grid and a mystery grid.
Installing
Part of D2 Nodes ComfyUI:
cd ComfyUI/custom_nodes
git clone https://github.com/da2el-ai/D2-nodes-ComfyUI
or search "D2 Nodes ComfyUI" in ComfyUI Manager. No models, no dependencies to speak of.
Real talk: if you're using D2 XY Plot Easy or D2 XY Plot, you probably never need this node - they hand annotations to the grid automatically. It exists for the people doing something the plots can't express, and when you're one of them, it's exactly the right tool. But if your grid comes out misaligned or unlabeled and you hand-wired an annotation, count your list entries first; that's the whole failure mode.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| title | STRING | — | |
| list | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| x / y_annotation | D2_TAnnotation | — |