Skip to content

fix(dashboard): widget audit bugs — titles, IconCard, Image, resize hooks, time axis, axis labels#62

Merged
HanSur94 merged 8 commits intomainfrom
fix/dashboard-widget-audit
Apr 23, 2026
Merged

fix(dashboard): widget audit bugs — titles, IconCard, Image, resize hooks, time axis, axis labels#62
HanSur94 merged 8 commits intomainfrom
fix/dashboard-widget-audit

Conversation

@HanSur94
Copy link
Copy Markdown
Owner

Summary

Fixes 7 widget bugs uncovered during a visual audit of the dashboard engine:

  1. BarChart / Histogram / Scatter / Heatmap / ImageTitle was stored but never rendered in the GUI (only in ASCII/JSON). Added title(obj.hAxes, obj.Title) in render and re-apply after refresh() since bar()/plot() trigger newplot which clears axes titles.
  2. IconCardWidget showed -- forever when bound to a SensorTag. Root cause: constructor did obj.Sensor = [] after setting Tag, but Phase 1011 made Sensor a Dependent alias for Tag — so it wiped the Tag it had just assigned. Also added a Tag.Y(end) fallback when valueAt(now) misses (sensor time-axis vs serial-date mismatch).
  3. ImageWidget rendered peaks(80) as a solid dark block — used image() (raw CData) instead of imagesc(). Now branches on ndims == 2 to use imagesc + explicit colormap.
  4. No SizeChangedFcn on pixel-dependent widgets (ChipBar, IconCard, MultiStatus, Number, Sparkline, Status, Text) — aspect-scaled circles and auto-sized fonts became stale after any resize. Added relayout_ hook.
  5. FastSense / EventTimeline time axis showed raw seconds as ×10⁴ for 24h data. Added formatTimeAxis_ helper that renders HH:MM:SS ticks when the range exceeds 300 s.
  6. ScatterWidget missing axis labels. Auto-derives xlabel/ylabel from SensorX.Name (Units) / SensorY.Name (Units) with sensible fallbacks.
  7. GaugeWidget thermometer style crammed into 4-column panels — fixed DataAspectRatio removed, axes Position widened, labels no longer overlap.

Test plan

Verified interactively in MATLAB R2025b by rendering every widget type (number, iconcard, sparkline, gauge × 4 styles, status, multistatus, chipbar, text, divider, fastsense, rawaxes, barchart, histogram, scatter, heatmap, image, table, timeline, group) in a single dashboard and confirming each fix visually:

  • BarChart shows Shift Counts title above bars
  • Histogram shows Temp Histogram title above bins
  • Scatter shows Temp vs Pressure title + Temperature (°F) / Pressure (psi) axis labels
  • Image shows full-color peaks surface (was solid purple)
  • IconCard bound to pressure sensor shows 95.0 psi with red alarm-colored icon (was --)
  • FastSense x-axis shows 00:00:00, 02:46:40, …, 22:13:20 (was 0…9 ×10⁴)
  • Timeline x-axis shows HH:MM:SS ticks
  • Gauge thermometer fills narrow panel correctly with title, value, bar, bulb, min/max labels
  • 13/14 widget examples still pass headless MATLAB R2025b -batch runs

Files changed

15 files in libs/Dashboard/, +227 / -5 lines. No new dependencies, pure MATLAB, backward compatible.

🤖 Generated with Claude Code

- BarChart/Histogram/Scatter/Heatmap/Image widgets now render Title on axes
- Uses canonical title block from RawAxesWidget (fg color + WidgetTitleFontSize)
- ImageWidget keeps axes invisible but forces title Visible='on'
….Y(end)

- valueAt(now) returns [] when Tag.X is seconds (not serial date)
- Added Tag.Y(end) fallback mirroring the Sensor branch
- Preserves Units inheritance block unchanged
…rmap for 2D data

- Branch on ndims(imgData)==2: imagesc+parula for matrices, image() for RGB
- image() was clipping scalar-field matrices to colormap 1..64, rendering a dark block
- Title kept visible in refresh() too (idempotent with render() setting)
- Scaling property untouched (API compat)
…endent widgets

- ChipBar/IconCard/MultiStatus/Number/Sparkline/Status/Text now rescale on resize
- relayout_ tears down uicontrols+axes children and re-renders (idempotent)
- try/catch guards SizeChangedFcn for Octave versions that reject it
- New private methods block added to SparklineCardWidget and TextWidget
…imeAxis_

- FastSenseWidget: call formatTimeAxis_ after fp.render() in render/rebuildForTag_
  and after updateData() in refresh/update paths
- EventTimelineWidget: call formatTimeAxis_ at end of refresh()
- Helper converts numeric seconds to HH:MM:SS (range >= 1h) or MM:SS (< 1h)
  via datestr(xt/86400, fmt); no-op for ranges <= 300s
