semiotic 3.0.0-beta.4 → 3.0.0-beta.6
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 +81 -126
- package/README.md +6 -3
- package/ai/cli.js +72 -0
- package/dist/CategoryColors.d.ts +48 -0
- package/dist/ChartGrid.d.ts +37 -0
- package/dist/ContextLayout.d.ts +38 -0
- package/dist/charts/index.d.ts +2 -0
- package/dist/charts/shared/statisticalOverlays.d.ts +76 -0
- package/dist/charts/shared/types.d.ts +4 -0
- package/dist/charts/shared/validateChartData.d.ts +3 -0
- package/dist/charts/shared/withChartWrapper.d.ts +18 -0
- package/dist/charts/xy/AreaChart.d.ts +22 -1
- package/dist/charts/xy/ConnectedScatterplot.d.ts +60 -0
- package/dist/charts/xy/LineChart.d.ts +12 -0
- package/dist/network.min.js +1 -1
- package/dist/network.module.min.js +1 -1
- package/dist/ordinal.min.js +1 -1
- package/dist/ordinal.module.min.js +1 -1
- package/dist/realtime.min.js +1 -1
- package/dist/realtime.module.min.js +1 -1
- package/dist/semiotic-ai.d.ts +8 -0
- package/dist/semiotic-ai.min.js +1 -1
- package/dist/semiotic-ai.module.min.js +1 -1
- package/dist/semiotic-data.min.js +1 -1
- package/dist/semiotic-data.module.min.js +1 -1
- package/dist/semiotic-xy.d.ts +1 -0
- package/dist/semiotic.d.ts +9 -3
- package/dist/semiotic.min.js +1 -1
- package/dist/semiotic.module.min.js +1 -1
- package/dist/server.min.js +1 -1
- package/dist/server.module.min.js +1 -1
- package/dist/stream/DataSourceAdapter.d.ts +3 -0
- package/dist/stream/PipelineStore.d.ts +6 -0
- package/dist/stream/SceneGraph.d.ts +1 -1
- package/dist/stream/keyboardNav.d.ts +39 -0
- package/dist/stream/networkTypes.d.ts +2 -0
- package/dist/stream/ordinalTypes.d.ts +2 -0
- package/dist/stream/types.d.ts +24 -0
- package/dist/stream/useResponsiveSize.d.ts +10 -0
- package/dist/xy.min.js +1 -1
- package/dist/xy.module.min.js +1 -1
- package/package.json +6 -2
package/CLAUDE.md
CHANGED
|
@@ -1,141 +1,106 @@
|
|
|
1
1
|
# Semiotic — AI Assistant Guide
|
|
2
2
|
|
|
3
3
|
## Quick Start
|
|
4
|
-
- Install: `npm install semiotic
|
|
5
|
-
- Import
|
|
6
|
-
- `semiotic
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- MCP: `npx semiotic-mcp` — MCP server rendering charts to static SVG
|
|
4
|
+
- Install: `npm install semiotic`
|
|
5
|
+
- Import: `semiotic`, `semiotic/xy`, `semiotic/ordinal`, `semiotic/network`, `semiotic/realtime`, `semiotic/ai`, `semiotic/data`
|
|
6
|
+
- CLI: `npx semiotic-ai [--schema|--compact|--examples|--doctor]`
|
|
7
|
+
- MCP: `npx semiotic-mcp`
|
|
8
|
+
- Every HOC has a built-in error boundary (never blanks the page) and dev-mode validation warnings
|
|
10
9
|
|
|
11
10
|
## Architecture
|
|
12
|
-
- **HOC Charts
|
|
13
|
-
-
|
|
14
|
-
- Every HOC accepts `frameProps` to pass through to the underlying Stream Frame
|
|
15
|
-
- TypeScript `strict: true`; all charts have `role="img"` + `aria-label`
|
|
11
|
+
- **HOC Charts**: Simple props, sensible defaults. **Stream Frames**: Full control.
|
|
12
|
+
- Every HOC accepts `frameProps` to pass through. TypeScript `strict: true`.
|
|
16
13
|
|
|
17
|
-
##
|
|
14
|
+
## Common Props (all HOCs)
|
|
15
|
+
`title`, `width` (600), `height` (400), `responsiveWidth`, `responsiveHeight`, `margin`, `className`, `enableHover` (true), `tooltip`, `showLegend`, `showGrid` (false), `frameProps`, `onObservation`, `chartId`
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
`title` (string), `width` (number, 600), `height` (number, 400), `margin` (object), `className` (string), `enableHover` (boolean, true), `tooltip` (fn), `showLegend` (boolean), `showGrid` (boolean, false), `frameProps` (object), `onObservation` (fn), `chartId` (string)
|
|
17
|
+
## XY Charts (`semiotic/xy`)
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
**LineChart** — `data`, `xAccessor` ("x"), `yAccessor` ("y"), `lineBy`, `lineDataAccessor` ("coordinates"), `colorBy`, `colorScheme`, `curve`, `lineWidth` (2), `showPoints`, `pointRadius` (3), `fillArea`, `areaOpacity` (0.3), `anomaly` (AnomalyConfig), `forecast` (ForecastConfig)
|
|
23
20
|
|
|
24
|
-
**
|
|
21
|
+
**AreaChart** — LineChart props + `areaBy`, `y0Accessor` (band/ribbon), `gradientFill` (boolean|{topOpacity,bottomOpacity}), `areaOpacity` (0.7), `showLine` (true)
|
|
25
22
|
|
|
26
|
-
**
|
|
23
|
+
**StackedAreaChart** — AreaChart + `normalize` (false)
|
|
27
24
|
|
|
28
|
-
**
|
|
25
|
+
**Scatterplot** — `data`, `xAccessor`, `yAccessor`, `colorBy`, `sizeBy`, `sizeRange`, `pointRadius` (5), `pointOpacity` (0.8), `marginalGraphics`
|
|
29
26
|
|
|
30
|
-
**
|
|
27
|
+
**BubbleChart** — Scatterplot + `sizeBy` (required), `sizeRange` ([5,40]), `bubbleOpacity` (0.6)
|
|
31
28
|
|
|
32
|
-
**
|
|
29
|
+
**ConnectedScatterplot** — `data`, `xAccessor`, `yAccessor`, `orderAccessor` (number|Date field for sequencing), `pointRadius` (4). Viridis colored start→end, line width = point radius, white halo under lines when <100 points.
|
|
33
30
|
|
|
34
|
-
**Heatmap** — `data
|
|
31
|
+
**Heatmap** — `data`, `xAccessor`, `yAccessor`, `valueAccessor`, `colorScheme`, `showValues`, `cellBorderColor`
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
## Ordinal Charts (`semiotic/ordinal`)
|
|
37
34
|
|
|
38
|
-
**BarChart** — `data
|
|
35
|
+
**BarChart** — `data`, `categoryAccessor`, `valueAccessor`, `orientation`, `colorBy`, `sort`, `barPadding`
|
|
36
|
+
**StackedBarChart** — + `stackBy` (required), `normalize`
|
|
37
|
+
**GroupedBarChart** — + `groupBy` (required)
|
|
38
|
+
**SwarmPlot** — `data`, `categoryAccessor`, `valueAccessor`, `colorBy`, `sizeBy`, `pointRadius`, `pointOpacity`
|
|
39
|
+
**BoxPlot** — + `showOutliers`, `outlierRadius`
|
|
40
|
+
**Histogram** — + `bins` (25), `relative`. Always horizontal.
|
|
41
|
+
**ViolinPlot** — + `bins`, `curve`, `showIQR`
|
|
42
|
+
**DotPlot** — + `sort` (true), `dotRadius`, `showGrid` default true
|
|
43
|
+
**PieChart** — `data`, `categoryAccessor`, `valueAccessor`, `colorBy`, `startAngle`, `slicePadding`
|
|
44
|
+
**DonutChart** — PieChart + `innerRadius` (60), `centerContent`
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
## Network Charts (`semiotic/network`)
|
|
41
47
|
|
|
42
|
-
**
|
|
48
|
+
**ForceDirectedGraph** — `nodes`, `edges`, `nodeIDAccessor`, `sourceAccessor`, `targetAccessor`, `colorBy`, `nodeSize`, `edgeWidth`, `iterations`, `showLabels`
|
|
49
|
+
**SankeyDiagram** — `edges`, `nodes`, `valueAccessor`, `edgeColorBy`, `orientation`, `nodeAlign`, `nodeWidth`, `showLabels`, `edgeOpacity`
|
|
50
|
+
**ChordDiagram** — `edges`, `nodes`, `valueAccessor`, `edgeColorBy`, `padAngle`, `groupWidth`, `showLabels`
|
|
51
|
+
**TreeDiagram** — `data` (root), `layout`, `orientation`, `childrenAccessor`, `colorBy`, `colorByDepth`, `edgeStyle`
|
|
52
|
+
**Treemap** — `data` (root), `childrenAccessor`, `valueAccessor`, `colorBy`, `colorByDepth`, `showLabels`, `labelMode`
|
|
53
|
+
**CirclePack** — `data` (root), `childrenAccessor`, `valueAccessor`, `colorBy`, `colorByDepth`, `circleOpacity`
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
## Realtime Charts (`semiotic/realtime`)
|
|
45
56
|
|
|
46
|
-
|
|
57
|
+
Push API: `chartRef.current.push({ time, value })`
|
|
47
58
|
|
|
48
|
-
**
|
|
59
|
+
**RealtimeLineChart** — `size`, `timeAccessor`, `valueAccessor`, `windowSize` (200), `windowMode`, `stroke`, `strokeWidth`
|
|
60
|
+
**RealtimeTemporalHistogram** — + `binSize` (required), `categoryAccessor`, `colors`
|
|
61
|
+
**RealtimeSwarmChart** — + `categoryAccessor`, `radius`, `opacity`
|
|
62
|
+
**RealtimeWaterfallChart** — + `positiveColor`, `negativeColor`
|
|
63
|
+
**RealtimeHeatmap** — + `heatmapXBins`, `heatmapYBins`, `aggregation`
|
|
64
|
+
**Streaming Sankey** — `StreamNetworkFrame` with `chartType="sankey"`, `showParticles`, `particleStyle`, `tensionConfig`, `thresholds`
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
Realtime encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely on all streaming charts.
|
|
51
67
|
|
|
52
|
-
|
|
68
|
+
## Coordinated Views
|
|
53
69
|
|
|
54
|
-
**
|
|
70
|
+
**LinkedCharts** — wraps charts. Props: `selections` (resolution: "union"|"intersect"|"crossfilter")
|
|
71
|
+
**CategoryColorProvider** — stable category→color mapping. Props: `colors` (map) or `categories` + `colorScheme`
|
|
72
|
+
Chart props: `selection`, `linkedHover`, `linkedBrush`. Hooks: `useSelection`, `useLinkedHover`, `useBrushSelection`, `useFilteredData`
|
|
73
|
+
**ScatterplotMatrix** — `data`, `fields`, `colorBy`, `cellSize`, `hoverMode`, `brushMode`
|
|
55
74
|
|
|
56
|
-
|
|
75
|
+
## Layout & Composition
|
|
57
76
|
|
|
58
|
-
|
|
77
|
+
**ChartGrid** — CSS Grid layout. `columns` (number|"auto"), `minCellWidth` (300), `gap` (16)
|
|
78
|
+
**ContextLayout** — primary + context panel. `context` (ReactNode), `position`, `contextSize` (250)
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
**SankeyDiagram** — `edges` (required), `nodes` (optional), `sourceAccessor`, `targetAccessor`, `valueAccessor` ("value"), `nodeIdAccessor` ("id"), `colorBy`, `edgeColorBy` ("source"|"target"|"gradient"|fn), `orientation` ("horizontal"|"vertical"), `nodeAlign` ("justify"|"left"|"right"|"center"), `nodePaddingRatio` (0.05), `nodeWidth` (15), `nodeLabel`, `showLabels` (true), `edgeOpacity` (0.5), `edgeSort`. Default 800x600.
|
|
63
|
-
|
|
64
|
-
**ChordDiagram** — `edges` (required), `nodes`, `sourceAccessor`, `targetAccessor`, `valueAccessor`, `nodeIdAccessor`, `colorBy`, `edgeColorBy`, `padAngle` (0.01), `groupWidth` (20), `sortGroups`, `nodeLabel`, `showLabels` (true), `edgeOpacity` (0.5)
|
|
65
|
-
|
|
66
|
-
**TreeDiagram** — `data` (required, single root with children), `layout` ("tree"|"cluster"|"partition"|"treemap"|"circlepack"), `orientation` ("vertical"|"horizontal"|"radial"), `childrenAccessor` ("children"), `valueAccessor`, `nodeIdAccessor` ("name"), `colorBy`, `colorByDepth` (false), `edgeStyle` ("line"|"curve"), `nodeLabel`, `showLabels` (true), `nodeSize` (5)
|
|
67
|
-
|
|
68
|
-
**Treemap** — `data` (required, root with children), `childrenAccessor`, `valueAccessor`, `nodeIdAccessor` ("name"), `colorBy`, `colorByDepth` (false), `showLabels` (true), `labelMode` ("leaf"|"parent"|"all"), `nodeLabel`, `padding` (4), `paddingTop` (0, auto 18 for "parent"). Hover shows ancestor breadcrumb.
|
|
69
|
-
|
|
70
|
-
**CirclePack** — `data` (required), `childrenAccessor`, `valueAccessor`, `nodeIdAccessor`, `colorBy`, `colorByDepth` (false), `showLabels` (true), `nodeLabel`, `circleOpacity` (0.7), `padding` (4). Labels hidden below 15px radius. Hover shows ancestor breadcrumb.
|
|
71
|
-
|
|
72
|
-
### Realtime Charts (from "semiotic" or "semiotic/realtime")
|
|
73
|
-
|
|
74
|
-
All use ref-based push API + canvas rendering: `chartRef.current.push({ time, value })`
|
|
75
|
-
|
|
76
|
-
**RealtimeLineChart** — `size` ([500,300]), `timeAccessor`, `valueAccessor`, `windowSize` (200), `windowMode` ("sliding"|"stepping"), `arrowOfTime` ("left"|"right"), `stroke`, `strokeWidth`, `strokeDasharray`, `timeExtent`, `valueExtent`, `extentPadding`, `showAxes`, `background`, `enableHover`, `tooltipContent`, `onHover`, `annotations`, `svgAnnotationRules`, `tickFormatTime`, `tickFormatValue`
|
|
77
|
-
|
|
78
|
-
**RealtimeTemporalHistogram** — RealtimeLineChart props plus `binSize` (required), `categoryAccessor`, `colors`, `fill`, `gap`, `decay`, `pulse`, `staleness`, `transition`
|
|
79
|
-
|
|
80
|
-
**RealtimeSwarmChart** — RealtimeLineChart props plus `categoryAccessor`, `colors`, `radius`, `fill`, `opacity`
|
|
81
|
-
|
|
82
|
-
**RealtimeWaterfallChart** — RealtimeLineChart props plus `positiveColor`, `negativeColor`, `connectorStroke`, `connectorWidth`, `gap`
|
|
83
|
-
|
|
84
|
-
**RealtimeHeatmap** — RealtimeLineChart props plus `heatmapXBins` (20), `heatmapYBins` (20), `aggregation` ("count"|"sum"|"mean"), `linkedHover`, `decay`, `pulse`, `staleness`
|
|
85
|
-
|
|
86
|
-
**Streaming Sankey** — Use `StreamNetworkFrame` with `chartType="sankey"`, `showParticles`, `particleStyle`, `tensionConfig`, `thresholds`, `onTopologyChange`. Ref: `push()`, `pushMany()`, `clear()`, `getTopology()`, `relayout()`, `getTension()`
|
|
87
|
-
|
|
88
|
-
### Realtime Visual Encoding (all streaming charts)
|
|
89
|
-
- `decay` — older data fades (`{ type, halfLife, minOpacity }`)
|
|
90
|
-
- `pulse` — new data flashes (`{ duration, color, glowRadius }`)
|
|
91
|
-
- `transition` — smooth interpolation (`{ duration, easing }`)
|
|
92
|
-
- `staleness` — stale feed detection (`{ threshold, dimOpacity, showBadge }`)
|
|
93
|
-
|
|
94
|
-
### Coordinated Views (from "semiotic" or "semiotic/ai")
|
|
95
|
-
|
|
96
|
-
**LinkedCharts** — Wraps charts for coordination. Props: `selections` (Record with resolution: "union"|"intersect"|"crossfilter")
|
|
97
|
-
|
|
98
|
-
Chart coordination props (on HOCs inside LinkedCharts):
|
|
99
|
-
- `selection` — consume named selection
|
|
100
|
-
- `linkedHover` — produce hover selections
|
|
101
|
-
- `linkedBrush` — produce brush selections (Scatterplot/BubbleChart only)
|
|
102
|
-
|
|
103
|
-
Hooks: `useSelection`, `useLinkedHover`, `useBrushSelection`, `useFilteredData`
|
|
104
|
-
|
|
105
|
-
**ScatterplotMatrix** — `data` (required), `fields` (required), `fieldLabels`, `colorBy`, `cellSize` (150), `cellGap` (4), `pointRadius` (2), `pointOpacity` (0.5), `diagonal` ("histogram"|"density"|"label"), `histogramBins` (20), `hoverMode` (true), `brushMode` ("crossfilter"|"intersect"|false), `unselectedOpacity` (0.1)
|
|
106
|
-
|
|
107
|
-
## Key Usage Patterns
|
|
80
|
+
## Key Patterns
|
|
108
81
|
|
|
109
82
|
```jsx
|
|
110
|
-
//
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
// Hierarchical data (TreeDiagram, Treemap, CirclePack) — single root with children
|
|
114
|
-
<Treemap data={rootNode} childrenAccessor="children" valueAccessor="value" />
|
|
115
|
-
|
|
116
|
-
// Network data
|
|
117
|
-
<SankeyDiagram nodes={nodes} edges={edges} valueAccessor="value" />
|
|
118
|
-
|
|
119
|
-
// Tooltips
|
|
120
|
-
<LineChart ... tooltip={MultiLineTooltip({ title: "name", fields: ["value"] })} />
|
|
121
|
-
|
|
122
|
-
// Coordinated views
|
|
83
|
+
// Cross-highlighting dashboard
|
|
84
|
+
<CategoryColorProvider categories={["North", "South", "East"]}>
|
|
123
85
|
<LinkedCharts>
|
|
124
|
-
<
|
|
125
|
-
|
|
86
|
+
<ChartGrid columns={2}>
|
|
87
|
+
<LineChart data={d} colorBy="region" linkedHover={{ name: "hl", fields: ["region"] }} selection={{ name: "hl" }} responsiveWidth />
|
|
88
|
+
<BarChart data={d} colorBy="region" linkedHover={{ name: "hl", fields: ["region"] }} selection={{ name: "hl" }} responsiveWidth />
|
|
89
|
+
</ChartGrid>
|
|
126
90
|
</LinkedCharts>
|
|
91
|
+
</CategoryColorProvider>
|
|
127
92
|
|
|
128
|
-
//
|
|
129
|
-
<
|
|
93
|
+
// Forecast + anomaly (auto)
|
|
94
|
+
<LineChart data={ts} xAccessor="time" yAccessor="value"
|
|
95
|
+
forecast={{ trainEnd: 60, steps: 15, confidence: 0.95 }}
|
|
96
|
+
anomaly={{ threshold: 2 }} />
|
|
130
97
|
|
|
131
|
-
//
|
|
132
|
-
<
|
|
98
|
+
// Forecast (pre-computed ML bounds)
|
|
99
|
+
<LineChart data={ml} xAccessor="time" yAccessor="value"
|
|
100
|
+
forecast={{ isTraining: "isTraining", isForecast: "isForecast", isAnomaly: "isAnomaly", upperBounds: "upper", lowerBounds: "lower" }} />
|
|
133
101
|
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// Browser export
|
|
138
|
-
await exportChart(el, { format: "png", scale: 2 })
|
|
102
|
+
// Gradient area + percentile band
|
|
103
|
+
<AreaChart data={d} xAccessor="x" yAccessor="p95" y0Accessor="p5" gradientFill />
|
|
139
104
|
|
|
140
105
|
// Realtime
|
|
141
106
|
const ref = useRef()
|
|
@@ -144,25 +109,15 @@ ref.current.push({ time: Date.now(), value: 42 })
|
|
|
144
109
|
```
|
|
145
110
|
|
|
146
111
|
## AI Features
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
## What Semiotic Does That Others Don't
|
|
161
|
-
- Network visualization (force, sankey, chord, tree, treemap, circlepack) with same clean API
|
|
162
|
-
- Streaming data (canvas 60fps push API) + streaming Sankey with particles
|
|
163
|
-
- Realtime visual encoding (decay, pulse, transitions, staleness)
|
|
164
|
-
- Coordinated views (LinkedCharts, crossfilter brushing, ScatterplotMatrix)
|
|
165
|
-
- Statistical summaries (box, violin, swarm, histogram, marginal graphics)
|
|
166
|
-
- AI observation hooks + chart state serialization
|
|
167
|
-
- Server-side SVG via `renderToStaticSVG()` (from "semiotic/server")
|
|
168
|
-
- Global theming with ThemeProvider
|
|
112
|
+
- `onObservation` — structured events (hover, click, brush, selection) on all HOCs
|
|
113
|
+
- `useChartObserver` — aggregates observations across LinkedCharts
|
|
114
|
+
- `toConfig`/`fromConfig`/`toURL`/`fromURL`/`copyConfig`/`configToJSX` — chart state serialization
|
|
115
|
+
- `DetailsPanel` — click-driven detail panel inside `ChartContainer`
|
|
116
|
+
- `validateProps(componentName, props)` — prop validation
|
|
117
|
+
- `ChartErrorBoundary` — error boundary
|
|
118
|
+
- `exportChart(el, { format: "png"|"svg" })` — browser export
|
|
119
|
+
- `renderToStaticSVG()` — server-side SVG (from `semiotic/server`)
|
|
120
|
+
- `npx semiotic-ai --doctor` — validate component + props JSON from CLI
|
|
121
|
+
|
|
122
|
+
## Differentiators
|
|
123
|
+
Network viz, streaming canvas, realtime encoding, coordinated views, statistical summaries, AI hooks, chart serialization, global theming, keyboard navigation
|
package/README.md
CHANGED
|
@@ -84,8 +84,10 @@ snapshots, or coordinated views across chart types.
|
|
|
84
84
|
**AI-ready.** Semiotic ships with structured schemas (`ai/schema.json`), an
|
|
85
85
|
`import from "semiotic/ai"` entry point, and an MCP server — all designed for
|
|
86
86
|
LLM code generation. AI coding assistants can generate correct Semiotic code on
|
|
87
|
-
the first try. Run `npx semiotic-ai --help` for CLI options
|
|
88
|
-
to
|
|
87
|
+
the first try. Run `npx semiotic-ai --help` for CLI options, `npx semiotic-ai --doctor`
|
|
88
|
+
to validate props from the command line, or add `semiotic-mcp` to your MCP client
|
|
89
|
+
config for tool-based chart rendering. Every HOC chart includes a built-in error
|
|
90
|
+
boundary and dev-mode validation warnings with actionable fix suggestions.
|
|
89
91
|
|
|
90
92
|
**Vega-Lite compatible.** Have existing Vega-Lite specs? `fromVegaLite(spec)`
|
|
91
93
|
translates them to Semiotic chart configs — instant onboarding from notebooks,
|
|
@@ -100,7 +102,7 @@ highlights new services as they appear. Visualization as product navigation.
|
|
|
100
102
|
## Install
|
|
101
103
|
|
|
102
104
|
```bash
|
|
103
|
-
npm install semiotic@3.0.0-beta.
|
|
105
|
+
npm install semiotic@3.0.0-beta.6
|
|
104
106
|
```
|
|
105
107
|
|
|
106
108
|
Requires React 18.1 or later.
|
|
@@ -218,6 +220,7 @@ import { LineChart, BarChart } from "semiotic"
|
|
|
218
220
|
| **Network** | `ForceDirectedGraph` `ChordDiagram` `SankeyDiagram` `TreeDiagram` `Treemap` `CirclePack` |
|
|
219
221
|
| **Realtime** | `RealtimeLineChart` `RealtimeHistogram` `RealtimeSwarmChart` `RealtimeWaterfallChart` `RealtimeHeatmap` |
|
|
220
222
|
| **Coordination** | `LinkedCharts` `ScatterplotMatrix` |
|
|
223
|
+
| **Layout** | `ChartGrid` `ContextLayout` `CategoryColorProvider` |
|
|
221
224
|
| **Frames** | `StreamXYFrame` `StreamOrdinalFrame` `StreamNetworkFrame` |
|
|
222
225
|
|
|
223
226
|
### Vega-Lite Translation
|
package/ai/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ Usage:
|
|
|
21
21
|
npx semiotic-ai --schema Print ai/schema.json (tool definitions)
|
|
22
22
|
npx semiotic-ai --compact Print ai/system-prompt.md (compact prompt)
|
|
23
23
|
npx semiotic-ai --examples Print ai/examples.md (copy-paste examples)
|
|
24
|
+
npx semiotic-ai --doctor Validate component + props JSON from stdin
|
|
24
25
|
npx semiotic-ai --help Show this help message
|
|
25
26
|
`.trim()
|
|
26
27
|
|
|
@@ -31,6 +32,77 @@ if (flag === "--help" || flag === "-h") {
|
|
|
31
32
|
process.exit(0)
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// --doctor: validate component + props from stdin or argv
|
|
36
|
+
if (flag === "--doctor") {
|
|
37
|
+
let input = ""
|
|
38
|
+
if (process.argv[3]) {
|
|
39
|
+
// npx semiotic-ai --doctor '{"component":"LineChart","props":{...}}'
|
|
40
|
+
input = process.argv.slice(3).join(" ")
|
|
41
|
+
} else if (!process.stdin.isTTY) {
|
|
42
|
+
// echo '...' | npx semiotic-ai --doctor
|
|
43
|
+
input = fs.readFileSync("/dev/stdin", "utf-8")
|
|
44
|
+
} else {
|
|
45
|
+
console.error("Usage: npx semiotic-ai --doctor '{\"component\":\"LineChart\",\"props\":{\"data\":[...]}}'")
|
|
46
|
+
console.error(" echo '{...}' | npx semiotic-ai --doctor")
|
|
47
|
+
process.exit(1)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const { component, props } = JSON.parse(input)
|
|
52
|
+
if (!component || !props) {
|
|
53
|
+
console.error("Input must be JSON with { component, props } fields.")
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Load validateProps from dist
|
|
58
|
+
const distPath = path.join(pkgRoot, "dist", "semiotic-ai.min.js")
|
|
59
|
+
let validateProps
|
|
60
|
+
try {
|
|
61
|
+
const mod = require(distPath)
|
|
62
|
+
validateProps = mod.validateProps
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error("Could not load semiotic/ai dist. Run 'npm run dist' first.")
|
|
65
|
+
process.exit(1)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!validateProps) {
|
|
69
|
+
console.error("validateProps not found in semiotic/ai exports.")
|
|
70
|
+
process.exit(1)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const result = validateProps(component, props)
|
|
74
|
+
if (result.valid) {
|
|
75
|
+
console.log(`✓ ${component}: props are valid.`)
|
|
76
|
+
// Additional data shape checks
|
|
77
|
+
if (props.data && Array.isArray(props.data) && props.data.length > 0) {
|
|
78
|
+
const sample = props.data[0]
|
|
79
|
+
console.log(` Data shape: ${props.data.length} items, keys: [${Object.keys(sample).join(", ")}]`)
|
|
80
|
+
if (props.xAccessor && typeof props.xAccessor === "string" && !(props.xAccessor in sample)) {
|
|
81
|
+
console.log(` ⚠ xAccessor "${props.xAccessor}" not in data keys. Available: ${Object.keys(sample).join(", ")}`)
|
|
82
|
+
}
|
|
83
|
+
if (props.yAccessor && typeof props.yAccessor === "string" && !(props.yAccessor in sample)) {
|
|
84
|
+
console.log(` ⚠ yAccessor "${props.yAccessor}" not in data keys. Available: ${Object.keys(sample).join(", ")}`)
|
|
85
|
+
}
|
|
86
|
+
if (props.categoryAccessor && typeof props.categoryAccessor === "string" && !(props.categoryAccessor in sample)) {
|
|
87
|
+
console.log(` ⚠ categoryAccessor "${props.categoryAccessor}" not in data keys. Available: ${Object.keys(sample).join(", ")}`)
|
|
88
|
+
}
|
|
89
|
+
if (props.valueAccessor && typeof props.valueAccessor === "string" && !(props.valueAccessor in sample)) {
|
|
90
|
+
console.log(` ⚠ valueAccessor "${props.valueAccessor}" not in data keys. Available: ${Object.keys(sample).join(", ")}`)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
console.log(`✗ ${component}: validation failed.`)
|
|
95
|
+
for (const err of result.errors) {
|
|
96
|
+
console.log(` • ${err}`)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error(`Failed to parse input: ${err.message}`)
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
process.exit(0)
|
|
104
|
+
}
|
|
105
|
+
|
|
34
106
|
const filePath = flag ? FILES[flag] : FILES.default
|
|
35
107
|
|
|
36
108
|
if (!filePath) {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Category→color mapping. Maps category values (like "North", "error", "active")
|
|
4
|
+
* to fixed color strings. Charts inside a CategoryColorProvider will use these
|
|
5
|
+
* colors consistently regardless of what subset of categories each chart displays.
|
|
6
|
+
*/
|
|
7
|
+
export type CategoryColorMap = Record<string, string>;
|
|
8
|
+
export interface CategoryColorProviderProps {
|
|
9
|
+
/** Explicit category→color mapping */
|
|
10
|
+
colors?: CategoryColorMap;
|
|
11
|
+
/**
|
|
12
|
+
* Category values to auto-assign colors from a scheme.
|
|
13
|
+
* Use when you want consistent colors but don't need specific assignments.
|
|
14
|
+
*/
|
|
15
|
+
categories?: string[];
|
|
16
|
+
/** Color scheme to use for auto-assignment. Default: "category10" */
|
|
17
|
+
colorScheme?: string | string[];
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* CategoryColorProvider — assigns stable colors to category values
|
|
22
|
+
* shared across all Semiotic charts within its subtree.
|
|
23
|
+
*
|
|
24
|
+
* Two modes:
|
|
25
|
+
* - **Explicit**: pass a `colors` map of category→color
|
|
26
|
+
* - **Auto**: pass a `categories` array and optional `colorScheme`
|
|
27
|
+
*
|
|
28
|
+
* Charts with `colorBy` inside this provider will use the mapped colors
|
|
29
|
+
* instead of computing their own color scale per-chart.
|
|
30
|
+
*
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <CategoryColorProvider colors={{ North: "#e41a1c", South: "#377eb8", East: "#4daf4a" }}>
|
|
33
|
+
* <ChartGrid columns={2}>
|
|
34
|
+
* <LineChart data={d1} colorBy="region" responsiveWidth />
|
|
35
|
+
* <BarChart data={d2} colorBy="region" responsiveWidth />
|
|
36
|
+
* </ChartGrid>
|
|
37
|
+
* </CategoryColorProvider>
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function CategoryColorProvider({ colors, categories, colorScheme, children, }: CategoryColorProviderProps): React.JSX.Element;
|
|
41
|
+
export declare namespace CategoryColorProvider {
|
|
42
|
+
var displayName: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Hook to access the category color map from the nearest provider.
|
|
46
|
+
* Returns null if no provider is present.
|
|
47
|
+
*/
|
|
48
|
+
export declare function useCategoryColors(): CategoryColorMap | null;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ChartGridProps {
|
|
3
|
+
/** Chart components to arrange in the grid */
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/** Number of columns. Default: "auto" (auto-fill based on minCellWidth) */
|
|
6
|
+
columns?: number | "auto";
|
|
7
|
+
/** Minimum cell width for auto columns. Default: 300 */
|
|
8
|
+
minCellWidth?: number;
|
|
9
|
+
/** Gap between cells in pixels. Default: 16 */
|
|
10
|
+
gap?: number;
|
|
11
|
+
/** CSS class for the grid container */
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Inline style overrides */
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ChartGrid — responsive grid layout for multiple Semiotic charts.
|
|
18
|
+
*
|
|
19
|
+
* Arranges child charts in a CSS Grid that reflows based on available space.
|
|
20
|
+
* Each cell automatically gets `responsiveWidth` behavior since the grid
|
|
21
|
+
* manages the cell dimensions.
|
|
22
|
+
*
|
|
23
|
+
* Works naturally with `LinkedCharts` for coordinated views:
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <LinkedCharts>
|
|
27
|
+
* <ChartGrid columns={2}>
|
|
28
|
+
* <LineChart data={d} xAccessor="x" yAccessor="y" responsiveWidth />
|
|
29
|
+
* <BarChart data={d} categoryAccessor="cat" valueAccessor="val" responsiveWidth />
|
|
30
|
+
* </ChartGrid>
|
|
31
|
+
* </LinkedCharts>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function ChartGrid({ children, columns, minCellWidth, gap, className, style, }: ChartGridProps): React.JSX.Element;
|
|
35
|
+
export declare namespace ChartGrid {
|
|
36
|
+
var displayName: string;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ContextLayoutProps {
|
|
3
|
+
/** The main chart (renders at full size in the primary slot) */
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/** Context chart(s) displayed alongside the primary chart */
|
|
6
|
+
context: React.ReactNode;
|
|
7
|
+
/** Position of the context panel. Default: "right" */
|
|
8
|
+
position?: "right" | "left" | "bottom" | "top";
|
|
9
|
+
/** Size of the context panel in pixels. Default: 250 */
|
|
10
|
+
contextSize?: number;
|
|
11
|
+
/** Gap between primary and context panels in pixels. Default: 12 */
|
|
12
|
+
gap?: number;
|
|
13
|
+
/** CSS class for the layout container */
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Inline style overrides */
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* ContextLayout — places a primary chart alongside one or more context charts.
|
|
20
|
+
*
|
|
21
|
+
* The primary chart fills available space while the context panel has a fixed
|
|
22
|
+
* width (or height for top/bottom). Context charts should use `mode="context"`
|
|
23
|
+
* for compact rendering without axes or labels.
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <ContextLayout
|
|
27
|
+
* context={<Treemap data={hierarchy} mode="context" responsiveWidth colorByDepth />}
|
|
28
|
+
* position="right"
|
|
29
|
+
* contextSize={250}
|
|
30
|
+
* >
|
|
31
|
+
* <LineChart data={timeSeries} xAccessor="time" yAccessor="value" responsiveWidth />
|
|
32
|
+
* </ContextLayout>
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function ContextLayout({ children, context, position, contextSize, gap, className, style, }: ContextLayoutProps): React.JSX.Element;
|
|
36
|
+
export declare namespace ContextLayout {
|
|
37
|
+
var displayName: string;
|
|
38
|
+
}
|
package/dist/charts/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { Scatterplot } from "./xy/Scatterplot";
|
|
10
10
|
export type { ScatterplotProps } from "./xy/Scatterplot";
|
|
11
|
+
export { ConnectedScatterplot } from "./xy/ConnectedScatterplot";
|
|
12
|
+
export type { ConnectedScatterplotProps } from "./xy/ConnectedScatterplot";
|
|
11
13
|
export { LineChart } from "./xy/LineChart";
|
|
12
14
|
export type { LineChartProps } from "./xy/LineChart";
|
|
13
15
|
export { AreaChart } from "./xy/AreaChart";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Statistical overlay processing for LineChart.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* **Auto mode** — provide `trainEnd` + optional `steps`/`confidence`.
|
|
6
|
+
* The module computes regression, generates forecast points, and builds
|
|
7
|
+
* annotations (envelope, anomaly band, boundary line).
|
|
8
|
+
*
|
|
9
|
+
* **Pre-computed mode** — provide field accessors (`isTraining`, `isForecast`,
|
|
10
|
+
* `isAnomaly`, `upperBounds`, `lowerBounds`). The module reads segment/bounds
|
|
11
|
+
* from the data and generates annotations without any statistical computation.
|
|
12
|
+
* Use this when bounds come from an external ML model.
|
|
13
|
+
*/
|
|
14
|
+
export interface AnomalyConfig {
|
|
15
|
+
/** Standard deviation multiplier for anomaly bounds. Default: 2 */
|
|
16
|
+
threshold?: number;
|
|
17
|
+
/** Show shaded anomaly band. Default: true */
|
|
18
|
+
showBand?: boolean;
|
|
19
|
+
/** Band fill color. Default: "#6366f1" */
|
|
20
|
+
bandColor?: string;
|
|
21
|
+
/** Band fill opacity. Default: 0.1 */
|
|
22
|
+
bandOpacity?: number;
|
|
23
|
+
/** Outlier dot color. Default: "#ef4444" */
|
|
24
|
+
anomalyColor?: string;
|
|
25
|
+
/** Outlier dot radius. Default: 6 */
|
|
26
|
+
anomalyRadius?: number;
|
|
27
|
+
/** Label for the band */
|
|
28
|
+
label?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ForecastConfig {
|
|
31
|
+
/** X-value where training data ends. Required for auto mode. */
|
|
32
|
+
trainEnd?: number;
|
|
33
|
+
/** Number of forecast steps beyond last data point. Default: 10 */
|
|
34
|
+
steps?: number;
|
|
35
|
+
/** Regression method. Default: "linear" */
|
|
36
|
+
method?: "linear" | "loess";
|
|
37
|
+
/** LOESS bandwidth (only for method="loess"). Default: 0.3 */
|
|
38
|
+
bandwidth?: number;
|
|
39
|
+
/** Confidence level for prediction interval (0-1). Default: 0.95 */
|
|
40
|
+
confidence?: number;
|
|
41
|
+
/** Field or function marking training data points */
|
|
42
|
+
isTraining?: string | ((d: Record<string, any>) => boolean);
|
|
43
|
+
/** Field or function marking forecast data points */
|
|
44
|
+
isForecast?: string | ((d: Record<string, any>) => boolean);
|
|
45
|
+
/** Field or function marking anomalous data points */
|
|
46
|
+
isAnomaly?: string | ((d: Record<string, any>) => boolean);
|
|
47
|
+
/** Field or function for upper envelope bound per data point */
|
|
48
|
+
upperBounds?: string | ((d: Record<string, any>) => number);
|
|
49
|
+
/** Field or function for lower envelope bound per data point */
|
|
50
|
+
lowerBounds?: string | ((d: Record<string, any>) => number);
|
|
51
|
+
/** Color for forecast line and envelope. Default: "#6366f1" */
|
|
52
|
+
color?: string;
|
|
53
|
+
/** Envelope fill opacity. Default: 0.15 */
|
|
54
|
+
bandOpacity?: number;
|
|
55
|
+
/** Dash pattern for training line segment. Default: "8,4" */
|
|
56
|
+
trainDasharray?: string;
|
|
57
|
+
/** Dash pattern for forecast line segment. Default: "4,4" */
|
|
58
|
+
forecastDasharray?: string;
|
|
59
|
+
/** Outlier dot color (pre-computed mode). Default: "#ef4444" */
|
|
60
|
+
anomalyColor?: string;
|
|
61
|
+
/** Outlier dot radius (pre-computed mode). Default: 6 */
|
|
62
|
+
anomalyRadius?: number;
|
|
63
|
+
/** Label for the forecast/envelope region */
|
|
64
|
+
label?: string;
|
|
65
|
+
}
|
|
66
|
+
/** Internal segment marker added to each datum */
|
|
67
|
+
export declare const SEGMENT_FIELD: "__forecastSegment";
|
|
68
|
+
export type SegmentType = "training" | "observed" | "forecast";
|
|
69
|
+
export declare function buildAnomalyAnnotations(config: AnomalyConfig): Record<string, any>[];
|
|
70
|
+
interface ForecastResult {
|
|
71
|
+
processedData: Record<string, any>[];
|
|
72
|
+
annotations: Record<string, any>[];
|
|
73
|
+
}
|
|
74
|
+
export declare function buildForecast(data: Record<string, any>[], xAccessor: string, yAccessor: string, forecastConfig: ForecastConfig, anomalyConfig?: AnomalyConfig): ForecastResult;
|
|
75
|
+
export declare function createSegmentLineStyle(baseStyle: (d: Record<string, any>) => Record<string, any>, forecastConfig: ForecastConfig): (d: Record<string, any>) => Record<string, any>;
|
|
76
|
+
export {};
|
|
@@ -50,6 +50,10 @@ export interface BaseChartProps {
|
|
|
50
50
|
height?: number;
|
|
51
51
|
/** Margin around the chart. Can be number (same on all sides) or object specifying each side */
|
|
52
52
|
margin?: MarginType;
|
|
53
|
+
/** Auto-match width to parent container. Default: false */
|
|
54
|
+
responsiveWidth?: boolean;
|
|
55
|
+
/** Auto-match height to parent container (requires parent with explicit height). Default: false */
|
|
56
|
+
responsiveHeight?: boolean;
|
|
53
57
|
/** CSS class name for the chart container */
|
|
54
58
|
className?: string;
|
|
55
59
|
/** Chart title displayed at the top */
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Validates chart data and accessors at render time.
|
|
3
3
|
* Returns null if data is valid, or an error message string if not.
|
|
4
4
|
*
|
|
5
|
+
* Error messages are designed for AI-agent consumption:
|
|
6
|
+
* they include the problem, the available fields, AND the suggested fix.
|
|
7
|
+
*
|
|
5
8
|
* Samples first, last, and a middle element to catch common mistakes
|
|
6
9
|
* (wrong field names, missing data) without iterating the entire dataset.
|
|
7
10
|
*/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
interface SafeRenderProps {
|
|
3
|
+
componentName: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wraps a chart's rendered output with an error boundary.
|
|
10
|
+
* If the chart throws during render, shows a visible error box
|
|
11
|
+
* with the component name and error message instead of crashing the page.
|
|
12
|
+
*/
|
|
13
|
+
export declare function SafeRender({ componentName, width, height, children }: SafeRenderProps): React.JSX.Element;
|
|
14
|
+
/** Warn if a string accessor isn't found in the first data element */
|
|
15
|
+
export declare function warnMissingField(componentName: string, data: any[] | undefined, accessorName: string, accessorValue: any): void;
|
|
16
|
+
/** Warn if data looks like the wrong shape for this chart type */
|
|
17
|
+
export declare function warnDataShape(componentName: string, data: any[] | undefined, expectedKeys: string[], hint: string): void;
|
|
18
|
+
export {};
|