<!-- GENERATED by scripts/build-llms.mjs from llms/charts.md — do not edit this file. -->

# `lr-histogram`

- **Import** `import '@aceshooting/lyra-ui/components/lr-histogram.js';` (stable tag alias; registers the tag)
- **Class** `LyraHistogram`, also available unregistered from `@aceshooting/lyra-ui/components/charts/chart/histogram.class.js`
- **Family** `components/charts/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** `chart.js`, `chartjs-plugin-annotation`, `chartjs-plugin-datalabels`, `chartjs-plugin-zoom` — see `llms/peers.md`
- **Themeable via** 16 parts, 37 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-histogram`

Bins `values` into `bins` equal-width buckets and renders as a bar chart (extends `LyraChart`,
`type` fixed to `'bar'`).

**Properties:**
- `bins: number = 10` — finite values are floored and clamped to 0–1,000 before allocation;
  non-finite values produce no buckets
- `values: number[] = []` (attribute: false)
- `seriesLabel: string = ''` (attribute `series-label`) — dataset label used for the
  legend/tooltip/table; empty falls back to localized "Frequency". Inherited `label` keeps its
  chart-wide accessible-name meaning.
- inherits `lr-chart`'s full surface, including `scaleType` (`scale-type`) and `annotations` —
  a logarithmic frequency axis and threshold/band markers both apply to a histogram
- `labels`/`datasets`/`type` are **derived, read-only** (installed as getter/setter pairs on the
  prototype; direct writes are silently ignored) — `labels`/`datasets` are computed from
  `values`/`bins` (memoized per instance, keyed by reference equality on `values` plus the
  normalized `bins`), and `type` always reads back `'bar'` regardless of any assignment. This
  specialist owns its controller because a non-bar type would contradict the derived distribution.
- All other `LyraChart` properties are inherited and usable: `description`, `grid`, `axes`, `compact`, `indexAxis`
  (`index-axis`), `hiddenDatasets`, `hiddenDatums`, `legendPosition` (`legend-position`),
  `legendMode` (`legend-mode`), `legendDisplay` (`legend-display`), `max`, `min`, `plugins`,
  `withoutAnimation` (`without-animation`), `withoutLegend` (`without-legend`), `withoutTooltip`
  (`without-tooltip`), `valueFormatter`, `formatter`, `tooltipTitleFormatter`,
  `tooltipFooterFormatter`, `area`, `zoom`, `config`, `height`, `xLabel` (`x-label`),
  `yLabel` (`y-label`), `y2Label` (`y2-label`), `beginAtZero` (`begin-at-zero`),
  `stacked`, `stackedAxes`, `dataLabels` (`data-labels`), `stackTotals` (`stack-totals`), `showDataTable`
  (`show-data-table`), `dataTableToggle` (`data-table-toggle`), `chartArea` (readonly).

**Methods:** `resetZoom()`, `refreshTheme()`, and `renderChart()` are inherited; `appendSamples(values,
maxSamples?)` appends finite raw samples and optionally retains only the newest samples.
`appendData()` remains a working compatibility adapter (no longer deprecated); prefer
`appendSamples()` for new code.

**Events:** `lr-zoom`, `lr-datum-activate`, `lr-point-click`, `lr-before-datum-visibility-change`
(cancelable), `lr-datum-visibility-change`, `lr-before-legend-visibility-change` (cancelable), and
`lr-legend-visibility-change` — inherited; `lr-point-click`'s `index` is the bucket index and
`label` the generated bucket range string (`"lo–hi"`, both bounds at one decimal place).
The inherited datum-visibility events apply only to radial controllers; the histogram keeps its
bar controller and dataset legend even with `legend-mode="datum"`.

**Slots:** default JSON configuration script, `data-table`, `center`.

**CSS parts:** `base`, `plot`, `canvas`, `legend`, `legend-item`, `legend-item-hidden`, `legend-swatch`,
`reset-zoom-button`, `description`, `notices`, `data-table`, `data-table-toggle`, `data-truncation`, `feature-warning`, `center`, `error` (neutral visible message
rendered in place of `canvas` when the optional `chart.js` peer dependency fails to load; the
failure transition is announced through the shared document-level light-DOM assertive sink —
inherited from `LyraChart`, unaffected by the binning logic).

**Themeable custom properties:** `--lr-chart-height`, `--lr-chart-grid-color`,
`--lr-chart-tick-color`, `--lr-chart-tick-font-size`, `--lr-chart-legend-color`, `--lr-chart-tooltip-bg`,
`--lr-chart-tooltip-text`, `--lr-chart-legend-item-hover-bg`,
`--lr-chart-legend-item-active-bg`, `--lr-chart-data-table-button-hover-bg`,
`--lr-chart-data-table-button-active-bg`, `--lr-chart-data-table-toggle-hover-bg`,
`--lr-chart-data-table-toggle-active-bg`, `--lr-chart-reset-zoom-button-hover-bg`,
`--lr-chart-reset-zoom-button-active-bg`, `--lr-chart-canvas-hover-outline-width`, and
`--lr-chart-canvas-hover-outline-color`, `--lr-chart-pattern-step`, plus `--lr-chart-legend-side-max` — inherited from `LyraChart`, identical in meaning, together with the
mirrored `--border-color-1`,
`--border-color-2`,
`--border-color-3`, `--border-color-4`, `--border-color-5`, `--border-color-6`, `--fill-color-1`,
`--fill-color-2`, `--fill-color-3`, `--fill-color-4`, `--fill-color-5`, `--fill-color-6`,
`--border-radius`, `--border-width`, `--grid-border-width`, `--grid-color`,
`--line-border-width`, and `--point-radius` hooks listed on the core chart.

**Optional peer deps:** the same `chart.js` peer, plus `chartjs-plugin-zoom` when `zoom` is set,
`chartjs-plugin-datalabels` when `data-labels` or `stack-totals` is set, and
`chartjs-plugin-annotation` when `annotations` contains a usable entry.

All of the above behave exactly as documented in `llms/components/lr-chart.md` — read that file for
their semantics, defaults, and gotchas.

```html
<lr-histogram bins="12"></lr-histogram>
<script>
  document.querySelector('lr-histogram').values = [1, 2, 2, 3, 5, 5, 5, 8, 13, 13];
</script>
```

**Known gotchas:**
- `bins <= 0` no longer crashes: `binValues()` now returns an empty bucket array for `binCount <= 0`
  (or empty `values`), so the histogram just renders with no bars instead of throwing.
- excessively large finite bin counts are capped at 1,000, preventing an attribute or direct
  property write from requesting an unbounded bucket array.
- non-finite samples in `values` are dropped before bucketing rather than corrupting bucket-index
  math; a constant domain produces one truthful single-value bucket, including at numeric extremes.
- raw `config.options` and plugins remain available, but `config.type` and `config.data` are ignored:
  the histogram owns its bar controller and derives all categories from `values`/`bins`.
- `values`/`bins`/`seriesLabel` changes join the inherited connected-and-visible redraw path. There is no
  second post-update refresh, so a same-tick disconnect cannot recreate Chart.js on a detached
  canvas and off-screen sample updates do not repaint it.
- calling `binValues()` directly (not through `<lr-histogram>`, which always passes its own
  resolved `effectiveLocale`) with an omitted `locale` (or `'auto'`) now resolves to the page's
  active `setLyraLocale()` locale instead of a hardcoded `'en'`, matching `utilities/format.ts`'s
  helpers; an app that never calls `setLyraLocale()` sees no change, and an explicit tag still wins.

---
