Scatter Plot Widget Roadmap
ScatterPlotWidget Development Roadmap
This document tracks remaining development tasks for the Scatter Plot Widget. For documentation of completed features and current architecture, see the main developer documentation.
Completed Work Summary
The following features are complete and documented in index.qmd:
Widget skeleton: EditorState pattern, registration, state/view/properties factories
State management:
ScatterPlotStatewithHorizontalAxisState,VerticalAxisStatecomposition;ScatterPlotStateDataserializable structAxis system:
HorizontalAxisWidget(X) andVerticalAxisWidget(Y) with bidirectional sync, including the “silent update” patternInteraction: Separated X/Y zoom, pan via shared
PlotInteractionHelpersProperties panel: Axis range controls in collapsible
Sectionwidgets; data source selection UI (key, column, offset per axis); reference line toggle; compatibility status labelOpenGL lifecycle:
ScatterPlotOpenGLWidgetinitialization, projection/view matrix management, pan/zoom mouse handlersState serialization: Full round-trip JSON via
rfl::jsonRegistration wiring:
timePositionSelected→EditorRegistry::setCurrentTime()connectionData source descriptor:
ScatterAxisSourcestruct defining data key, tensor column, and temporal offsetRow type compatibility validation:
resolveSourceRowType()andcheckSourceCompatibility()functions inCore/SourceCompatibility.hpp/.cppwith full test coverage (21 test cases, 52 assertions)Data source UI: Key/column/offset combo boxes per axis with DataManager observer, compatibility label displaying
checkSourceCompatibility()resultsPoint pair computation:
buildScatterPoints()factory function inCore/BuildScatterPoints.hpp/.cppsupporting all compatible source type combinations (ATS×ATS, ATS×TensorTFI, TensorTFI×ATS, TensorTFI×TensorTFI, Ordinal×Ordinal, Interval×Interval) with temporal offset and TimeFrameIndex join. Tested inBuildScatterPoints.test.cpp.Point rendering: SceneBuilder→SceneRenderer pipeline using
addGlyphs()for points with single instanced draw callAuto-fit bounds: Automatic X/Y bounds detection from data with 5% padding on first data load (when bounds are at defaults)
Reference line rendering: \(y = x\) diagonal via
addPolyLine()with show/hide toggle in properties panel; endpoints update on pan/zoomDataManager observer: Observer registration/removal in properties widget for combo box synchronization; stale key handling clears axis source when selected data key is deleted from DataManager; tested in
ScatterPlotPropertiesWidget.test.cppDouble-click-to-navigate: Point hit testing via shared
SceneHitTester+QuadTree<EntityId>spatial index,pointDoubleClicked→timePositionSelected→EditorRegistry::setCurrentTime()signal chain, yellow highlight glyph for navigated-to pointGlyph customization:
GlyphStyleDatainScatterPlotStateDatawith default blue circle style (#3388FF, size 5, alpha 0.8);GlyphStyleStateowned byScatterPlotStatewithglyphStyleChangedsignal;GlyphStyleControlsembedded in properties panel “Glyph Options” collapsible section; rendering usestoRenderableGlyphType()andhexColorToVec4()fromGlyphStyleConversion.hpp; full round-trip JSON serializationPoint selection: Dual selection modes (SinglePoint/Polygon) via combo box in properties panel; SinglePoint mode: Ctrl+Click toggles selection, Shift+Click removes; Polygon mode: Ctrl+Click adds vertices, Enter closes polygon, Backspace undoes, Escape cancels;
selectPointsInPolygon()utility inCorePlotting/Selection/; selected points rendered with distinct style (orange, +4 size); integration withGroupContextMenuHandlerfor right-click group operations; fully testedTemporal offset for outlier detection: Per-axis
time_offsetfield inScatterAxisSourceenables lag-plots (\(x(t)\) vs \(x(t-1)\));buildScatterPoints()applies offsets for all source type combinations; offset spinboxes (-10000 to 10000) in properties panel per axis; points where offset pushes index outside valid range are excluded; tested inBuildScatterPoints.test.cppHover tooltip:
PlotTooltipManagerintegration showing X/Y values andTimeFrameIndexon dwell; pan/zoom suppression; text provider with 3-decimal precision
Not yet implemented: feature coloring (Phase 7), stale key handling (Phase 6.3).
Phase 7: Feature Coloring via TensorData
Status: Design phase. Depends on point rendering and the shared colormap infrastructure.
Goal: Color scatter points by an external feature value from a TensorData column, enabling visual grouping by continuous or categorical features.
7.1 Color Configuration
struct ScatterColorConfig {
std::string color_mode = "fixed"; ///< "fixed" or "by_feature"
// For feature-based coloring
std::string tensor_key; ///< DataManager key for the color TensorData
std::string column_name; ///< Column within the TensorData
std::string colormap = "viridis"; ///< Colormap name
double color_min = 0.0;
double color_max = 1.0;
bool use_auto_range = true;
};7.3 Properties Panel
Add to ScatterPlotPropertiesWidget in a “Point Coloring” collapsible section:
- Color mode combo — Fixed / By Feature
- TensorData combo box — lists
TensorDatakeys from DataManager - Column combo box — shows columns of the selected
TensorData - Colormap combo — colormap preset selection
- Range controls — auto/manual min/max spinboxes
Phase 8: Hover Tooltip
Status: ✅ Implemented. See index.qmd § Hover Tooltip for documentation.
Design Decisions
Point count scalability: The
SceneBuilder::addGlyphs()→GlyphRendererpipeline uses instanced rendering (single GPU draw call for all points in a batch). This is the same path EventPlotWidget uses for large spike counts and scales well to tens of thousands of points. No dedicatedPointBatchRendereris needed.Polygon interaction: Uses the existing
PolygonInteractionControllerfromCorePlotting/Interaction/. This shared controller handles click-based polygon creation, vertex drag modification, cursor preview, and auto-close detection.Reference line: Only \(y = x\) reference line for now. Can be generalized to arbitrary linear reference lines (\(y = ax + b\)) in a future phase if needed.
Hit testing via shared QuadTree: Point hit testing uses the existing
SceneHitTester(CorePlotting/Interaction/SceneHitTester.hpp) which queries theQuadTree<EntityId>spatial index built automatically bySceneBuilder::addGlyphs(). This is the same infrastructure used by EventPlotWidget for double-click navigation and click-to-select. The QuadTree providesO(log n)nearest-neighbor lookup, scaling well to large point counts without widget-specific spatial indexing code. Navigation usesmouseDoubleClickEvent, matching EventPlotWidget. Hover tooltips (Phase 8) use the shared PlotTooltipManager for dwell timer and lifecycle management.Two-batch rendering for selection/highlight:
GlyphRendererrenders eachRenderableGlyphBatchin order, with its ownu_point_size/u_glyph_sizeuniform. Per-instance color is already supported by the shader (a_instance_color/a_colorVBO attribute), but per-instance size is not — size is a per-batch uniform. Therefore, rendering selected/highlighted points at a different size requires a secondaddGlyphs()call. This results in exactly two GPU draw calls (one for unselected, one for selected) regardless of the selection count, with no shader changes needed.Single dataset per plot: Each ScatterPlotWidget displays a single X/Y data source pair. Users can open multiple scatter plot instances via the Analysis Dashboard for side-by-side comparison of different variable pairs.
See Also
- ScatterPlotWidget Documentation — Full architecture and feature documentation
- Plot Widget Guide — Shared architecture, axis types, DataManager integration
- LinePlotWidget Roadmap — Group integration pattern (Phase 1), feature coloring (Phase 3)
- EventPlotWidget Roadmap — TensorData feature coloring/sorting (Phase 5)
- HeatmapWidget Roadmap — Colormap infrastructure (Phase 2)
- TemporalProjectionViewWidget — Polygon selection with PointData, shared rendering