{"content":"# aux4/chart\n\nTurn data into beautiful chart images from the command line. Give it JSON, get back a polished PNG or SVG — bar, line, area, pie, doughnut, scatter, and radar charts, styled with a clean default theme so they look good out of the box.\n\nCharts are rendered entirely offline and self-contained: no browser, no headless Chrome, no native modules, and no network access. The same install works on macOS, Linux, and Windows.\n\n## Installation\n\n``bash\naux4 aux4 pkger install aux4/chart\n`\n\n## System Dependencies\n\nThis package runs on Node.js. If it is not already available, the installer can provision it:\n\n- [brew](/r/public/packages/aux4/system-installer-brew)\n- [linux](/r/public/packages/aux4/system-installer-linux)\n\n## Quick Start\n\nThe headline use case is charting **records** — a JSON array of row objects, exactly what aux4 db ... execute emits — straight from a pipe:\n\n`bash\naux4 db mydb execute --query \"SELECT month, revenue, cost FROM sales\" | aux4 chart bar --x month --y revenue,cost --output sales.png\n`\n\n`text\nSaved PNG chart to sales.png (800x600)\n`\n\nThe same works with inline --data:\n\n`bash\naux4 chart bar --data '[{\"month\":\"Jan\",\"revenue\":12000,\"cost\":8000},{\"month\":\"Feb\",\"revenue\":15000,\"cost\":9000}]' --x month --y revenue,cost --output sales.png\n`\n\n## Commands\n\nOne command per chart type. All commands share the same flags and the same data schema.\n\n| Command | Chart |\n|---------|-------|\n| aux4 chart bar | Vertical bar chart |\n| aux4 chart line | Line chart |\n| aux4 chart area | Filled area chart |\n| aux4 chart pie | Pie chart |\n| aux4 chart doughnut | Doughnut (pie with a hollow center) |\n| aux4 chart scatter | Scatter plot of [x, y] points |\n| aux4 chart radar | Radar / spider chart |\n| aux4 chart generate | Render any type chosen dynamically with --type |\n\nThe per-type commands are the everyday interface. [generate](#generate-dynamic-type) is for scripting when the type is a variable.\n\n## Options\n\nEvery command accepts the same flags:\n\n- --data — Input data as JSON (see [Data](#data)). Required, from this flag **or** from standard input. When JSON is piped on stdin, it takes precedence over --data.\n- --x — Records mode: the category/label column (x-axis, or pie slice labels). Auto-inferred when omitted.\n- --y — Records mode: value column(s), comma-separated. Each column becomes a series (wide format). Auto-inferred (numeric columns) when omitted.\n- --series — Records mode: optional pivot column for long/tidy data. Distinct values in this column become series; requires a single --y measure column. Not used by pie or radar.\n- --output — Where to send the chart. A **file path** (e.g. chart.png) saves it, with the extension deciding the format (.png or .svg). A literal **--output=-** writes raw bytes to standard output for piping/redirecting. **Omitting** --output previews the chart inline in supported terminals (Ghostty, Kitty, iTerm2). See [Terminal Preview](#terminal-preview-the-default) and [Piping / Redirecting the Image](#piping--redirecting-the-image).\n- --format — Explicit format override, png or svg. Defaults to the --output extension, or png otherwise. Inline previews are always PNG.\n- --title — Title drawn at the top of the chart.\n- --width — Width in pixels (default: 800).\n- --height — Height in pixels (default: 600).\n- --theme — Visual theme, light (default) or dark.\n- --colors — Color override: name-maps and/or a positional palette, mixable in one value. See [Colors](#colors).\n\n## Data\n\n--data (or stdin) accepts three shapes; the type is detected automatically.\n\n### 1. Records array (the primary shape)\n\nA JSON array of row objects — the tabular output of aux4 db ... execute and most APIs. Columns are mapped to chart dimensions with --x, --y, and --series.\n\n`json\n[\n { \"month\": \"Jan\", \"revenue\": 12000, \"cost\": 8000 },\n { \"month\": \"Feb\", \"revenue\": 15000, \"cost\": 9000 },\n { \"month\": \"Mar\", \"revenue\": 18000, \"cost\": 11000 }\n]\n`\n\n**Wide format** — one column per series. --x is the category column, --y lists the value columns (comma-separated); each becomes a series:\n\n`bash\naux4 db mydb execute --query \"SELECT month, revenue, cost FROM sales\" | aux4 chart bar --x month --y revenue,cost --output sales.png\n`\n\n**Long / tidy format** — --series pivots a column into series (requires a single --y measure). Distinct values of the pivot column become the series:\n\n`bash\necho '[{\"month\":\"Jan\",\"product\":\"A\",\"sales\":10},{\"month\":\"Jan\",\"product\":\"B\",\"sales\":20},{\"month\":\"Feb\",\"product\":\"A\",\"sales\":15},{\"month\":\"Feb\",\"product\":\"B\",\"sales\":25}]' | aux4 chart bar --x month --series product --y sales --output sales.png\n`\n\n**Auto-inference** — with no --x/--y the columns are inferred: the x-axis is the first non-numeric column (or the first column if all are numeric), and the series are the remaining numeric columns. So this just works:\n\n`bash\necho '[{\"month\":\"Jan\",\"revenue\":12000,\"cost\":8000},{\"month\":\"Feb\",\"revenue\":15000,\"cost\":9000}]' | aux4 chart bar --output sales.png\n`\n\nHow each chart type maps records:\n\n- **bar / line / area** — categories from --x; series from the --y columns (wide) or the --series pivot (long).\n- **pie / doughnut** — each row is a slice: label from --x, value from a single --y. --series is not applicable.\n- **scatter** — --x is the numeric x column, each --y column is a series of [x, y] points; --series may group points into series.\n- **radar** — the --y columns are the axes (metrics) and each row is a series named by its --x value.\n\n### 2. Explicit schema (full manual control)\n\nA JSON object with an optional title, a categories array, and a series array — for when you want to control everything by hand:\n\n`json\n{\n \"title\": \"Monthly Sales\",\n \"categories\": [\"Jan\", \"Feb\", \"Mar\"],\n \"series\": [\n { \"name\": \"2024\", \"data\": [120, 200, 150] },\n { \"name\": \"2025\", \"data\": [180, 230, 210] }\n ]\n}\n`\n\n- **bar / line / area** — categories label the x-axis, each series[].data is a row of numbers.\n- **pie / doughnut** — slices as data: [{ \"name\", \"value\" }], as series[0].data with the same shape, or categories paired with one series' data.\n- **scatter** — each series[].data is an array of [x, y] pairs.\n- **radar** — indicators (or categories) name each axis; each series[].data is one value per axis. An axis may be an object { \"name\", \"max\" } to fix its scale.\n\n`bash\naux4 chart radar --data '{\"indicators\":[\"Speed\",\"Power\",\"Range\",\"Defense\",\"Agility\"],\"series\":[{\"name\":\"Model X\",\"data\":[80,90,70,85,60]},{\"name\":\"Model Y\",\"data\":[70,60,90,75,95]}]}' --title \"Comparison\" --output radar.png\n`\n\n### 3. Simple array\n\nA bare array of numbers becomes a single auto-labeled series — handy for a quick sketch:\n\n`bash\naux4 chart bar --data '[5, 10, 3, 8]' --output quick.png\n`\n\n(A bare array of [x, y] pairs is also accepted as a single scatter series.)\n\n## Colors\n\nBy default charts use a clean built-in categorical palette (Tableau 10). Override it with --colors — colors no longer live in the data. --colors takes a comma-separated value that mixes two kinds of entry:\n\n- **name=color** — force a specific part **by name** (e.g. Chrome=#4285F4, revenue=#DB4437). Name matching is case-insensitive and whitespace is trimmed.\n- **bare color** — a positional palette applied in order to the parts that have **no** name match.\n\nColors apply to the chart's \"parts\" dimension:\n\n- **pie / doughnut, and any single-series bar / line / area / scatter** — the parts are the **categories**. Category names are matched against the map; the rest take the palette (then the default).\n- **multi-series charts** — the parts are the **series**. Series names are matched; the rest take the palette (then the default).\n\nAccepted color forms: hex (#rgb, #rrggbb, #rrggbbaa), rgb()/rgba()/hsl()/hsla(), and CSS color names. An invalid color is ignored (it falls back) rather than failing the render.\n\n**Color a pie by category name:**\n\n`bash\necho '[{\"browser\":\"Chrome\",\"share\":63},{\"browser\":\"Safari\",\"share\":19},{\"browser\":\"Edge\",\"share\":12}]' | aux4 chart pie --x browser --y share --colors \"Chrome=#4285F4,Safari=#FF6B6B,Edge=#0F9D58\" --output browsers.png\n`\n\n**Color a bar chart's series by name:**\n\n`bash\naux4 chart bar --data '[{\"month\":\"Jan\",\"revenue\":12000,\"cost\":8000},{\"month\":\"Feb\",\"revenue\":15000,\"cost\":9000}]' --x month --y revenue,cost --colors \"revenue=#4285F4,cost=#DB4437\" --output sales.png\n`\n\n**Mix a name-map with a positional palette** — revenue is forced blue, every other series takes the grey palette in order:\n\n`bash\naux4 chart bar --data '[{\"month\":\"Jan\",\"revenue\":100,\"cost\":80,\"tax\":20}]' --x month --y revenue,cost,tax --colors \"revenue=#4285F4,#cccccc,#999999\" --output sales.png\n`\n\n--theme light|dark is independent — it controls the background, text, and axis colors only, never the categorical series/slice colors.\n\n## Saving to a File\n\nGive --output a path ending in .png or .svg. A short confirmation with the path and dimensions is printed to standard error, so it never pollutes piped output:\n\n`bash\naux4 chart bar --data '[5,10,3,8]' --output quick.svg\n`\n\n`text\nSaved SVG chart to quick.svg (800x600)\n`\n\nForce a format regardless of the extension with --format:\n\n`bash\naux4 chart bar --data '[5,10,3,8]' --output quick.dat --format png\n`\n\n## Terminal Preview (the default)\n\nWhen you **omit** --output, the chart is previewed inline in your terminal as a PNG. The output mode is chosen from the terminal environment (TERM, TERM_PROGRAM, LC_TERMINAL, KITTY_WINDOW_ID) — it does **not** depend on whether standard output is a TTY, so it works even though aux4 runs the command behind a pipe. Supported terminals:\n\n- **iTerm2** — rendered via the iTerm2 inline image protocol (detected from TERM_PROGRAM=iTerm.app or LC_TERMINAL=iTerm2).\n- **Kitty** and **Ghostty** — rendered via the Kitty graphics protocol (detected from TERM containing kitty or ghostty, TERM_PROGRAM=ghostty, or KITTY_WINDOW_ID being set).\n\n`bash\naux4 chart bar --data '{\"categories\":[\"A\",\"B\",\"C\"],\"series\":[{\"name\":\"n\",\"data\":[3,7,4]}]}'\n`\n\nIf the terminal is **not** recognized as supporting inline images, the chart is **not** written to the terminal (raw image bytes are never dumped into a terminal). Instead a hint is printed to standard error and the command exits non-zero:\n\n`text\nchart: can't preview inline in this terminal (TERM=dumb). Use --output <file.png> to save, or --output - to pipe raw bytes.\n`\n\n### Forcing an inline protocol\n\nSet AUX4_CHART_FORCE_INLINE=kitty or AUX4_CHART_FORCE_INLINE=iterm2 to force the given inline protocol regardless of TERM. This is mainly useful for testing and for capturing the escape sequence to inspect it:\n\n`bash\nAUX4_CHART_FORCE_INLINE=kitty aux4 chart bar --data '[1,2,3]' > kitty.out\n`\n\n## Piping / Redirecting the Image\n\nTo send the raw image bytes to standard output — for piping to another tool or redirecting to a file — use --output=- (a literal dash). Nothing but the image bytes is written to standard output:\n\n`bash\naux4 chart bar --data '[5,10,3,8]' --output=- > chart.png\naux4 chart pie --data '[{\"name\":\"A\",\"value\":30},{\"name\":\"B\",\"value\":70}]' --output=- --format svg > chart.svg\n`\n\n> **Note:** use the --output=- form (with =). aux4's argument parser treats a space-separated bare - (as in --output -) as a boolean flag, so it does not reach the command as a value.\n\n## generate (dynamic type)\n\ngenerate renders any chart type chosen at runtime with --type, instead of a fixed subcommand. It is a thin dispatcher: aux4 chart generate --type bar ... routes through the exact same code path as aux4 chart bar ... and produces identical output. It shares **all** the flags above (--data, --x, --y, --series, --output, --format, --title, --width, --height, --theme, --colors).\n\n`bash\nTYPE=bar\naux4 chart generate --type \"$TYPE\" --data '[{\"month\":\"Jan\",\"revenue\":12000},{\"month\":\"Feb\",\"revenue\":15000}]' --x month --y revenue --output sales.png\n`\n\nValid types are bar, line, area, pie, doughnut, scatter, and radar. An invalid or missing --type` fails with a clear message listing the valid types and exits non-zero.\n\n## License\n\nThis package is licensed under the Apache License 2.0.\n"}