Nodes/ꘇ Genereti/ꘇ dat.totop
ComfyUI Node

ꘇ dat.totop

A numeric table as a grayscale image

By languel·Created about a month ago·Updated 3 days ago· 1
ꘇ dat.totop
  • input
  • image
◄headerfalse►

ꘇ dat.totop maps a table to pixels: columns run along x, rows down y, each numeric cell becomes a grayscale value, and the result is an IMAGE you can preview, save, or push into the pack's texture operators. Rows of data become rows of a picture. That's the whole node.

What it is

In the TouchDesigner mental model, DAT is the text-and-tables world and TOP is pixels; conversions between them are how you go from "the numbers I authored" to "something I can see and composite". This is the DAT→TOP direction, and unusually for a conversion node it's the one that feels finished: there's a single boolean parameter, a documented clamp, and a documented size limit, and no rate control because a table isn't a live stream. Change a cell and the image changes.

Practical uses: turning a hand-authored CSV of values into a texture map for a displacement or a mask, eyeballing a dataset (a row per prompt variant, a column per score) without leaving the graph, and generating small image assets from numeric tables that you'd otherwise need Python for.

How it works

The table's rows come in as strings. Each cell is parsed as a float; anything that fails to parse stays zero rather than raising - including empty cells and headers, so a stray text label doesn't blow up the conversion. Results are clamped to 0..1 and NaN/inf are scrubbed before the matrix is turned into an image, which is then repeated across R, G and B with an opaque alpha, giving you a single-frame grayscale IMAGE.

Two limits are hard-coded and worth knowing before you build a workflow around it. The maximum output is 512×512: the output array is at most 512 rows tall and 512 columns wide, and anything past that is dropped, not scaled, so overflow quietly disappears off the right/bottom edge. And the header checkbox is real arithmetic, not decoration - with header on, the first row is skipped before the matrix is built, so a CSV whose first row is column names doesn't become a stripe of black pixels.

The inputs and outputs that matter

  • input - the GENERETI_DAT table. Anything in the family produces one: ꘇ dat.table from CSV text, ꘇ dat.json, ꘇ dat.text, ꘇ chop.todat from a signal, or ꘇ top.todat from an image.
  • header - BOOLEAN, default false. Turn it on to skip the first row. Off by default because most programmatic sources (ꘇ chop.todat, ꘇ dat.json) don't include one.
  • image out - one RGB frame, grayscale content, opaque alpha, clamped 0..1, at most 512×512. Feed it to a preview, a Save node, or any TOP operator in the pack.

That's the entire schema. No width or layout choice, unlike ꘇ chop.totop - the table's own shape decides the image's shape.

Install

Everything here ships in the genereti pack. Manager → search genereti (title "ꘇ Genereti") → install → restart ComfyUI → hard-refresh the browser tab. Manual:

cd ComfyUI
git clone https://github.com/languel/genereti.git custom_nodes/genereti
./.venv/bin/python -m pip install -r custom_nodes/genereti/requirements.txt

Use your ComfyUI's Python for that pip step. The requirement list is comfyui-frontend-package>=1.53.6, one line - no models, no extra server, nothing that can conflict with your existing packs. The ꘇ-OpenTouch-Operators-and-Lessons workflow under Workflows → Genereti demonstrates the table family and the conversions between families.

Common issues

Your division is at the wrong scale. A two-column table becomes a two-pixel-wide image. There's no stretching - the mapping is one cell to one pixel - so build the table at a size that reads, or put a texture operator after it.

The header row is a black stripe. Set header to true when the first row is labels. Conversely, if your data has no header and you leave it on, you lose a real row of data.

Text cells become zero. Non-numeric content is treated as 0, not as an error, so a table with mixed content converts to a mostly-black image with no complaint.

Values outside 0..1 are clipped. Negative numbers and anything above 1 saturate. Normalize upstream - ꘇ dat.expression is the natural place, since it evaluates per cell.

Large tables lose their edges. 512×512 is a truncation limit, and there's no warning when you cross it.

It's an alpha pack. The README says it plainly: super alpha, early classroom testing, expect bugs and changing interfaces. Back up workflows before updating.

CategoryGenereti / DAT

Inputs (2)

NameTypeDefaultDescription
inputGENERETI_DAT—
headerBOOLEANfalse—

Outputs (1)

NameTypeDescription
imageIMAGE—