Skip to content

feat: tree transform#526

Draft
RobertFrenken wants to merge 5 commits into
svelteplot:mainfrom
RobertFrenken:feat/tree-transform
Draft

feat: tree transform#526
RobertFrenken wants to merge 5 commits into
svelteplot:mainfrom
RobertFrenken:feat/tree-transform

Conversation

@RobertFrenken

Copy link
Copy Markdown
Contributor

Add hierarchy layout transforms wrapping d3-hierarchy: tree, treemap, pack, and partition.

All transforms use a curried factory pattern (treeNode(options)({ data })) that produces new record sets compatible with existing marks (Dot, Link, Rect, Text). Paired *Node/*Link transforms share a WeakMap-based cache so the layout computes only once per data array.

treeNode/treeLink follow the Observable Plot tree transform API. treemapNode, packNode, and partitionNode/partitionLink extend beyond Observable Plot's API, wrapping d3-hierarchy layouts directly.

Partially addresses #92 (Tree mark) and #75 (missing transform types) — the transforms are implemented but a dedicated <Tree> convenience mark is not included in this PR.

What's included

  • Shared infrastructure (hierarchy.ts): buildHierarchy() for path-based and id/parentId stratification, cachedLayout() for paired transform caching
  • 4 transform modules with full TypeScript types and JSDoc
  • 59 unit tests across 4 test files (path/id-parentId stratification, horizontal swap, edge cases, channel passthrough, coordinate correctness)
  • 4 documentation pages with live examples and options tables
  • 8 example pages (tree, cluster, horizontal, step-curve, id/parentId, treemap, pack, partition)
  • flare.csv sample dataset
  • New dependency: d3-hierarchy + @types/d3-hierarchy

Design decisions

  • Curried factory pattern rather than the direct fn({data, ...channels}) pattern used by stack/bin/group — hierarchy transforms produce entirely new record sets (nodes/links) rather than modifying existing channel data. This matches Observable Plot's approach.
  • No dedicated <Tree> mark — keeping this PR focused on transforms. A convenience mark that composes treeNode + treeLink + Dot + Link could follow as a separate PR.

Test plan

  • pnpm test — 817 tests pass (95 files)
  • pnpm lint — clean
  • pnpm check — 0 errors
  • pnpm build — successful static build

🤖 Generated with Claude Code

RobertFrenken and others added 2 commits March 23, 2026 00:23
Adds d3-hierarchy layout transforms following Observable Plot's
*Node/*Link paired convention:

- treeNode/treeLink: tree and cluster diagrams
- treemapNode: space-filling rectangular treemaps
- packNode: circle-packing layouts
- partitionNode/partitionLink: icicle/sunburst partition layouts

Shared infrastructure in hierarchy.ts provides stratification
(flat data → hierarchy) and a WeakMap cache that deduplicates
layout computation across paired transforms.

Includes docs page, sidebar entries, 5 tree examples, flare.csv
dataset, and 59 tests across 4 test files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix record interface types: [key: string]: unknown → any, add
  [key: symbol]: any for compatibility with Record<string|symbol, RawValue>
- Move examples from examples/graph/ to per-transform directories
  (examples/tree/, treemap/, pack/, partition/) to fix prerender 404
  caused by [group] route resolving graph → /marks/graph
- Wrap computed values in $derived() for Svelte 5 reactivity correctness
- Add `as [number, number]` tuple casts on size options
- Apply Prettier formatting to all new files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Mar 23, 2026

Copy link
Copy Markdown

Deploy Preview for svelteplot ready!

Name Link
🔨 Latest commit 4c00236
🔍 Latest deploy log https://app.netlify.com/projects/svelteplot/deploys/69c19969fe51e4000858c5c4
😎 Deploy Preview https://deploy-preview-526--svelteplot.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

RobertFrenken and others added 3 commits March 23, 2026 12:31
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Wire delimiter option through buildHierarchy() — d3's stratify().path()
  hardcodes '/' as separator, so custom delimiters (like '.') are now
  converted before passing to d3. This was the root cause of flat/broken
  hierarchy plots.

- Fix Text marks rendering literal "null" — filter data to leaf nodes
  before passing to <Text> instead of returning null from the accessor
  (String(null) → "null" in Text.svelte).

- Normalize padding as fraction of layout size in treemap/pack/partition —
  padding: 0.01 now means 1% regardless of layout size parameter.

- Fix treemap/partition examples: padding was in absolute layout units,
  consuming entire space with size: [1,1]. Pack example: switched to
  normalized coordinates with derived pixelSize for r conversion.

- Expose two-tier API: treeLayout, treemapLayout, packLayout,
  partitionLayout as public low-level functions returning raw d3 hierarchy
  roots. Matches the force transform's forceLayout / forceNode pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Generate screenshot thumbnails for all hierarchy examples (tree,
  treemap, pack, partition) via screenshot-examples.js on OSC.

- Add --no-sandbox and --disable-setuid-sandbox to Puppeteer launch
  options, required for headless Chrome on HPC compute nodes and CI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gka

gka commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

I set this back to draft as it needs some more work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feature: Add treeNode transform feature: Add treeLink transform feature: add Tree transform

2 participants