Data Viewer Widget
Data Viewer Widget Overview
The data viewer widget is designed for visualizing plots of time series data. It can operate on multiple distinct data types, such as analog time series, interval series, and event series. The widget contains a table of compatible data types and their corresponding keys, which can be selected for display in the viewer. It houses options to enable the visualization of different types and also includes an OpenGL canvas responsible for rendering the data according to user specifications.
Visualization Capabilities
Multiple pieces of data can be drawn on the same canvas. Some data can be drawn in an overlapping manner, or they may be drawn with different axis offsets. Both the Y and X axes are zoomable, and data-specific scaling can be applied to the Y-axis to allow data with different magnitudes to be easily visualized simultaneously. Drawing is synced to the time scroll bar in the main program, enabling the user to scroll through the plot while concurrently visualizing data in other widgets, such as movies collected at the same time.
Critically, the data viewer has a concept of different sampling rates for different data types and accounts for this during drawing. For instance, event data from camera frames sampled at 500 frames per second can be plotted appropriately with electrophysiological data sampled at 30,000 Hertz. A “Time frame concept” within the data manager is responsible for handling these conversions between coordinate systems, and the data viewer is responsible for plotting this data appropriately.
Handling Grouped Data and Custom Arrangement
Some temporal data in neuroscience involves the concept of a group of signals that are collected simultaneously and would be visualized simultaneously. For instance, 32 channels recorded simultaneously from a silicon probe would be expected to have the same scaling properties and spacing. Consequently, groups of data like this should, by default, have mostly matching configuration options but maintain the ability to be adjusted individually as needed. For example, if there are dead channels on a probe, it should be easy for the user to turn these off from the display.
The arrangement of data in the viewer is also important. Again, considering a silicon probe, the numerical channel arrangement is often not the same as the spatial channel arrangement, though the user may wish to view this data spatially arranged. The user should be able to customize this arrangement.
Interactive Analysis and Pre-processing
This representation may provide the user with information useful for certain data pre-processing tasks. For instance, the user may be able to determine a numerical threshold for event detection in a particular channel. Alternatively, in this view, the user may wish to determine the temporal range where it appears some behavior is taking place based on an analog signal change. For example, viewing the whisker angle versus time when zoomed out may be useful to identify times when the animal is whisking versus when it is stationary.
The user may even wish to interactively define events or intervals within this viewer window based on the temporal representation of data that would not be so easy to see in other widgets. Consequently, the data viewer is not just passive in its relationship with the data it is displaying but rather facilitates active engagement.
Event Viewer Features
The EventViewer_Widget provides controls for digital event series visualization with two main display modes:
Display Modes
- Stacked Mode (Default): Events are positioned in separate horizontal lanes with configurable spacing
- Each event series gets its own horizontal “lane”
- Configurable vertical spacing between lanes
- Configurable event line height
- Auto-calculation of optimal spacing when event groups are loaded
- Full Canvas Mode: Events stretch from top to bottom of the entire canvas
- Original behavior maintained for compatibility
- All events span the full height of the display area
Auto-Spacing for Event Groups
When a tree of digital event series is selected and enabled, the system automatically calculates optimal spacing to fit all events on the canvas:
- If 40 events are enabled on a 400-pixel tall canvas, each event gets approximately 10 pixels of space
- Spacing and height are calculated to ensure visual separation between different event series
- Uses 80% of available canvas height, leaving margins at top and bottom
- Event height is set to 60% of calculated spacing to prevent overlap
User Controls
The EventViewer_Widget provides: - Display Mode: Combo box to switch between Stacked and Full Canvas modes - Vertical Spacing: Adjustable spacing between stacked event series (0.01-1.0 normalized units) - Event Height: Adjustable height of individual event lines (0.01-0.5 normalized units) - Color Controls: Standard color picker for event line colors and transparency
Implementation Details
- Event stacking uses normalized coordinates for consistent spacing across different canvas sizes
- State is preserved when switching between data series
- Integration with existing TreeWidgetStateManager for persistence
- Optimized rendering with proper OpenGL line thickness and positioning
Time Frame Synchronization
The DataViewer Widget properly handles multi-rate data synchronization:
- Master Time Frame: OpenGLWidget maintains a reference to the master time frame (“master” or “time”) used for X-axis coordinates
- Time Frame Conversion: When data series use different time frames from the master, proper coordinate conversion ensures synchronized display
- Cross-Rate Compatibility: Supports simultaneous visualization of data collected at different sampling rates (e.g., 30kHz electrophysiology with 500Hz video)
- Consistent X-Axis: All data types (analog time series, digital events, digital intervals) are rendered with consistent X-axis positioning regardless of their native time frame
- Range Query Optimization: Data range queries are optimized for each time frame to ensure efficient rendering of large datasets
Interactive Interval Editing
The DataViewer Widget supports interactive editing of digital interval series through a mouse-based dragging interface that handles multi-timeframe data seamlessly.
Interval Selection and Highlighting
- Click-to-Select: Users can click on digital intervals to select them for editing
- Visual Feedback: Selected intervals are highlighted with enhanced borders for clear identification
- Per-Series Selection: Each digital interval series maintains its own independent selection state
Interval Edge Dragging
The widget provides precise interval boundary editing through a sophisticated dragging system:
Core Functionality
- Edge Detection: Mouse hover near interval boundaries (within 10 pixels) changes cursor to resize indicator
- Drag Initiation: Click and drag on interval edges to modify interval start or end times
- Real-time Preview: During dragging, both original (dimmed) and new (semi-transparent) interval positions are shown
- Collision Prevention: Automatic constraint enforcement prevents intervals from overlapping with existing intervals
Multi-Timeframe Support
The interval dragging system automatically handles time frame conversion for data collected at different sampling rates:
- Coordinate Conversion: Mouse coordinates (in master time frame) are automatically converted to the series’ native time frame indices
- Precision Handling: Dragged positions are rounded to the nearest valid index in the target time frame, accommodating different sampling resolutions
- Constraint Enforcement: Collision detection and boundary constraints are performed in the series’ native time frame for accuracy
- Display Consistency: Visual feedback remains in master time frame coordinates for consistent user experience
Error Handling and Robustness
- Graceful Degradation: Failed time frame conversions abort the drag operation while preserving original data
- Data Integrity: Invalid interval bounds (e.g., start ≥ end) are rejected without modifying existing data
- State Management: Drag operations can be cancelled (ESC key) to restore original interval boundaries
Example Use Cases
- Behavioral Annotation: Researchers can precisely adjust behavioral event boundaries recorded at video frame rates (30-120 Hz) while viewing synchronized neural data at higher sampling rates (20-30 kHz)
- Event Refinement: Fine-tune automatically detected events by dragging boundaries to match observed signal characteristics across different data modalities
- Cross-Modal Synchronization: Align interval boundaries across different measurement systems with varying temporal resolutions
Technical Implementation
The interval editing system leverages the existing TimeFrame infrastructure:
- TimeFrame.getIndexAtTime(): Converts master time coordinates to series-specific indices
- TimeFrame.getTimeAtIndex(): Converts series indices back to master time coordinates for display
- Automatic Snapping: Ensures all interval boundaries align with valid time points in the target series
- Thread Safety: All operations maintain data consistency during concurrent access
This functionality enables precise temporal analysis workflows while abstracting away the complexity of multi-rate data synchronization from the end user.
Vertical Space Coordination
The DataViewer_Widget includes a sophisticated vertical space management system that prevents overlap between different data types and ensures optimal use of screen real estate.
VerticalSpaceManager
The VerticalSpaceManager
class handles automatic positioning and scaling for all data series:
- Order-preserving: New data positioned below existing data
- Type-aware spacing: Different configurations for analog (larger heights), digital events (compact), and intervals (moderate)
- Auto-redistribution: Adding new series triggers recalculation to prevent overlap
- Canvas-independent: Uses normalized coordinates for flexibility
MVP Matrix Architecture
The rendering system uses a systematic Model-View-Projection (MVP) matrix approach for consistent positioning and scaling across all data types:
Model Matrix - Series-Specific Transforms
Handles individual series positioning and scaling:
// For VerticalSpaceManager-positioned series:
= glm::translate(Model, glm::vec3(0, series_center_y, 0)); // Position
Model = glm::scale(Model, glm::vec3(1, series_height * 0.5f, 1)); // Scale
Model
// For analog series, additional amplitude scaling:
float amplitude_scale = 1.0f / (stdDev * scale_factor);
= glm::scale(Model, glm::vec3(1, amplitude_scale, 1)); Model
View Matrix - Global Operations
Handles operations applied to all series equally:
= glm::translate(View, glm::vec3(0, _verticalPanOffset, 0)); // Global panning View
Projection Matrix - Coordinate System Mapping
Maps world coordinates to screen coordinates:
// X axis: time range [start_time, end_time] → screen width
// Y axis: world coordinates [min_y, max_y] → screen height
= glm::ortho(start_time, end_time, min_y, max_y); Projection
Vertex Coordinate Systems
VerticalSpaceManager Mode (recommended): - Vertices use normalized coordinates (-1 to +1 in local space) - Model matrix handles all positioning and scaling - Consistent across all data types
Legacy Mode (backward compatibility): - Vertices use world coordinates directly - Positioning handled by coordinate calculations - Index-based spacing for events
Detection of Positioning Mode
The system automatically detects which positioning mode to use:
- Digital Events:
vertical_spacing == 0.0f
signals VerticalSpaceManager mode - Analog Series:
y_offset != 0.0f
signals VerticalSpaceManager mode
- Digital Intervals:
y_offset != 0.0f
signals VerticalSpaceManager mode
This ensures backward compatibility while enabling the new systematic approach.