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

> 150 lines of code and 12 definitions.

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

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

## Definitions

- `pairRows` (lexical_declaration, line 12)
- `structureFindings` (lexical_declaration, line 19)
- `graphFindings` (lexical_declaration, line 147, exported)
- `uniformityFinding` (lexical_declaration, line 75)
- `compositionFinding` (lexical_declaration, line 102)
- `orderedFinding` (lexical_declaration, line 124)
- `LIFT_KEY` (lexical_declaration, line 10)
- `member` (lexical_declaration, line 76)
- `verdict` (lexical_declaration, line 77)
- `observed` (lexical_declaration, line 78)
- `{ composition }` (lexical_declaration, line 103)
- `{ ordered }` (lexical_declaration, line 125)

## 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)
- [core/normalizers/math.normalizer.ts](https://banes-lab.com/source/patterns/core/normalizers/math.normalizer.ts.md)

## Used by

- [core/plugins/representation.graph.plugin.ts](https://banes-lab.com/source/patterns/core/plugins/representation.graph.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/normalizers](https://banes-lab.com/anatomy/patterns/folder-patterns-core-normalizers.md)
- [core/plugins](https://banes-lab.com/anatomy/patterns/folder-patterns-core-plugins.md)

## Source

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

const LIFT_KEY = "lift";

const pairRows = function pairRows(
    rows: readonly [string[], number][],
    key: string,
): Readonly<Record<string, unknown>>[] {
    return rows.map(([pair, value]) => ({ [key]: key === LIFT_KEY ? fixedTo(value, ROUNDING.fine) : value, pair }));
};

const structureFindings = function structureFindings(field: string, summary: GraphSummary): Finding[] {
    return [
        explanationFinding({
            analysis: "relation",
            explained: GRAPH_STRINGS.cooccurrenceExplained,
            field,
            name: "cooccurrence",
            observation: {
                distinctTargets: summary.distinctTargets,
                edges: summary.edges,
                meanDegree: fixedTo(summary.meanDegree, ROUNDING.fine),
                topPairs: pairRows(summary.topPairs, "count"),
            },
            observed: GRAPH_STRINGS.cooccurrenceObserved(
                String(summary.distinctTargets),
                summary.meanDegree.toFixed(ROUNDING.standard),
            ),
            ontology: "relation",
            representation: "topology",
        }),
        explanationFinding({
            analysis: "relation",
            explained: GRAPH_STRINGS.liftExplained,
            field,
            name: LIFT_KEY,
            observation: { topLift: pairRows(summary.topLift, LIFT_KEY) },
            observed: GRAPH_STRINGS.liftObserved,
            ontology: "relation",
            representation: "probability",
        }),
        explanationFinding({
            analysis: "structure",
            explained: GRAPH_STRINGS.positionalExplained,
            field,
            name: "positional",
            observation: {
                positional: summary.positional.map(([index, value, count]) => ({ count, index, value })),
                slotPatterns: summary.slotPatterns.map(([index, from, to, count]) => ({ count, from, index, to })),
            },
            observed: GRAPH_STRINGS.positionalObserved,
            ontology: "structure",
            representation: "symbolic",
        }),
        explanationFinding({
            analysis: "structure",
            explained: GRAPH_STRINGS.combinatoricsExplained(summary.repeatRate.toFixed(ROUNDING.standard)),
            field,
            name: "combinatorics",
            observation: { distinctSets: summary.distinctSets, repeatRate: fixedTo(summary.repeatRate, ROUNDING.fine) },
            observed: GRAPH_STRINGS.combinatoricsObserved(String(summary.distinctSets)),
            ontology: "composition",
            representation: "computation",
        }),
    ];
};

const uniformityFinding = function uniformityFinding(field: string, summary: GraphSummary): Finding {
    const member = summary.memberUniformity;
    const verdict = member.uniform ? GRAPH_STRINGS.membersUniform : GRAPH_STRINGS.membersDepart;
    const observed = GRAPH_STRINGS.uniformityObserved(member.chiSquare.toFixed(ROUNDING.coarse), String(member.dof));
    return makeFinding({
        coordinate: coordinate({
            analysis: "statistical",
            ontology: "probability",
            reasoning: "explanation",
            representation: "probability",
        }),
        field,
        name: "member-uniformity",
        narrative: reasonOf(observed, GRAPH_STRINGS.uniformityExplained(verdict)),
        observation: {
            memberUniformity: member,
            topMembers: summary.topMembers.map(([value, count]) => ({ count, value })),
        },
        significance: {
            nullModel: NULL_MODEL_LABELS.memberUniformity,
            pValue: member.pValue,
            significant: !member.uniform,
            statistic: member.chiSquare,
        },
    });
};

const compositionFinding = function compositionFinding(field: string, summary: GraphSummary): Finding | null {
    const { composition } = summary;
    if (composition === null) {
        return null;
    }
    return explanationFinding({
        analysis: "structure",
        explained: GRAPH_STRINGS.compositionExplained(composition.highRatio.toFixed(ROUNDING.standard)),
        field,
        name: "composition",
        observation: {
            composition: {
                highRatio: fixedTo(composition.highRatio, ROUNDING.fine),
                oddRatio: fixedTo(composition.oddRatio, ROUNDING.fine),
            },
        },
        observed: GRAPH_STRINGS.compositionObserved(composition.oddRatio.toFixed(ROUNDING.standard)),
        ontology: "composition",
        representation: "number",
    });
};

const orderedFinding = function orderedFinding(field: string, summary: GraphSummary): Finding | null {
    const { ordered } = summary;
    if (ordered === null) {
        return null;
    }
    return explanationFinding({
        analysis: "space",
        explained: GRAPH_STRINGS.orderedExplained(ordered.symmetry.toFixed(ROUNDING.standard)),
        field,
        name: "ordered-domain",
        observation: {
            ordered: {
                adjacencyRate: fixedTo(ordered.adjacencyRate, ROUNDING.fine),
                bands: ordered.bands,
                symmetry: fixedTo(ordered.symmetry, ROUNDING.fine),
            },
        },
        observed: GRAPH_STRINGS.orderedObserved(ordered.adjacencyRate.toFixed(ROUNDING.standard)),
        ontology: "space",
        representation: "geometry",
    });
};

export const graphFindings = function graphFindings(field: string, summary: GraphSummary): Finding[] {
    return withSupport(
        [
            uniformityFinding(field, summary),
            ...structureFindings(field, summary),
            compositionFinding(field, summary),
            orderedFinding(field, summary),
        ],
        summary.records,
    );
};
```
