* Shared binning for `Histogram`/`BinCounts`. Returns the bin edges and the * count in each bin, or `undefined` if the input is not a usable finite * numeric collection. * * The final bin is *closed* on both ends (`[edge, lastEdge]`) so the dataset * maximum is counted — every interior bin is h
( xs: Expression, binsArg: Expression )
| 65 | } from '../boxed-expression/utils.js'; |
| 66 | import { numberLiteralOf, toInteger } from '../boxed-expression/numerics.js'; |
| 67 | import { randomCount } from './random-utils.js'; |
| 68 | import { checkDeadline } from '../../common/interruptible.js'; |
| 69 | import { findFit } from '../nonlinear-fit.js'; |
| 70 | import { |
| 71 | distributionMean, |
| 72 | distributionStandardDeviation, |
| 73 | distributionVariance, |
| 74 | isDistributionExpression, |
| 75 | } from './distributions.js'; |
| 76 | |
| 77 | // Geometric mean: |
| 78 | // Harmonic mean: |
| 79 | |
| 80 | /** |
| 81 | * Shared binning for `Histogram`/`BinCounts`. Returns the bin edges and the |
| 82 | * count in each bin, or `undefined` if the input is not a usable finite |
| 83 | * numeric collection. |
| 84 | * |
| 85 | * The final bin is *closed* on both ends (`[edge, lastEdge]`) so the dataset |
| 86 | * maximum is counted — every interior bin is half-open `[edge, next)`. |
| 87 | * (Previously every bin was half-open, so the max value, which equals the |
| 88 | * last edge, was never counted.) |
| 89 | */ |
| 90 | function computeBinning( |
| 91 | xs: Expression, |
| 92 | binsArg: Expression |
| 93 | ): { binEdges: number[]; counts: number[] } | undefined { |
| 94 | if (!xs.isFiniteCollection) return undefined; |
| 95 | |
| 96 | const data = (Array.from(xs.each()) as Expression[]) |
| 97 | .map((x) => x.re) |
| 98 | .filter(Number.isFinite); |
| 99 | if (data.length === 0) return undefined; |
| 100 | |
| 101 | const min = Math.min(...data); |
| 102 | const max = Math.max(...data); |
| 103 | |
| 104 | let binEdges: number[]; |
| 105 | if (binsArg.isCollection) { |
| 106 | binEdges = [...binsArg.each()].map((op) => op.re); |
| 107 | } else { |
| 108 | const binCount = toInteger(binsArg); |
| 109 | if (binCount === null || binCount <= 0) return undefined; |
| 110 | const binWidth = (max - min) / binCount; |
| 111 | binEdges = Array.from( |
| 112 | { length: binCount + 1 }, |
no test coverage detected