terminal_graph/multiplot_graphs

Responsive, ANSI-aware layouts for combining rendered terminal graphs.

The classic multiplot overload accepts a fixed integer column count. MultiplotOptions adds CSS-grid-like auto fitting, shared track widths, horizontal and vertical alignment, and optional expansion across the available terminal width:

var layout = initMultiplotOptions()
layout.columns = autoColumns
layout.availableWidth = 100 # Zero detects the terminal width.
layout.minimumCellWidth = 32
layout.horizontalAlignment = mhaCenter
layout.breakpoints = @[
  multiplotBreakpoint(0, 1),
  multiplotBreakpoint(80, 2),
  multiplotBreakpoint(120, 3)
]
echo multiplot(renderedPlots, layout)

Already-rendered strings can reflow but cannot change their own dimensions. Use multiplotResponsive with MultiplotRenderer callbacks when each graph should be rendered at the width assigned to its grid track. Importing this module never queries or modifies the terminal; width detection occurs only when a responsive layout is rendered with availableWidth = 0.

Types

MultiplotBreakpoint = object
  minimumWidth*: int
  columns*: int
A minimum available width and the column count selected at that width.
MultiplotColumnKind = enum
  mckAuto, mckFixed
Chooses whether the grid auto-fits or targets an explicit column count.
MultiplotColumns = object
  case kind*: MultiplotColumnKind
  of mckAuto:
    nil
  of mckFixed:
    count*: int
Typed column selection used by MultiplotOptions.
MultiplotHorizontalAlignment = enum
  mhaLeft, mhaCenter, mhaRight
Positions content within the shared width of its grid column.
MultiplotOptions = object
  columns*: MultiplotColumns
  availableWidth*: int
  minimumCellWidth*: int
  horizontalGap*: int
  verticalGap*: int
  horizontalAlignment*: MultiplotHorizontalAlignment
  verticalAlignment*: MultiplotVerticalAlignment
  expandColumns*: bool
  constrainToAvailableWidth*: bool ## Prevents terminal wrapping by reflowing tracks and clipping an
                                   ## individually over-wide, already-rendered line. The concise
                                   ## ``multiplot`` overload disables this for deterministic legacy output.
  breakpoints*: seq[MultiplotBreakpoint]

Complete responsive-grid configuration.

availableWidth = 0 detects the current terminal width at render time. expandColumns distributes unused width across column tracks, while constrainToAvailableWidth prevents physical line wrapping. Optional breakpoints override content-based auto-fit in autoColumns mode; the matching breakpoint with the greatest minimum width wins.

MultiplotRenderer = proc (width: int): string {.closure.}
Deferred graph renderer receiving its complete grid-cell width budget.
MultiplotVerticalAlignment = enum
  mvaTop, mvaMiddle, mvaBottom
Positions shorter plots within the shared height of their grid row.

Consts

autoColumns = (kind: mckAuto, count: 0)
Selects the largest column count that fits availableWidth.

Procs

proc fixedColumns(count: int): MultiplotColumns {....raises: [ValueError],
    tags: [], forbids: [].}

Requests an explicit positive number of grid columns.

Constrained responsive layouts still reduce this count when necessary to prevent physical terminal wrapping.

proc initMultiplotOptions(): MultiplotOptions {....raises: [], tags: [],
    forbids: [].}
Returns a responsive, auto-fitting layout configuration.
proc multiplot(plots: openArray[string]; columns = 0; horizontalGap = 3;
               verticalGap = 1): string {....raises: [ValueError],
    tags: [ReadEnvEffect], forbids: [].}

Arranges already-rendered plots using a deterministic column count.

columns = 0 places every plot side by side. Logical columns share a width across grid rows. For responsive behavior use MultiplotOptions.

proc multiplot(plots: openArray[string]; options: MultiplotOptions): string {.
    ...raises: [ValueError], tags: [ReadEnvEffect], forbids: [].}

Arranges rendered plots in an aligned, optionally responsive grid.

ANSI sequences are preserved but ignored for measurement. Auto columns reflow the plots without resizing them; use multiplotResponsive when the graph renderers should receive and honor a width budget.

proc multiplotBreakpoint(minimumWidth, columns: int): MultiplotBreakpoint {.
    ...raises: [ValueError], tags: [], forbids: [].}
Creates a CSS-like responsive breakpoint.
proc multiplotResponsive(renderers: openArray[MultiplotRenderer];
                         options = initMultiplotOptions()): string {.
    ...raises: [ValueError, Exception], tags: [ReadEnvEffect, RootEffect],
    forbids: [].}

Assigns grid-track widths before rendering and returns the combined grid.

The callback width is a complete cell budget. A renderer that emits wider content is clipped unless constrainToAvailableWidth is disabled. Auto mode recalculates its column count on every call, making this overload suitable for terminal-resize-aware streaming dashboards.