- Cosmetic-only: underlying numeric X data untouched, zoom may regenerate
  numeric ticks (known limitation)
…om SensorX/SensorY

- refresh() now calls xlabel/ylabel after plot when SensorX/SensorY set
- axisLabelForSensor_ helper builds 'Name (Units)' with graceful Key/empty fallback
- No-op when sensors unset (preserves current behavior)
BarChartWidget.refresh and HistogramWidget.refresh now re-apply the
title after bar()/plot() calls. Those plot commands internally call
newplot which clears the axes title, so the render-time title was
being wiped the moment data rendered.

GaugeWidget.renderThermometer drops the fixed DataAspectRatio [1 2 1]
and widens its axes Position ([0.15 0.10 0.7 0.80]) so the thermometer
fills a narrow 4-column panel instead of cramping the bulb, value, and
min/max labels on top of each other.

Follow-up to quick-task 260423-q3v audit bugs.
The constructor's "if Tag is set, clear Sensor" block was destructive:
after Phase 1011 migrated Sensor to a Dependent alias for Tag (see
DashboardWidget.set.Sensor), `obj.Sensor = []` resolves to
`obj.Tag = []` and wipes the Tag we just assigned. The refresh loop
then hits the empty-Tag branch and the widget shows "--" forever,
even with a fully populated SensorTag bound.

This was the real root cause of bug #2 in the widget audit — the
valueAt(now)/Y(end) fallback I added in quick-260423-q3v-02 never
ran because Tag was already empty by the time refresh fired.

Kept the Threshold clear (Threshold is a real independent property).
@HanSur94
Copy link
Copy Markdown
Owner Author

Code Review (independent)

Verdict: APPROVE WITH COMMENTS — no must-fix issues.

Per-commit risk

Commit Rating
title rendering (5 widgets) 🟢
IconCardWidget Tag.Y(end) fallback 🟢
ImageWidget imagesc branch 🟡
relayout_ + SizeChangedFcn 🟡
formatTimeAxis_ 🟡
title re-apply + thermometer 🟢
IconCardWidget constructor fix 🟢

Should-fix (follow-ups, not blocking this PR)

  1. relayout_ re-entrance risk — 7 widgets implement identical relayout_ that calls render(obj.hPanel) which re-wires SizeChangedFcn. Low-severity loop risk on R2022a+. Suggested: add IsRelayingOut_ guard flag on DashboardWidget base class + shared relayout_ method to eliminate 7-way duplication.
  2. formatTimeAxis_ assumes epoch-seconds implicitly. If X-axis is already datetime/datenum, labels will be wrong. Also datestr is deprecated in R2022b+; datetime+duration is forward-compatible. Consider XAxisUnits property.
  3. ImageWidget edge cases: logical arrays get parula (misleading for binary masks — gray would be better); sparse 2D matrices error in Octave (needs full()); all-NaN is silently blank.

Nits

  1. formatTimeAxis_ duplicated verbatim between FastSense and EventTimeline — move to libs/Dashboard/private/.
  2. getTheme() + title() called on every refresh() — minor waste; Dirty guard would avoid.
  3. title() called in both render() and refresh() for BarChart/Histogram — harmless but worth a comment.

Positive notes

  • Diagnosis of the Sensor = [] / Tag Dependent alias trap is precise — in-code comment is exemplary.
  • relayout_ pattern is consistent across all 7 widgets, making future refactor to base class trivial.
  • formatTimeAxis_ no-op for rangeSec <= 300 is a thoughtful UX choice.
  • axisLabelForSensor_ uses isprop defensively — correct for polymorphic Tag API.

Merging. Should-fix items tracked as follow-up work.

@HanSur94 HanSur94 merged commit 2e2537c into main Apr 23, 2026
12 of 13 checks passed
@HanSur94 HanSur94 deleted the fix/dashboard-widget-audit branch April 23, 2026 17:34
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'FastSense Performance'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.10.

