@rokkit/chart 1.0.0-next.37 → 1.0.0-next.39

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/chart",
3
- "version": "1.0.0-next.37",
3
+ "version": "1.0.0-next.39",
4
4
  "description": "Components for making interactive charts.",
5
5
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  "typescript": "^5.1.6",
24
24
  "vite": "^4.4.7",
25
25
  "vitest": "~0.33.0",
26
- "shared-config": "1.0.0-next.37"
26
+ "shared-config": "1.0.0-next.39"
27
27
  },
28
28
  "dependencies": {
29
29
  "d3-array": "^3.2.4",
@@ -35,9 +35,10 @@
35
35
  "date-fns": "^2.30.0",
36
36
  "ramda": "^0.29.0",
37
37
  "yootils": "^0.3.1",
38
- "@rokkit/core": "1.0.0-next.37",
39
- "@rokkit/stores": "1.0.0-next.37",
40
- "@rokkit/molecules": "1.0.0-next.37"
38
+ "@rokkit/core": "1.0.0-next.39",
39
+ "@rokkit/molecules": "1.0.0-next.39",
40
+ "@rokkit/atoms": "1.0.0-next.39",
41
+ "@rokkit/stores": "1.0.0-next.39"
41
42
  },
42
43
  "files": [
43
44
  "src/**/*.js",
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import { setContext } from 'svelte'
3
3
  import { writable } from 'svelte/store'
4
- import { compact } from '../lib/utils'
4
+ import { compact } from '@rokkit/core'
5
5
  import { builtIn } from '../lib/theme'
6
6
 
7
7
  let chart = writable({})
package/src/lib/axis.js CHANGED
@@ -1,11 +1,13 @@
1
+ function getOrigin(scale, axis) {
2
+ const origin = scale[axis].ticks
3
+ ? scale(Math.max(0, Math.min(...scale[axis].domain())))
4
+ : scale[axis].range()[0]
5
+ return origin
6
+ }
1
7
  export function axis(scale) {
2
8
  const origin = {
3
- x: scale.x.ticks
4
- ? scale.x(Math.max(0, Math.min(...scale.x.domain())))
5
- : scale.x.range()[0],
6
- y: scale.y.ticks
7
- ? scale.y(Math.max(0, Math.min(...scale.y.domain())))
8
- : scale.y.range()[0]
9
+ x: getOrigin(scale, 'x'),
10
+ y: getOrigin(scale, 'y')
9
11
  }
10
12
  const ticks = {
11
13
  x: axisTicks(scale.x, { axis: 'x', origin }),
@@ -1,3 +1,8 @@
1
+ import patterns__ from './patterns.json'
2
+ import __palette from './palette.json'
3
+
4
+ export const __patterns__ = patterns__
5
+ export const palette = __palette
1
6
  export const __muted__ = {
2
7
  color: '#eeeeee',
3
8
  fill: 'empty',
@@ -19,52 +24,6 @@ export const __colors__ = [
19
24
  '#7EFFF5'
20
25
  ]
21
26
 
22
- export const __patterns__ = {
23
- A: 'M0 5A6 6 0 0 0 10 5',
24
- B: 'M0 10L10 0',
25
- C: 'M0 0A10 10 0 0 0 10 10',
26
- D: 'M0 0L10 10',
27
- E: 'M10 5A6 6 0 0 0 0 5',
28
- F: 'M10 10A10 10 0 0 0 0 0',
29
- G: 'M0 0L10 10ZM10 0L0 10Z',
30
- H: 'M1 1L9 1L9 9L1 9Z',
31
- I: 'M4 0L4 10M6 10L6 0M0 4L10 4M10 6L0 6',
32
- J: 'M0 2L8 10M2 0L10 8M0 8L8 0M2 10L10 2',
33
- K: 'M5 1A 4 4 0 0 0 9 5A4 4 0 0 0 5 9A4 4 0 0 0 1 5A4 4 0 0 0 5 1',
34
- L: 'M1 3L7 9M3 1L9 7M1 7L7 1M3 9L9 3',
35
- M: 'M2 2A4 4 0 0 0 8 2A4 4 0 0 0 8 8A4 4 0 0 0 2 8A4 4 0 0 0 2 2',
36
- N: 'M0 0A5 5 0 0 0 10 0A5 5 0 0 0 10 10A5 5 0 0 0 0 10A5 5 0 0 0 0 0',
37
- O: 'M5 2A 3 3 0 0 0 8 5A3 3 0 0 0 5 8A3 3 0 0 0 2 5A3 3 0 0 0 5 2',
38
- P: 'M2 5L5 2L8 5L5 8Z',
39
- Q: 'M3 5A2 2 0 0 0 7 5A2 2 0 0 0 3 5M1 5L9 5M5 1L5 9',
40
- R: 'M2 8L8 2ZM1.5 3.5L3.5 1.5ZM6.5 8.5L8.5 6.5ZM0 0L10 10Z',
41
- S:
42
- 'M2 8L8 2ZM1.5 3.5L3.5 1.5Z' +
43
- 'M6.5 8.5L8.5 6.5Z' +
44
- 'M2 2L8 8M1.5 6.5L3.5 8.5' +
45
- 'M6.5 1.5L8.5 3.5',
46
- T:
47
- 'M5 1 A6 6 0 0 0 5 9' +
48
- 'A6 6 0 0 0 5 1' +
49
- 'M1 5A6 6 0 0 0 9 5A6 6 0 0 0 1 5',
50
- U:
51
- 'M1.5 5A1 1 0 0 0 3.5 5A1 1 0 0 0 1.5 5' +
52
- 'M6.5 5A1 1 0 0 0 8.5 5A1 1 0 0 0 6.5 5' +
53
- 'M5 1.5A1 1 0 0 0 5 3.5A1 1 0 0 0 5 1.5' +
54
- 'M5 6.5A1 1 0 0 0 5 8.5A1 1 0 0 0 5 6.5',
55
- V:
56
- 'M1.5 2.5A1 1 0 0 0 3.5 2.5A1 1 0 0 0 1.5 2.5' +
57
- 'M6.5 2.5A1 1 0 0 0 8.5 2.5A1 1 0 0 0 6.5 2.5' +
58
- 'M2.5 6.5A1 1 0 0 0 2.5 8.5A1 1 0 0 0 2.5 6.5' +
59
- 'M7.5 6.5A1 1 0 0 0 7.5 8.5A1 1 0 0 0 7.5 6.5' +
60
- 'M3.5 5A1 1 0 0 0 6.5 5A1 1 0 0 0 3.5 5',
61
- W: 'M5 0L6 4L10 5L6 6L5 10L4 6L0 5L4 4Z' + 'M2 1V3M1 2H3' + 'M8 9V7M9 8H7',
62
- X: 'M5 2L2.5 9L8.8 4.6L1.2 4.6L7.5 9Z',
63
- Y: 'M0 5A5 5 0 0 0 5 0' + 'M5 10A5 5 0 0 0 0 5' + 'M5 10A5 5 0 0 0 5 0',
64
- Z: 'M0 0L10 10M5 0L10 5M0 5 L5 10',
65
- Z1: 'M0 0L10 10M3 0L10 7M0 7 L3 10'
66
- }
67
-
68
27
  export const colors = [
69
28
  '#FFDE6B',
70
29
  '#EF89EE',
@@ -80,303 +39,3 @@ export const colors = [
80
39
  '#af7aa1',
81
40
  '#7EFFF5'
82
41
  ]
83
- export const palette = {
84
- indigo: {
85
- 50: '#eef2ff',
86
- 100: '#e0e7ff',
87
- 200: '#c7d2fe',
88
- 300: '#a5b4fc',
89
- 400: '#818cf8',
90
- 500: '#6366f1',
91
- 600: '#4f46e5',
92
- 700: '#4338ca',
93
- 800: '#3730a3',
94
- 900: '#312e81'
95
- },
96
- blue: {
97
- 50: '#eff6ff',
98
- 100: '#dbeafe',
99
- 200: '#bfdbfe',
100
- 300: '#93c5fd',
101
- 400: '#60a5fa',
102
- 500: '#3b82f6',
103
- 600: '#2563eb',
104
- 700: '#1d4ed8',
105
- 800: '#1e40af',
106
- 900: '#1e3a8a'
107
- },
108
- sky: {
109
- 50: '#f0f9ff',
110
- 100: '#e0f2fe',
111
- 200: '#bae6fd',
112
- 300: '#7dd3fc',
113
- 400: '#38bdf8',
114
- 500: '#0ea5e9',
115
- 600: '#0284c7',
116
- 700: '#0369a1',
117
- 800: '#075985',
118
- 900: '#0c4a6e'
119
- },
120
- cyan: {
121
- 50: '#ecfeff',
122
- 100: '#cffafe',
123
- 200: '#a5f3fc',
124
- 300: '#67e8f9',
125
- 400: '#22d3ee',
126
- 500: '#06b6d4',
127
- 600: '#0891b2',
128
- 700: '#0e7490',
129
- 800: '#155e75',
130
- 900: '#164e63'
131
- },
132
- teal: {
133
- 50: '#f0fdfa',
134
- 100: '#ccfbf1',
135
- 200: '#99f6e4',
136
- 300: '#5eead4',
137
- 400: '#2dd4bf',
138
- 500: '#14b8a6',
139
- 600: '#0d9488',
140
- 700: '#0f766e',
141
- 800: '#115e59',
142
- 900: '#134e4a'
143
- },
144
- emerald: {
145
- 50: '#ecfdf5',
146
- 100: '#d1fae5',
147
- 200: '#a7f3d0',
148
- 300: '#6ee7b7',
149
- 400: '#34d399',
150
- 500: '#10b981',
151
- 600: '#059669',
152
- 700: '#047857',
153
- 800: '#065f46',
154
- 900: '#064e3b'
155
- },
156
- green: {
157
- 50: '#f0fdf4',
158
- 100: '#dcfce7',
159
- 200: '#bbf7d0',
160
- 300: '#86efac',
161
- 400: '#4ade80',
162
- 500: '#22c55e',
163
- 600: '#16a34a',
164
- 700: '#15803d',
165
- 800: '#166534',
166
- 900: '#14532d'
167
- },
168
- lime: {
169
- 50: '#f7fee7',
170
- 100: '#ecfccb',
171
- 200: '#d9f99d',
172
- 300: '#bef264',
173
- 400: '#a3e635',
174
- 500: '#84cc16',
175
- 600: '#65a30d',
176
- 700: '#4d7c0f',
177
- 800: '#3f6212',
178
- 900: '#365314'
179
- },
180
- yellow: {
181
- 50: '#fefce8',
182
- 100: '#fef9c3',
183
- 200: '#fef08a',
184
- 300: '#fde047',
185
- 400: '#facc15',
186
- 500: '#eab308',
187
- 600: '#ca8a04',
188
- 700: '#a16207',
189
- 800: '#854d0e',
190
- 900: '#713f12'
191
- },
192
- amber: {
193
- 50: '#fffbeb',
194
- 100: '#fef3c7',
195
- 200: '#fde68a',
196
- 300: '#fcd34d',
197
- 400: '#fbbf24',
198
- 500: '#f59e0b',
199
- 600: '#d97706',
200
- 700: '#b45309',
201
- 800: '#92400e',
202
- 900: '#78350f'
203
- },
204
- orange: {
205
- 50: '#fff7ed',
206
- 100: '#ffedd5',
207
- 200: '#fed7aa',
208
- 300: '#fdba74',
209
- 400: '#fb923c',
210
- 500: '#f97316',
211
- 600: '#ea580c',
212
- 700: '#c2410c',
213
- 800: '#9a3412',
214
- 900: '#7c2d12'
215
- },
216
- red: {
217
- 50: '#fef2f2',
218
- 100: '#fee2e2',
219
- 200: '#fecaca',
220
- 300: '#fca5a5',
221
- 400: '#f87171',
222
- 500: '#ef4444',
223
- 600: '#dc2626',
224
- 700: '#b91c1c',
225
- 800: '#991b1b',
226
- 900: '#7f1d1d'
227
- },
228
- rose: {
229
- 50: '#fff1f2',
230
- 100: '#ffe4e6',
231
- 200: '#fecdd3',
232
- 300: '#fda4af',
233
- 400: '#fb7185',
234
- 500: '#f43f5e',
235
- 600: '#e11d48',
236
- 700: '#be123c',
237
- 800: '#9f1239',
238
- 900: '#881337'
239
- },
240
- pink: {
241
- 50: '#fdf2f8',
242
- 100: '#fce7f3',
243
- 200: '#fbcfe8',
244
- 300: '#f9a8d4',
245
- 400: '#f472b6',
246
- 500: '#ec4899',
247
- 600: '#db2777',
248
- 700: '#be185d',
249
- 800: '#9d174d',
250
- 900: '#831843'
251
- },
252
- fuchsia: {
253
- 50: '#fdf4ff',
254
- 100: '#fae8ff',
255
- 200: '#f5d0fe',
256
- 300: '#f0abfc',
257
- 400: '#e879f9',
258
- 500: '#d946ef',
259
- 600: '#c026d3',
260
- 700: '#a21caf',
261
- 800: '#86198f',
262
- 900: '#701a75'
263
- },
264
- purple: {
265
- 50: '#faf5ff',
266
- 100: '#f3e8ff',
267
- 200: '#e9d5ff',
268
- 300: '#d8b4fe',
269
- 400: '#c084fc',
270
- 500: '#a855f7',
271
- 600: '#9333ea',
272
- 700: '#7e22ce',
273
- 800: '#6b21a8',
274
- 900: '#581c87'
275
- },
276
- violet: {
277
- 50: '#f5f3ff',
278
- 100: '#ede9fe',
279
- 200: '#ddd6fe',
280
- 300: '#c4b5fd',
281
- 400: '#a78bfa',
282
- 500: '#8b5cf6',
283
- 600: '#7c3aed',
284
- 700: '#6d28d9',
285
- 800: '#5b21b6',
286
- 900: '#4c1d95'
287
- },
288
- warmGray: {
289
- 50: '#fafaf9',
290
- 100: '#f5f5f4',
291
- 200: '#e7e5e4',
292
- 300: '#d6d3d1',
293
- 400: '#a8a29e',
294
- 500: '#78716c',
295
- 600: '#57534e',
296
- 700: '#44403c',
297
- 800: '#292524',
298
- 900: '#1c1917'
299
- },
300
- trueGray: {
301
- 50: '#fafafa',
302
- 100: '#f5f5f5',
303
- 200: '#e5e5e5',
304
- 300: '#d4d4d4',
305
- 400: '#a3a3a3',
306
- 500: '#737373',
307
- 600: '#525252',
308
- 700: '#404040',
309
- 800: '#262626',
310
- 900: '#171717'
311
- },
312
- gray: {
313
- 50: '#fafafa',
314
- 100: '#f4f4f5',
315
- 200: '#e4e4e7',
316
- 300: '#d4d4d8',
317
- 400: '#a1a1aa',
318
- 500: '#71717a',
319
- 600: '#52525b',
320
- 700: '#3f3f46',
321
- 800: '#27272a',
322
- 900: '#18181b'
323
- },
324
- blueGray: {
325
- 50: '#f8fafc',
326
- 100: '#f1f5f9',
327
- 200: '#e2e8f0',
328
- 300: '#cbd5e1',
329
- 400: '#94a3b8',
330
- 500: '#64748b',
331
- 600: '#475569',
332
- 700: '#334155',
333
- 800: '#1e293b',
334
- 900: '#0f172a'
335
- }
336
- }
337
-
338
- export const shapePaths = {
339
- // square: ['M', 1, 1, 'L', 9, 1, 'L', 9, 9, 'L', 1, 9, 'Z'],
340
- square: [
341
- ['M', 0.1, 0],
342
- ['A', 0.1, 0.1, 0, 0, 0, 0, 0.1, 'V', 0.9],
343
- ['A', 0.1, 0.1, 0, 0, 0, 0.1, 1, 'H', 0.9],
344
- ['A', 0.1, 0.1, 0, 0, 0, 1, 0.9, 'V', 0.1],
345
- ['A', 0.1, 0.1, 0, 0, 0, 0.9, 0, 'Z']
346
- ],
347
- circle: [
348
- ['M', 0, 5],
349
- ['A', 5, 5, 0, 0, 0, 10, 5],
350
- ['A', 5, 5, 0, 0, 0, 0, 5]
351
- ],
352
- triangle: ['M', 5, 0, 'L', 10, 10, 'L', 0, 10, 'Z'],
353
- diamond: [
354
- ['M', 5, 0],
355
- ['A', 7, 7, 0, 0, 0, 10, 5],
356
- ['A', 7, 7, 0, 0, 0, 5, 10],
357
- ['A', 7, 7, 0, 0, 0, 0, 5],
358
- ['A', 7, 7, 0, 0, 0, 5, 0]
359
- ],
360
- rhombus: ['M', 0, 5, 'L', 5, 0, 'L', 10, 5, 'L', 5, 10, 'Z'],
361
- heart: [
362
- ['M', 9, 5],
363
- ['A', 0.8, 0.8, 0, 0, 0, 5, 2],
364
- ['A', 0.8, 0.8, 0, 0, 0, 1, 5],
365
- ['L', 5, 9],
366
- ['L', 9, 5]
367
- ],
368
- star: [
369
- ['M', 4.80001, 0],
370
- ['L', 5.92258, 3.45491],
371
- ['H', 9.55529],
372
- ['L', 6.61637, 5.59017],
373
- ['L', 7.73894, 9.04509],
374
- ['L', 4.80001, 6.90983],
375
- ['L', 1.86108, 9.04509],
376
- ['L', 2.98365, 5.59017],
377
- ['L', 0.0447266, 3.45491],
378
- ['H', 3.67744],
379
- ['L', 4.80001, 0],
380
- ['Z']
381
- ]
382
- }
@@ -1,6 +1,6 @@
1
1
  import { clamp } from 'yootils'
2
2
  import { ColorBrewer } from './color'
3
- import { toHexString, uniqueId } from './utils'
3
+ import { toHexString, uniqueId, addToArray, toArray } from './utils'
4
4
 
5
5
  export const builtIn = [
6
6
  { path: 'M0 5A6 6 0 0 0 10 5', minAngle: 0, maxAngle: 90 },
@@ -125,20 +125,18 @@ export class PatternBrewer {
125
125
  }
126
126
 
127
127
  add(path) {
128
- let paths = Array.isArray(path) ? path : [path]
129
- this.paths = [...this.paths, ...paths]
130
-
128
+ this.paths = addToArray(this.pathc, path)
131
129
  return this
132
130
  }
133
131
 
134
132
  filter(indices) {
135
- indices = Array.isArray(indices) ? indices : [indices]
133
+ indices = toArray(indices)
136
134
  this.indices = indices.filter((i) => i >= 0 && i < this.paths.length)
137
135
  return this
138
136
  }
139
137
 
140
138
  colors(shades, repeat = false) {
141
- this.shades = Array.isArray(shades) ? shades : [shades]
139
+ this.shades = toArray(shades)
142
140
  this.repeat = repeat
143
141
  return this
144
142
  }
package/src/lib/shape.js CHANGED
@@ -1,13 +1,9 @@
1
1
  import { ColorBrewer } from './color'
2
- import { scaledPath } from './utils'
3
- import { shapePaths } from './constants'
4
-
2
+ import { symbols } from '@rokkit/atoms/symbols'
3
+ import { addToArray, toArray } from './utils'
5
4
  export class ShapeBrewer {
6
5
  constructor() {
7
- this.shapes = Object.entries(shapePaths).reduce(
8
- (acc, [name, path]) => ({ ...acc, [name]: (s) => scaledPath(s, path) }),
9
- {}
10
- )
6
+ this.shapes = Object.keys(symbols)
11
7
  this.repeat = false
12
8
  this.keys = Object.keys(this.shapes)
13
9
  this.gray = new ColorBrewer().gray()
@@ -16,26 +12,24 @@ export class ShapeBrewer {
16
12
  }
17
13
 
18
14
  clear() {
19
- this.shapes = {}
15
+ this.shapes = []
20
16
  return this
21
17
  }
22
18
 
23
19
  add(shape) {
24
- const shapes = typeof shape === 'object' ? shape : { shape }
25
- this.shapes = { ...this.shapes, ...shapes }
20
+ this.shapes = addToArray(this.shapes, shape)
26
21
 
27
22
  return this
28
23
  }
29
24
 
30
25
  filter(keys) {
31
- keys = Array.isArray(keys) ? keys : [keys]
32
- this.keys = keys.filter((key) => key in this.shapes)
26
+ this.keys = toArray(keys).filter((key) => key in this.shapes)
33
27
 
34
28
  return this
35
29
  }
36
30
 
37
31
  colors(shades, repeat = false) {
38
- this.shades = Array.isArray(shades) ? shades : [shades]
32
+ this.shades = toArray(shades)
39
33
  this.repeat = repeat
40
34
  return this
41
35
  }
package/src/lib/utils.js CHANGED
@@ -4,9 +4,11 @@ import { ascending, quantile } from 'd3-array'
4
4
  import { nest } from 'd3-collection'
5
5
  import { omit } from 'ramda'
6
6
 
7
- export function scaledPath(size, x) {
8
- if (Array.isArray(x)) return x.map((x) => scaledPath(size, x)).join(' ')
9
- return typeof size === 'number' ? x * size : x
7
+ export function toArray(value) {
8
+ return Array.isArray(value) ? value : [value]
9
+ }
10
+ export function addToArray(array, value) {
11
+ return [...array, ...toArray(value)]
10
12
  }
11
13
  /**
12
14
  * Calculates a grid of centres to fit a list of items of `size` within the number of `columns` and `rows`.
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import { getContext } from 'svelte'
3
- import { compact } from '../lib/utils-2'
3
+ import { compact } from '@rokkit/core'
4
4
  import { funnel } from '../lib/funnel'
5
5
 
6
6
  const chart = getContext('chart')
@@ -1,125 +0,0 @@
1
- import { scaleBand, scaleLinear } from 'd3-scale'
2
- import { min, max } from 'd3-array'
3
- import { ascending, quantile } from 'd3-array'
4
- import { nest } from 'd3-collection'
5
- import { omit } from 'ramda'
6
-
7
- /**
8
- * Calculates a grid of centres to fit a list of items of `size` within the number of `columns` and `rows`.
9
- *
10
- * - Attempts to find a best fit square if both columns and rows are not specified
11
- * - Value in columns is prioritized over rows for recalculating the grid
12
- * - Supports padding between the items
13
- *
14
- * @param {number} count
15
- * @param {number} size
16
- * @param {number} pad
17
- * @param {number} columns
18
- * @param {number} rows
19
- * @returns
20
- */
21
- export function swatch(count, size, pad = 0, columns, rows) {
22
- if (columns > 0) {
23
- rows = Math.ceil(count / columns)
24
- } else if (rows > 0) {
25
- columns = Math.ceil(count / rows)
26
- } else {
27
- columns = Math.ceil(Math.sqrt(count))
28
- rows = Math.ceil(count / columns)
29
- }
30
-
31
- const width = (size + pad) * columns + pad
32
- const height = (size + pad) * rows + pad
33
- const data = [...Array(count).keys()].map((index) => ({
34
- cx: (size + pad) / 2 + (index % columns) * (size + pad),
35
- cy: (size + pad) / 2 + Math.floor(index / columns) * (size + pad),
36
- r: size / 2
37
- }))
38
-
39
- return { width, height, data }
40
- }
41
- /**
42
- * Get a scale function mapping the values between a range of lower and upper values
43
- *
44
- * @param {array} values
45
- * @param {array[2]} bounds
46
- * @param {number} buffer
47
- * @returns
48
- */
49
- export function getScale(values, bounds, buffer = 0) {
50
- if (values.some(isNaN)) {
51
- return scaleBand().range(bounds).domain(values).padding(0.5)
52
- } else {
53
- // ensure that all numeric values are converted to numbers so that d3 min/max provide correct results
54
- values = values.map((n) => +n)
55
-
56
- let minValue = min(values)
57
- let maxValue = max(values)
58
-
59
- if (minValue < 0 && maxValue > 0) {
60
- maxValue = max([-1 * minValue, maxValue])
61
- minValue = -1 * maxValue
62
- }
63
- const margin = (maxValue - minValue) * buffer
64
- return scaleLinear()
65
- .domain([minValue - margin, maxValue + margin])
66
- .range(bounds)
67
- }
68
- }
69
- /**
70
- * Obtain the scale function for the `x` and `y` fields in the data set.
71
- *
72
- * @param {array<dict>} data
73
- * @param {string} x
74
- * @param {string} y
75
- * @param {number} width
76
- * @param {number} height
77
- * @returns
78
- */
79
- export function getScales(data, x, y, width, height) {
80
- const xValues = [...new Set(data.map((item) => item[x]))]
81
- const yValues = [...new Set(data.map((item) => item[y]))]
82
-
83
- return {
84
- scaleX: getScale(xValues, [0, width]),
85
- scaleY: getScale(yValues, [height, 0], 0.1)
86
- }
87
- }
88
-
89
- /**
90
- * Summarize `data` by fields `x` and `y` and return a nested array with
91
- * key as unique `x` values and value as statistical summaries of `y` values
92
- *
93
- * @param {*} data
94
- * @param {*} x
95
- * @param {*} y
96
- * @returns
97
- */
98
- export function aggregate(data, x, y) {
99
- const summary = nest()
100
- .key((d) => d[x])
101
- .rollup((d) => {
102
- let values = d.map((g) => g[y]).sort(ascending)
103
- let q1 = quantile(values, 0.25)
104
- let q3 = quantile(values, 0.75)
105
- let median = quantile(values, 0.5)
106
- let interQuantileRange = q3 - q1
107
- let min = q1 - 1.5 * interQuantileRange
108
- let max = q3 + 1.5 * interQuantileRange
109
- return { q1, q3, median, interQuantileRange, min, max }
110
- })
111
- .entries(data)
112
- return summary
113
- }
114
- export function getPaletteForValues(values, { palette, fallback }) {
115
- return values.map((value, index) =>
116
- index < palette.length ? palette[index] : fallback
117
- )
118
- }
119
-
120
- export function toNested(data, key, label) {
121
- return nest()
122
- .key((d) => d[key])
123
- .rollup((values) => values.map((value) => omit([key], value)))
124
- .entries(data.sort((a, b) => ascending(a[label], b[label])))
125
- }