semiotic 3.0.0-beta.4 → 3.0.0-beta.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # Semiotic — AI Assistant Guide
2
2
 
3
3
  ## Quick Start
4
- - Install: `npm install semiotic@3.0.0-beta.4`
4
+ - Install: `npm install semiotic`
5
5
  - Import from `semiotic` or granular: `semiotic/xy`, `semiotic/ordinal`, `semiotic/network`, `semiotic/realtime`, `semiotic/ai`, `semiotic/data`
6
6
  - `semiotic/ai` exports HOC charts + TooltipProvider + MultiLineTooltip + ThemeProvider + exportChart + validateProps + useChartObserver + DetailsPanel + ChartContainer
7
7
  - `semiotic/data` exports: `bin`, `rollup`, `groupBy`, `pivot`
@@ -17,13 +17,13 @@
17
17
  ## Component Reference
18
18
 
19
19
  ### Common props (all HOCs unless noted)
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)
20
+ `title` (string), `width` (number, 600), `height` (number, 400), `responsiveWidth` (boolean, false), `responsiveHeight` (boolean, false), `margin` (object), `className` (string), `enableHover` (boolean, true), `tooltip` (fn), `showLegend` (boolean), `showGrid` (boolean, false), `frameProps` (object), `onObservation` (fn), `chartId` (string)
21
21
 
22
22
  ### XY Charts (from "semiotic" or "semiotic/xy")
23
23
 
24
- **LineChart** — `data` (required), `xAccessor` ("x"), `yAccessor` ("y"), `lineBy`, `lineDataAccessor` ("coordinates"), `colorBy`, `colorScheme` ("category10"), `curve` ("linear"|"monotoneX"|"monotoneY"|"step"|"stepAfter"|"stepBefore"|"basis"|"cardinal"|"catmullRom"), `lineWidth` (2), `showPoints` (false), `pointRadius` (3), `fillArea` (false), `areaOpacity` (0.3), `xLabel`, `yLabel`, `xFormat`, `yFormat`
24
+ **LineChart** — `data` (required), `xAccessor` ("x"), `yAccessor` ("y"), `lineBy`, `lineDataAccessor` ("coordinates"), `colorBy`, `colorScheme` ("category10"), `curve` ("linear"|"monotoneX"|"monotoneY"|"step"|"stepAfter"|"stepBefore"|"basis"|"cardinal"|"catmullRom"), `lineWidth` (2), `showPoints` (false), `pointRadius` (3), `fillArea` (false), `areaOpacity` (0.3), `xLabel`, `yLabel`, `xFormat`, `yFormat`, `anomaly` (AnomalyConfig), `forecast` (ForecastConfig)
25
25
 
26
- **AreaChart** — Same as LineChart plus: `areaBy`, `areaOpacity` (0.7), `showLine` (true), curve default "monotoneX"
26
+ **AreaChart** — Same as LineChart plus: `areaBy`, `y0Accessor` (per-point lower bound for band/ribbon charts), `gradientFill` (boolean|{topOpacity,bottomOpacity} — fade fill from line to baseline), `areaOpacity` (0.7), `showLine` (true), curve default "monotoneX"
27
27
 
28
28
  **StackedAreaChart** — Same as AreaChart plus: `normalize` (false)
29
29
 
@@ -131,6 +131,12 @@ Hooks: `useSelection`, `useLinkedHover`, `useBrushSelection`, `useFilteredData`
131
131
  // Theming
132
132
  <ThemeProvider theme="dark"><LineChart ... /></ThemeProvider>
133
133
 
134
+ // Shared category colors across charts
135
+ <CategoryColorProvider colors={{ North: "#e41a1c", South: "#377eb8" }}>
136
+ <LineChart data={d1} colorBy="region" />
137
+ <BarChart data={d2} colorBy="region" /> {/* same colors */}
138
+ </CategoryColorProvider>
139
+
134
140
  // Data transforms
135
141
  import { bin, rollup, groupBy, pivot } from "semiotic/data"
136
142
 
@@ -141,6 +147,21 @@ await exportChart(el, { format: "png", scale: 2 })
141
147
  const ref = useRef()
142
148
  ref.current.push({ time: Date.now(), value: 42 })
143
149
  <RealtimeLineChart ref={ref} timeAccessor="time" valueAccessor="value" />
