Skip to content

Add treemap explorer view for physical block visualization#8613

Draft
robert3005 wants to merge 15 commits into
developfrom
claude/stoic-brown-5pzm5s
Draft

Add treemap explorer view for physical block visualization#8613
robert3005 wants to merge 15 commits into
developfrom
claude/stoic-brown-5pzm5s

Conversation

@robert3005

Copy link
Copy Markdown
Contributor

Rationale for this change

This PR adds a new Treemap view to the explorer that visualizes the physical layout of blocks in a Vortex file. The treemap renders every encoded block down to the leaves, sized by byte footprint and colored by dtype, providing insight into file structure, chunk distribution, and encoding density. This complements the existing swimlane explorer which focuses on logical structure.

The treemap view:

  • Renders nested layouts with their array-encoding buffers as subdivisions
  • Displays each block's name locally (in container headers or leaf bodies) without collision
  • Shows physical statistics (data/metadata bytes, % of file, bytes-per-row density) on hover
  • Allows expanding flat layouts to reveal their array buffers in place
  • Syncs selection with the tree panel and detail sidebar
  • Follows the app theme (dark by default, matching explore.vortex.dev)

What changes are included in this PR?

New components:

  • BlockTreemap.tsx: Core treemap rendering using D3 hierarchy and squarified treemap layout. Handles hit testing, hover/selection, and tooltip display.
  • TreemapExplorer.tsx: Top-level view combining the treemap with a dtype legend and metadata sidebar.
  • physicalStats.ts: Utilities for computing physical statistics (data bytes, metadata, density, row counts) aggregated over subtrees.

Modified components:

  • FileHeader.tsx: Added view switcher buttons ("Explorer" / "Treemap") to toggle between the detail panel and treemap views.
  • MainArea.tsx: Refactored to accept a view prop and conditionally render either the detail panel or treemap explorer.
  • ExplorerShell.tsx: Updated to manage view state and pass it through the component tree.
  • App.tsx: Updated to manage and pass the view state.

Documentation & stories:

  • TreemapExplorer.stories.tsx: Added Storybook stories demonstrating the treemap with three datasets (orders, wide columns, heavy chunks).
  • README.md: Added section documenting the treemap explorer with screenshots and usage notes.

Theme context:

  • ThemeContext.tsx: Exported ThemeContext for use in Storybook preview configuration.
  • .storybook/preview.ts: Updated to wrap stories with ThemeContext so theme switching works in Storybook.

What APIs are changed? Are there any user-facing changes?

User-facing changes:

  • New "Treemap" view toggle in the file header (next to theme picker)
  • Clicking the toggle switches between the detail explorer and full-file treemap
  • Hovering blocks in the treemap shows physical statistics in a tooltip
  • Clicking a block selects it and syncs with the tree panel and sidebar
  • Flat layouts can be expanded in place by clicking them

Component API changes:

  • FileHeader now requires view and onViewChange props
  • MainArea now requires a view prop
  • ExplorerView type exported from MainArea to indicate the two view modes

No breaking changes to public APIs outside the explorer shell.

https://claude.ai/code/session_01AgSCUYWJ7tJmrtUGkgEV4A

@robert3005 robert3005 requested a review from a team June 27, 2026 20:10
@robert3005 robert3005 marked this pull request as draft June 27, 2026 20:10
Add a new top-level "Treemap" view to the file explorer that visualises the
file's physical blocks as a zoomable, pannable treemap. Layouts subdivide the
canvas first; flat layouts subdivide further into their array-encoding buffers,
so the deepest tiles are the physical blocks. Tiles are sized by byte footprint,
coloured by encoding, and shaded with a WinDirStat-style cushion gradient.

- BlockTreemap: SVG treemap rendered in screen space with wheel-zoom, drag-pan,
  zoom-to-fit on double-click, zoom buttons, hover tooltip with physical stats,
  and click-to-select that lazily expands array encodings. Selection/hover sync
  through SelectionContext so the tree and map stay in lock-step.
- physicalStats: shared helper for physical properties (data/metadata bytes,
  % of file, bytes/row density, segment/buffer counts).
- TreemapExplorer: composes the map with an encoding legend, a metadata +
  physical-statistics sidebar, and the shared data-sample preview.
- FileHeader/App/MainArea: Explorer | Treemap view switcher; TreePanel, file map
  and data preview stay shared between views.
- Storybook stories for the explorer plus orders/wide/heavy-chunk fixtures.

Signed-off-by: Robert <robert@spiraldb.com>
…th theme

Document the treemap explorer in the README with rendered screenshots
(overview, hover-with-stats, and many-chunks views).

To render the screenshots from Storybook, supply the theme via a global
preview decorator so components using `useTheme` render in stories and follow
the Storybook theme toolbar. Export `ThemeContext` to enable this, mirroring
the existing `SelectionContext` export.

Signed-off-by: Robert <robert@spiraldb.com>
Replace the WinDirStat-style saturated, cushion-shaded tiles with the
translucent, dtype-coloured treatment used by the detail treemap and swimlane:
flat tint fills (0.06 container / 0.18 leaf / 0.4 selected), thin app borders,
Geist Mono fg/dim labels, and the standard dtype legend. The hover tooltip now
uses the shared swimlane tooltip card (name + dtype badge + stat grid). Zoom,
pan, selection sync, and physical statistics are unchanged.

