Group
Start here
Section titled “Start here”Most grouping is one command: pick category columns with -g, map them to dimensions with -p, open the HTML.
vizb bar sales.csv -g region,product -p y,x -o sales.htmlPOST / on vizb serve. The API takes inlineinput, not a file path.
{ "input": "order_date,region,category,product,quantity,amount\n2024-01-01,Central,Hardware,Connector,16,2488.24\n2024-01-02,East,Tools,Gear,42,207.08\n2024-01-03,North,Mechanical,Sensor,20,3465.22\n2024-01-04,West,Electronics,Valve,24,7633.44\n2024-03-12,South,Industrial,Widget,31,5088.10\n2024-06-18,East,Electronics,Relay,12,2214.50\n2024-09-05,North,Hardware,Bolt,28,1724.27\n2024-12-20,West,Tools,Gadget,19,2938.82\n2025-02-08,Central,Mechanical,Valve,27,7350.26\n2025-04-14,South,Electronics,Widget,41,3278.77\n2025-07-22,East,Industrial,Connector,15,5093.42\n2025-10-03,North,Tools,Gear,33,4102.15\n2025-11-19,West,Hardware,Sensor,22,2890.40\n2025-12-28,South,Mechanical,Gadget,26,611.32\n", "parser": "csv", "grouping": { "columns": [ "region", "product" ], "pattern": "y,x" }, "charts": { "types": [ "bar" ] }, "output": { "format": "html" }}GitHub Action step. Same conversion as the CLI.
- uses: goptics/vizb@v0 with: file: sales.csv group: region,product group-pattern: y,x charts: bar output-html: sales.html| Goal | Jump to |
|---|---|
| Decide group vs select | Group vs Select |
| What n / x / y / z mean | Dimensions |
| Separators, brackets, regex, labels | Sections below on this page |
What is group
Section titled “What is group”Group turns each row into a point with up to four dimensions (Name, X, Y, Z — see Dimensions). That structure is what makes multi-axis charts possible.
It always works in two stages:
- Build a label for the row.
- For CSV/JSON, you pick columns with
--group. Vizb joins their per-row values using the same separators declared in--group-pattern. - For benchmarks, the benchmark name is the label already (e.g.
BenchmarkSort/1024/QuickSort).
- For CSV/JSON, you pick columns with
- Split the label into dimensions with
--group-pattern(separator-based) or--group-regex(named captures). This stage is identical for both inputs.
The two flows differ only in stage 1 — where the label comes from. The same pattern and regex syntax serves both.
Why group
Section titled “Why group”Without group, every row is an isolated bar or point. With it, vizb can:
- Separate charts by logical category (e.g. one chart per algorithm or region).
- Populate axes with meaningful values (e.g. input size on the X-axis).
- Create series for variants (e.g. different data distributions on the Y-axis).
| Without group | With group |
|---|---|
| Single flat chart with all rows | Multiple charts grouped by name |
| No axis structure | X-axis and Y-axis with meaningful categories |
| Hard to compare across dimensions | Easy side-by-side comparison |
Group CSV/JSON data
Section titled “Group CSV/JSON data”CSV and JSON rows have no benchmark name. You tell vizb which columns carry the structure. The --group / -g flag selects columns. The --group-pattern / -p flag assigns each column to a dimension. By default each column maps to one dimension (-p y,x). Use bracket slots [...] when a single column’s cell value encodes multiple dimensions (dates, slash paths, underscore IDs, etc.).
Matching separators
Section titled “Matching separators”For tabular data, -g and -p must use the same separators between column slots. If they disagree, vizb exits before parsing:
--group "<g>" and --group-pattern "<p>" separators do not match (expected "<from g>", got "<from p>")The expected side is derived from how -g declares column boundaries. The got side is what -p declares. Fix whichever flag is wrong so both use the same separator sequence.
--group style |
Matching -p |
Row label (example) | Mismatch would report |
|---|---|---|---|
Comma list (-g region,product,category) |
Commas (-p x,y,z) |
Asia,Widget,Electronics |
-p x/y/z → expected ", ,", got "/ /" |
Quoted string (-g "region product") |
Spaces (-p "y x") |
UAE Gadget |
— |
Single value (-g "region/product/category") |
Same separators (-p x/y/z) |
EU/Widget/Sports |
-p x,y/z → expected "/ /", got ", /" |
Structured (-g region,product/category) |
Same shape (-p y,x/z) |
Asia,Widget/Electronics |
— |
Comma-separated -g (the usual pflag form) requires comma-separated -p. For example, use -g region,product,category with -p x,y,z, not x/y/z. Every separator in -g must appear in -p at the same positions.
When -g and -p define a different number of slots (common with bracket patterns), vizb reports a separate dimension-count error:
--group and --group-pattern dimension count do not match: N column(s) in "<g>", M slot(s) in --group-pattern "<p>"Take this sales.csv:
| region | product | category | sales | latency |
|---|---|---|---|---|
| Asia | Widget | Electronics | 100 | 12 |
| UAE | Gadget | Home | 80 | 15 |
| EU | Gizmo | Sports | 60 | 11 |
vizb sales.csv --group region,product -p y,x -o sales.htmlFor the first row, vizb joins the selected columns into the label Asia,Widget, then the pattern y,x splits it: y → Asia (YAxis), x → Widget (XAxis).
Space-separated columns — pass one quoted -g value and use spaces in -p:
vizb sales.csv -g "region product" -p "y x" -o sales.htmlStructured grouping — mix separators inside -g (commas between pflag values, / or _ inside a value) to declare a hierarchy. -p must mirror the same shape:
vizb sales.csv -g region,product/category -p y,x/z -o sales.htmlvizb sales.csv -g "region/product/category" -p x/y/z -o sales.htmlBracket slots — split a column’s cell value
Section titled “Bracket slots — split a column’s cell value”When one column holds an encoded string (not separate columns), wrap the inner pattern in [...]. Each top-level slot lines up 1:1 with a -g column:
| Slot form | Meaning |
|---|---|
x, y, n, z |
Whole cell value → that dimension |
x{label} |
Whole cell → dimension, axis titled label (overrides column name) |
[inner] |
Split the cell value with inner separators → multiple dimensions |
n{year}-y{months} inside [...] |
Split value and set per-dimension axis titles |
Top-level separators between slots still match -g (commas for -g a,b, spaces for -g "a b"). Benchmarks do not use brackets. Keep flat -p n/x/y for bench.txt.
Bracket slots can attach {label} to each inner dimension — see Axis labels.
Date + category — split 2022-2-30 into year/month/day, keep category whole:
vizb sales.csv -g date,category -p "[x-y-n],z" -o sales.html| date | category | Pattern | Result |
|---|---|---|---|
2022-2-30 |
Widget |
[x-y-n] splits on -, z ← category |
x=2022, y=2, n=30, z=Widget |
More bracket-slot examples (ISO dates, slash paths, underscore IDs, mixed separators)
ISO dates (YYYY-MM-DD) — use a bracket slot when the date is one column. {year}, {months}, and {dates} only set axis titles. Splitting is driven by - between dimension tokens. The same prefix/middle/trailing skip rules from Separators apply inside brackets too — e.g. [n{year}-x{months}-] drops the day, [n{year}--x{dates}] skips the month.
vizb sales.csv -g date,category -p '[n{year}-y{months}-x{dates}],z' -o sales.html| date | Pattern | Result |
|---|---|---|
2024-01-01 |
[n{year}-y{months}-x{dates}] |
n=2024, y=01, x=01 |
Slash-encoded benchmark column — same layout as Go bench names, stored in CSV:
vizb results.csv -g benchmark -p "[n/x/y]" -o out.html| benchmark | Pattern | Result |
|---|---|---|
Sort/1024/QuickSort |
[n/x/y] |
n=Sort, x=1024, y=QuickSort |
Underscore-delimited ID:
vizb runs.csv -g id -p "[n_y_x]" -o out.html| id | Result |
|---|---|
lib_func_case |
n=lib, y=func, x=case |
Space-separated label in one column:
vizb data.csv -g "label region" -p "[x n y],z" -o out.html| label | region | Result |
|---|---|---|
alpha beta gamma |
EU |
x=alpha, n=beta, y=gamma, z=EU |
Prefix skip inside a bracket (leading / drops the first segment of the cell value):
vizb data.csv -g name -p "[/n/y]" -o out.html| name | Result |
|---|---|
BenchmarkTest/JSON/Marshal |
n=JSON, y=Marshal |
Mix value-split with whole columns — date parts + region on Z:
vizb sales.csv -g date,region -p "[n-y-x],z" -o sales.html| date | region | Result |
|---|---|---|
2022-2-30 |
Asia |
n=2022, y=2, x=30, z=Asia |
The columns you don’t select decide the chart values:
- Unselected numeric columns each become their own chart. Here
salesandlatencyeach become a separate chart (oneStatper column). - Non-numeric unselected columns are ignored. A
notestext column would simply be dropped. - No
--groupat all → dimensions stay empty. No rows are merged. Each row becomes one point, and every numeric column renders as its own chart. This is useful for a quick chart of a wide table.
Competitor columns — --col-axis / -A
Section titled “Competitor columns — --col-axis / -A”When several numeric columns are the same metric for different series (frameworks, libraries, versions), you usually want one chart, not one chart per column. --col-axis (short -A) places those column names onto a free group dimension (n, x, y, or z), like merge’s --tag-axis.
Example wide table:
load,default,chi,echo,gin,goframe,httpz100,3103.62,3103.73,3104.59,3103.72,3114.20,3105.101000,32423.67,32421.28,32413.72,32408.85,32411.78,32413.10# Frameworks on X, load levels as Y series — single chartvizb bar concurrency.csv -g load -p y -A x -o out.html
# Load on X, frameworks as Y series (classic grouped bar)vizb bar concurrency.csv -g load -p x -A y -o out.html| Rule | Behaviour |
|---|---|
| Requires group | Needs -g / -r / non-default -p (or auto-group). Without group: warn and skip |
| csv/json only | Other parsers: warn and skip |
| Free axis | Target must not already be used by -p (e.g. -p x -A x is fatal) |
z |
Requires both x and y group dimensions |
| Chart title | Expanded points omit stats[].type; the UI uses the dataset name (-n) as the chart title |
Aggregation
Section titled “Aggregation”When group is active (--group or auto-group), multiple rows can share the same (name, x, y, z) key. Vizb sums their values into a single point. A 200k-row export collapses into a few thousand chart points. You’ll see it in the CLI output when duplicates were merged:
🧮 Aggregating 50000 rows by columns: region, product, month (name: region, x: product, y: month)...✅ Aggregated into 1200 grouped data pointsIf every row already has a unique group key (e.g. auto-group picked a high-cardinality ID column), vizb still runs the sum step but nothing collapses — the closing line instead reports ✅ N grouped rows — all unique (no duplicates to sum).
See Tabular Data (CSV & JSON) for the full parser rules.
Group benchmarks
Section titled “Group benchmarks”Benchmark names already encode structure. A name like BenchmarkSort/1024/QuickSort carries the function, the input size, and the variant. There are no columns to pick. So --group-pattern / --group-regex do all the extraction. Set axis titles with {label} suffixes in -p (see Axis labels).
go test -bench . | vizb -p n/x/y -o output.html| Benchmark Name | Name | XAxis | YAxis |
|---|---|---|---|
BenchmarkSort/1024/QuickSort |
Sort | 1024 | QuickSort |
BenchmarkSort/2048/MergeSort |
Sort | 2048 | MergeSort |
Every metric the benchmark reports (time, memory, allocations, …) becomes its own chart automatically. You only group the name.
Pattern Syntax
Section titled “Pattern Syntax”The --group-pattern flag splits the label using the separators you declare between dimension tokens. It assigns each segment to a dimension. It applies to both flows — the benchmark name or the CSV/JSON label built from --group.
Separators
Section titled “Separators”Any single character works between dimension tokens. Vizb reads them from your -p string:
| Separator | Typical use |
|---|---|
/ |
Go/Rust/JS benchmark names (n/x/y) and slash-structured -g (region/product) |
_ |
Underscore-delimited bench names (n_y_x) and structured -g specs |
, |
Comma-separated --group lists (y,x with -g region,product) |
(space) |
Quoted --group specs ("y x" with -g "region product") |
#, ., etc. |
Any single character works when -g and -p agree (e.g. -g "a#b#c" -p "x#y#z") |
Three skip patterns drop segments without assigning them to a dimension:
| Pattern | Example | Effect |
|---|---|---|
| Leading separator | /n/y |
First value segment is unused (prefix skip) |
| Consecutive separators | n--x or x//y |
Middle segment is unused |
| Trailing separator | n-x- |
Last value segment is unused |
Each repeated separator character adds one more split point and one empty dimension slot. A single trailing - after the last token is enough to drop the final segment. You do not need ---.
Works in flat benchmark patterns and inside bracket slots (e.g. [n{year}-x{month}-] on a CSV date column).
Components
Section titled “Components”| Component | Shorthand | Meaning |
|---|---|---|
name |
n |
Chart group name |
xAxis |
x |
X-axis values |
yAxis |
y |
Y-axis series |
zAxis |
z |
Z-axis depth layer (3D, requires x + y) |
The default pattern is x — a single segment mapped to the X-axis.
Examples
Section titled “Examples”Slash-separated n/x/y:
vizb bench.txt --group-pattern "n/x/y" -o output.html| Label | Name | XAxis | YAxis |
|---|---|---|---|
BenchmarkSort/1024/QuickSort |
Sort | 1024 | QuickSort |
BenchmarkSort/2048/MergeSort |
Sort | 2048 | MergeSort |
BenchmarkSort/4096/QuickSort |
Sort | 4096 | QuickSort |
Underscore-separated n_y_x:
vizb bench.txt --group-pattern "n_y_x" -o output.html| Label | Name | YAxis | XAxis |
|---|---|---|---|
BenchmarkHash_SHA256_1KB |
Hash | SHA256 | 1KB |
BenchmarkHash_MD5_4KB |
Hash | MD5 | 4KB |
2D with n/y (no X-axis grouping):
vizb bench.txt --group-pattern "n/y" -o output.html| Label | Name | YAxis |
|---|---|---|
BenchmarkJSON/Marshal |
JSON | Marshal |
BenchmarkJSON/Unmarshal |
JSON | Unmarshal |
Prefix skip with /n/y (leading slash discards the first segment):
vizb bench.txt --group-pattern "/n/y" -o output.html| Label | Name | YAxis |
|---|---|---|
BenchmarkTest/JSON/Marshal |
JSON | Marshal |
BenchmarkTest/XML/Parse |
XML | Parse |
Middle skip with n//y (consecutive separators discard the middle segment):
vizb bench.txt --group-pattern "n//y" -o output.html| Label | Name | YAxis |
|---|---|---|
Sort/1024/QuickSort |
Sort | QuickSort |
Trailing skip with n-x- (trailing separator discards the last segment):
vizb bench.txt --group-pattern "n-x-" -o output.html| Label | Name | XAxis |
|---|---|---|
2024-01-01 |
2024 | 01 |
4D with n/x/y/z (renders a 3D chart):
vizb bench.txt --group-pattern "n/x/y/z" -o output.html| Label | Name | XAxis | YAxis | ZAxis |
|---|---|---|---|---|
BenchmarkSort/1024/QuickSort/warm |
Sort | 1024 | QuickSort | warm |
BenchmarkSort/2048/MergeSort/cold |
Sort | 2048 | MergeSort | cold |
Regex Syntax
Section titled “Regex Syntax”The --group-regex flag uses Go-style named capture groups. It runs on the label — a benchmark name, or the CSV/JSON label built from --group. Use it when the label does not follow a simple separator pattern. When set, regex takes precedence over --group-pattern.
Named Capture Groups
Section titled “Named Capture Groups”| Group Name | Shorthand | Dimension |
|---|---|---|
(?<name>...) |
(?<n>...) |
Chart group name |
(?<xAxis>...) |
(?<x>...) |
X-axis values |
(?<yAxis>...) |
(?<y>...) |
Y-axis series |
(?<zAxis>...) |
(?<z>...) |
Z-axis depth layer (3D, requires x + y) |
Examples
Section titled “Examples”| Label | Regex | Extracted |
|---|---|---|
BenchmarkHashing64MD5 |
Hashing64(?<x>.*) |
X: MD5 |
BenchmarkJSONByMarshal |
(?<x>.*)By(?<y>.*) |
X: JSON, Y: Marshal |
BenchmarkDecode/text=digits/level=speed |
(?<n>.*)/text=(?<x>.*)/level=(?<y>.*) |
N: Decode, X: digits, Y: speed |
vizb bench.txt --group-regex "(?<n>.*)/text=(?<x>.*)/level=(?<y>.*)" -o output.htmlAxis labels
Section titled “Axis labels”Set chart axis titles in --group-pattern / -p by appending {title} immediately after a dimension token (no space):
| Shorthand | Syntax | Chart title |
|---|---|---|
n |
n{Algorithm} |
Algorithm |
x |
x{Product} |
Product |
y |
y{Region} |
Region |
z |
z{Category} |
Category |
Works on flat patterns, bracket slots, and benchmarks. The same syntax is used everywhere -p is used.
# CSV — titles independent of column namesvizb sales.csv -g region,product -p 'y{Region},x{Product}' -o sales.html
# Bracket slot — one column, multiple titled dimensionsvizb sales.csv -g date,category -p '[n{year}-y{months}-x{dates}],z{Category}' -o sales.html
# Benchmark — no --group requiredvizb bench.txt -p 'n{Algorithm}/x{Size}/y{Variant}' -o out.htmlOmit {label} on CSV/JSON and the matching --group column name becomes the axis title. When {label} is present, it always overrides that default.
Choosing a Method
Section titled “Choosing a Method”Use --group-pattern when the label follows a consistent separator format — standard Go benchmarks (BenchmarkFunc/size/variant) or CSV/JSON columns that map cleanly to dimensions. Use --group-regex when the format is non-standard or you need fine-grained extraction, e.g. --group-regex "Hash(?<n>[A-Za-z]+)(?<x>\d+)" to pull a name and size out of HashingMD5Test1024 without a stable separator.