Add Treemap and Sunburst trace types; upgrade plotly.js from 3.0.1 to 3.6.0#406
Open
jqnatividad wants to merge 8 commits into
Open
Add Treemap and Sunburst trace types; upgrade plotly.js from 3.0.1 to 3.6.0#406jqnatividad wants to merge 8 commits into
jqnatividad wants to merge 8 commits into
Conversation
Add hierarchical Treemap and Sunburst traces, mirroring the existing Pie trace pattern: - Treemap<V>: labels/parents/values hierarchy with BranchValues, plus Tiling (Packing) and PathBar (Side) helper structs - Sunburst<V>: same hierarchy plus Leaf, rotation and inside_text_orientation - New Treemap/Sunburst PlotType variants and top-level re-exports - treemapcolorway/extendtreemapcolors Layout options - Unit tests, doctests, basic_charts examples and book pages Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the shared common::Marker on Treemap with a treemap-specific
Marker exposing the treemap-only attributes: pad (Pad{t,l,r,b}),
corner_radius, and depth_fade (true/false/"reversed"). The shared
color/colorscale/colorbar/line/pattern machinery is retained, and the
scatter-only fields (size, symbol, ...) that don't apply to treemaps are
dropped. Showcased in the styled_treemap example.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jqnatividad
added a commit
to dathere/qsv
that referenced
this pull request
Jun 26, 2026
…lone 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>
Replaces the three vendored plotly.min.js copies (plotly, plotly_static, docs/book) with v3.6.0 and bumps the pinned CDN version strings in plot.rs, the jupyter notebook template, plotly_static template, and the book header. Closes plotly#407 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surfaces the user-facing attributes added across plotly.js 3.1.0 through 3.6.0 (now bundled), following the existing Option<T> + FieldSetter pattern: - Layout: hoversort (HoverSort), hoveranywhere, clickanywhere - Axis: zerolinelayer (ZeroLineLayer), minorloglabels, modebardisable (ModeBarDisable), ticklabelposition (TickLabelPosition), unifiedhovertitle (UnifiedHoverTitle), and ExponentFormat::SIExtended - Legend: maxheight - Configuration: displayNotifier - common::Label (hover labels): showarrow - common::Pattern: path (arbitrary SVG path fill) - Candlestick/Ohlc: hovertemplate - hovertemplatefallback / texttemplatefallback across applicable traces These are additive (new fields/enums/variants). Because FieldSetter and layout_structs generate per-field Restyle/Relayout enum variants, adding any field is a semver-breaking change; this targets the next breaking release (0.15.0), consistent with the Treemap/Sunburst additions already on this branch. Refs plotly#407 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Plotly.js pattern schema marks `path` as arrayOk (pathsrc present), like shape/bgcolor/fgcolor/size/solidity. Modeling it as Option<String> prevented per-point custom SVG path fills. Switch to Option<Dim<String>> so FieldSetter generates both scalar and array setters, and add a serialize_pattern_path test covering both forms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
|
Pushed two more commits:
Updated the PR description with the Plotly.js 3.0.1→3.6.0 upgrade (#407) and the full list of newly exposed attributes. All builds/clippy/nightly-fmt/tests pass locally (the only failing tests are the pre-existing browser-export ones that need a chromedriver binary). |
Plotly's `insidetextorientation` attribute expects the full words `horizontal`/`radial`/`tangential`/`auto`, but the field reused the general `Orientation` enum which serializes to single-letter codes (`h`/`v`/`r`/`t`). `Orientation::Radial` emitted `"r"`, which plotly.js silently coerces to the default `"auto"` — so setting a radial sunburst orientation was a no-op. Add a sunburst-specific `InsideTextOrientation` enum (`#[serde(rename_all = "lowercase")]` -> full words) and switch the field to it. The shared `Orientation` enum is left untouched so bars, boxes, legends and sankey keep their correct `h`/`v` codes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Sunburst inside_text_orientation setter takes the Sunburst-specific InsideTextOrientation enum, not common::Orientation. Update the example import and call so the basic-charts example crate compiles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jqnatividad
added a commit
to dathere/qsv
that referenced
this pull request
Jun 27, 2026
…l sunburst text, unified hover) (#4085) * feat(viz): adopt plotly.js 3.6.0 attributes (richer OHLC hover, radial sunburst text, unified hover) Upgrades the dathere plotly fork pin to its plotly.js 3.0.1 -> 3.6.0 branch (feat/treemap-sunburst-traces @ aeb1e59, upstream PR plotly/plotly.rs#406) and adopts three new additive, non-breaking attributes in `viz`: - Candlestick/OHLC `hover_template`: clean Open/High/Low/Close readout with `<extra></extra>` to drop the trace-name box, plus a defensive `hover_template_fallback` (financial traces have known hover-variable gaps). - Sunburst `inside_text_orientation(Radial)`: label+value+percent runs along each ring's spoke so deep-path sectors stay legible (standalone + smart panel). - `x unified` hover (Layout `hover_mode`) scoped to ordered-x chart kinds (line, candlestick, ohlc) — one tooltip per x across series. Excludes scatter/bar/box; the smart dashboard builds its own layout and is untouched. Regenerates the example gallery (now CDN plotly 3.6.0) so the figures reflect the new attributes. Adds/extends tests for all three (viz_candlestick, viz_ohlc, viz_sunburst_standalone, new viz_line_unified_hover). Verified: 126 viz tests pass; clippy clean; candlestick hover confirmed to resolve %{open}/%{high}/%{low}/%{close} at runtime in a browser. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(viz): emit valid "radial" sunburst inside-text orientation (#3211) `Sunburst::inside_text_orientation(Orientation::Radial)` serialized to `"insidetextorientation":"r"` — the shared `Orientation` enum's single-letter code (correct for bars/boxes/legends/sankey, wrong here). plotly.js 3.6.0 only accepts the full words `horizontal`/`radial`/`tangential`/`auto` and silently coerces `"r"` to the default `"auto"`, so the radial sunburst text was a no-op and the test locked in the invalid value. Fix in the dathere plotly fork by adding a sunburst-specific `InsideTextOrientation` enum that serializes to full words, leaving the general `Orientation` enum untouched. Re-pin `Cargo.lock` at the fork branch tip (3c185f8), switch the call site, drop the now-unused `Orientation` import, update the test to assert `"radial"`, and regenerate the gallery. Browser-verified against plotly.js 3.6.0: `_fullData` resolves the orientation to `"radial"` (not coerced to `"auto"`) and labels render radially along each ring's spoke. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(viz): regenerate --dictionary infer gallery figures (radial sunburst) Refresh the two LLM-dependent smart-dashboard gallery artifacts (smart_dict_treemap.html, smart_dict_sunburst.html) from the current qsv binary via describegpt `--dictionary infer` (local LM Studio, google/gemma-3-27b), and rebuild gallery.html to reference them. The sunburst dict figure now carries the valid `"insidetextorientation":"radial"` attribute (was the no-op `"r"`); both pages embed plotly.js 3.6.0 from the CDN. Browser-verified: 14 and 5 panels respectively, 0 render errors, sunburst resolves to radial. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
|
Thanks for the PR. I will review it soon |
Author
|
Great! FYI, once this lands, I have dathere#2 that's based on this. BTW, if you want to check out how qsv uses plotly.rs, check https://github.com/dathere/qsv/wiki/Visualization |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two hierarchical trace types —
TreemapandSunburst— to theplotlycrate, upgrades the bundled Plotly.js, and exposes the new attributes that came with it. The trace types follow the existingPiepattern and share Plotly'slabels/parents/ids/valuesdata model.What's added
Trace types
Treemap<V>: hierarchy fields (branch_values,count,level,max_depth),domain, full text/hover set,Tiling(Packing) andPathBar(Side) helper structs, and a dedicatedtreemap::Markerexposing the treemap-onlypad,corner_radius, anddepth_fadeattributes (on top of the shared color/colorscale/colorbar/line/pattern machinery).Sunburst<V>: same hierarchy/text/hover set plusLeaf,rotation, andinside_text_orientation.PlotType::Treemap/PlotType::Sunburstvariants and top-level re-exports; newtreemapcolorway/extendtreemapcolorslayout options.Bundled Plotly.js upgrade (#407)
plotly.min.jscopies (plotly/resource,plotly_static/resource,docs/book) and the pinned CDN version strings inplot.rs, the Jupyter template,plotly_static/template.rs, and the book header.New 3.1–3.6 attributes exposed
Additive bindings for the user-facing attributes added across Plotly.js 3.1.0 → 3.6.0, following the existing
Option<T>+FieldSetterpattern:Layout:hoversort(HoverSort),hoveranywhere,clickanywhereAxis:zerolinelayer(ZeroLineLayer),minorloglabels,modebardisable(ModeBarDisable),ticklabelposition(TickLabelPosition),unifiedhovertitle(UnifiedHoverTitle), andExponentFormat::SIExtendedLegend:maxheightConfiguration:displayNotifiercommon::Label(hover labels):showarrowcommon::Pattern:path(arbitrary SVG path fill,arrayOk)Candlestick/Ohlc:hovertemplatehovertemplatefallback/texttemplatefallbackacross applicable tracesTests & docs
basic_chartsexamples, and book pages.Compatibility note
Because
FieldSetter/layout_structsgenerate a per-field variant in theRestyle*/RelayoutLayoutenums, adding any field is a semver-breaking change (cargo-semver-checksflagsenum_variant_added). Combined with the newPlotTypeandExponentFormatvariants, this targets the next breaking release (0.15.0).I used Claude Code Opus 4.8 and reviewed the code and tested it with my project - qsv.
See https://github.com/dathere/qsv/wiki/Visualization
Closes #405
Closes #407