Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clinerules
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Helpers: `resolveReferenceGeography("world-110m"|"world-50m")`, `mergeData(featu

Push API: `ref.current.push({ time, value })`. All pushed data **must** include a time field.

**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)
**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`, `direction`), **TemporalHistogram** (static-data sibling of RealtimeHistogram — same props minus `windowSize`/`windowMode`; takes a bounded `data` array), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)

Encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely.

Expand Down
2 changes: 1 addition & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Helpers: `resolveReferenceGeography("world-110m"|"world-50m")`, `mergeData(featu

Push API: `ref.current.push({ time, value })`. All pushed data **must** include a time field.

**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)
**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`, `direction`), **TemporalHistogram** (static-data sibling of RealtimeHistogram — same props minus `windowSize`/`windowMode`; takes a bounded `data` array), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)

Encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely.

Expand Down
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Helpers: `resolveReferenceGeography("world-110m"|"world-50m")`, `mergeData(featu

Push API: `ref.current.push({ time, value })`. All pushed data **must** include a time field.

**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)
**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`, `direction`), **TemporalHistogram** (static-data sibling of RealtimeHistogram — same props minus `windowSize`/`windowMode`; takes a bounded `data` array), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)

Encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely.

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ jobs:
# first time and skipped on subsequent runs — which left
# single-test misses (a flaky run, a renamed test) permanently
# failing CI because no second bootstrap pass would fire.
run: npx playwright test --update-snapshots=missing
run: npx playwright test --update-snapshots=changed

- name: Upload snapshot baselines
if: always()
Expand Down
2 changes: 1 addition & 1 deletion .windsurfrules
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Helpers: `resolveReferenceGeography("world-110m"|"world-50m")`, `mergeData(featu

Push API: `ref.current.push({ time, value })`. All pushed data **must** include a time field.

**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)
**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`, `direction`), **TemporalHistogram** (static-data sibling of RealtimeHistogram — same props minus `windowSize`/`windowMode`; takes a bounded `data` array), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)

Encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely.

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Helpers: `resolveReferenceGeography("world-110m"|"world-50m")`, `mergeData(featu

Push API: `ref.current.push({ time, value })`. All pushed data **must** include a time field.

**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)
**RealtimeLineChart**, **RealtimeHistogram** (+ `brush`, `onBrush`, `linkedBrush`, `direction`), **TemporalHistogram** (static-data sibling of RealtimeHistogram — same props minus `windowSize`/`windowMode`; takes a bounded `data` array), **RealtimeSwarmChart**, **RealtimeWaterfallChart**, **RealtimeHeatmap**, **Streaming Sankey** (StreamNetworkFrame + `showParticles`)

Encoding: `decay`, `pulse`, `transition`, `staleness` — compose freely.

Expand Down
13 changes: 13 additions & 0 deletions ai/capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,19 @@
"specialFeatures": [
"live-stream"
]
},
"TemporalHistogram": {
"category": "realtime",
"supportsLegend": true,
"supportsSelection": true,
"supportsLinkedHover": true,
"supportsPush": false,
"supportsSSR": false,
"colorModel": "categorical",
"layoutMode": "plugin",
"specialFeatures": [
"brush"
]
}
}
}
11 changes: 9 additions & 2 deletions ai/componentMetadata.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const COMPONENTS_BY_CATEGORY = {
"ChoroplethMap", "ProportionalSymbolMap", "FlowMap", "DistanceCartogram",
],
realtime: [
"RealtimeLineChart", "RealtimeHistogram", "RealtimeSwarmChart",
"RealtimeLineChart", "RealtimeHistogram", "TemporalHistogram", "RealtimeSwarmChart",
"RealtimeWaterfallChart", "RealtimeHeatmap",
],
}
Expand Down Expand Up @@ -52,11 +52,18 @@ function importPathForCategory(category) {
function metadataForComponent(entryOrName) {
const name = typeof entryOrName === "string" ? entryOrName : entryOrName.name
const category = categoryForComponent(name)
// Realtime push-streaming charts are browser-only by design.
// TemporalHistogram is the static-data sibling living in the
// "realtime" category for documentation grouping — it accepts a
// bounded data array and is renderable through the SSR path like
// any other static HOC. Matches the name-prefix exclusion the
// check-surface-parity script applies.
const isPushOnly = category === "realtime" && name.startsWith("Realtime")
return {
name,
category,
importPath: importPathForCategory(category),
renderable: category !== "realtime",
renderable: !isPushOnly,
description: typeof entryOrName === "string" ? undefined : entryOrName.description,
}
}
Expand Down
4 changes: 3 additions & 1 deletion ai/componentRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
BarChart, StackedBarChart, GroupedBarChart, SwarmPlot, BoxPlot, DotPlot,
Histogram, ViolinPlot, RidgelinePlot,
PieChart, DonutChart, GaugeChart, FunnelChart, LikertChart, SwimlaneChart,
ForceDirectedGraph, ChordDiagram, SankeyDiagram, ProcessSankey, TreeDiagram, Treemap, CirclePack, OrbitDiagram
ForceDirectedGraph, ChordDiagram, SankeyDiagram, ProcessSankey, TreeDiagram, Treemap, CirclePack, OrbitDiagram,
TemporalHistogram
} from "semiotic/ai"

import {
Expand All @@ -36,6 +37,7 @@ export const COMPONENT_REGISTRY: Record<string, RegistryEntry> = {
QuadrantChart: { component: QuadrantChart, category: "xy" },
MultiAxisLineChart: { component: MultiAxisLineChart, category: "xy" },
CandlestickChart: { component: CandlestickChart, category: "xy" },
TemporalHistogram: { component: TemporalHistogram, category: "xy" },

BarChart: { component: BarChart, category: "ordinal" },
StackedBarChart: { component: StackedBarChart, category: "ordinal" },
Expand Down
27 changes: 27 additions & 0 deletions ai/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,33 @@ const data = [

Key props: `orderAccessor` sequences points along the path, Viridis gradient from start→end

### TemporalHistogram

```jsx
import { TemporalHistogram } from "semiotic/ai"

// One row per event; the chart bins events into `binSize` time buckets.
const events = [
{ time: 1700000000000, value: 1, category: "errors" },
{ time: 1700000005000, value: 1, category: "warnings" },
{ time: 1700000007000, value: 1, category: "errors" },
{ time: 1700000020000, value: 1, category: "info" },
{ time: 1700000022000, value: 1, category: "info" },
{ time: 1700000040000, value: 1, category: "errors" },
{ time: 1700000045000, value: 1, category: "warnings" }
]

<TemporalHistogram
data={events}
binSize={15000}
categoryAccessor="category"
colors={{ errors: "#dc3545", warnings: "#fd7e14", info: "#007bff" }}
enableHover
/>
```

Static-data sibling of `RealtimeHistogram` — accepts a bounded `data` array instead of a push-mode ref. Same props minus `windowSize` / `windowMode`. Use for backfilled or historical temporal histograms where the time range is fixed; reach for `RealtimeHistogram` when events arrive over time and you want a sliding window.

---

## Flat Array — Ordinal Charts
Expand Down
Loading
Loading