150
+
151
+ // Forecast + anomaly detection (LineChart only)
152
+ // Auto mode: training=dashed, observed=solid, forecast=dotted with confidence envelope
153
+ <LineChart data={timeSeries} xAccessor="time" yAccessor="value"
154
+ forecast={{ trainEnd: 60, steps: 15, confidence: 0.95 }}
155
+ anomaly={{ threshold: 2, anomalyColor: "#ef4444" }} />
156
+
157
+ // Pre-computed mode: bring your own bounds from an ML model
158
+ // Data: { time, value, isTraining?, isForecast?, isAnomaly?, upperBounds?, lowerBounds? }
159
+ // Envelope follows per-point bounds (non-rectilinear)
160
+ <LineChart data={mlOutput} xAccessor="time" yAccessor="value"
161
+ forecast={{
162
+ isTraining: "isTraining", isForecast: "isForecast",
163
+ isAnomaly: "isAnomaly", upperBounds: "upper", lowerBounds: "lower",
164
+ }} />
144
165
  ```
145
166
 
146
167
  ## AI Features
@@ -153,6 +174,10 @@ ref.current.push({ time: Date.now(), value: 42 })
153
174
 
154
175
  **DetailsPanel** — selection-driven detail panel. Props: `children` (render fn), `position` ("right"|"bottom"|"overlay"), `size` (300), `trigger` ("click"|"hover"), `chartId`, `dismissOnEmpty`, `showClose`. Use inside ChartContainer via `detailsPanel` prop.
155
176
 
177
+ **ChartGrid** — responsive grid layout for multiple charts. Props: `columns` (number|"auto"), `minCellWidth` (300), `gap` (16). Works with LinkedCharts.
178
+
179
+ **ContextLayout** — places a primary chart alongside context chart(s). Props: `context` (ReactNode), `position` ("right"|"left"|"top"|"bottom"), `contextSize` (250), `gap` (12). Context charts use `mode="context"` for compact rendering.
180
+
156
181
  **ChartErrorBoundary** — `fallback` (ReactNode), `onError` (fn)
157
182
 
158
183
  **validateProps(componentName, props)** — returns `{ valid, errors }`
@@ -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
+ }
@@ -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 */
@@ -60,7 +60,28 @@ export interface AreaChartProps<TDatum extends Record<string, any> = Record<stri
60
60
  */
61
61
  curve?: "linear" | "monotoneX" | "monotoneY" | "step" | "stepAfter" | "stepBefore" | "basis" | "cardinal" | "catmullRom";
62
62
  /**
63
- * Area opacity
63
+ * Per-point lower bound accessor for band/ribbon charts.
64
+ * When set, the area fills between yAccessor (top) and y0Accessor (bottom)
65
+ * instead of filling down to the axis. Use for percentile bands (p5–p95),
66
+ * confidence intervals, or any ribbon visualization.
67
+ * @example
68
+ * ```ts
69
+ * // Data: [{ x: 0, p95: 80, p5: 20 }, ...]
70
+ * <AreaChart data={d} xAccessor="x" yAccessor="p95" y0Accessor="p5" />
71
+ * ```
72
+ */
73
+ y0Accessor?: ChartAccessor<TDatum, number>;
74
+ /**
75
+ * Gradient fill from line to baseline. Set `true` for default (80% → 5%)
76
+ * or `{ topOpacity, bottomOpacity }` for custom values.
77
+ * @default false
78
+ */
79
+ gradientFill?: boolean | {
80
+ topOpacity: number;
81
+ bottomOpacity: number;
82
+ };
83
+ /**
84
+ * Area opacity (flat fill, ignored when gradientFill is set)
64
85
  * @default 0.7
65
86
  */
66
87
  areaOpacity?: number;
@@ -2,6 +2,7 @@ import * as React from "react";
2
2
  import type { StreamXYFrameProps } from "../../stream/types";
3
3
  import type { BaseChartProps, AxisConfig, ChartAccessor } from "../shared/types";
4
4
  import { type TooltipProp } from "../../Tooltip/Tooltip";
5
+ import type { AnomalyConfig, ForecastConfig } from "../shared/statisticalOverlays";
5
6
  /**
6
7
  * LineChart component props
7
8
  */
@@ -115,6 +116,17 @@ export interface LineChartProps<TDatum extends Record<string, any> = Record<stri
115
116
  * Annotation objects to render on the chart
116
117
  */
117
118
  annotations?: Record<string, any>[];
119
+ /**
120
+ * Anomaly detection configuration. Highlights outlier points and shows
121
+ * a shaded band representing the expected range (mean +/- threshold * stddev).
122
+ */
123
+ anomaly?: AnomalyConfig;
124
+ /**
125
+ * Forecast configuration. Splits the line into training (dashed),
126
+ * observed (solid), and forecast (dotted) segments. Shows a confidence
127
+ * envelope around the extrapolated forecast region.
128
+ */
129
+ forecast?: ForecastConfig;
118
130
  /**
119
131
  * Additional StreamXYFrame props for advanced customization
120
132
  * For full control, consider using StreamXYFrame directly