-
Notifications
You must be signed in to change notification settings - Fork 0
Dashboard Engine Guide
Build rich, interactive dashboards with mixed widget types, sensor bindings, JSON persistence, and a visual editor.
FastSense provides two dashboard systems:
| Feature | FastSenseGrid | DashboardEngine |
|---|---|---|
| Grid | Fixed rows x cols | 24-column responsive |
| Tile content | FastSense instances only | 8 widget types (plots, gauges, numbers, tables, etc.) |
| Persistence | None | JSON save/load + .m script export |
| Visual editor | No | Yes (drag/resize, palette, properties panel) |
| Scrolling | No | Auto-scrollbar when content overflows |
| Global time | No | Dual sliders controlling all widgets |
| Sensor binding | Via addSensor per tile | Direct widget property (auto-title, auto-units) |
| Live mode | Per-figure timer | Engine-level timer refreshing all widgets |
When to use FastSenseGrid: You need a simple tiled grid of FastSense time series plots with linked axes and a toolbar.
When to use DashboardEngine: You need mixed widget types (gauges, KPIs, tables, timelines), JSON persistence, or the visual editor.
setup;
% Create some data
x = linspace(0, 100, 10000);
y = sin(x) + 0.1 * randn(size(x));
% Build a dashboard
d = DashboardEngine('My First Dashboard');
d.Theme = 'dark';
d.addWidget('fastsense', 'Title', 'Signal', ...
'Position', [1 1 24 6], ...
'XData', x, 'YData', y);
d.addWidget('number', 'Title', 'Latest Value', ...
'Position', [1 7 8 2], ...
'StaticValue', y(end), 'Units', 'V');
d.render();DashboardEngine uses a 24-column grid. Widget positions are specified as:
Position = [col, row, width, height]
-
col: column (1-24), left to right -
row: row (1+), top to bottom -
width: number of columns to span (1-24) -
height: number of rows to span
Examples:
[1 1 24 4] % Full width, 4 rows tall, top of dashboard
[1 1 12 4] % Left half
[13 1 12 4] % Right half
[1 5 8 2] % Left third, row 5If a new widget overlaps an existing one, it is automatically pushed down to the next free row.
% Sensor-bound (recommended)
d.addWidget('fastsense', 'Position', [1 1 12 8], 'Sensor', mySensor);
% Inline data
d.addWidget('fastsense', 'Title', 'Raw', 'Position', [13 1 12 8], ...
'XData', x, 'YData', y);
% From MAT file
d.addWidget('fastsense', 'Title', 'File', 'Position', [1 9 24 6], ...
'File', 'data.mat', 'XVar', 'x', 'YVar', 'y');When bound to a Sensor, threshold rules apply automatically (resolved violations are shown). The widget title, X-axis label ('Time'), and Y-axis label (sensor Units or Name) are auto-derived.
d.addWidget('number', 'Title', 'Temperature', ...
'Position', [1 1 6 2], ...
'Sensor', sTemp, 'Units', 'degF', 'Format', '%.1f');Shows a large number with a trend arrow (up/down/flat) computed from recent sensor data. Layout: [Title | Value+Trend | Units].
d.addWidget('status', 'Title', 'Pump', ...
'Position', [7 1 5 2], ...
'Sensor', sTemp);Shows a colored dot (green/amber/red) and the sensor's latest value. Status is derived automatically from threshold rules.
d.addWidget('gauge', 'Title', 'Flow Rate', ...
'Position', [1 3 8 6], ...
'Sensor', sFlow, 'Range', [0 160], 'Units', 'L/min', ...
'Style', 'donut');Styles: 'arc' (default), 'donut', 'bar', 'thermometer'.
When Sensor-bound, range and units are auto-derived from threshold rules and sensor properties.
d.addWidget('text', 'Title', 'Plant Overview', ...
'Position', [1 1 6 1], ...
'Content', 'Line 4 - Shift A', 'FontSize', 16);% Static data
d.addWidget('table', 'Title', 'Alarm Log', ...
'Position', [13 9 12 4], ...
'ColumnNames', {'Time', 'Tag', 'Value'}, ...
'Data', {{'12:00', 'T-401', '85.2'; '12:05', 'P-201', '72.1'}});
% Sensor data (last N rows)
d.addWidget('table', 'Title', 'Recent Data', ...
'Position', [1 9 12 4], ...
'Sensor', sTemp, 'N', 15);d.addWidget('rawaxes', 'Title', 'Temperature Distribution', ...
'Position', [1 5 8 4], ...
'PlotFcn', @(ax) histogram(ax, tempData, 50, ...
'FaceColor', [0.31 0.80 0.64], 'EdgeColor', 'none'));The PlotFcn receives MATLAB axes as the first argument. When Sensor-bound, it also receives the Sensor object and optionally a time range.
% From event structs
events = struct('startTime', {0, 3600}, 'endTime', {3600, 7200}, ...
'label', {'Idle', 'Running'}, 'color', {[0.6 0.6 0.6], [0.2 0.7 0.3]});
d.addWidget('timeline', 'Title', 'Machine Mode', ...
'Position', [1 13 24 3], ...
'Events', events);
% From EventStore
d.addWidget('timeline', 'Title', 'Alarms', ...
'Position', [1 16 24 3], ...
'EventStoreObj', myEventStore);The recommended way to drive dashboard widgets is through Sensor objects. Create sensors with data, state channels, and threshold rules, then bind them to widgets:
% Create and configure sensor
sTemp = Sensor('T-401', 'Name', 'Temperature');
sTemp.X = t;
sTemp.Y = temp;
sc = StateChannel('machine');
sc.X = [0 7200 43200]; sc.Y = [0 1 0];
sTemp.addStateChannel(sc);
sTemp.addThresholdRule(struct('machine', 1), 78, ...
'Direction', 'upper', 'Label', 'Hi Warn');
sTemp.addThresholdRule(struct('machine', 1), 85, ...
'Direction', 'upper', 'Label', 'Hi Alarm');
sTemp.resolve();
% All of these auto-derive from the Sensor:
d.addWidget('fastsense', 'Sensor', sTemp, 'Position', [1 1 12 8]);
d.addWidget('number', 'Sensor', sTemp, 'Position', [13 1 6 2], 'Units', 'degF');
d.addWidget('status', 'Sensor', sTemp, 'Position', [19 1 6 2]);
d.addWidget('gauge', 'Sensor', sTemp, 'Position', [13 3 12 6]);Benefits of Sensor binding:
-
Title: auto-derived from
Sensor.NameorSensor.Key -
Units: auto-derived from
Sensor.Units -
Value: uses
Sensor.Y(end)for number, gauge, and status widgets - Thresholds: FastSenseWidget renders resolved thresholds and violations
- Status: StatusWidget checks the latest value against all threshold rules
-
Live refresh: calling
refresh()re-reads the sensor data
d.save('dashboard.json');The JSON file contains the dashboard name, theme, live interval, grid settings, and each widget's type, title, position, and data source.
d2 = DashboardEngine.load('dashboard.json');
d2.render();To re-bind Sensor objects on load, provide a resolver function:
d2 = DashboardEngine.load('dashboard.json', ...
'SensorResolver', @(name) SensorRegistry.get(name));
d2.render();d.exportScript('rebuild_dashboard.m');Generates a readable .m file with DashboardEngine constructor and addWidget calls that recreates the dashboard.
DashboardEngine uses DashboardTheme, which extends FastSenseTheme with dashboard-specific fields (widget backgrounds, border colors, status indicator colors, etc.).
d = DashboardEngine('My Dashboard');
d.Theme = 'dark'; % or 'light', 'industrial', 'scientific', 'ocean'
d.render();Available presets: 'default', 'dark', 'light', 'industrial', 'scientific', 'ocean'.
DashboardEngine supports live data updates via a timer that periodically calls refresh() on all widgets.
d = DashboardEngine('Live Monitor');
d.Theme = 'dark';
d.LiveInterval = 2; % refresh every 2 seconds
d.addWidget('fastsense', 'Sensor', sTemp, 'Position', [1 1 24 8]);
d.addWidget('number', 'Sensor', sTemp, 'Position', [1 9 12 2]);
d.render();
d.startLive(); % start periodic refresh
% ... later
d.stopLive(); % stopYou can also toggle live mode from the toolbar's Live button.
The time panel at the bottom of the dashboard has two sliders that control the visible time range across all widgets. Moving the sliders calls setTimeRange(tStart, tEnd) on each widget.
- FastSenseWidget: sets xlim on the FastSense axes
- EventTimelineWidget: sets xlim on the timeline axes
- RawAxesWidget: passes the time range to the PlotFcn
If a user manually zooms a specific widget, that widget detaches from global time (UseGlobalTime = false). Click the Sync button in the toolbar to re-attach all widgets.
Click the Edit button in the toolbar to enter edit mode:
- A palette sidebar appears on the left with buttons for each widget type
- A properties panel appears on the right showing the selected widget's settings
- Drag handles let you reposition widgets on the grid
- Resize handles let you change widget dimensions
- Click Apply to save property changes
- Click Done to exit edit mode
The editor snaps to the 24-column grid. You can change the widget's title, position, axis labels, and data source directly in the properties panel.
This example creates a process monitoring dashboard with sensor-bound widgets:
setup;
%% Generate data
rng(42);
N = 10000;
t = linspace(0, 86400, N); % 24 hours
% Machine mode state channel
scMode = StateChannel('machine');
scMode.X = [0, 3600, 7200, 28800, 36000];
scMode.Y = [0, 1, 1, 2, 1 ];
% Temperature sensor
sTemp = Sensor('T-401', 'Name', 'Temperature');
sTemp.X = t;
sTemp.Y = 74 + 3*sin(2*pi*t/3600) + randn(1,N)*1.2;
sTemp.addStateChannel(scMode);
sTemp.addThresholdRule(struct('machine', 1), 78, ...
'Direction', 'upper', 'Label', 'Hi Warn');
sTemp.addThresholdRule(struct('machine', 1), 85, ...
'Direction', 'upper', 'Label', 'Hi Alarm');
sTemp.resolve();
% Pressure sensor
sPress = Sensor('P-201', 'Name', 'Pressure');
sPress.X = t;
sPress.Y = 55 + 20*sin(2*pi*t/7200) + randn(1,N)*1.5;
sPress.addThresholdRule(struct(), 65, 'Direction', 'upper', 'Label', 'Hi Warn');
sPress.addThresholdRule(struct(), 70, 'Direction', 'upper', 'Label', 'Hi Alarm');
sPress.resolve();
%% Build dashboard
d = DashboardEngine('Process Monitoring — Line 4');
d.Theme = 'light';
d.LiveInterval = 5;
% Header row: text + numbers + status
d.addWidget('text', 'Title', 'Overview', 'Position', [1 1 4 2], ...
'Content', 'Line 4 — Shift A', 'FontSize', 16);
d.addWidget('number', 'Title', 'Temperature', 'Position', [5 1 5 2], ...
'Sensor', sTemp, 'Units', 'degF', 'Format', '%.1f');
d.addWidget('number', 'Title', 'Pressure', 'Position', [10 1 5 2], ...
'Sensor', sPress, 'Units', 'psi', 'Format', '%.0f');
d.addWidget('status', 'Title', 'Temp', 'Position', [15 1 5 2], ...
'Sensor', sTemp);
d.addWidget('status', 'Title', 'Press', 'Position', [20 1 5 2], ...
'Sensor', sPress);
% Plot row: sensor-bound FastSense widgets
d.addWidget('fastsense', 'Position', [1 3 12 8], 'Sensor', sTemp);
d.addWidget('fastsense', 'Position', [13 3 12 8], 'Sensor', sPress);
% Bottom row: gauge + custom plot
d.addWidget('gauge', 'Title', 'Pressure', 'Position', [1 11 8 6], ...
'Sensor', sPress, 'Range', [0 100], 'Units', 'psi');
d.addWidget('rawaxes', 'Title', 'Temp Distribution', 'Position', [9 11 8 6], ...
'PlotFcn', @(ax) histogram(ax, sTemp.Y, 50, ...
'FaceColor', [0.31 0.80 0.64], 'EdgeColor', 'none'));
d.render();
%% Save
d.save(fullfile(tempdir, 'process_dashboard.json'));- API Reference: Dashboard -- Full API reference for all dashboard classes
- API Reference: Sensors -- Sensor, StateChannel, ThresholdRule
- Live Mode Guide -- Live data polling
-
Examples --
example_dashboard_engine,example_dashboard_all_widgets
FastSense Wiki
API Reference
Guides
Use Cases
Internals
Resources