Skip to content

HistogramWidget: add a Normalization mode (count / probability / pdf) #266

Description

@HanSur94

Problem / motivation

HistogramWidget plots raw counts and offers no way to normalize. refresh does:

[counts, edges] = histcounts(data, nBins);
centers = (edges(1:end-1) + edges(2:end)) / 2;
bar(obj.hAxes, centers, counts, 1);

(libs/Dashboard/HistogramWidget.m:63,67) and the public props are only
DataFcn / NumBins / ShowNormalFit / EdgeColor (:2-7) — verified
grep -ciE "normaliz|probability|pdf|density" over the file returns 1, a
doc-comment, not a normalization mode.

Two consequences:

  1. Distributions of different sample sizes can't be compared. Comparing the
    pressure distribution before vs. after a change, two recordings of unequal length,
    or two sensors sampled at different rates is a core exploratory move — but with raw
    counts the taller histogram is just the longer recording, not the more concentrated
    distribution.
  2. The existing ShowNormalFit Gaussian is hard-scaled to counts. The overlay
    already computes a density and rescales it back to the count axis —
    yFit = numel(data)*binWidth*(1/(sigma*sqrt(2*pi)))*exp(...) (:75-76). On a true
    density axis the fit would be a plain pdf and directly comparable across histograms.

Proposed feature

Add an opt-in Normalization property accepting 'count' (default), 'probability',
and 'pdf' ('density' alias) — the same vocabulary as MATLAB's own
histogram/histcounts, so it's instantly familiar.

  • 'count' — raw counts (today's behavior, unchanged).
  • 'probability'counts ./ sum(counts) (bar heights sum to 1).
  • 'pdf' / 'density'counts ./ (sum(counts) .* diff(edges)) (area = 1; robust to
    non-uniform bins).

Rough sketch

  • Lib / class: libs/Dashboard/HistogramWidget.m (single file).
  • Public API: Normalization = 'count' added to the public properties block.
  • Render: after histcounts, transform counts per the mode above before the
    bar(...) call; adapt the ShowNormalFit scale factor to match (keep
    numel(data)*binWidth for 'count', use binWidth for 'probability', drop both
    for 'pdf'); set the y-label to Count / Probability / Probability density.
    Computed by hand on the already-returned countsno reliance on histcounts'
    own 'Normalization' name-value, so it stays Octave-7-safe (the file already calls
    histcounts, confirming availability).
  • Serialize: emit s.normalization = obj.Normalization in toStruct (:121-130)
    when not 'count'; read it in fromStruct (:134-150) with default 'count' when
    absent.

Value

Medium-High. Cross-sample distribution comparison is a recurring sensor-analysis need,
and raw-count histograms actively mislead when N differs. 'pdf' also turns the
ShowNormalFit overlay into a genuine density curve, making the histogram and its fit
directly comparable.

Constraints check

  • Toolbox-free: ✅ plain arithmetic on counts + bar; no toolbox calls.
  • Backward-compatible: ✅ default 'count' is byte-identical to today; old
    serialized dashboards have no normalization key and load as 'count'.
  • Pure MATLAB/Octave: ✅ no histcounts 'Normalization' dependency; manual
    transform works on R2020b+ and Octave 7+.
  • Widget contract: ✅ purely additive property on HistogramWidget; no
    DashboardWidget base-class or layout change.

Effort estimate

S–M — one property + a ~3-line counts transform + a small ShowNormalFit
scale-factor branch + a y-label + a toStruct/fromStruct round-trip. One test:
'probability' ⇒ Σ(heights) = 1; 'pdf' ⇒ Σ(height·binwidth) ≈ 1; default 'count'
unchanged; value round-trips through serialization.

Dedup

Distinct from #251 (percentile overlay lines), #256 (cumulative/CDF display — a
running-sum transform, not per-bin rescale), #253 (axis labels), #211 (threshold
overlays). gh issue list --search "histogram normalization probability pdf density"
→ 0; no open PR touches HistogramWidget.

Note (separate bug, not part of this feature)

EdgeColor is a declared, serialized HistogramWidget prop that is never applied
the bar(...) call at :67 passes no 'EdgeColor'. A fixer touching this same bar
call could wire it at the same time, but it should be tracked/handled as a bug, not as
part of this enhancement.


AI-proposed via /feature-scout — needs a human product decision before implementation.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions