# core/converters/finding.distribution.converter.ts

> 139 lines of code and 14 definitions.

Tree: GovLab Patterns
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/patterns#file-patterns-core-converters-finding-distribution-converter-ts
Source text: https://banes-lab.com/source/patterns/core/converters/finding.distribution.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/patterns/core/converters.md), after [core/converters/finding.converter.ts](https://banes-lab.com/source/patterns/core/converters/finding.converter.ts.md) and before [core/converters/finding.graph.converter.ts](https://banes-lab.com/source/patterns/core/converters/finding.graph.converter.ts.md).

## Definitions

- `distributionFindings` (lexical_declaration, line 131, exported)
- `plainFindings` (lexical_declaration, line 47)
- `uniformityFinding` (lexical_declaration, line 27)
- `predictionFinding` (lexical_declaration, line 109)
- `frequencyFinding` (lexical_declaration, line 13)
- `seasonalityFinding` (lexical_declaration, line 92)
- `{ count, distinct, top, witnesses }` (lexical_declaration, line 14)
- `{ chiSquare, dof, pValue, uniform }` (lexical_declaration, line 28)
- `verdict` (lexical_declaration, line 29)
- `observed` (lexical_declaration, line 30)
- `{ temporal }` (lexical_declaration, line 93)
- `[top]` (lexical_declaration, line 110)
- `[mode]` (lexical_declaration, line 114)
- `explained` (lexical_declaration, line 115)

## Contained in

- [core/converters](https://banes-lab.com/anatomy/patterns/folder-patterns-core-converters.md)

## Uses

- [core/converters/finding.converter.ts](https://banes-lab.com/source/patterns/core/converters/finding.converter.ts.md)
- [core/factories/axis.factory.ts](https://banes-lab.com/source/patterns/core/factories/axis.factory.ts.md)
- [core/factories/finding.factory.ts](https://banes-lab.com/source/patterns/core/factories/finding.factory.ts.md)

## Used by

- [core/plugins/representation.distribution.plugin.ts](https://banes-lab.com/source/patterns/core/plugins/representation.distribution.plugin.ts.md)

## Linked from

- [core/converters](https://banes-lab.com/anatomy/patterns/folder-patterns-core-converters.md)
- [core/factories](https://banes-lab.com/anatomy/patterns/folder-patterns-core-factories.md)
- [core/plugins](https://banes-lab.com/anatomy/patterns/folder-patterns-core-plugins.md)

## Source

```typescript
import {
    DISTRIBUTION_STRINGS,
    NULL_MODEL_LABELS,
    PREDICTION_METHODS,
} from "#configuration/strings/representation.strings";
import { explanationFinding, makeFinding, reasonOf } from "#core/factories/finding.factory";
import type { DistributionSummary } from "#types/representation.types";
import type { Finding } from "#types/finding.types";
import { ROUNDING } from "#configuration/constants/math.constants";
import { coordinate } from "#core/factories/axis.factory";
import { withSupport } from "#core/converters/finding.converter";

const frequencyFinding = function frequencyFinding(field: string, summary: DistributionSummary): Finding {
    const { count, distinct, top, witnesses } = summary;
    return explanationFinding({
        analysis: "frequency",
        explained: DISTRIBUTION_STRINGS.freqExplained(summary.entropyBits.toFixed(ROUNDING.standard)),
        field,
        name: "frequency",
        observation: { count, distinct, top, witnesses },
        observed: DISTRIBUTION_STRINGS.freqObserved(String(count), String(distinct)),
        ontology: "probability",
        representation: "symbolic",
    });
};

const uniformityFinding = function uniformityFinding(field: string, summary: DistributionSummary): Finding {
    const { chiSquare, dof, pValue, uniform } = summary.uniformity;
    const verdict = uniform ? DISTRIBUTION_STRINGS.uniformUniform : DISTRIBUTION_STRINGS.uniformDeparts;
    const observed = DISTRIBUTION_STRINGS.uniformObserved(chiSquare.toFixed(ROUNDING.coarse), String(dof));
    const explained = DISTRIBUTION_STRINGS.uniformExplained(pValue.toFixed(ROUNDING.fine), verdict);
    return makeFinding({
        coordinate: coordinate({
            analysis: "statistical",
            ontology: "probability",
            reasoning: "explanation",
            representation: "probability",
        }),
        field,
        name: "uniformity",
        narrative: reasonOf(observed, explained),
        observation: { chiSquare, dof, pValue, uniform },
        significance: { nullModel: NULL_MODEL_LABELS.uniformity, pValue, significant: !uniform, statistic: chiSquare },
    });
};

const plainFindings = function plainFindings(field: string, summary: DistributionSummary): Finding[] {
    return [
        explanationFinding({
            analysis: "time",
            explained: DISTRIBUTION_STRINGS.recencyExplained,
            field,
            name: "recency",
            observation: { overdue: summary.overdue },
            observed: DISTRIBUTION_STRINGS.recencyObserved,
            ontology: "time",
            representation: "symbolic",
        }),
        explanationFinding({
            analysis: "frequency",
            explained: DISTRIBUTION_STRINGS.temperatureExplained,
            field,
            name: "temperature",
            observation: { cold: summary.cold, hot: summary.hot },
            observed: DISTRIBUTION_STRINGS.temperatureObserved,
            ontology: "change",
            representation: "number",
        }),
        explanationFinding({
            analysis: "change",
            explained: DISTRIBUTION_STRINGS.driftExplained,
            field,
            name: "drift",
            observation: { drift: summary.drift },
            observed: DISTRIBUTION_STRINGS.driftObserved,
            ontology: "change",
            representation: "number",
        }),
        explanationFinding({
            analysis: "complexity",
            explained: DISTRIBUTION_STRINGS.complexityExplained,
            field,
            name: "complexity",
            observation: { complexity: summary.complexity },
            observed: DISTRIBUTION_STRINGS.complexityObserved,
            ontology: "novelty",
            representation: "information-theory",
        }),
    ];
};

const seasonalityFinding = function seasonalityFinding(field: string, summary: DistributionSummary): Finding | null {
    const { temporal } = summary;
    if (temporal === null) {
        return null;
    }
    return explanationFinding({
        analysis: "time",
        explained: DISTRIBUTION_STRINGS.seasonalityExplained,
        field,
        name: "seasonality",
        observation: { temporal },
        observed: DISTRIBUTION_STRINGS.seasonalityObserved(temporal.first, temporal.last),
        ontology: "time",
        representation: "number",
    });
};

const predictionFinding = function predictionFinding(field: string, summary: DistributionSummary): Finding | null {
    const [top] = summary.top;
    if (!top) {
        return null;
    }
    const [mode] = top;
    const explained = DISTRIBUTION_STRINGS.predictionExplained(summary.modeAccuracy.toFixed(ROUNDING.standard));
    return makeFinding({
        coordinate: coordinate({
            analysis: "prediction",
            ontology: "probability",
            reasoning: "prediction",
            representation: "probability",
        }),
        field,
        name: "mode-prediction",
        narrative: reasonOf(DISTRIBUTION_STRINGS.predictionObserved(mode), explained),
        observation: { accuracy: summary.modeAccuracy, mode },
        prediction: { accuracy: summary.modeAccuracy, method: PREDICTION_METHODS.mode },
    });
};

export const distributionFindings = function distributionFindings(
    field: string,
    summary: DistributionSummary,
): Finding[] {
    return withSupport(
        [
            frequencyFinding(field, summary),
            uniformityFinding(field, summary),
            ...plainFindings(field, summary),
            seasonalityFinding(field, summary),
            predictionFinding(field, summary),
        ],
        summary.count,
    );
};
```
