semiotic 3.5.4 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +61 -3
- package/README.md +17 -10
- package/ai/dist/mcp-server.js +249 -2
- package/ai/schema.json +34 -9
- package/ai/system-prompt.md +1 -1
- package/dist/components/ai/audienceProfile.d.ts +90 -0
- package/dist/components/ai/audiences.d.ts +31 -0
- package/dist/components/ai/chartCapabilities.d.ts +55 -0
- package/dist/components/ai/chartCapabilityTypes.d.ts +196 -0
- package/dist/components/ai/diffProfile.d.ts +51 -0
- package/dist/components/ai/inferIntent.d.ts +24 -0
- package/dist/components/ai/intents.d.ts +34 -0
- package/dist/components/ai/profileData.d.ts +16 -0
- package/dist/components/ai/qualityFixtures.d.ts +2 -0
- package/dist/components/ai/qualityScorecard.d.ts +82 -0
- package/dist/components/ai/repairChartConfig.d.ts +73 -0
- package/dist/components/ai/streamingTypes.d.ts +64 -0
- package/dist/components/ai/suggestCharts.d.ts +76 -0
- package/dist/components/ai/suggestDashboard.d.ts +92 -0
- package/dist/components/ai/suggestStreamCharts.d.ts +34 -0
- package/dist/components/ai/suggestStretchCharts.d.ts +60 -0
- package/dist/components/ai/useChartSuggestions.d.ts +22 -0
- package/dist/components/charts/geo/ChoroplethMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/DistanceCartogram.capability.d.ts +2 -0
- package/dist/components/charts/geo/FlowMap.capability.d.ts +2 -0
- package/dist/components/charts/geo/ProportionalSymbolMap.capability.d.ts +2 -0
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/network/ChordDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/CirclePack.capability.d.ts +2 -0
- package/dist/components/charts/network/ForceDirectedGraph.capability.d.ts +2 -0
- package/dist/components/charts/network/OrbitDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/ProcessSankey.capability.d.ts +2 -0
- package/dist/components/charts/network/SankeyDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/TreeDiagram.capability.d.ts +2 -0
- package/dist/components/charts/network/Treemap.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/BoxPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DonutChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/DotPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/FunnelChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GaugeChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/GroupedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/Histogram.d.ts +4 -2
- package/dist/components/charts/ordinal/LikertChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/LikertChart.d.ts +1 -1
- package/dist/components/charts/ordinal/LikertChart.defaults.d.ts +1 -0
- package/dist/components/charts/ordinal/PieChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/RidgelinePlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/StackedBarChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwarmPlot.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/SwimlaneChart.capability.d.ts +2 -0
- package/dist/components/charts/ordinal/ViolinPlot.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHeatmap.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeHistogram.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeLineChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeSwarmChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/RealtimeWaterfallChart.capability.d.ts +2 -0
- package/dist/components/charts/realtime/TemporalHistogram.capability.d.ts +7 -0
- package/dist/components/charts/shared/chartSpecs.d.ts +0 -34
- package/dist/components/charts/xy/AreaChart.capability.d.ts +10 -0
- package/dist/components/charts/xy/BubbleChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/CandlestickChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/ConnectedScatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/DifferenceChart.capability.d.ts +8 -0
- package/dist/components/charts/xy/Heatmap.capability.d.ts +9 -0
- package/dist/components/charts/xy/LineChart.capability.d.ts +9 -0
- package/dist/components/charts/xy/MinimapChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/MultiAxisLineChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.capability.d.ts +2 -0
- package/dist/components/charts/xy/QuadrantChart.d.ts +5 -2
- package/dist/components/charts/xy/QuadrantChart.defaults.d.ts +2 -0
- package/dist/components/charts/xy/Scatterplot.capability.d.ts +2 -0
- package/dist/components/charts/xy/StackedAreaChart.capability.d.ts +2 -0
- package/dist/components/data/DataSummarizer.d.ts +45 -0
- package/dist/components/semiotic-ai.d.ts +35 -0
- package/dist/components/semiotic-xy.d.ts +1 -1
- package/dist/components/semiotic.d.ts +1 -1
- package/dist/components/store/useChartFocus.d.ts +43 -0
- package/dist/components/store/useChartInterrogation.d.ts +141 -0
- package/dist/ordinal.min.js +1 -1
- package/dist/ordinal.module.min.js +1 -1
- package/dist/semiotic-ai.d.ts +35 -0
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-utils.min.js +1 -1
- package/dist/semiotic-utils.module.min.js +1 -1
- package/dist/semiotic-xy.d.ts +1 -1
- package/dist/semiotic.d.ts +1 -1
- package/dist/semiotic.min.js +1 -1
- package/dist/semiotic.module.min.js +1 -1
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +13 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AudienceProfile } from "./audienceProfile";
|
|
2
|
+
/**
|
|
3
|
+
* Three example AudienceProfile shapes. Not authoritative — these are
|
|
4
|
+
* sketches based on rough industry stereotypes, useful for documentation,
|
|
5
|
+
* demos, and as starting points consumers can fork.
|
|
6
|
+
*
|
|
7
|
+
* To use one in production, copy it and tune to your audience's actual
|
|
8
|
+
* survey/telemetry data. Do not assume these defaults represent your team.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Executive audience — high familiarity with bar/line/pie/gauge,
|
|
12
|
+
* limited tolerance for unfamiliar chart shapes. Most likely to encounter
|
|
13
|
+
* dashboards built by analysts; not building their own.
|
|
14
|
+
*/
|
|
15
|
+
export declare const executivePersona: AudienceProfile;
|
|
16
|
+
/**
|
|
17
|
+
* Analyst audience — broader chart vocabulary, comfortable with
|
|
18
|
+
* distribution-shape and matrix-shape charts. Building dashboards for
|
|
19
|
+
* others; can read most things on first encounter.
|
|
20
|
+
*/
|
|
21
|
+
export declare const analystPersona: AudienceProfile;
|
|
22
|
+
/**
|
|
23
|
+
* Data scientist audience — comfortable with the full distribution-chart
|
|
24
|
+
* family, regression overlays, and density encodings. Will accept most
|
|
25
|
+
* exotic shapes if they're more honest about the data.
|
|
26
|
+
*/
|
|
27
|
+
export declare const dataScientistPersona: AudienceProfile;
|
|
28
|
+
/**
|
|
29
|
+
* Convenience map for consumers loading audience by name (e.g. from a config string).
|
|
30
|
+
*/
|
|
31
|
+
export declare const BUILT_IN_AUDIENCES: Record<string, AudienceProfile>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ChartCapability } from "./chartCapabilityTypes";
|
|
2
|
+
import { LineChartCapability } from "../charts/xy/LineChart.capability";
|
|
3
|
+
import { AreaChartCapability } from "../charts/xy/AreaChart.capability";
|
|
4
|
+
import { StackedAreaChartCapability } from "../charts/xy/StackedAreaChart.capability";
|
|
5
|
+
import { ScatterplotCapability } from "../charts/xy/Scatterplot.capability";
|
|
6
|
+
import { ConnectedScatterplotCapability } from "../charts/xy/ConnectedScatterplot.capability";
|
|
7
|
+
import { BubbleChartCapability } from "../charts/xy/BubbleChart.capability";
|
|
8
|
+
import { QuadrantChartCapability } from "../charts/xy/QuadrantChart.capability";
|
|
9
|
+
import { MultiAxisLineChartCapability } from "../charts/xy/MultiAxisLineChart.capability";
|
|
10
|
+
import { MinimapChartCapability } from "../charts/xy/MinimapChart.capability";
|
|
11
|
+
import { DifferenceChartCapability } from "../charts/xy/DifferenceChart.capability";
|
|
12
|
+
import { CandlestickChartCapability } from "../charts/xy/CandlestickChart.capability";
|
|
13
|
+
import { HeatmapCapability } from "../charts/xy/Heatmap.capability";
|
|
14
|
+
import { BarChartCapability } from "../charts/ordinal/BarChart.capability";
|
|
15
|
+
import { GroupedBarChartCapability } from "../charts/ordinal/GroupedBarChart.capability";
|
|
16
|
+
import { StackedBarChartCapability } from "../charts/ordinal/StackedBarChart.capability";
|
|
17
|
+
import { DotPlotCapability } from "../charts/ordinal/DotPlot.capability";
|
|
18
|
+
import { PieChartCapability } from "../charts/ordinal/PieChart.capability";
|
|
19
|
+
import { DonutChartCapability } from "../charts/ordinal/DonutChart.capability";
|
|
20
|
+
import { FunnelChartCapability } from "../charts/ordinal/FunnelChart.capability";
|
|
21
|
+
import { GaugeChartCapability } from "../charts/ordinal/GaugeChart.capability";
|
|
22
|
+
import { LikertChartCapability } from "../charts/ordinal/LikertChart.capability";
|
|
23
|
+
import { SwimlaneChartCapability } from "../charts/ordinal/SwimlaneChart.capability";
|
|
24
|
+
import { HistogramCapability } from "../charts/ordinal/Histogram.capability";
|
|
25
|
+
import { BoxPlotCapability } from "../charts/ordinal/BoxPlot.capability";
|
|
26
|
+
import { SwarmPlotCapability } from "../charts/ordinal/SwarmPlot.capability";
|
|
27
|
+
import { ViolinPlotCapability } from "../charts/ordinal/ViolinPlot.capability";
|
|
28
|
+
import { RidgelinePlotCapability } from "../charts/ordinal/RidgelinePlot.capability";
|
|
29
|
+
import { ForceDirectedGraphCapability } from "../charts/network/ForceDirectedGraph.capability";
|
|
30
|
+
import { SankeyDiagramCapability } from "../charts/network/SankeyDiagram.capability";
|
|
31
|
+
import { ChordDiagramCapability } from "../charts/network/ChordDiagram.capability";
|
|
32
|
+
import { ProcessSankeyCapability } from "../charts/network/ProcessSankey.capability";
|
|
33
|
+
import { TreeDiagramCapability } from "../charts/network/TreeDiagram.capability";
|
|
34
|
+
import { TreemapCapability } from "../charts/network/Treemap.capability";
|
|
35
|
+
import { CirclePackCapability } from "../charts/network/CirclePack.capability";
|
|
36
|
+
import { OrbitDiagramCapability } from "../charts/network/OrbitDiagram.capability";
|
|
37
|
+
import { ChoroplethMapCapability } from "../charts/geo/ChoroplethMap.capability";
|
|
38
|
+
import { ProportionalSymbolMapCapability } from "../charts/geo/ProportionalSymbolMap.capability";
|
|
39
|
+
import { FlowMapCapability } from "../charts/geo/FlowMap.capability";
|
|
40
|
+
import { DistanceCartogramCapability } from "../charts/geo/DistanceCartogram.capability";
|
|
41
|
+
/**
|
|
42
|
+
* Register a capability for a chart (built-in or third-party). Re-registering by
|
|
43
|
+
* component name replaces the previous descriptor — useful for overriding defaults.
|
|
44
|
+
*/
|
|
45
|
+
export declare function registerChartCapability(capability: ChartCapability): void;
|
|
46
|
+
/** Remove a previously-registered capability. Does not affect built-ins. */
|
|
47
|
+
export declare function unregisterChartCapability(component: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Current capability list — built-ins, then user-registered, with user-registered
|
|
50
|
+
* overriding built-ins by component name.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getCapabilities(): ReadonlyArray<ChartCapability>;
|
|
53
|
+
/** Look up a capability by component name. */
|
|
54
|
+
export declare function getCapability(component: string): ChartCapability | undefined;
|
|
55
|
+
export { LineChartCapability, AreaChartCapability, StackedAreaChartCapability, ScatterplotCapability, ConnectedScatterplotCapability, BubbleChartCapability, QuadrantChartCapability, MultiAxisLineChartCapability, MinimapChartCapability, DifferenceChartCapability, CandlestickChartCapability, HeatmapCapability, BarChartCapability, GroupedBarChartCapability, StackedBarChartCapability, DotPlotCapability, PieChartCapability, DonutChartCapability, FunnelChartCapability, GaugeChartCapability, LikertChartCapability, SwimlaneChartCapability, HistogramCapability, BoxPlotCapability, SwarmPlotCapability, ViolinPlotCapability, RidgelinePlotCapability, ForceDirectedGraphCapability, SankeyDiagramCapability, ChordDiagramCapability, ProcessSankeyCapability, TreeDiagramCapability, TreemapCapability, CirclePackCapability, OrbitDiagramCapability, ChoroplethMapCapability, ProportionalSymbolMapCapability, FlowMapCapability, DistanceCartogramCapability, };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Datum } from "../charts/shared/datumTypes";
|
|
2
|
+
import type { DataSummary } from "../data/DataSummarizer";
|
|
3
|
+
import type { IntentId } from "./intents";
|
|
4
|
+
/**
|
|
5
|
+
* Chart family — high-level taxonomy used for filtering and intent matching.
|
|
6
|
+
*/
|
|
7
|
+
export type ChartFamily = "time-series" | "categorical" | "distribution" | "relationship" | "flow" | "network" | "hierarchy" | "geo" | "realtime" | "custom";
|
|
8
|
+
/**
|
|
9
|
+
* Where a chart is imported from. Used by generators to emit correct import paths.
|
|
10
|
+
*/
|
|
11
|
+
export type ChartImportPath = "semiotic/xy" | "semiotic/ordinal" | "semiotic/network" | "semiotic/geo" | "semiotic/realtime" | "semiotic/ai" | "semiotic";
|
|
12
|
+
/**
|
|
13
|
+
* Familiarity/accuracy/precision rubric (1-5 each).
|
|
14
|
+
* Familiarity = how well-known the chart is to a general audience.
|
|
15
|
+
* Accuracy = how faithfully it represents the underlying data.
|
|
16
|
+
* Precision = how readable individual values are.
|
|
17
|
+
*/
|
|
18
|
+
export interface ChartRubric {
|
|
19
|
+
familiarity: number;
|
|
20
|
+
accuracy: number;
|
|
21
|
+
precision: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The kind of value a field holds, used for axis fitness.
|
|
25
|
+
*/
|
|
26
|
+
export type FieldKind = "numeric" | "categorical" | "date" | "boolean" | "unknown";
|
|
27
|
+
/**
|
|
28
|
+
* A candidate field for a given role (x, y, series, etc.), with a quality score.
|
|
29
|
+
*/
|
|
30
|
+
export interface FieldCandidate {
|
|
31
|
+
field: string;
|
|
32
|
+
kind: FieldKind;
|
|
33
|
+
/** 0..1 — how good this field is for the role being considered. */
|
|
34
|
+
quality: number;
|
|
35
|
+
/** Field-level stats for downstream scorers. */
|
|
36
|
+
distinctCount?: number;
|
|
37
|
+
/** True if the field's values are strictly increasing in row order. */
|
|
38
|
+
monotonic?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Profile of a dataset for chart-fitness scoring. Extends DataSummary with
|
|
42
|
+
* shape inference (axis candidates, structure detection, primary roles).
|
|
43
|
+
*/
|
|
44
|
+
export interface ChartDataProfile extends DataSummary {
|
|
45
|
+
/** Original rows (read-only); used by capabilities to compute their own stats. */
|
|
46
|
+
data: ReadonlyArray<Datum>;
|
|
47
|
+
/** Candidate fields per role, sorted best-first. */
|
|
48
|
+
candidates: {
|
|
49
|
+
x: FieldCandidate[];
|
|
50
|
+
y: FieldCandidate[];
|
|
51
|
+
size: FieldCandidate[];
|
|
52
|
+
category: FieldCandidate[];
|
|
53
|
+
series: FieldCandidate[];
|
|
54
|
+
time: FieldCandidate[];
|
|
55
|
+
};
|
|
56
|
+
/** Best-guess primary assignment per role (the top candidate, if any). */
|
|
57
|
+
primary: {
|
|
58
|
+
x?: string;
|
|
59
|
+
y?: string;
|
|
60
|
+
size?: string;
|
|
61
|
+
category?: string;
|
|
62
|
+
series?: string;
|
|
63
|
+
time?: string;
|
|
64
|
+
};
|
|
65
|
+
/** Distinct count of the primary category field, if any. */
|
|
66
|
+
categoryCount?: number;
|
|
67
|
+
/** Distinct count of the primary series field, if any. */
|
|
68
|
+
seriesCount?: number;
|
|
69
|
+
/** Distinct count of the primary x field, if any. */
|
|
70
|
+
uniqueXCount?: number;
|
|
71
|
+
/** True when some x value appears in more than one row (suggests aggregation). */
|
|
72
|
+
hasRepeatedX: boolean;
|
|
73
|
+
/** True when the primary x candidate is monotonic. */
|
|
74
|
+
monotonicX: boolean;
|
|
75
|
+
/** True when there is at least one date-typed candidate. */
|
|
76
|
+
hasTimeAxis: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* How the primary x role was inferred. Capabilities can use this to detect
|
|
79
|
+
* the "scatter fallback" case (x picked only because there were 2+ numerics,
|
|
80
|
+
* not because the field is genuinely an x-axis) and decline to recommend
|
|
81
|
+
* themselves for trend-shaped intents.
|
|
82
|
+
*
|
|
83
|
+
* • "time" — explicit date/time field
|
|
84
|
+
* • "named" — numeric whose name matches an x-pattern (month, year, index, …)
|
|
85
|
+
* • "scatter"— filled in via the two-numeric scatter fallback; weak signal
|
|
86
|
+
* • "none" — no x role inferred
|
|
87
|
+
*/
|
|
88
|
+
xProvenance: "time" | "named" | "scatter" | "none";
|
|
89
|
+
/** Source dataset looks like a hierarchy (had a `children` array at root). */
|
|
90
|
+
hasHierarchy: boolean;
|
|
91
|
+
/** Source dataset looks like a node/edge graph. */
|
|
92
|
+
hasNetwork: boolean;
|
|
93
|
+
/** Source dataset looks like GeoJSON (FeatureCollection). */
|
|
94
|
+
hasGeo: boolean;
|
|
95
|
+
/** Extracted network payload when hasNetwork is true. */
|
|
96
|
+
network?: {
|
|
97
|
+
nodes: ReadonlyArray<Datum>;
|
|
98
|
+
edges: ReadonlyArray<Datum>;
|
|
99
|
+
};
|
|
100
|
+
/** Extracted hierarchy root when hasHierarchy is true. */
|
|
101
|
+
hierarchy?: Datum;
|
|
102
|
+
/** Extracted GeoJSON FeatureCollection when hasGeo is true. */
|
|
103
|
+
geo?: {
|
|
104
|
+
features: ReadonlyArray<Datum>;
|
|
105
|
+
points?: ReadonlyArray<Datum>;
|
|
106
|
+
flows?: ReadonlyArray<Datum>;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* An intent scorer is either a static 0..5 score or a function evaluated against the profile.
|
|
111
|
+
*/
|
|
112
|
+
export type IntentScorer = number | ((profile: ChartDataProfile) => number);
|
|
113
|
+
/**
|
|
114
|
+
* Variant — a configuration of the chart that meaningfully changes what it's good for.
|
|
115
|
+
*
|
|
116
|
+
* Variants compose into suggestions. The `intentDeltas` are additive against the
|
|
117
|
+
* base capability's intent scores (clamped to 0..5 by the engine).
|
|
118
|
+
*/
|
|
119
|
+
export interface ChartVariant {
|
|
120
|
+
key: string;
|
|
121
|
+
label: string;
|
|
122
|
+
description?: string;
|
|
123
|
+
/** Props to merge into the base chart props. */
|
|
124
|
+
props: Record<string, unknown>;
|
|
125
|
+
/** Style/role tags (used by consumers like vizmart for filtering). */
|
|
126
|
+
tags?: ReadonlyArray<string>;
|
|
127
|
+
/** Per-intent additive score deltas (e.g. {"trend": +1, "outlier-detection": -2}). */
|
|
128
|
+
intentDeltas?: Partial<Record<IntentId, number>>;
|
|
129
|
+
/** Rubric deltas — usually small, e.g. smoothing trades precision for familiarity. */
|
|
130
|
+
rubricDeltas?: Partial<ChartRubric>;
|
|
131
|
+
/** Caveats specific to this variant — surfaced in suggestion.caveats. */
|
|
132
|
+
caveats?: ReadonlyArray<string>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Result of a capability's `fits()` gate. `null` means the chart fits. A string
|
|
136
|
+
* is the human-readable reason it doesn't, used for diagnostics and reasoning.
|
|
137
|
+
*/
|
|
138
|
+
export type FitResult = null | string;
|
|
139
|
+
/**
|
|
140
|
+
* The capability descriptor each chart ships alongside itself.
|
|
141
|
+
*
|
|
142
|
+
* Charts that declare a capability participate in `suggestCharts`, `useChartSuggestions`,
|
|
143
|
+
* and the `interrogateChart` MCP tool's recommendation surface.
|
|
144
|
+
*/
|
|
145
|
+
export interface ChartCapability {
|
|
146
|
+
component: string;
|
|
147
|
+
family: ChartFamily;
|
|
148
|
+
importPath: ChartImportPath;
|
|
149
|
+
/** Base rubric, before variant/profile adjustments. */
|
|
150
|
+
rubric: ChartRubric;
|
|
151
|
+
/**
|
|
152
|
+
* Hard requirements gate. Return null if the chart can render this profile,
|
|
153
|
+
* or a human-readable string explaining why not (e.g. "no numeric y candidate").
|
|
154
|
+
*/
|
|
155
|
+
fits: (profile: ChartDataProfile) => FitResult;
|
|
156
|
+
/**
|
|
157
|
+
* Per-intent suitability score (0..5). Missing intents default to 0.
|
|
158
|
+
* Values may be functions for profile-aware scoring.
|
|
159
|
+
*/
|
|
160
|
+
intentScores: Partial<Record<IntentId, IntentScorer>>;
|
|
161
|
+
/**
|
|
162
|
+
* Variants — different settings that change what the chart is useful for.
|
|
163
|
+
* Suggestion engine emits one suggestion per (capability × variant) pair.
|
|
164
|
+
* If empty, the engine still emits a base suggestion.
|
|
165
|
+
*/
|
|
166
|
+
variants?: ReadonlyArray<ChartVariant>;
|
|
167
|
+
/** Caveats independent of variants (e.g. "log scale skipped for negative values"). */
|
|
168
|
+
caveats?: (profile: ChartDataProfile) => ReadonlyArray<string>;
|
|
169
|
+
/**
|
|
170
|
+
* Build the props you'd pass to this chart for this dataset. Should produce
|
|
171
|
+
* a runnable config (accessor names, etc.) so consumers can `<Component {...props}>`.
|
|
172
|
+
*/
|
|
173
|
+
buildProps: (profile: ChartDataProfile, variant?: ChartVariant) => Record<string, unknown>;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* One suggestion produced by `suggestCharts`. Consumers render this as a card,
|
|
177
|
+
* pass it to an LLM for re-ranking, or hand the props straight to the chart.
|
|
178
|
+
*/
|
|
179
|
+
export interface Suggestion {
|
|
180
|
+
component: string;
|
|
181
|
+
family: ChartFamily;
|
|
182
|
+
importPath: ChartImportPath;
|
|
183
|
+
variant?: ChartVariant;
|
|
184
|
+
/** Composite score for the ranking intent(s), 0..5. */
|
|
185
|
+
score: number;
|
|
186
|
+
/** Per-intent scores after variant deltas. */
|
|
187
|
+
intentScores: Partial<Record<IntentId, number>>;
|
|
188
|
+
/** Rubric after variant/profile adjustments. */
|
|
189
|
+
rubric: ChartRubric;
|
|
190
|
+
/** Narrative reasons this chart fits — suitable for tooltips or LLM context. */
|
|
191
|
+
reasons: ReadonlyArray<string>;
|
|
192
|
+
/** Gotchas / things to be careful about. */
|
|
193
|
+
caveats: ReadonlyArray<string>;
|
|
194
|
+
/** Ready-to-spread props. */
|
|
195
|
+
props: Record<string, unknown>;
|
|
196
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ChartDataProfile, FieldKind } from "./chartCapabilityTypes";
|
|
2
|
+
export type PrimaryRole = "x" | "y" | "size" | "category" | "series" | "time";
|
|
3
|
+
export interface FieldTypeChange {
|
|
4
|
+
field: string;
|
|
5
|
+
from: FieldKind | "unknown";
|
|
6
|
+
to: FieldKind | "unknown";
|
|
7
|
+
}
|
|
8
|
+
export interface PrimaryRoleChange {
|
|
9
|
+
role: PrimaryRole;
|
|
10
|
+
from: string | undefined;
|
|
11
|
+
to: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface ProfileDiff {
|
|
14
|
+
/** Row count change (b.rowCount - a.rowCount). */
|
|
15
|
+
rowCountChange: number;
|
|
16
|
+
/** Fields present in b but not in a. */
|
|
17
|
+
added: ReadonlyArray<string>;
|
|
18
|
+
/** Fields present in a but not in b. */
|
|
19
|
+
removed: ReadonlyArray<string>;
|
|
20
|
+
/** Fields whose inferred type changed. */
|
|
21
|
+
typeChanges: ReadonlyArray<FieldTypeChange>;
|
|
22
|
+
/** Primary role re-assignments (e.g. x switched from "month" to "date"). */
|
|
23
|
+
primaryChanges: ReadonlyArray<PrimaryRoleChange>;
|
|
24
|
+
/** Suggestion components that fit a but not b. */
|
|
25
|
+
becameUnfit: ReadonlyArray<string>;
|
|
26
|
+
/** Suggestion components that fit b but not a. */
|
|
27
|
+
becameFit: ReadonlyArray<string>;
|
|
28
|
+
/** True when no observable change was detected. */
|
|
29
|
+
unchanged: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Compare two profiles and report what changed plus how the change affects
|
|
33
|
+
* chart suitability. Useful for:
|
|
34
|
+
*
|
|
35
|
+
* • "Why does my dashboard look different after the data refreshed?"
|
|
36
|
+
* • Editor warnings when a CSV upload would change the visible charts.
|
|
37
|
+
* • CI checks that flag when a fixture migration affects descriptor coverage.
|
|
38
|
+
*
|
|
39
|
+
* Doesn't compute *which suggestions ranked first* (that requires intent +
|
|
40
|
+
* full suggestCharts). Reports only structural deltas — added/removed fields,
|
|
41
|
+
* type changes, primary role re-assignments, fit set changes.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const a = profileData(yesterdaysData)
|
|
45
|
+
* const b = profileData(todaysData)
|
|
46
|
+
* const diff = diffProfile(a, b)
|
|
47
|
+
* if (diff.becameUnfit.length) {
|
|
48
|
+
* console.warn(`These charts no longer fit: ${diff.becameUnfit.join(", ")}`)
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
export declare function diffProfile(a: ChartDataProfile, b: ChartDataProfile): ProfileDiff;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IntentId } from "./intents";
|
|
2
|
+
export interface InferIntentResult {
|
|
3
|
+
intent: IntentId;
|
|
4
|
+
/** 1..5 score for ranking ties. Higher = stronger match. */
|
|
5
|
+
confidence: number;
|
|
6
|
+
/** Other plausible intents, sorted by confidence. */
|
|
7
|
+
alternates: ReadonlyArray<{
|
|
8
|
+
intent: IntentId;
|
|
9
|
+
confidence: number;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Map a natural-language query to a built-in intent. Returns `null` when no
|
|
14
|
+
* pattern matches with meaningful confidence.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* inferIntent("when did revenue peak?")
|
|
18
|
+
* // → { intent: "outlier-detection", confidence: 4, alternates: [] }
|
|
19
|
+
* inferIntent("show me the trend over time")
|
|
20
|
+
* // → { intent: "trend", confidence: 4, alternates: [] }
|
|
21
|
+
* inferIntent("hello")
|
|
22
|
+
* // → null
|
|
23
|
+
*/
|
|
24
|
+
export declare function inferIntent(query: string): InferIntentResult | null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical intent taxonomy for chart suggestion / interrogation.
|
|
3
|
+
*
|
|
4
|
+
* An "intent" is what the user is trying to *see* in the data. Charts declare how
|
|
5
|
+
* well they serve each intent in their capability descriptor. The suggestion engine
|
|
6
|
+
* filters and ranks by intent.
|
|
7
|
+
*
|
|
8
|
+
* The taxonomy is fixed but extensible: consumers can call `registerIntent` to add
|
|
9
|
+
* domain-specific intents at runtime. The IntentId type stays union-of-known so
|
|
10
|
+
* built-in code remains type-safe; registered intents are addressable as plain strings.
|
|
11
|
+
*/
|
|
12
|
+
export type BuiltInIntentId = "trend" | "compare-series" | "compare-categories" | "rank" | "part-to-whole" | "distribution" | "correlation" | "flow" | "hierarchy" | "geo" | "outlier-detection" | "composition-over-time" | "change-detection";
|
|
13
|
+
/**
|
|
14
|
+
* Any intent — built-in or user-registered. Custom intents are plain strings.
|
|
15
|
+
*/
|
|
16
|
+
export type IntentId = BuiltInIntentId | (string & {});
|
|
17
|
+
export interface IntentDescriptor {
|
|
18
|
+
id: IntentId;
|
|
19
|
+
label: string;
|
|
20
|
+
description: string;
|
|
21
|
+
/** Soft hint of which chart family typically serves this intent. */
|
|
22
|
+
familyHint?: "time-series" | "categorical" | "distribution" | "relationship" | "flow" | "network" | "hierarchy" | "geo";
|
|
23
|
+
}
|
|
24
|
+
/** Get an intent descriptor by id, or undefined if not registered. */
|
|
25
|
+
export declare function getIntent(id: IntentId): IntentDescriptor | undefined;
|
|
26
|
+
/** All currently-registered intents (built-in + user-added). */
|
|
27
|
+
export declare function listIntents(): IntentDescriptor[];
|
|
28
|
+
/**
|
|
29
|
+
* Register a custom intent at runtime. Idempotent — re-registering with the same id
|
|
30
|
+
* replaces the descriptor.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerIntent(intent: IntentDescriptor): void;
|
|
33
|
+
/** Sentinel set used by capability authors to opt out of an intent without misspelling. */
|
|
34
|
+
export declare const BUILT_IN_INTENT_IDS: ReadonlySet<BuiltInIntentId>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Datum } from "../charts/shared/datumTypes";
|
|
2
|
+
import type { ChartDataProfile } from "./chartCapabilityTypes";
|
|
3
|
+
export interface ProfileDataOptions {
|
|
4
|
+
/** If you have access to the raw input (which might be {nodes, edges} or GeoJSON), pass it for structure detection. */
|
|
5
|
+
rawInput?: unknown;
|
|
6
|
+
/** Override the field used as the primary series, useful when the heuristic guesses wrong. */
|
|
7
|
+
seriesField?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build a ChartDataProfile from row data. Extends DataSummary with shape inference —
|
|
11
|
+
* candidate fields per role, distinct counts, monotonicity, and structure detection.
|
|
12
|
+
*
|
|
13
|
+
* Designed to be called once per dataset; the result is what `suggestCharts` and
|
|
14
|
+
* capability evaluators consume.
|
|
15
|
+
*/
|
|
16
|
+
export declare function profileData(data: ReadonlyArray<Datum> | null | undefined, options?: ProfileDataOptions): ChartDataProfile;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Datum } from "../charts/shared/datumTypes";
|
|
2
|
+
import type { ChartCapability } from "./chartCapabilityTypes";
|
|
3
|
+
import type { IntentId } from "./intents";
|
|
4
|
+
/**
|
|
5
|
+
* One canonical fixture in a scorecard run. Pair canonical data with the
|
|
6
|
+
* intents/components a human expert would expect to win on it. Use null
|
|
7
|
+
* `expected` when the fixture is a stress-test that should produce no
|
|
8
|
+
* fitting chart at all (e.g. flat single-column data, broken GeoJSON).
|
|
9
|
+
*/
|
|
10
|
+
export interface ScorecardFixture {
|
|
11
|
+
name: string;
|
|
12
|
+
/** Free-text shape description, used in scorecard output for context. */
|
|
13
|
+
shape?: string;
|
|
14
|
+
data: ReadonlyArray<Datum>;
|
|
15
|
+
/** Optional non-tabular payload (network/hierarchy/GeoJSON). */
|
|
16
|
+
rawInput?: unknown;
|
|
17
|
+
/** Intent to rank by. If omitted, scored without intent (mean-of-all). */
|
|
18
|
+
intent?: IntentId;
|
|
19
|
+
/** Components the human expert would pick. Empty = "anything fits". */
|
|
20
|
+
expected?: ReadonlyArray<string>;
|
|
21
|
+
/** True if the fixture should produce zero fitting suggestions. Mutually exclusive with `expected`. */
|
|
22
|
+
expectsNoFit?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface PerCapabilityScore {
|
|
25
|
+
component: string;
|
|
26
|
+
family: ChartCapability["family"];
|
|
27
|
+
/** Number of fixtures where this capability fit. */
|
|
28
|
+
fitsOn: number;
|
|
29
|
+
/** Number of fixtures where this capability was rejected. */
|
|
30
|
+
rejectedOn: number;
|
|
31
|
+
/** Number of fixtures where this capability appeared in the top-3 ranked suggestions. */
|
|
32
|
+
inTopThreeOn: number;
|
|
33
|
+
/** Fixtures where the human expert picked this chart AND it was in top-3 ranking. */
|
|
34
|
+
expertAgreementCount: number;
|
|
35
|
+
/** Mean composite score across fixtures where it fit. */
|
|
36
|
+
averageScore: number;
|
|
37
|
+
/** Fraction of suggestions that included at least one caveat. */
|
|
38
|
+
caveatCoverage: number;
|
|
39
|
+
/** Fraction of suggestions that picked a non-base variant. */
|
|
40
|
+
variantUtilization: number;
|
|
41
|
+
}
|
|
42
|
+
export interface PerFixtureScore {
|
|
43
|
+
fixture: string;
|
|
44
|
+
shape?: string;
|
|
45
|
+
intent?: IntentId;
|
|
46
|
+
expected?: ReadonlyArray<string>;
|
|
47
|
+
topPick?: {
|
|
48
|
+
component: string;
|
|
49
|
+
variantKey?: string;
|
|
50
|
+
score: number;
|
|
51
|
+
};
|
|
52
|
+
topThree: ReadonlyArray<{
|
|
53
|
+
component: string;
|
|
54
|
+
variantKey?: string;
|
|
55
|
+
score: number;
|
|
56
|
+
}>;
|
|
57
|
+
fittingCount: number;
|
|
58
|
+
rejectedCount: number;
|
|
59
|
+
/** True if the top-3 ranking contained at least one expected component (when expected is provided). */
|
|
60
|
+
expertAgreement: boolean | null;
|
|
61
|
+
/** Did the engine honor `expectsNoFit`? */
|
|
62
|
+
noFitHonored: boolean | null;
|
|
63
|
+
}
|
|
64
|
+
export interface ScorecardReport {
|
|
65
|
+
perCapability: PerCapabilityScore[];
|
|
66
|
+
perFixture: PerFixtureScore[];
|
|
67
|
+
summary: {
|
|
68
|
+
fixtureCount: number;
|
|
69
|
+
capabilityCount: number;
|
|
70
|
+
/** Fraction of expectation-bearing fixtures where the engine agreed with the expert. */
|
|
71
|
+
expertAgreementRate: number;
|
|
72
|
+
/** Average caveat coverage across all suggestions. */
|
|
73
|
+
overallCaveatCoverage: number;
|
|
74
|
+
/** Average variant utilization across all suggestions. */
|
|
75
|
+
overallVariantUtilization: number;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Run the scorecard. Pure — does no I/O — so it can be called from CI scripts,
|
|
80
|
+
* vizmart UIs, or test suites.
|
|
81
|
+
*/
|
|
82
|
+
export declare function runQualityScorecard(fixtures: ReadonlyArray<ScorecardFixture>, capabilities?: ReadonlyArray<ChartCapability>): ScorecardReport;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Datum } from "../charts/shared/datumTypes";
|
|
2
|
+
import type { ChartDataProfile, Suggestion } from "./chartCapabilityTypes";
|
|
3
|
+
import type { IntentId } from "./intents";
|
|
4
|
+
/**
|
|
5
|
+
* Repair result when the chosen chart fits the data — nothing to fix.
|
|
6
|
+
*/
|
|
7
|
+
export interface RepairOkResult {
|
|
8
|
+
status: "ok";
|
|
9
|
+
component: string;
|
|
10
|
+
/** The same data profile that was evaluated. */
|
|
11
|
+
profile: ChartDataProfile;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Repair result when the chosen chart doesn't fit. Carries the diagnostic
|
|
15
|
+
* reason from the capability's `fits()` plus ranked alternatives that *do*
|
|
16
|
+
* fit, with their reasons surfaced for caller narration.
|
|
17
|
+
*/
|
|
18
|
+
export interface RepairAlternativeResult {
|
|
19
|
+
status: "alternative";
|
|
20
|
+
/** The component the caller asked about. */
|
|
21
|
+
component: string;
|
|
22
|
+
/** Why it doesn't fit. */
|
|
23
|
+
reason: string;
|
|
24
|
+
/** Whether the caller intended one of the alternatives anyway. */
|
|
25
|
+
alternatives: Suggestion[];
|
|
26
|
+
profile: ChartDataProfile;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Repair result when no capability is registered for the asked component.
|
|
30
|
+
*/
|
|
31
|
+
export interface RepairUnknownResult {
|
|
32
|
+
status: "unknown";
|
|
33
|
+
component: string;
|
|
34
|
+
/** Closest matches by family/intent — best effort. */
|
|
35
|
+
alternatives: Suggestion[];
|
|
36
|
+
profile: ChartDataProfile;
|
|
37
|
+
}
|
|
38
|
+
export type RepairResult = RepairOkResult | RepairAlternativeResult | RepairUnknownResult;
|
|
39
|
+
export interface RepairOptions {
|
|
40
|
+
/** Caller's intent — informs ranking of alternatives when the chart doesn't fit. */
|
|
41
|
+
intent?: IntentId | IntentId[];
|
|
42
|
+
/** Non-tabular payload (network/hierarchy/GeoJSON). Forwarded to profileData. */
|
|
43
|
+
rawInput?: unknown;
|
|
44
|
+
/** Limit number of alternatives returned (default 3). */
|
|
45
|
+
maxAlternatives?: number;
|
|
46
|
+
/** Pre-computed profile, avoids recomputation. */
|
|
47
|
+
profile?: ChartDataProfile;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate that a chart component is a sensible choice for a dataset, and
|
|
51
|
+
* if not, propose alternatives that *do* fit — ranked by the caller's
|
|
52
|
+
* intent if provided.
|
|
53
|
+
*
|
|
54
|
+
* This is the "auto-fix" surface for `--doctor` and agent retry loops.
|
|
55
|
+
* Given a chart + data, returns either:
|
|
56
|
+
*
|
|
57
|
+
* - { status: "ok", component } — the chart fits, ship it
|
|
58
|
+
* - { status: "alternative", reason, alternatives } — the chart doesn't
|
|
59
|
+
* fit; here are charts that do, ranked by intent if specified
|
|
60
|
+
* - { status: "unknown", alternatives } — we don't have a
|
|
61
|
+
* capability for that component name; here are sensible defaults
|
|
62
|
+
*
|
|
63
|
+
* The contract: a caller can always render `alternatives[0]` and get
|
|
64
|
+
* something useful. The `reason` field is suitable for verbatim display
|
|
65
|
+
* to the user.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* repairChartConfig("PieChart", productData, { intent: "rank" })
|
|
69
|
+
* // → { status: "alternative",
|
|
70
|
+
* // reason: "9 slices is too many for a pie chart",
|
|
71
|
+
* // alternatives: [BarChart, DotPlot, ...] }
|
|
72
|
+
*/
|
|
73
|
+
export declare function repairChartConfig(component: string, data: ReadonlyArray<Datum> | null | undefined, options?: RepairOptions): RepairResult;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ChartRubric } from "./chartCapabilityTypes";
|
|
2
|
+
import type { IntentId } from "./intents";
|
|
3
|
+
/**
|
|
4
|
+
* Streaming chart selection has a different shape than static. We don't have
|
|
5
|
+
* rows yet — we have a *schema*: which fields will arrive, what types, plus
|
|
6
|
+
* environment hints (throughput, retention).
|
|
7
|
+
*
|
|
8
|
+
* Rather than overloading `profileData` (which is row-statistics-centric) we
|
|
9
|
+
* model streams as a parallel API. The two share the intent vocabulary —
|
|
10
|
+
* "trend" still means trend — but the suitability logic is its own thing.
|
|
11
|
+
*/
|
|
12
|
+
export type StreamFieldKind = "numeric" | "categorical" | "date" | "boolean";
|
|
13
|
+
export interface StreamFieldSchema {
|
|
14
|
+
name: string;
|
|
15
|
+
kind: StreamFieldKind;
|
|
16
|
+
/** Optional role hint — overrides the engine's inference. */
|
|
17
|
+
role?: "x" | "y" | "value" | "category" | "series" | "size";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Schema describing what a stream emits. No data, just shape + environment hints.
|
|
21
|
+
*/
|
|
22
|
+
export interface StreamSchema {
|
|
23
|
+
fields: ReadonlyArray<StreamFieldSchema>;
|
|
24
|
+
/**
|
|
25
|
+
* Hint about expected event rate. Affects chart selection — heatmaps and
|
|
26
|
+
* waterfalls amortize high-throughput streams better than line charts do.
|
|
27
|
+
* • "low" — < 1 event/sec, line/area charts read well
|
|
28
|
+
* • "medium" — ~1-100 events/sec
|
|
29
|
+
* • "high" — > 100 events/sec, prefer aggregating visualizations
|
|
30
|
+
*/
|
|
31
|
+
throughput?: "low" | "medium" | "high";
|
|
32
|
+
/**
|
|
33
|
+
* Hint about how long events are kept in view.
|
|
34
|
+
* • "windowed" — only recent events visible (default)
|
|
35
|
+
* • "cumulative" — all events accumulate
|
|
36
|
+
*/
|
|
37
|
+
retention?: "windowed" | "cumulative";
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Stream capability descriptor — parallel to ChartCapability but operates on
|
|
41
|
+
* a schema. No `fits(profile)`; instead `fits(schema)` returns null/reason.
|
|
42
|
+
*/
|
|
43
|
+
export interface StreamChartCapability {
|
|
44
|
+
component: string;
|
|
45
|
+
importPath: "semiotic/realtime";
|
|
46
|
+
rubric: ChartRubric;
|
|
47
|
+
fits: (schema: StreamSchema) => null | string;
|
|
48
|
+
intentScores: Partial<Record<IntentId, StreamIntentScorer>>;
|
|
49
|
+
caveats?: (schema: StreamSchema) => ReadonlyArray<string>;
|
|
50
|
+
buildProps: (schema: StreamSchema) => Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
export type StreamIntentScorer = number | ((schema: StreamSchema) => number);
|
|
53
|
+
export interface StreamSuggestion {
|
|
54
|
+
component: string;
|
|
55
|
+
family: "realtime";
|
|
56
|
+
importPath: "semiotic/realtime";
|
|
57
|
+
score: number;
|
|
58
|
+
intentScores: Partial<Record<IntentId, number>>;
|
|
59
|
+
rubric: ChartRubric;
|
|
60
|
+
reasons: ReadonlyArray<string>;
|
|
61
|
+
caveats: ReadonlyArray<string>;
|
|
62
|
+
/** Props ready to spread into the matching realtime chart. */
|
|
63
|
+
props: Record<string, unknown>;
|
|
64
|
+
}
|