Signed-off-by: Robert <robert@spiraldb.com>
The app is dark by default (matching explore.vortex.dev), so default the
TreemapExplorer story to the dark theme and refresh the README screenshots in
dark. The treemap already renders in dark via the shared theme tokens
(#1a1a1e surface, #e4e4e8 text, #2cb9d1 accent); this just makes the preview
and docs reflect the production default.

Signed-off-by: Robert <robert@spiraldb.com>
Nested container labels (e.g. customer → id, amount → data, status → values)
rendered as plain text one padding-band apart and visually collided. Give each
container a tinted header bar in its padding band, coloured by its dtype, so
nested parent names read as a stacked staircase of title strips instead of
overlapping. Labels sit within their own bar; the bytes line stays leaf-only.

Signed-off-by: Robert <robert@spiraldb.com>
Replace the per-container header bars with a single sticky breadcrumb overlaid
on the treemap: only leaf blocks are labelled inline, and the hovered block's
full path (e.g. "status / values") is shown pinned to the corner. This is
simpler than reserving a labelled padding band per nesting level and removes
parent-name overlaps by construction, since parent names are never stacked
inline. Leaf name + bytes labels and all interactions are unchanged.

Signed-off-by: Robert <robert@spiraldb.com>
Replace the overlay breadcrumb with sticky header bars. Each container layout
draws a title strip in its padding band; when the container scrolls above the
top of the view, its strip pins just below its parent's, so ancestor strips
stack into the current path as you pan and zoom. Strips are coloured by dtype,
highlight on hover/selection, and sit in their natural band at rest. Leaf name
and bytes labels are unchanged.

Signed-off-by: Robert <robert@spiraldb.com>
A pinned (stuck) sticky header bar was translucent, so content scrolling
underneath bled through it. Draw an opaque surface base beneath the dtype tint
once a bar is stuck, so it reads as solid and the children sit cleanly below
it. In-band (non-stuck) strips keep their light tint.

Signed-off-by: Robert <robert@spiraldb.com>
The header bars were piling up on top of each other (and on leaf labels) at
the top of the map because `.paddingTop(18)` was being overridden: d3's
`.paddingOuter(1)` also sets the top pad and was called after it, collapsing the
band to 1px. Set `paddingTop` last so each container gets a real 18px band, and
lay out PAD_TOP taller with an upward shift so the root's own band doesn't leave
a top margin. Strips now sit in their own bands with no overlap.

Signed-off-by: Robert <robert@spiraldb.com>
Replace the nested treemap (and its per-container header strips, the source of
the overlapping labels) with a drill-down box: the box shows the current
layout's child blocks one level deep, each a single labelled tile sized by its
subtree bytes. A header bar at the top is the current path — click a block to
drill in, click a path segment to drill back out. Because every visible tile is
one level deep, labels never collide. Hover still drives the tooltip, sidebar,
and data sample; selection stays in sync with the tree panel. Drops the
pan/zoom transform and sticky-header machinery.

Signed-off-by: Robert <robert@spiraldb.com>
The one-level drill view hid the blocks (a dominant field was just one big empty
tile). Render the full nested tree down to the leaves again so every physical
block is visible, but label only leaf blocks — parent names come from a single
path header at the top, which shows the path to the block under the cursor
(e.g. "root / amount / data / [4]"). Because containers carry no inline label,
nothing overlaps. Click a block to select it (flat blocks expand in place to
reveal their buffers); click a path segment to focus that subtree.

Signed-off-by: Robert <robert@spiraldb.com>
… header

Move each layout's name back onto its own block: container layouts label their
header band (which their children never occupy, so labels cannot collide) and
leaves label their body with name + bytes. Drop the top path header. The full
nested tree still renders down to the leaves so every physical block is visible,
coloured by dtype; hover drives the tooltip/sidebar and click selects (flat
blocks expand in place). Relies on the corrected header band (paddingTop set
after paddingOuter) so nested names stack cleanly without overlap.

Signed-off-by: Robert <robert@spiraldb.com>
@robert3005 robert3005 force-pushed the claude/stoic-brown-5pzm5s branch from 6f08e27 to 2bde076 Compare June 27, 2026 20:11
@codspeed-hq

codspeed-hq Bot commented Jun 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 2 improved benchmarks
❌ 1 regressed benchmark
✅ 1592 untouched benchmarks
⏩ 4 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation slice_empty_vortex 339.4 ns 397.8 ns -14.66%
Simulation bitwise_not_vortex_buffer_mut[128] 244.4 ns 215.3 ns +13.55%
Simulation bitwise_not_vortex_buffer_mut[1024] 304.7 ns 275.6 ns +10.58%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/stoic-brown-5pzm5s (a6a3616) with develop (bf2be52)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Replace the simpler TreemapPane with the richer BlockTreemap as the detail
panel's "Treemap" tab, rooted at the selected node and rendering every physical
block down to the leaves with local per-layout labels (container header bands +
leaf bodies). Single-click highlights a block; double-click selects it, which
re-roots the tab there (zoom in) — zoom back out via the detail-panel
breadcrumb. Remove the standalone top-level Treemap view and its Explorer|Treemap
header toggle (TreemapExplorer, MainArea/FileHeader/App view plumbing), and drop
the old TreemapPane. Add a BlockTreemap story (root, zoomed field, heavy chunks).

Signed-off-by: Robert <robert@spiraldb.com>
…k to zoom

Single-clicking a block now selects it — highlighting it and scrolling the tree
panel to it — instead of only highlighting locally. To keep select separate from
zoom, the Treemap tab now roots at the whole file with its own internal drill
state: double-click zooms into a block (re-root) and an "↑" control zooms back
out, while selection just highlights and syncs the tree/sidebar/preview.

Signed-off-by: Robert <robert@spiraldb.com>
Selecting a node in the tree panel now re-roots (zooms) the treemap at it. The
map distinguishes selections it made itself (single-click highlight, which must
not re-zoom) from external selections (tree panel, breadcrumb) via a ref, and
only the latter drive the zoom. Double-click and the "↑" control still adjust
the zoom directly.

Signed-off-by: Robert <robert@spiraldb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant