@rokkit/chart 1.3.6 → 1.3.8

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.
Files changed (93) hide show
  1. package/dist/AnimatedPlot.svelte +26 -8
  2. package/dist/AnimatedPlot.svelte.d.ts +5 -0
  3. package/dist/Chart.svelte +1 -1
  4. package/dist/FacetPlot.svelte +1 -1
  5. package/dist/Plot/Axis.svelte +21 -10
  6. package/dist/Plot/Grid.svelte +32 -13
  7. package/dist/Plot/Grid.svelte.d.ts +6 -1
  8. package/dist/Plot/Root.svelte +64 -46
  9. package/dist/Plot/Root.svelte.d.ts +27 -2
  10. package/dist/Plot/Timeline.svelte +39 -13
  11. package/dist/Plot/index.d.ts +4 -4
  12. package/dist/Plot/index.js +4 -4
  13. package/dist/Plot.svelte +128 -164
  14. package/dist/Plot.svelte.d.ts +18 -2
  15. package/dist/PlotState.svelte.d.ts +23 -0
  16. package/dist/PlotState.svelte.js +155 -16
  17. package/dist/PlotSurface.svelte +162 -0
  18. package/dist/PlotSurface.svelte.d.ts +25 -0
  19. package/dist/charts/AreaChart.svelte +37 -4
  20. package/dist/charts/AreaChart.svelte.d.ts +12 -2
  21. package/dist/charts/BarChart.svelte +32 -3
  22. package/dist/charts/BarChart.svelte.d.ts +10 -1
  23. package/dist/charts/BoxPlot.svelte +4 -2
  24. package/dist/charts/BoxPlot.svelte.d.ts +1 -0
  25. package/dist/charts/BubbleChart.svelte +34 -3
  26. package/dist/charts/BubbleChart.svelte.d.ts +11 -1
  27. package/dist/charts/LineChart.svelte +35 -4
  28. package/dist/charts/LineChart.svelte.d.ts +11 -2
  29. package/dist/charts/PieChart.svelte +1 -1
  30. package/dist/charts/ScatterPlot.svelte +32 -3
  31. package/dist/charts/ScatterPlot.svelte.d.ts +10 -1
  32. package/dist/charts/ViolinPlot.svelte +4 -2
  33. package/dist/charts/ViolinPlot.svelte.d.ts +1 -0
  34. package/dist/examples/BarChartExample.svelte +1 -1
  35. package/dist/geoms/Arc.svelte +3 -2
  36. package/dist/geoms/Area.svelte +20 -3
  37. package/dist/geoms/Bar.svelte +57 -13
  38. package/dist/geoms/Box.svelte +131 -76
  39. package/dist/geoms/Box.svelte.d.ts +7 -0
  40. package/dist/geoms/Candlestick.svelte +17 -11
  41. package/dist/geoms/Highlight.svelte +105 -0
  42. package/dist/geoms/Highlight.svelte.d.ts +10 -0
  43. package/dist/geoms/Jitter.svelte +82 -0
  44. package/dist/geoms/Jitter.svelte.d.ts +15 -0
  45. package/dist/geoms/Line.svelte +26 -9
  46. package/dist/geoms/Point.svelte +37 -11
  47. package/dist/geoms/Rule.svelte +113 -0
  48. package/dist/geoms/Rule.svelte.d.ts +16 -0
  49. package/dist/geoms/Trend.svelte +66 -0
  50. package/dist/geoms/Trend.svelte.d.ts +12 -0
  51. package/dist/geoms/Violin.svelte +30 -6
  52. package/dist/geoms/Violin.svelte.d.ts +5 -0
  53. package/dist/geoms/Waterfall.svelte +16 -9
  54. package/dist/geoms/lib/areas.d.ts +6 -2
  55. package/dist/geoms/lib/areas.js +17 -11
  56. package/dist/geoms/lib/bars.d.ts +18 -3
  57. package/dist/geoms/lib/bars.js +70 -96
  58. package/dist/index.d.ts +30 -4
  59. package/dist/index.js +31 -5
  60. package/dist/lib/brewing/ViolinBrewer.svelte.d.ts +1 -1
  61. package/dist/lib/brewing/brewer.svelte.d.ts +1 -0
  62. package/dist/lib/brewing/marks/arcs.js +7 -1
  63. package/dist/lib/brewing/marks/boxes.d.ts +11 -2
  64. package/dist/lib/brewing/marks/boxes.js +32 -11
  65. package/dist/lib/brewing/marks/lines.d.ts +6 -2
  66. package/dist/lib/brewing/marks/lines.js +19 -12
  67. package/dist/lib/brewing/marks/swarm.d.ts +32 -0
  68. package/dist/lib/brewing/marks/swarm.js +125 -0
  69. package/dist/lib/brewing/marks/violins.d.ts +4 -20
  70. package/dist/lib/brewing/marks/violins.js +41 -25
  71. package/dist/lib/brewing/stats.d.ts +3 -1
  72. package/dist/lib/brewing/stats.js +28 -11
  73. package/dist/lib/highlight.d.ts +10 -0
  74. package/dist/lib/highlight.js +43 -0
  75. package/dist/lib/plot/scales.js +12 -7
  76. package/dist/lib/plot/types.d.ts +9 -1
  77. package/dist/lib/plot/types.js +3 -1
  78. package/dist/lib/scale.d.ts +10 -0
  79. package/dist/lib/scale.js +14 -0
  80. package/dist/lib/select.d.ts +22 -0
  81. package/dist/lib/select.js +22 -0
  82. package/dist/lib/trend.d.ts +27 -0
  83. package/dist/lib/trend.js +113 -0
  84. package/dist/patterns/README.md +1 -1
  85. package/package.json +1 -1
  86. package/dist/Plot/Area.svelte +0 -54
  87. package/dist/Plot/Area.svelte.d.ts +0 -14
  88. package/dist/Plot/Bar.svelte +0 -69
  89. package/dist/Plot/Bar.svelte.d.ts +0 -11
  90. package/dist/Plot/Line.svelte +0 -54
  91. package/dist/Plot/Line.svelte.d.ts +0 -13
  92. package/dist/Plot/Point.svelte +0 -58
  93. package/dist/Plot/Point.svelte.d.ts +0 -13
@@ -0,0 +1,113 @@
1
+ export function mean(ys) {
2
+ if (!ys.length) return null
3
+ return ys.reduce((s, v) => s + v, 0) / ys.length
4
+ }
5
+
6
+ export function median(ys) {
7
+ if (!ys.length) return null
8
+ const sorted = [...ys].sort((a, b) => a - b)
9
+ const mid = Math.floor(sorted.length / 2)
10
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2
11
+ }
12
+
13
+ /** Least-squares line. Returns { m, b } or null (< 2 points or zero x-variance). */
14
+ export function linearRegression(xs, ys) {
15
+ const n = xs.length
16
+ if (n < 2) return null
17
+ const mx = mean(xs)
18
+ const my = mean(ys)
19
+ let num = 0
20
+ let den = 0
21
+ for (let i = 0; i < n; i++) {
22
+ const dx = xs[i] - mx
23
+ num += dx * (ys[i] - my)
24
+ den += dx * dx
25
+ }
26
+ if (den === 0) return null
27
+ const m = num / den
28
+ return { m, b: my - m * mx }
29
+ }
30
+
31
+ /** Trailing simple moving average; length preserved (partial window at the head). */
32
+ export function movingAverage(ys, window) {
33
+ const w = Math.max(1, Math.floor(window))
34
+ const out = []
35
+ for (let i = 0; i < ys.length; i++) {
36
+ const start = Math.max(0, i - w + 1)
37
+ const slice = ys.slice(start, i + 1)
38
+ out.push(slice.reduce((s, v) => s + v, 0) / slice.length)
39
+ }
40
+ return out
41
+ }
42
+
43
+ /** Exponential moving average; alpha = alpha ?? 2/(span+1). Length preserved. */
44
+ export function ema(ys, { span, alpha } = {}) {
45
+ if (!ys.length) return []
46
+ const a = alpha ?? 2 / ((span ?? 7) + 1)
47
+ const out = [ys[0]]
48
+ for (let i = 1; i < ys.length; i++) out.push(a * ys[i] + (1 - a) * out[i - 1])
49
+ return out
50
+ }
51
+
52
+ /** Fit y = a·e^(bx) via log-linear least squares. Null if any y ≤ 0 or < 2 points. */
53
+ export function expRegression(xs, ys) {
54
+ if (xs.length < 2) return null
55
+ if (ys.some((v) => v <= 0)) return null
56
+ const reg = linearRegression(xs, ys.map((v) => Math.log(v)))
57
+ if (!reg) return null
58
+ return { a: Math.exp(reg.b), b: reg.m }
59
+ }
60
+
61
+ function normalize(method) {
62
+ if (typeof method === 'number') return { type: 'value', value: method }
63
+ if (typeof method === 'string') return { type: method === 'mean' ? 'avg' : method }
64
+ if (method && typeof method === 'object' && method.type)
65
+ return { ...method, type: method.type === 'mean' ? 'avg' : method.type }
66
+ return null
67
+ }
68
+
69
+ /**
70
+ * Compute a trend for `rows` on channels {x, y}.
71
+ * @returns {{kind:'constant', value:number} | {kind:'series', values:number[]} | null}
72
+ */
73
+ export function computeTrend(rows, channels, method) {
74
+ const cfg = normalize(method)
75
+ if (!cfg || !Array.isArray(rows) || rows.length === 0) return null
76
+ const { x, y } = channels
77
+ const ys = rows.map((r) => Number(r[y]))
78
+ const xs = rows.map((r, i) => {
79
+ const v = Number(r[x])
80
+ return Number.isFinite(v) ? v : i
81
+ })
82
+
83
+ switch (cfg.type) {
84
+ case 'avg':
85
+ return { kind: 'constant', value: mean(ys) }
86
+ case 'median':
87
+ return { kind: 'constant', value: median(ys) }
88
+ case 'min':
89
+ return { kind: 'constant', value: Math.min(...ys) }
90
+ case 'max':
91
+ return { kind: 'constant', value: Math.max(...ys) }
92
+ case 'value':
93
+ return typeof cfg.value === 'number' ? { kind: 'constant', value: cfg.value } : null
94
+ case 'linear': {
95
+ const reg = linearRegression(xs, ys)
96
+ if (!reg) return null
97
+ return { kind: 'series', values: xs.map((v) => reg.m * v + reg.b) }
98
+ }
99
+ case 'ma': {
100
+ if (!cfg.window) return null
101
+ return { kind: 'series', values: movingAverage(ys, cfg.window) }
102
+ }
103
+ case 'ema':
104
+ return { kind: 'series', values: ema(ys, { span: cfg.span, alpha: cfg.alpha }) }
105
+ case 'exp': {
106
+ const reg = expRegression(xs, ys)
107
+ if (!reg) return null
108
+ return { kind: 'series', values: xs.map((v) => reg.a * Math.exp(reg.b * v)) }
109
+ }
110
+ default:
111
+ return null
112
+ }
113
+ }
@@ -1,3 +1,3 @@
1
1
  # Patterns
2
2
 
3
- These patterns are inspired from https://superdesigner.co/tools/svg-backgrounds
3
+ These patterns are inspired from <https://superdesigner.co/tools/svg-backgrounds>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/chart",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "type": "module",
5
5
  "description": "Data-driven chart components",
6
6
  "repository": {
@@ -1,54 +0,0 @@
1
- <script lang="ts">
2
- import { getContext } from 'svelte'
3
- import { area as d3Area, type CurveFactory } from 'd3-shape'
4
- import type { PlotState } from '../PlotState.svelte.js'
5
-
6
- type Datum = Record<string, unknown> | number
7
-
8
- type Props = {
9
- data?: Datum[]
10
- x?: string
11
- y?: string
12
- y0?: string
13
- fill?: string
14
- opacity?: number
15
- curve?: CurveFactory
16
- }
17
-
18
- let {
19
- data = [],
20
- x = undefined,
21
- y = undefined,
22
- y0 = undefined,
23
- fill = 'steelblue',
24
- opacity = 0.7,
25
- curve = undefined
26
- }: Props = $props()
27
-
28
- const state = getContext<PlotState>('plot-state')
29
-
30
- const accessor = (d: Datum, field: string | undefined): unknown =>
31
- field && typeof d === 'object' ? d[field] : d
32
-
33
- const path = $derived.by(() => {
34
- if (!state?.xScale || !state?.yScale || !data?.length) return null
35
- const xScale = state.xScale
36
- const yScale = state.yScale
37
- const innerHeight = state.innerHeight
38
- const areaGen = d3Area<Datum>()
39
- .x((d) => xScale(accessor(d, x)) ?? 0)
40
- .y1((d) => yScale(accessor(d, y)) ?? 0)
41
- .y0((d) =>
42
- y0 !== undefined
43
- ? (yScale((typeof d === 'object' ? d[y0] : undefined) ?? y0) ?? innerHeight)
44
- : innerHeight
45
- )
46
- .defined((d) => d != null)
47
- if (curve) areaGen.curve(curve)
48
- return areaGen(data)
49
- })
50
- </script>
51
-
52
- {#if path}
53
- <path d={path} {fill} {opacity} stroke="none" data-plot-element="area" />
54
- {/if}
@@ -1,14 +0,0 @@
1
- import { type CurveFactory } from 'd3-shape';
2
- type Datum = Record<string, unknown> | number;
3
- type Props = {
4
- data?: Datum[];
5
- x?: string;
6
- y?: string;
7
- y0?: string;
8
- fill?: string;
9
- opacity?: number;
10
- curve?: CurveFactory;
11
- };
12
- declare const Area: import("svelte").Component<Props, {}, "">;
13
- type Area = ReturnType<typeof Area>;
14
- export default Area;
@@ -1,69 +0,0 @@
1
- <script lang="ts">
2
- import { getContext } from 'svelte'
3
- import type { PlotState } from '../PlotState.svelte.js'
4
-
5
- type Datum = Record<string, unknown> | number
6
-
7
- type Props = {
8
- data?: Datum[]
9
- x?: string
10
- y?: string
11
- fill?: string
12
- opacity?: number
13
- }
14
-
15
- let { data = undefined, x = undefined, y = undefined, fill = 'steelblue', opacity = 1 }: Props =
16
- $props()
17
-
18
- const state = getContext<PlotState>('plot-state')
19
-
20
- const accessor = (d: Datum, field: string | undefined): unknown =>
21
- field && typeof d === 'object' ? d[field] : d
22
-
23
- const bars = $derived.by(() => {
24
- if (!state?.xScale || !state?.yScale) return []
25
- const xScale = state.xScale
26
- const yScale = state.yScale
27
- const innerHeight = state.innerHeight
28
- const src = data ?? []
29
- if (!src.length) return []
30
-
31
- const bw = typeof xScale.bandwidth === 'function' ? xScale.bandwidth() : 20
32
- const padding = typeof xScale.bandwidth === 'function' ? bw * 0.05 : 0
33
-
34
- // Baseline at y=0 when domain spans zero (supports negative bars)
35
- const yDomain = typeof yScale.bandwidth !== 'function' ? yScale.domain?.() : null
36
- const baseline =
37
- yDomain && yDomain[0] <= 0 && yDomain[yDomain.length - 1] >= 0
38
- ? (yScale(0) ?? innerHeight)
39
- : innerHeight
40
-
41
- return src.map((d) => {
42
- const xVal = accessor(d, x)
43
- const yVal = accessor(d, y)
44
- const xPos = (xScale(xVal) ?? 0) + padding
45
- const yPos = yScale(yVal) ?? baseline
46
- return {
47
- x: xPos,
48
- y: Math.min(yPos, baseline),
49
- width: bw * 0.9,
50
- height: Math.abs(baseline - yPos),
51
- label: `${xVal}: ${yVal}`
52
- }
53
- })
54
- })
55
- </script>
56
-
57
- {#each bars as bar, i (i)}
58
- <rect
59
- x={bar.x}
60
- y={bar.y}
61
- width={bar.width}
62
- height={bar.height}
63
- {fill}
64
- {opacity}
65
- data-plot-element="bar"
66
- role="graphics-symbol"
67
- aria-label={bar.label}
68
- />
69
- {/each}
@@ -1,11 +0,0 @@
1
- type Datum = Record<string, unknown> | number;
2
- type Props = {
3
- data?: Datum[];
4
- x?: string;
5
- y?: string;
6
- fill?: string;
7
- opacity?: number;
8
- };
9
- declare const Bar: import("svelte").Component<Props, {}, "">;
10
- type Bar = ReturnType<typeof Bar>;
11
- export default Bar;
@@ -1,54 +0,0 @@
1
- <script lang="ts">
2
- import { getContext } from 'svelte'
3
- import { line as d3Line, type CurveFactory } from 'd3-shape'
4
- import type { PlotState } from '../PlotState.svelte.js'
5
-
6
- type Datum = Record<string, unknown> | number
7
-
8
- type Props = {
9
- data?: Datum[]
10
- x?: string
11
- y?: string
12
- stroke?: string
13
- strokeWidth?: number
14
- curve?: CurveFactory
15
- }
16
-
17
- let {
18
- data = [],
19
- x = undefined,
20
- y = undefined,
21
- stroke = 'steelblue',
22
- strokeWidth = 2,
23
- curve = undefined
24
- }: Props = $props()
25
-
26
- const state = getContext<PlotState>('plot-state')
27
-
28
- const accessor = (d: Datum, field: string | undefined): unknown =>
29
- field && typeof d === 'object' ? d[field] : d
30
-
31
- const path = $derived.by(() => {
32
- if (!state?.xScale || !state?.yScale || !data?.length) return null
33
- const xScale = state.xScale
34
- const yScale = state.yScale
35
- const lineGen = d3Line<Datum>()
36
- .x((d) => xScale(accessor(d, x)) ?? 0)
37
- .y((d) => yScale(accessor(d, y)) ?? 0)
38
- .defined((d) => d != null)
39
- if (curve) lineGen.curve(curve)
40
- return lineGen(data)
41
- })
42
- </script>
43
-
44
- {#if path}
45
- <path
46
- d={path}
47
- fill="none"
48
- {stroke}
49
- stroke-width={strokeWidth}
50
- stroke-linejoin="round"
51
- stroke-linecap="round"
52
- data-plot-element="line"
53
- />
54
- {/if}
@@ -1,13 +0,0 @@
1
- import { type CurveFactory } from 'd3-shape';
2
- type Datum = Record<string, unknown> | number;
3
- type Props = {
4
- data?: Datum[];
5
- x?: string;
6
- y?: string;
7
- stroke?: string;
8
- strokeWidth?: number;
9
- curve?: CurveFactory;
10
- };
11
- declare const Line: import("svelte").Component<Props, {}, "">;
12
- type Line = ReturnType<typeof Line>;
13
- export default Line;
@@ -1,58 +0,0 @@
1
- <script lang="ts">
2
- import { getContext } from 'svelte'
3
- import type { PlotState } from '../PlotState.svelte.js'
4
-
5
- type Datum = Record<string, unknown> | number
6
-
7
- type Props = {
8
- data?: Datum[]
9
- x?: string
10
- y?: string
11
- r?: number
12
- fill?: string
13
- stroke?: string
14
- strokeWidth?: number
15
- }
16
-
17
- let {
18
- data = [],
19
- x = undefined,
20
- y = undefined,
21
- r = 4,
22
- fill = 'steelblue',
23
- stroke = 'white',
24
- strokeWidth = 1
25
- }: Props = $props()
26
-
27
- const state = getContext<PlotState>('plot-state')
28
-
29
- const accessor = (d: Datum, field: string | undefined): unknown =>
30
- field && typeof d === 'object' ? d[field] : d
31
-
32
- const points = $derived.by(() => {
33
- if (!state?.xScale || !state?.yScale || !data?.length) return []
34
- const xScale = state.xScale
35
- const yScale = state.yScale
36
- return data
37
- .map((d) => ({
38
- cx: xScale(accessor(d, x)) ?? null,
39
- cy: yScale(accessor(d, y)) ?? null,
40
- label: `(${accessor(d, x)}, ${accessor(d, y)})`
41
- }))
42
- .filter((p) => p.cx !== null && p.cy !== null)
43
- })
44
- </script>
45
-
46
- {#each points as pt, i (i)}
47
- <circle
48
- cx={pt.cx}
49
- cy={pt.cy}
50
- {r}
51
- {fill}
52
- {stroke}
53
- stroke-width={strokeWidth}
54
- data-plot-element="point"
55
- role="graphics-symbol"
56
- aria-label={pt.label}
57
- />
58
- {/each}
@@ -1,13 +0,0 @@
1
- type Datum = Record<string, unknown> | number;
2
- type Props = {
3
- data?: Datum[];
4
- x?: string;
5
- y?: string;
6
- r?: number;
7
- fill?: string;
8
- stroke?: string;
9
- strokeWidth?: number;
10
- };
11
- declare const Point: import("svelte").Component<Props, {}, "">;
12
- type Point = ReturnType<typeof Point>;
13
- export default Point;