Skip to content

Commit 9fa1f05

Browse files
jqnatividadclaude
andauthored
feat(viz): treemap & sunburst hierarchy charts (smart panels + standalone subcommands) (#4080)
* feat(viz): treemap & sunburst hierarchy panels + standalone subcommands Add categorical part-to-whole hierarchy charts to `viz`, backed by the Treemap/Sunburst trace types from the plotly.rs fork (PR plotly/plotly.rs#406). `viz smart` now adds a hierarchy panel when the dataset has 2+ genuine (String) low-cardinality dimensions, auto-selecting the chart by depth per visualization best practice: a treemap for a shallow (2-level) hierarchy (area encodes size for accurate comparison) and a sunburst for a deeper (3-level) one (rings emphasize parent-child structure). Override with `--hierarchy-style auto|treemap|sunburst`. The chosen dimensions keep their own frequency bars; the panel is domain-based, so (like map/geo/3D) it renders via the inline path. Restricting dims to String type with cardinality >= 3 keeps numeric codes/booleans out and avoids forcing small dashboards inline. Also add standalone `viz treemap` / `viz sunburst` subcommands (--cols for the hierarchy levels, optional additive --value/--agg). Treemap tiles use the fork's treemap-specific Marker (rounded corners, inner padding, white outline). - one-pass leaf accumulation + pure flat-array builder (top-N per level with an "Other (k)" bucket, path-joined ids, rolled-up branchvalues=total) - 5 unit + 6 integration tests - regenerated docs/help/viz.md, the qsv-viz MCP skill, and the examples gallery (incl. two `viz smart --dictionary infer` dashboards showcasing both charts) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(viz): validate --value measure for treemap/sunburst (roborev #3190) In value mode, `accumulate_hierarchy_counts` silently coerced parse failures to 0.0 and accepted negative / non-finite values, so a typo'd or non-numeric --value column produced a blank or misleading area chart while the command succeeded. Now non-empty value cells must parse to a finite, non-negative number; empty cells stay a benign missing measure (skipped). Unusable cells are skipped and tallied with a warning, and an all-unusable measure column returns a clear error instead of charting zeros. Adds value-sum and all-invalid-value tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(viz): error on any invalid --value cell for treemap/sunburst (roborev #3191) Follow-up to #3190: invalid non-empty --value cells only warned (when at least one valid value existed), so a partially-malformed measure column still produced a "successful" treemap/sunburst with rows silently dropped — quietly misstating every part-to-whole proportion. Make any unusable measure cell (non-numeric, negative, or non-finite) a hard error reporting the bad-cell count; empty cells remain a benign missing measure (skipped). Adds a mixed valid/invalid test alongside the all-invalid case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(viz): add standalone treemap & sunburst figures to the examples gallery The gallery showcased the treemap/sunburst hierarchy only via the `viz smart` dashboards; add the two standalone chart types as individual figures too: - treemap: customer_spend plan -> region, sized by summed monthly_spend (exercises the validated --value path + the treemap-specific marker) - sunburst: sales_sample region -> product_category -> payment_method Regenerated gallery.html (29 figures). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 887976b commit 9fa1f05

15 files changed

Lines changed: 1478 additions & 184 deletions

.claude/skills/qsv/qsv-viz.json

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"name": "subcommand",
1111
"type": "string",
1212
"required": true,
13-
"description": "Subcommand to execute. Valid values: bar, box, candlestick, contour, geo, heatmap, histogram, line, map, ohlc, pie, radar, sankey, scatter, scatter3d, smart",
13+
"description": "Subcommand to execute. Valid values: bar, box, candlestick, contour, geo, heatmap, histogram, line, map, ohlc, pie, radar, sankey, scatter, scatter3d, smart, sunburst, treemap",
1414
"enum": [
1515
"bar",
1616
"box",
@@ -27,7 +27,9 @@
2727
"sankey",
2828
"scatter",
2929
"scatter3d",
30-
"smart"
30+
"smart",
31+
"sunburst",
32+
"treemap"
3133
]
3234
},
3335
{
@@ -41,7 +43,7 @@
4143
{
4244
"flag": "--agg",
4345
"type": "string",
44-
"description": "For bar/line, aggregate the y values when the x value repeats. One of: sum, mean, count, min, max."
46+
"description": "For bar/line, aggregate the y values when the x value repeats. One of: sum, mean, count, min, max. For treemap/sunburst, only additive aggregations apply: count (default) or sum (requires --value)."
4547
},
4648
{
4749
"flag": "--bins",
@@ -66,7 +68,7 @@
6668
{
6769
"flag": "--cols",
6870
"type": "string",
69-
"description": "Columns to use. For heatmap: numeric columns for the correlation matrix (default: all numeric). For radar: the numeric axes to plot."
71+
"description": "Columns to use. For heatmap: numeric columns for the correlation matrix (default: all numeric). For radar: the numeric axes to plot. For treemap/sunburst: the categorical dimensions that form the hierarchy levels, outermost first (e.g. region,category,subcategory)."
7072
},
7173
{
7274
"flag": "--delimiter",
@@ -104,6 +106,11 @@
104106
"type": "string",
105107
"description": "Image height in pixels for static export. Default 600; for `smart`, auto-scaled to the number of panel rows."
106108
},
109+
{
110+
"flag": "--hierarchy-style",
111+
"type": "string",
112+
"description": "For `smart`, the chart used for the categorical part-to-whole hierarchy panel (built when 2+ low-cardinality dimensions exist). One of: auto (default), treemap, sunburst. auto follows best practice — a treemap for a shallow 2-level hierarchy (accurate size comparison) and a sunburst for a deep 3-level one (parent child structure). Only affects `smart`."
113+
},
107114
{
108115
"flag": "--high",
109116
"type": "string",
@@ -238,7 +245,7 @@
238245
{
239246
"flag": "--value",
240247
"type": "string",
241-
"description": "Flow value column for a sankey diagram. When omitted, each row counts as a flow of 1."
248+
"description": "Flow value column for a sankey diagram. When omitted, each row counts as a flow of 1. For treemap/sunburst: a numeric measure summed per sector (when omitted, each row counts as 1)."
242249
},
243250
{
244251
"flag": "--width",
@@ -355,6 +362,14 @@
355362
{
356363
"description": "Projection map of earthquakes (token-free), marker color by magnitude",
357364
"command": "qsv viz geo quakes.csv --lat lat --lon lon --color magnitude --projection natural-earth -o geo.html"
365+
},
366+
{
367+
"description": "Treemap of part-to-whole sales by region then category, sized by amount",
368+
"command": "qsv viz treemap sales.csv --cols region,category --value amount --agg sum -o treemap.html"
369+
},
370+
{
371+
"description": "Sunburst of a deep 3-level web-traffic hierarchy, sized by row count",
372+
"command": "qsv viz sunburst web.csv --cols source,campaign,landing_page -o sunburst.html"
358373
}
359374
]
360375
}

0 commit comments

Comments
 (0)