-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
FastPlot uses a render‑once, re‑downsample‑on‑zoom architecture. Instead of pushing millions of points to the GPU, it maintains a lightweight cache and re‑downsamples only the visible range on every interaction. A dynamic downsampling engine, lazy multi‑resolution pyramid, and optional MEX acceleration ensure that datasets from a few hundred to over 100 million points remain responsive during pan and zoom.
FastPlot/
├── install.m # Path install + MEX compilation
├── libs/
│ ├── FastSense/ # Core plotting engine
│ │ ├── FastSense.m # Main plotting class
│ │ ├── FastSenseGrid.m # Tiled grid layout
│ │ ├── FastSenseDock.m # Tabbed container
│ │ ├── FastSenseToolbar.m # Interactive toolbar
│ │ ├── FastSenseTheme.m # Theme system
│ │ ├── FastSenseDataStore.m # SQLite‑backed chunked storage
│ │ ├── SensorDetailPlot.m # Sensor detail view
│ │ ├── NavigatorOverlay.m # Minimap zoom navigator
│ │ ├── ConsoleProgressBar.m # Progress indication
│ │ ├── binary_search.m # Binary search utility
│ │ ├── HoverCrosshair.m # Hover cross‑hair
│ │ ├── build_mex.m # MEX compilation script
│ │ └── private/ # Internal algorithms + MEX sources
│ ├── SensorThreshold/ # Tag‑based monitoring + pipeline
│ │ ├── Tag.m # Abstract Tag base
│ │ ├── SensorTag.m # Sensor data tag
│ │ ├── StateTag.m # Discrete state tag
│ │ ├── MonitorTag.m # 0/1 threshold monitor
│ │ ├── CompositeTag.m # Composite aggregation
│ │ ├── DerivedTag.m # Derived signal tag
│ │ ├── TagRegistry.m # Singleton catalog
│ │ ├── BatchTagPipeline.m # Batch raw‑data ingestion
│ │ ├── LiveTagPipeline.m # Timer‑driven polling pipeline
│ │ └── private/ # Parse/format + MEX wrappers
│ ├── EventDetection/ # Event detection and viewer
│ │ ├── Event.m # Event data object
│ │ ├── EventStore.m # Persistence / cluster‑mode store
│ │ ├── EventBinding.m # Event↔Tag many‑to‑many registry
│ │ ├── EventViewer.m # Gantt viewer
│ │ ├── LiveEventPipeline.m # Real‑time violation pipeline
│ │ ├── NotificationService.m # Email alerts
│ │ ├── DataSource.m # Abstract data source
│ │ ├── MatFileDataSource.m # .mat file polling
│ │ ├── MockDataSource.m # Test data generator
│ │ └── private/ # Grouping algorithms
│ ├── Dashboard/ # Dashboard engine
│ │ ├── DashboardEngine.m # Orchestrator
│ │ ├── DashboardBuilder.m # Edit‑mode drag‑resize
│ │ ├── DashboardLayout.m # 24‑column responsive grid
│ │ ├── DashboardSerializer.m # JSON / .m export
│ │ ├── DashboardTheme.m # Theme for dashboard
│ │ ├── DashboardToolbar.m # Top toolbar
│ │ ├── DashboardWidget.m # Abstract widget base
│ │ ├── FastSenseWidget.m # FastSense‑bound widget
│ │ ├── GaugeWidget.m # Arc / donut / bar gauge
│ │ ├── NumberWidget.m # Big number
│ │ ├── StatusWidget.m # Colored dot indicator
│ │ ├── TextWidget.m # Static label
│ │ ├── TableWidget.m # uitable wrapper
│ │ ├── RawAxesWidget.m # User‑supplied plot function
│ │ ├── EventTimelineWidget.m # Event Gantt widget
│ │ ├── GroupWidget.m # Collapsible / tabbed groups
│ │ ├── MultiStatusWidget.m # Grid of status dots
│ │ ├── SparklineCardWidget.m # KPI with mini sparkline
│ │ ├── ChipBarWidget.m # Health chip row
│ │ ├── IconCardWidget.m # Mushroom‑style card
│ │ ├── BarChartWidget.m # Bar chart
│ │ ├── ScatterWidget.m # Scatter plot
│ │ ├── HeatmapWidget.m # heatmap
│ │ ├── HistogramWidget.m # Histogram
│ │ ├── ImageWidget.m # Image display
│ │ ├── DividerWidget.m # Horizontal divider
│ │ ├── MarkdownRenderer.m # Info panel HTML
│ │ └── TimeRangeSelector.m # Slider with envelope preview
│ └── WebBridge/ # TCP server for web visualization
│ ├── WebBridge.m
│ └── WebBridgeProtocol.m
├── examples/ # 40+ runnable examples
└── tests/ # 30+ test suites
- User calls
render(). - Create figure/axes if not parented.
- Validate all data (X monotonic, dimensions match).
- Switch to disk storage mode if data exceeds
MemoryLimit. - Allocate downsampling buffers based on axes pixel width.
- For each line: initial downsample of full range, create graphics object.
- Create threshold, band, shading, marker objects.
- Install XLim PostSet listener for zoom/pan events.
- Set axis limits, disable auto‑limits.
-
drawnowto display.
When the user zooms or pans:
- XLim listener fires.
- Compare new XLim to cached value (skip if unchanged).
- For each line:
- Binary search visible X range — O(log N).
- Select pyramid level with sufficient resolution.
- Build pyramid level lazily if needed.
- Downsample visible range to ~4,000 points.
- Update
hLine.XData/YData(dot notation for speed).
- Recompute violation markers (fused SIMD with pixel culling).
- If
LinkGroupactive: propagate XLim to linked plots. -
drawnow limitrate(caps display at 20 FPS).
For each pixel bucket, keep the minimum and maximum Y values. Preserves signal envelope and extreme values. Fast O(N/bucket) per bucket.
Visually optimal downsampling that preserves signal shape by maximizing triangle area between consecutive buckets. Better visual fidelity but slightly slower.
Both algorithms handle NaN gaps by segmenting contiguous non‑NaN regions independently.
Problem: At full zoom‑out with 50M+ points, scanning all data is O(N).
Solution: Pre‑computed MinMax pyramid with configurable reduction factor (default 100× per level):
Level 0: Raw data (50,000,000 points)
Level 1: 100× reduction ( 500,000 points)
Level 2: 100× reduction ( 5,000 points)
On zoom, the coarsest level with sufficient resolution is selected. Full zoom‑out reads level 2 (5K points) and downsamples to ~4K in under 1 ms.
Levels are built lazily on first access — the first zoom‑out pays a one‑time build cost (~70 ms with MEX), subsequent queries are instant.
Optional C MEX functions with SIMD intrinsics (AVX2 on x86_64, NEON on arm64). A shared simd_utils.h abstraction layer provides a single code base for all platforms. Detection of AVX2, fallback to SSE2, and arm64‑NEON is handled at build_mex time.
| Function | Speedup | Description |
|---|---|---|
binary_search_mex |
10–20× | O(log N) visible range lookup |
minmax_core_mex |
3–10× | Per‑pixel MinMax reduction |
lttb_core_mex |
10–50× | Triangle area computation |
violation_cull_mex |
significant | Fused detection + pixel culling |
compute_violations_mex |
significant | Batch violation detection for resolve()
|
resolve_disk_mex |
significant | SQLite disk‑based sensor resolution |
build_store_mex |
2–3× | Bulk SQLite writer for DataStore init |
to_step_function_mex |
significant | SIMD step‑function conversion for thresholds |
delimited_parse_mex |
(plan 1028) | SIMD delimited file parsing for tag pipeline |
If MEX is unavailable, pure-MATLAB implementations are used with identical behavior.
Raw Data (X, Y arrays)
↓
FastSenseDataStore (optional, for large datasets)
↓
Downsampling Engine (MinMax/LTTB)
↓
Pyramid Cache (lazy multi‑resolution)
↓
Graphics Objects (line handles)
↓
Interactive Display
- Memory mode: X/Y arrays held in MATLAB workspace.
-
Disk mode: Data chunked into SQLite database via
FastSenseDataStore. -
Auto mode: Switches to disk when data exceeds
MemoryLimit(default 500 MB).
For datasets exceeding available memory (100M+ points), FastSenseDataStore provides SQLite‑backed chunked storage:
- Data is split into chunks (~10K‑500K points each, auto‑tuned).
- Each chunk stored as a pair of typed BLOBs (X and Y) with X range metadata.
- On zoom/pan, only chunks overlapping the visible range are loaded.
- Pre‑computed L1 MinMax pyramid for instant zoom‑out.
The bulk write path uses build_store_mex — a single C call that writes all chunks with SIMD‑accelerated Y min/max computation, replacing ~20K mksqlite round‑trips.
The API Reference: Sensors Sensor.resolve() algorithm is segment‑based:
- Collect all state‑change timestamps from all
StateChannels. - For each segment between state changes:
- Evaluate which
ThresholdRulesmatch the current state. - Group rules with identical conditions.
- Evaluate which
- Assign threshold values per segment.
- Detect violations using SIMD‑accelerated comparison.
Complexity: O(S × R) where S = state segments and R = rules, instead of O(N × R) per‑point evaluation.
The modern path uses the Tag domain model. A MonitorTag wraps a parent SensorTag or CompositeTag and continuously evaluates a user‑provided ConditionFn:
m = MonitorTag('temp_hi', tempSensor, @(x,y) y > 80, 'OnEventStart', eventLogger());MonitorTag fires OnEventStart / OnEventEnd callbacks and can emit Event objects to an EventStore. The pipeline for detecting, persisting, and notifying these events is described in the Event Detection Architecture.
For datasets that originate from raw delimited files, FastPlot includes a batch and live pipeline to convert raw CSV/txt to per‑tag .mat files.
BatchTagPipeline LiveTagPipeline
raw/*.csv → <OutputDir>/<tag>.mat raw/*.csv → <OutputDir>/<tag>.mat
- one‑shot - polling timer (default 15 s)
- MEX‑accelerated parsing - incremental append
- per‑tag file‑cache dedup
Both pipelines use the same underlying readRawDelimited_ + selectTimeAndValue_ + writeTagMat_ stack, ensuring byte‑identical output. The live variant mimics MatFileDataSource’s modTime + lastIndex pattern for raw delimited files without an intermediate .mat store.
The event detection system provides real‑time threshold violation monitoring with configurable notifications and data persistence.
-
Tag Domain:
SensorTag,StateTag,MonitorTag,CompositeTag,DerivedTag - MonitorTag: wraps a parent tag and emits events on rising/falling edges of its condition.
- EventStore: persistence handler for events (single‑user or cluster‑mode via SQLite).
- EventBinding: many‑to‑many mapping between events and tags.
-
LiveTagPipeline: timer‑driven polling of raw files (matching
LiveEventPipelinetiming). -
LiveEventPipeline (legacy DataSource‑based): polls
DataSourceMapand firesIncrementalEventDetector.
-
MatFileDataSource: Polls
.matfiles for new data. - MockDataSource: Generates synthetic test signals with violations.
-
LiveTagPipelinepolls raw CSV/txt files and appends new samples toSensorTag/StateTagviaupdateData. -
updateDatacascades to registeredMonitorTaglisteners →MonitorTag.appendData. -
appendDatacarries the hysteresis FSM andMinDurationdebouncing forward, emittingEventhandles for completed runs. - Events are persisted via
EventStore.append().
When EscalateSeverity is enabled, events are promoted to the highest violated threshold:
- A violation starts at “Warning” level.
- If “Alarm” threshold is also crossed, the event is escalated to “Alarm”.
- The event retains the highest severity level encountered.
Element override > Tile theme > Figure theme > 'default' preset
Each level fills in only the fields it specifies; unspecified fields cascade from the next level. The function DashboardTheme(...) merges FastSense theme fields with dashboard‑specific colours, fonts, etc.
-
Dashboard: simple tiled grid of
FastSenseinstances with optional live mode. - Dashboard Engine Guide: full‑widget dashboard with gauges, numbers, status indicators, multi‑page support, edit mode, and serializable JSON configurations.
DashboardEngine
├── DashboardToolbar — Top toolbar (Live, Edit, Save, Export, Sync)
├── DashboardLayout — 24‑column responsive grid with scrollable canvas
├── DashboardTheme — FastSenseTheme + dashboard‑specific tokens
├── DashboardBuilder — Edit‑mode overlay (drag/resize, palette, properties)
├── DashboardSerializer — JSON save/load and .m script export
└── Widgets (DashboardWidget subclasses)
├── FastSenseWidget — FastSense instance (Sensor/DataStore/inline)
├── GaugeWidget — Arc/donut/bar/thermometer gauge
├── NumberWidget — Big number with trend arrow
├── StatusWidget — Colored dot indicator
├── TextWidget — Static label or header
├── TableWidget — uitable display
├── RawAxesWidget — User‑supplied plot function
├── EventTimelineWidget — Colored event bars on timeline
├── GroupWidget — Collapsible panels, tabbed containers
├── MultiStatusWidget — Grid of sensor status dots
├── IconCardWidget — Mushroom‑style KPI card
├── ChipBarWidget — Row of health chips
├── SparklineCardWidget — KPI number + mini sparkline
├── BarChartWidget — Bar chart
├── ScatterWidget — Scatter plot
├── HeatmapWidget — Heatmap
├── HistogramWidget — Histogram
├── DividerWidget — Horizontal divider
└── ImageWidget — Image display
-
DashboardEngine.render()creates the figure. -
DashboardTheme(preset)generates the full theme struct. -
DashboardToolbarcreates the top toolbar panel. - Time control panel (dual sliders) is created at the bottom.
-
DashboardLayout.createPanels()computes grid positions, creates a scrollable canvas (if content exceeds viewport), and allocates a uipanel per widget. - Each widget’s
render(parentPanel)is called to populate its panel. -
updateGlobalTimeRange()scans widgets for data bounds and configures the time sliders.
When startLive() is called, a timer fires at LiveInterval seconds:
-
File‑watch: For sensor‑bound widgets, checks
LiveFilemodification date. - Each widget’s
refresh()is called. -
updateLiveTimeRange()expands time bounds from new data. - All widgets bound to global time are updated via
broadcastTimeRange. - A toolbar timestamp label is updated.
Clicking “Edit” in the toolbar creates a DashboardBuilder instance:
- A palette sidebar (left) shows draggable widget cards.
- A properties panel (right) shows selected widget settings.
- Drag/resize overlays appear on each widget panel.
- The content area narrows to accommodate sidebars.
- Mouse up/down/motion handlers manage drag‑and‑drop placement.
- Grid snap rounds positions to the nearest 24‑column grid cell.
DashboardSerializer handles round‑trip serialization:
-
Save: each widget’s
toStruct()produces a plain struct; the whole dashboard config is written as JSON. -
Load: JSON is decoded, each widget struct dispatched to the correct
fromStruct()static method. -
Multi‑page support:
DashboardPageobjects are serialized with their contained widgets. -
Export script: generates a portable
.mscript that reconstructs the dashboard usingDashboardEngineconstructor calls andaddWidgetstatements.
ConsoleProgressBar provides hierarchical progress feedback:
- Single‑line ASCII/Unicode bars with backspace‑based updates.
- Indentation support for nested operations (e.g., dock → tabs → tiles).
-
freeze()/finish()methods for permanent status lines.
- API Reference: FastPlot: Data cursor, crosshair, grid toggle, autoscale, export, live mode.
- DashboardToolbar: live toggle, edit mode, save/export, config, info.
-
NavigatorOverlay: Minimap with draggable zoom rectangle for
SensorDetailPlot. - HoverCrosshair: shows vertical cross‑hair and multi‑line data‑tip while hovering.
Multiple FastSense instances can share synchronized zoom/pan via LinkGroup strings. When one plot’s XLim changes, all plots in the same group update automatically. This works across FastSenseGrid tiles and FastSenseWidget dashboards.
In dashboard live mode, the “Follow” toggle attaches an XLim tail‑tracking behaviour: the time window slides to keep the latest data point visible, while preserving zoom width.
FastPlot Wiki
API Reference
Guides
Use Cases
Internals
Resources