Benchmark suite Current: 2fead09 Previous: c289374 Ratio
Downsample mean (1M) 3.823 ms 2.646 ms 1.44
Downsample mean std(1M) 0.066 ms 0.045 ms 1.47
Render mean (1M) 216.531 ms 192.157 ms 1.13
Zoom cycle mean std(1M) 3.548 ms 3.076 ms 1.15
Downsample mean (5M) 19.384 ms 12.9 ms 1.50
Downsample mean std(5M) 0.402 ms 0.033 ms 12.18
Render mean (5M) 231.994 ms 203.173 ms 1.14
Downsample mean (10M) 40.413 ms 26.213 ms 1.54
Instantiation mean (10M) 175.349 ms 156.791 ms 1.12
Render mean (10M) 246.043 ms 211.733 ms 1.16
Render mean std10M) 2.589 ms 1.062 ms 2.44
Downsample mean (50M) 204.273 ms 129.161 ms 1.58
Instantiation mean (50M) 1248.854 ms 1019.416 ms 1.23
Instantiation mean std50M) 14.289 ms 8.804 ms 1.62
Render mean (50M) 236.654 ms 208.936 ms 1.13
Downsample mean (100M) 410.17 ms 254.62 ms 1.61
Instantiation mean (100M) 2372.79 ms 2032.334 ms 1.17
Render mean (100M) 244.766 ms 216.216 ms 1.13
Downsample mean (500M) 2058.116 ms 1624.835 ms 1.27
Downsample mean ( std00M) 31.884 ms 0.709 ms 44.97
Instantiation mean ( std00M) 1534.64 ms 177.636 ms 8.64
Render mean ( std00M) 212.294 ms 1.913 ms 110.97
Dashboard live tick mean 1.239 ms 0.923 ms 1.34
Dashboard page switch mean 0.141 ms 0.081 ms 1.74
Dashboard page switch stdmean 0.074 ms 0.052 ms 1.42

This comment was automatically generated by workflow using github-action-benchmark.

CC: @HanSur94

HanSur94 added a commit that referenced this pull request Apr 23, 2026
Resolves conflicts from main's #61 ".planning/ exclusion" against the
milestone-archive work on this branch. All .planning/ files accepted
main's deletion — the repo now tracks planning locally only.

Also pulls in:
- #62 dashboard widget audit (titles, IconCard, Image, resize hooks, axis labels)
- #64 MATLAB test-suite migration for v2.0 Tag API

Phase 1013 code changes preserved:
- .github/workflows/refresh-mex-binaries.yml (new)
- 5 existing workflows rewired to reuse committed MEX
- libs/FastSense/mex_stamp.m (public scope)
- 27 prebuilt macOS ARM64 MEX binaries
- .gitignore MEX allow-list
- install.m stamp gate
HanSur94 added a commit that referenced this pull request Apr 23, 2026
Phase 1013: prebuilt MEX binaries for macOS/Windows/Linux so end users skip compilation.

Plans 01-06: stamp helper, gitignore allow-list, Octave subdir layout, macOS ARM64 binaries (27 files), refresh-mex-binaries.yml 7-platform matrix workflow, rewire 5 existing workflows.

Plan 07 (gap closure): git mv mex_stamp.m to public scope so install.m can reach it. Fixes dead stamp fast-path that private/ scoping had hidden.

Quick 260423-s4s: auto-trigger refresh workflow when mex_stamp.m formula itself changes (defensive).

v2.0 milestone archived — planning artifacts kept local only (per #61 repo policy).

Merge brings main's dashboard widget audit (#62) and MATLAB test migration (#64).
HanSur94 added a commit that referenced this pull request Apr 24, 2026
Resolves Phase 1012 (live event markers + click-to-details) against main's
concurrent evolution (~30 commits since the merge-base at 6502d30):

  Phase 1013  MEX binaries prebuilt
  Phase 1014  MATLAB test migration for v2.0 Tag API
  Phase 1015  showcase demo + theme trim
  Phase 1016  time slider rework
  PR #61      exclude .planning/ + .superpowers/ from repo (gitignore)
  PR #62      widget audit bugs
  PR #66      v2.0 test migration finish
  PR #69      per-widget render progress bar
  PR #72      Dashboard toolbar rework

Conflict resolution summary:

libs/Dashboard/FastSenseWidget.m (4 chunks, manual):
  - properties block: both sides added properties; kept all
    (ShowEventMarkers + EventStore + LiveViewMode)
  - refresh() + update() try blocks: kept both post-updateData actions
    (obj.refreshEventMarkers_() + obj.formatTimeAxis_(ax))
  - private methods: kept both new methods side-by-side
    (refreshEventMarkers_ and formatTimeAxis_)

libs/FastSense/FastSense.m — auto-merged cleanly (31 Phase-1012 markers + 13 main markers present)
libs/Dashboard/DashboardTheme.m — auto-merged cleanly (EventMarkerSize=8 preserved)

.planning/ + .superpowers/ — untracked via git rm -r --cached per main's PR #61
gitignore policy. Planning artifacts remain on disk for local reference.

No test runs yet; recommend running tests/suite/TestEventIsOpen,
TestMonitorTagOpenEvent, TestFastSenseEventClick, TestFastSenseWidgetEventMarkers
after pulling to verify the merged FastSenseWidget.m still satisfies
Phase-1012 contracts alongside main's FormatTimeAxis additions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant