XYZ Grid Stitch
Turning Nine Images Into a Labeled Grid
- images
- grid_image
This is the node you've been working toward. XYZ Grid Stitch takes all the images your sweep collected, arranges them into a grid, and paints labels on top - the A1111-style comparison sheet that makes parameter testing actually legible instead of a wall of similar-looking images. Every other node in this pack feeds this one.
The mechanism is pure PIL. It parses your label lists, assumes every incoming image is the same size, and pastes them into a canvas with axis labels drawn in the margins. Nothing clever, which is exactly what you want from the final step.
The is_complete gate - don't skip this
The single most important connection in the pack. Stitch takes an optional is_complete input that defaults to true, and that default will bite you. If you forget to wire it, the node stitches on every run - your "grid" is a 1×1 image of whatever you just made, over and over.
Connect the Auto Collector's is_complete output to Stitch's is_complete input, and the behavior flips: while the sweep is running, Stitch sees false and returns a tiny black placeholder instead of a real grid. The "Skipping - waiting for all images to be collected" message in the console is normal, not an error. Only on the final run does is_complete go true and the real grid materialize.
The inputs that matter
images- the batch from the Auto Collector.x_labels,y_labels,z_labels- comma-separated labels. These are the text that ends up on the grid, so make them short enough to actually fit. Leavez_labelsempty for a 2D grid.label_height(default 120) andlabel_width(default 150) - how much canvas the top and left label areas take. Cut-off labels mean bump these up.gap_size(default 4) - spacing between cells.layout_style- the interesting one, with two choices:- A1111 Style (X blocks) - each X value gets its own block containing a Y×Z sub-grid. This is the classic layout and the default.
- Z Horizontal - each Z value gets a full 2D grid, and the grids sit side by side.
Output is a single grid_image tensor, ready for a Save Image or Preview node.
Where people get burned
Mixed image sizes are the classic trap. The node takes the dimensions of the first image and assumes the rest match - generate at a fixed resolution for the whole sweep or your grid comes out mangled. If labels look tiny, that's usually the font fallback: it tries arial.ttf and falls back to PIL's tiny default font on systems without arial installed (a common Linux thing), which is when you crank label_height/label_width well past the defaults. And again, no is_complete wire means instant broken output - it's the first thing to check when you're getting 1×1 images.
Installing
One pack, one install. ComfyUI Manager → search "XYZ Grid", or:
cd ComfyUI/custom_nodes/
git clone https://github.com/psdwizzard/Comfyui-XYZ-stitch.git
Restart ComfyUI. No extra dependencies - torch, PIL, and numpy, all already in ComfyUI.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| x_labels | STRING | red, blue, green | Comma-separated labels for X axis (columns) |
| y_labels | STRING | 1, 2, 3 | Comma-separated labels for Y axis (rows) |
| z_labels | STRING | Comma-separated labels for Z axis (separate grids) | |
| label_height | INT | 1200–300 | Height in pixels for label area (top) - increased for larger fonts |
| label_width | INT | 1500–300 | Width in pixels for Y label area (left) - increased for larger fonts |
| gap_size | INT | 40–50 | Gap size between images in pixels |
| layout_style | COMBO | A1111 Style (X blocks) | A1111: Each X value gets a block with Y×Z grid inside | Z Horizontal: Z values create grids side-by-side |
| is_completeopt | BOOLEAN | true | Only stitch when True (connect from Auto Collector) |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| grid_image | IMAGE | — |