Problem / motivation
The Tag analysis family is broad — statistics (getStats, #223), order-statistics (percentile/quantile, #339), relational (correlate #340, lagCorrelation #341), data-cleaning (removeOutliers #343), comparison (compareWindows #358), plus the earlier derivative / integral / movingStat / exceedance / findGaps / resampleUniform / findPeaks / crossings / spectrum batch. But there is no value-distribution / bin-count primitive — no way to ask a Tag "how many samples fall in each value band?" programmatically.
The distribution is computed in the codebase, but only inside the render layer: HistogramWidget bins its bound series with histcounts (libs/Dashboard/HistogramWidget.m:63, auto bin count at :58-60). So the histogram exists as a widget but not as a Tag method. To get a distribution off a Tag today for a report table, a headless QA gate, or a script, you must pull [~, Y] = tag.getXY() (libs/SensorThreshold/Tag.m:123) and hand-roll histcounts(Y, ...) yourself — re-implementing the exact binning the widget already does. It is the missing order-stat/distribution sibling of getStats.
Proposed feature
A public, read-only histogram method on the Tag base class (concrete for every subclass via the abstract getXY) returning the binned distribution of the tag's values:
[counts, edges, centers] = tag.histogram() % auto bins
[counts, edges, centers] = tag.histogram(20) % 20 bins
[counts, edges, centers] = tag.histogram(edgesVector) % explicit edges
edges optional: default auto bin count max(10, round(sqrt(numel(Y)))) (matching HistogramWidget.m:58-60); an integer → bin count; a numeric vector → explicit bin edges.
- Drops NaNs from the value vector before binning.
- Returns raw
counts, the edges used, and convenience bin centers.
Rough sketch
- Lib/class:
libs/SensorThreshold/Tag.m — one new base method (all SensorTag/StateTag/DerivedTag/CompositeTag/MonitorTag inherit it, since each implements getXY).
- Public-API shape:
[counts, edges, centers] = histogram(obj, edges).
- Impl:
[~, Y] = obj.getXY(); Y = Y(~isnan(Y)); [counts, edges] = histcounts(Y, edges|nbins); centers = (edges(1:end-1)+edges(2:end))/2; — the same histcounts call the dashboard already uses, so no new dependency.
- Test: known series + explicit edges → expected counts; auto-edges shape; empty series → empty counts; NaN-drop verified.
Value
Distribution / bin-count is bread-and-butter for a sensor engineer producing a report ("samples per pressure band"), a headless QA gate, or any script that needs counts without opening a dashboard. It completes the numeric-summary surface alongside getStats (#223) and percentile (#339). Value is real but widget-adjacent — the visual need is already met by HistogramWidget; this is the programmatic/report axis of the same computation.
Constraints check
- Toolbox-free: ✅
histcounts is base MATLAB and already used in-repo (HistogramWidget.m:63); Octave-safe; a manual-accumulate fallback is trivial if ever needed.
- Backward-compatible: ✅ pure read-only addition — no serialization touched, no existing method changed, existing scripts and serialized dashboards/tags unaffected.
- Pure MATLAB/Octave: ✅ no MEX, no new files.
- Contract: ✅ works through the existing
Tag/getXY contract; no DashboardWidget/Tag base-contract change.
Effort estimate
S — one base method on Tag.m + one test. (Optional follow-ons, out of this slice: a getXYRange-scoped time-window overload, and a 'Normalization' mode count/probability/pdf.)
Open product decisions (flag for human)
- Return shape:
counts + edges + centers (proposed) vs a single struct.
- Whether a
'Normalization' option is in v1 or deferred — proposal keeps v1 to raw counts.
AI-proposed via /feature-scout — needs a human product decision before implementation.
Problem / motivation
The
Taganalysis family is broad — statistics (getStats, #223), order-statistics (percentile/quantile, #339), relational (correlate#340,lagCorrelation#341), data-cleaning (removeOutliers#343), comparison (compareWindows#358), plus the earlier derivative / integral / movingStat / exceedance / findGaps / resampleUniform / findPeaks / crossings / spectrum batch. But there is no value-distribution / bin-count primitive — no way to ask a Tag "how many samples fall in each value band?" programmatically.The distribution is computed in the codebase, but only inside the render layer:
HistogramWidgetbins its bound series withhistcounts(libs/Dashboard/HistogramWidget.m:63, auto bin count at:58-60). So the histogram exists as a widget but not as a Tag method. To get a distribution off a Tag today for a report table, a headless QA gate, or a script, you must pull[~, Y] = tag.getXY()(libs/SensorThreshold/Tag.m:123) and hand-rollhistcounts(Y, ...)yourself — re-implementing the exact binning the widget already does. It is the missing order-stat/distribution sibling ofgetStats.Proposed feature
A public, read-only
histogrammethod on theTagbase class (concrete for every subclass via the abstractgetXY) returning the binned distribution of the tag's values:edgesoptional: default auto bin countmax(10, round(sqrt(numel(Y))))(matchingHistogramWidget.m:58-60); an integer → bin count; a numeric vector → explicit bin edges.counts, theedgesused, and convenience bincenters.Rough sketch
libs/SensorThreshold/Tag.m— one new base method (allSensorTag/StateTag/DerivedTag/CompositeTag/MonitorTaginherit it, since each implementsgetXY).[counts, edges, centers] = histogram(obj, edges).[~, Y] = obj.getXY(); Y = Y(~isnan(Y)); [counts, edges] = histcounts(Y, edges|nbins); centers = (edges(1:end-1)+edges(2:end))/2;— the samehistcountscall the dashboard already uses, so no new dependency.Value
Distribution / bin-count is bread-and-butter for a sensor engineer producing a report ("samples per pressure band"), a headless QA gate, or any script that needs counts without opening a dashboard. It completes the numeric-summary surface alongside
getStats(#223) andpercentile(#339). Value is real but widget-adjacent — the visual need is already met byHistogramWidget; this is the programmatic/report axis of the same computation.Constraints check
histcountsis base MATLAB and already used in-repo (HistogramWidget.m:63); Octave-safe; a manual-accumulate fallback is trivial if ever needed.Tag/getXYcontract; noDashboardWidget/Tagbase-contract change.Effort estimate
S — one base method on
Tag.m+ one test. (Optional follow-ons, out of this slice: agetXYRange-scoped time-window overload, and a'Normalization'modecount/probability/pdf.)Open product decisions (flag for human)
counts + edges + centers(proposed) vs a single struct.'Normalization'option is in v1 or deferred — proposal keeps v1 to raw counts.AI-proposed via /feature-scout — needs a human product decision before implementation.