@graphenedata/cli 0.0.15 → 0.0.17

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 (117) hide show
  1. package/README.md +174 -0
  2. package/dist/cli/bigQuery-OQUNH3VT.js +75 -0
  3. package/dist/cli/bigQuery-OQUNH3VT.js.map +7 -0
  4. package/dist/cli/chunk-56K2FF57.js +53 -0
  5. package/dist/cli/chunk-56K2FF57.js.map +7 -0
  6. package/dist/cli/chunk-TZTTALAV.js +12868 -0
  7. package/dist/cli/chunk-TZTTALAV.js.map +7 -0
  8. package/dist/cli/cli.js +260 -11196
  9. package/dist/cli/clickhouse-S3BJSKND.js +65 -0
  10. package/dist/cli/clickhouse-S3BJSKND.js.map +7 -0
  11. package/dist/cli/duckdb-TKVMONRK.js +87 -0
  12. package/dist/cli/duckdb-TKVMONRK.js.map +7 -0
  13. package/dist/cli/serve2-S2LL4D4D.js +448 -0
  14. package/dist/cli/serve2-S2LL4D4D.js.map +7 -0
  15. package/dist/cli/snowflake-3VPDEYYP.js +128 -0
  16. package/dist/cli/snowflake-3VPDEYYP.js.map +7 -0
  17. package/dist/index.d.ts +63 -0
  18. package/dist/lang/index.d.ts +63 -0
  19. package/dist/skills/graphene/SKILL.md +156 -95
  20. package/dist/skills/graphene/references/big-value.md +6 -41
  21. package/dist/skills/graphene/references/date-range.md +64 -0
  22. package/dist/skills/graphene/references/dropdown.md +3 -4
  23. package/dist/skills/graphene/references/echarts.md +162 -0
  24. package/dist/skills/graphene/references/gsql.md +55 -25
  25. package/dist/skills/graphene/references/model-gsql.md +70 -0
  26. package/dist/skills/graphene/references/table.md +13 -14
  27. package/dist/skills/graphene/references/text-input.md +2 -1
  28. package/dist/ui/app.css +239 -340
  29. package/dist/ui/component-utilities/dataShaping.ts +484 -0
  30. package/dist/ui/component-utilities/dataSummary.ts +57 -0
  31. package/dist/ui/component-utilities/enrich.ts +793 -0
  32. package/dist/ui/component-utilities/format.ts +177 -0
  33. package/dist/ui/component-utilities/inputUtils.ts +44 -8
  34. package/dist/ui/component-utilities/theme.ts +200 -0
  35. package/dist/ui/component-utilities/themeStores.ts +21 -8
  36. package/dist/ui/component-utilities/types.ts +70 -0
  37. package/dist/ui/components/AreaChart.svelte +57 -105
  38. package/dist/ui/components/BarChart.svelte +71 -129
  39. package/dist/ui/components/BigValue.svelte +24 -40
  40. package/dist/ui/components/Column.svelte +10 -18
  41. package/dist/ui/components/DateRange.svelte +54 -21
  42. package/dist/ui/components/Dropdown.svelte +47 -26
  43. package/dist/ui/components/DropdownOption.svelte +1 -2
  44. package/dist/ui/components/ECharts.svelte +181 -67
  45. package/dist/ui/components/InlineDelta.svelte +50 -31
  46. package/dist/ui/components/LineChart.svelte +54 -125
  47. package/dist/ui/components/PieChart.svelte +27 -37
  48. package/dist/ui/components/QueryLoad.svelte +77 -45
  49. package/dist/ui/components/Row.svelte +2 -1
  50. package/dist/ui/components/ScatterPlot.svelte +52 -0
  51. package/dist/ui/components/Skeleton.svelte +32 -0
  52. package/dist/ui/components/Table.svelte +3 -2
  53. package/dist/ui/components/TableGroupRow.svelte +28 -36
  54. package/dist/ui/components/TableHarness.svelte +32 -0
  55. package/dist/ui/components/TableHeader.svelte +34 -59
  56. package/dist/ui/components/TableRow.svelte +14 -38
  57. package/dist/ui/components/TableSubtotalRow.svelte +18 -21
  58. package/dist/ui/components/TableTotalRow.svelte +27 -37
  59. package/dist/ui/components/TextInput.svelte +13 -12
  60. package/dist/ui/components/Value.svelte +25 -0
  61. package/dist/ui/components/_Table.svelte +72 -70
  62. package/dist/ui/internal/ChartGallery.svelte +527 -0
  63. package/dist/ui/internal/ErrorDisplay.svelte +22 -97
  64. package/dist/ui/internal/LocalApp.svelte +84 -19
  65. package/dist/ui/internal/PageNavGroup.svelte +269 -0
  66. package/dist/ui/internal/Sidebar.svelte +178 -0
  67. package/dist/ui/internal/SidebarToggle.svelte +47 -0
  68. package/dist/ui/internal/StyleGallery.svelte +244 -0
  69. package/dist/ui/internal/clientCache.ts +2 -2
  70. package/dist/ui/internal/pageInputs.svelte.js +292 -0
  71. package/dist/ui/internal/queryEngine.ts +112 -129
  72. package/dist/ui/internal/runSocket.ts +31 -14
  73. package/dist/ui/internal/sidebar.svelte.js +18 -0
  74. package/dist/ui/internal/telemetry.ts +51 -16
  75. package/dist/ui/internal/types.d.ts +7 -0
  76. package/dist/ui/web.js +30 -11
  77. package/package.json +40 -38
  78. package/dist/skills/graphene/references/area-chart.md +0 -95
  79. package/dist/skills/graphene/references/bar-chart.md +0 -112
  80. package/dist/skills/graphene/references/line-chart.md +0 -108
  81. package/dist/skills/graphene/references/pie-chart.md +0 -29
  82. package/dist/skills/graphene/references/value-formats.md +0 -104
  83. package/dist/ui/component-utilities/autoFormatting.js +0 -280
  84. package/dist/ui/component-utilities/builtInFormats.js +0 -481
  85. package/dist/ui/component-utilities/chartContext.js +0 -12
  86. package/dist/ui/component-utilities/chartWindowDebug.js +0 -21
  87. package/dist/ui/component-utilities/checkInputs.js +0 -84
  88. package/dist/ui/component-utilities/convert.js +0 -15
  89. package/dist/ui/component-utilities/dateParsing.js +0 -56
  90. package/dist/ui/component-utilities/dropdownContext.ts +0 -1
  91. package/dist/ui/component-utilities/echarts.js +0 -252
  92. package/dist/ui/component-utilities/echartsThemes.js +0 -443
  93. package/dist/ui/component-utilities/formatTitle.js +0 -24
  94. package/dist/ui/component-utilities/formatting.js +0 -241
  95. package/dist/ui/component-utilities/getColumnExtents.js +0 -79
  96. package/dist/ui/component-utilities/getColumnSummary.js +0 -62
  97. package/dist/ui/component-utilities/getCompletedData.js +0 -122
  98. package/dist/ui/component-utilities/getDistinctCount.js +0 -7
  99. package/dist/ui/component-utilities/getDistinctValues.js +0 -15
  100. package/dist/ui/component-utilities/getSeriesConfig.js +0 -231
  101. package/dist/ui/component-utilities/getSortedData.js +0 -9
  102. package/dist/ui/component-utilities/getStackPercentages.js +0 -45
  103. package/dist/ui/component-utilities/getStackedData.js +0 -19
  104. package/dist/ui/component-utilities/getYAxisIndex.js +0 -15
  105. package/dist/ui/component-utilities/globalContexts.js +0 -1
  106. package/dist/ui/component-utilities/helpers/getCompletedData.helpers.js +0 -119
  107. package/dist/ui/component-utilities/replaceNulls.js +0 -16
  108. package/dist/ui/component-utilities/tableUtils.ts +0 -107
  109. package/dist/ui/component-utilities/tidyWithTypes.js +0 -9
  110. package/dist/ui/components/Area.svelte +0 -214
  111. package/dist/ui/components/Bar.svelte +0 -347
  112. package/dist/ui/components/Chart.svelte +0 -995
  113. package/dist/ui/components/Line.svelte +0 -227
  114. package/dist/ui/internal/NavSidebar.svelte +0 -396
  115. package/dist/ui/internal/theme.ts +0 -60
  116. package/dist/ui/public/inter-latin-ext.woff2 +0 -0
  117. package/dist/ui/public/inter-latin.woff2 +0 -0
@@ -1,241 +0,0 @@
1
- import ssf from 'ssf'
2
- import {getContext} from 'svelte'
3
-
4
- import {findImplicitAutoFormat, autoFormat, fallbackFormat, isAutoFormat} from './autoFormatting'
5
- import {BUILT_IN_FORMATS} from './builtInFormats'
6
- import {standardizeDateString} from './dateParsing'
7
- import {CUSTOM_FORMATTING_SETTINGS_CONTEXT_KEY} from './globalContexts'
8
-
9
- const AXIS_FORMATTING_CONTEXT = 'axis'
10
- const VALUE_FORMATTING_CONTEXT = 'value'
11
-
12
- export const getCustomFormats = () => {
13
- try {
14
- return getContext(CUSTOM_FORMATTING_SETTINGS_CONTEXT_KEY)?.getCustomFormats() || []
15
- } catch {
16
- return []
17
- }
18
- }
19
-
20
- /**
21
- * @param {*} columnName the name of the column
22
- * @returns a format object (built-in or custom) based on the column name if it matches the pattern column_${formatTag}, otherwise returns undefined
23
- */
24
- export const lookupColumnFormat = (columnName, columnEvidenceType, columnUnitSummary) => {
25
- let potentialFormatTag = maybeExtractFormatTag(columnName)
26
-
27
- if (columnEvidenceType.evidenceType === 'string') {
28
- return undefined
29
- }
30
-
31
- if (potentialFormatTag) {
32
- let customFormats = getCustomFormats()
33
- let matchingFormat = [...BUILT_IN_FORMATS, ...customFormats].find(format => format.formatTag?.toLowerCase() === potentialFormatTag?.toLowerCase?.())
34
- if (matchingFormat) {
35
- return matchingFormat
36
- }
37
- }
38
-
39
- let matchingImplicitAutoFormat = findImplicitAutoFormat(columnName, columnEvidenceType, columnUnitSummary)
40
- if (matchingImplicitAutoFormat) {
41
- return matchingImplicitAutoFormat
42
- }
43
-
44
- return undefined
45
- }
46
-
47
- /**
48
- * Returns an Evidence format object to be used in the applyFormatting function
49
- * @param {string} formatString string containing an Excel-style format code, or a format name matching a built-in or custom format
50
- * @param {'number' | 'date' | 'boolean' | 'string'} [valueType] optional - a string representing the data type within the column that will be formatted ('number', 'date', 'boolean', or 'string)
51
- * @returns a format object based on the formatString matching a built-in or custom format name, or a new custom format object containing an Excel-style format code
52
- */
53
- export function getFormatObjectFromString(formatString, valueType = undefined) {
54
- let potentialFormatTag = formatString
55
- let customFormats = getCustomFormats()
56
- let matchingFormat = [...BUILT_IN_FORMATS, ...customFormats].find(format => format.formatTag?.toLowerCase() === potentialFormatTag?.toLowerCase?.())
57
- let newFormat = {}
58
- if (matchingFormat) {
59
- if (!valueType || matchingFormat.valueType === valueType) return matchingFormat
60
- return {...matchingFormat, valueType}
61
- } else {
62
- newFormat = {
63
- formatTag: 'custom',
64
- formatCode: potentialFormatTag,
65
- }
66
- if (valueType) {
67
- newFormat.valueType = valueType
68
- }
69
- return newFormat
70
- }
71
- }
72
-
73
- export const formatValue = (value, columnFormat = undefined, columnUnitSummary = undefined) => {
74
- try {
75
- return applyFormatting(value, columnFormat, columnUnitSummary, VALUE_FORMATTING_CONTEXT)
76
- } catch (error) {
77
- //fallback to default
78
- console.warn(`Unexpected error calling applyFormatting(${value}, ${columnFormat}, ${VALUE_FORMATTING_CONTEXT}, ${columnUnitSummary}). Error=${error}`)
79
- return value
80
- }
81
- }
82
-
83
- export const formatAxisValue = (value, columnFormat = undefined, columnUnitSummary = undefined) => {
84
- try {
85
- return applyFormatting(value, columnFormat, columnUnitSummary, AXIS_FORMATTING_CONTEXT)
86
- } catch {
87
- //fallback to default
88
- }
89
- return value
90
- }
91
-
92
- export const applyTitleTagReplacement = (columnName, columnFormatSettings) => {
93
- let result = columnName
94
- if (columnName && columnFormatSettings?.formatTag) {
95
- let lastIndexOfTag = columnName.toLowerCase().lastIndexOf(`_${columnFormatSettings.formatTag.toLowerCase()}`)
96
- let titleTagReplacement = ''
97
- if (lastIndexOfTag > 0) {
98
- //explicitly ignore columns starting with _, hence >0 instead of => 0
99
- if (typeof columnFormatSettings?.titleTagReplacement === 'string') {
100
- titleTagReplacement = columnFormatSettings.titleTagReplacement
101
- }
102
- result = columnName.substring(0, lastIndexOfTag) + titleTagReplacement
103
- }
104
- }
105
- return result
106
- }
107
-
108
- export const defaultExample = valueType => {
109
- switch (valueType) {
110
- case 'number':
111
- return 1234
112
- case 'date':
113
- return '2022-01-03'
114
- default:
115
- return undefined
116
- }
117
- }
118
-
119
- export const formatExample = format => {
120
- let normalizedUserInput = format.userInput?.trim()
121
- let preFormattedValue = normalizedUserInput || format.exampleInput || defaultExample(format.valueType)
122
-
123
- if (preFormattedValue) {
124
- try {
125
- let columnUnitSummary = undefined
126
- if (format.valueType === 'number') {
127
- let numericValue = Number(preFormattedValue)
128
- columnUnitSummary = {
129
- min: numericValue,
130
- max: numericValue,
131
- median: numericValue,
132
- maxDecimals: numericValue.toString().split('.')[1]?.length || 0,
133
- unitType: 'number',
134
- }
135
- }
136
- return applyFormatting(preFormattedValue, format, columnUnitSummary, VALUE_FORMATTING_CONTEXT)
137
- } catch {
138
- //return default value
139
- }
140
- }
141
- return ''
142
- }
143
-
144
- function applyFormatting(value, columnFormat = undefined, columnUnitSummary = undefined, formattingContext = VALUE_FORMATTING_CONTEXT) {
145
- if (value === undefined || value === null) {
146
- return '-'
147
- }
148
-
149
- let result = undefined
150
- if (columnFormat) {
151
- try {
152
- let formattingCode = getEffectiveFormattingCode(columnFormat, formattingContext)
153
- let typedValue
154
- try {
155
- if (columnFormat.valueType === 'date' && typeof value === 'string') {
156
- typedValue = new Date(standardizeDateString(value))
157
- } else if (value instanceof Date) {
158
- // "2023-09-06T22:40:43.000Z" minus the Z is interpreted
159
- // as local time
160
- // similar in behavior to standardizeDateString
161
- typedValue = new Date(value.toISOString().slice(0, -1))
162
- } else if (columnFormat.valueType === 'number' && typeof value !== 'number' && !Number.isNaN(value)) {
163
- typedValue = Number(value)
164
- } else {
165
- typedValue = value
166
- }
167
- } catch {
168
- typedValue = value
169
- }
170
- if (isAutoFormat(columnFormat, formattingCode)) {
171
- try {
172
- result = autoFormat(typedValue, columnFormat, columnUnitSummary)
173
- } catch (error) {
174
- console.warn(`Unexpected error applying auto formatting. Error=${error}`)
175
- }
176
- } else if (columnFormat.valueType === 'number' && typeof typedValue === 'number' && isYearOnlyFormat(formattingCode)) {
177
- result = formatNumericYear(typedValue, formattingCode)
178
- } else {
179
- result = ssf.format(formattingCode, typedValue)
180
- }
181
- } catch (error) {
182
- console.warn(`Unexpected error applying formatting ${error}`)
183
- }
184
- }
185
- if (result === undefined) {
186
- result = fallbackFormat(value, columnUnitSummary)
187
- }
188
- return result
189
- }
190
-
191
- function isYearOnlyFormat(formattingCode) {
192
- return typeof formattingCode === 'string' && /^y{2,4}$/i.test(formattingCode.trim())
193
- }
194
-
195
- function formatNumericYear(value, formattingCode) {
196
- let year = String(Math.trunc(value))
197
- let width = formattingCode.trim().length
198
- if (width === 2) {
199
- return year.slice(-2).padStart(2, '0')
200
- }
201
- return year.padStart(width, '0')
202
- }
203
-
204
- function getEffectiveFormattingCode(columnFormat, formattingContext = VALUE_FORMATTING_CONTEXT) {
205
- if (typeof columnFormat === 'string') {
206
- // This should only be used by end users, not by components.
207
- return columnFormat
208
- } else {
209
- if (formattingContext === AXIS_FORMATTING_CONTEXT && columnFormat?.axisFormatCode) {
210
- return columnFormat.axisFormatCode
211
- }
212
- return columnFormat?.formatCode
213
- }
214
- }
215
-
216
- /**
217
- * Extracts a possible format tag from a column name based on the column name pattern
218
- * @returns "column_${formatTag}" will return ${formatTag} or undefined if the columnName doesn't match the pattern
219
- */
220
- function maybeExtractFormatTag(columnName) {
221
- let normalizedColName = columnName.toLowerCase()
222
- let lastUnderScoreIndex = normalizedColName.lastIndexOf('_')
223
-
224
- if (lastUnderScoreIndex > 0) {
225
- return normalizedColName.substr(lastUnderScoreIndex).replace('_', '')
226
- } else {
227
- return undefined
228
- }
229
- }
230
-
231
- /**
232
- * Formats a value to whichever format is passed in
233
- * @param {*} value the value to be formatted
234
- * @param {string} format string containing an Excel-style format code, or a format name matching a built-in or custom format
235
- * @param {'number' | 'date' | 'boolean' | 'string'} [valueType] the known column type
236
- * @returns a formatted value
237
- */
238
- export function fmt(value, format, valueType = undefined) {
239
- let formatObj = getFormatObjectFromString(format, valueType)
240
- return formatValue(value, formatObj)
241
- }
@@ -1,79 +0,0 @@
1
- import {tidy, summarize, min, max, median, mean, n, nDistinct, sum} from '@tidyjs/tidy'
2
-
3
- /**
4
- *
5
- * @param {Record<string, unknown>[]} data
6
- * @param {string} columnName
7
- * @param {boolean} [isNumeric]
8
- * @returns {{ min?: number, max?: number, median?: number, mean?: number, count?: number, countDistinct?: number, sum?: number, maxDecimals: number, unitType: string }}
9
- */
10
- export function getColumnUnitSummary(data, columnName, isNumeric = true) {
11
- let seriesExtents = tidy(
12
- data,
13
- isNumeric
14
- ? summarize({
15
- count: n(columnName),
16
- countDistinct: nDistinct(columnName),
17
- min: min(columnName),
18
- max: max(columnName),
19
- median: median(columnName),
20
- mean: mean(columnName),
21
- sum: sum(columnName),
22
- })
23
- : summarize({count: n(columnName), countDistinct: nDistinct(columnName)}),
24
- )[0]
25
-
26
- // TODO try to use summarize spec in tidy
27
- let {maxDecimals, unitType} = summarizeUnits(data.map(row => row[columnName]))
28
-
29
- return {
30
- min: seriesExtents.min,
31
- max: seriesExtents.max,
32
- median: seriesExtents.median,
33
- mean: seriesExtents.mean,
34
- count: seriesExtents.count,
35
- countDistinct: seriesExtents.countDistinct,
36
- sum: seriesExtents.sum,
37
- maxDecimals: maxDecimals,
38
- unitType: unitType,
39
- }
40
- }
41
-
42
- /**
43
- *
44
- * @param {Record<string, unknown>[]} data
45
- * @param {string} column
46
- * @returns {[number?, number?]}
47
- */
48
- export function getColumnExtentsLegacy(data, column) {
49
- let domainData = tidy(data, summarize({min: min(column), max: max(column)}))[0]
50
- return [domainData.min, domainData.max]
51
- }
52
-
53
- /**
54
- *
55
- * @param {number[]} series
56
- * @returns {{ maxDecimals: number, unitType: string }}
57
- */
58
- function summarizeUnits(series) {
59
- if (series === undefined || series === null || series.length === 0) {
60
- return {
61
- maxDecimals: 0,
62
- unitType: 'unknown',
63
- }
64
- } else {
65
- let maxDecimals = 0
66
-
67
- for (let element of series) {
68
- let decimal_places = element?.toString().split('.')[1]?.length
69
- if (decimal_places > maxDecimals) {
70
- maxDecimals = decimal_places
71
- }
72
- }
73
-
74
- return {
75
- maxDecimals: maxDecimals,
76
- unitType: 'number',
77
- }
78
- }
79
- }
@@ -1,62 +0,0 @@
1
- import {lookupColumnFormat} from './formatting.js'
2
- import formatTitle from './formatTitle.js'
3
- import {getColumnUnitSummary} from './getColumnExtents.js'
4
-
5
- const EvidenceType = {
6
- BOOLEAN: 'boolean',
7
- NUMBER: 'number',
8
- STRING: 'string',
9
- DATE: 'date',
10
- }
11
-
12
- /**
13
- * @typedef {Object} ColumnSummary
14
- * @property {string} title
15
- * @property {string} type
16
- * @property {Object} evidenceColumnType
17
- * @property {ReturnType<typeof lookupColumnFormat>} format
18
- * @property {ReturnType<typeof getColumnUnitSummary>} columnUnitSummary
19
- */
20
-
21
- /**
22
- * @function
23
- * @template T
24
- * @param {Record<string, unknown>[]} data
25
- * @param {T} returnType
26
- * @returns {T extends 'object' ? Record<string, ColumnSummary> : (ColumnSummary & { id: string })[]}
27
- */
28
- export default function getColumnSummary(data, returnType = 'object') {
29
- /** @type {Record<string, ColumnSummary>} */
30
- let columnSummary = {}
31
-
32
- let types = Array.isArray(data?._evidenceColumnTypes) ? data._evidenceColumnTypes : []
33
-
34
- for (let colName of Object.keys(data[0])) {
35
- let evidenceColumnType = types.find(item => item.name?.toLowerCase() === colName?.toLowerCase()) ?? {
36
- name: colName,
37
- evidenceType: EvidenceType.STRING,
38
- }
39
- let type = evidenceColumnType.evidenceType
40
- let columnUnitSummary = evidenceColumnType.evidenceType === EvidenceType.NUMBER ? getColumnUnitSummary(data, colName, true) : getColumnUnitSummary(data, colName, false)
41
-
42
- if (evidenceColumnType.evidenceType !== EvidenceType.NUMBER) {
43
- columnUnitSummary.maxDecimals = 0
44
- columnUnitSummary.unitType = evidenceColumnType.evidenceType
45
- }
46
- let format = lookupColumnFormat(colName, evidenceColumnType, columnUnitSummary)
47
-
48
- columnSummary[colName] = {
49
- title: formatTitle(colName, format),
50
- type,
51
- evidenceColumnType,
52
- format,
53
- columnUnitSummary,
54
- }
55
- }
56
-
57
- if (returnType !== 'object') {
58
- return Object.entries(columnSummary).map(([key, value]) => ({id: key, ...value}))
59
- }
60
-
61
- return columnSummary
62
- }
@@ -1,122 +0,0 @@
1
- import {tidy, complete} from '@tidyjs/tidy'
2
-
3
- import getDistinctValues from './getDistinctValues'
4
- import {findInterval, vectorSeq} from './helpers/getCompletedData.helpers.js'
5
-
6
- /**
7
- * This function fills missing data points in the given data array for a specific series.
8
- *
9
- * @param {Record<string, unknown>[]} _data - The data as an array of objects.
10
- * @param {string} x - The property used as x-axis.
11
- * @param {string} y - The property used as y-axis.
12
- * @param {string} series - The specific series in the data to be filled.
13
- * @param {boolean} [nullsZero=false] - A flag indicating whether nulls should be replaced with zero.
14
- * @param {boolean} [fillX=false] - A flag indicating whether the x-axis values should be filled (based on the found interval distance).
15
- * @return {Record<string, unknown>[]} An array containing the filled data objects.
16
- */
17
- export default function getCompletedData(_data, x, y, series, nullsZero = false, fillX = false) {
18
- let xIsDate = false
19
- let data = _data
20
- .map(d =>
21
- Object.assign({}, d, {
22
- [x]: d[x] instanceof Date ? ((xIsDate = true), d[x].toISOString()) : d[x],
23
- }),
24
- )
25
- .filter(d => d[x] !== undefined && d[x] !== null)
26
- let groups = Array.from(data).reduce((a, v) => {
27
- if (v[x] instanceof Date) {
28
- v[x] = v[x].toISOString()
29
- xIsDate = true
30
- }
31
- if (series) {
32
- if (!a[v[series] ?? 'null']) a[v[series] ?? 'null'] = []
33
- a[v[series] ?? 'null'].push(v)
34
- } else {
35
- if (!a.default) a.default = []
36
- a.default.push(v)
37
- }
38
- return a
39
- }, {})
40
-
41
- // Ensures that all permutations of this map exist in the output
42
- // e.g. can include series and x values to ensure that all series have all x values
43
- let expandKeys = {}
44
-
45
- /** @type {Array<number | string>} */
46
- let xDistinct
47
-
48
- let exampleX = data.find(item => item && item[x] !== null && item[x] !== undefined)?.[x] ?? null
49
- // const exampleX = data[0]?.[x];
50
- switch (typeof exampleX) {
51
- case 'object':
52
- if (exampleX === null) {
53
- throw new Error(`Column '${x}' is entirely null. Column must contain at least one non-null value.`)
54
- } else {
55
- throw new Error('Unexpected object property, expected string, date, or number')
56
- }
57
- case 'number':
58
- // Numbers are the most straightforward
59
- xDistinct = getDistinctValues(data, x)
60
- if (fillX) {
61
- // Attempt to derive the interval between X values and interpolate missing values in that set (within the bounds of min/max)
62
- let interval = findInterval(xDistinct)
63
- expandKeys[x] = vectorSeq(xDistinct, interval)
64
- }
65
- break
66
- case 'string':
67
- xDistinct = getDistinctValues(data, x)
68
- expandKeys[x] = xDistinct
69
- break
70
- }
71
-
72
- let output = []
73
-
74
- for (let value of Object.values(groups)) {
75
- let nullySpec = series ? {[series]: null} : {}
76
- if (nullsZero) {
77
- if (y instanceof Array) {
78
- for (let i = 0; i < y.length; i++) {
79
- nullySpec[y[i]] = 0
80
- }
81
- } else {
82
- nullySpec[y] = 0
83
- }
84
- } else {
85
- // Ensure null for consistency
86
- if (y instanceof Array) {
87
- for (let i = 0; i < y.length; i++) {
88
- nullySpec[y[i]] = null
89
- }
90
- } else {
91
- nullySpec[y] = null
92
- }
93
- }
94
-
95
- if (series) {
96
- expandKeys[series] = series
97
- }
98
-
99
- let tidyFuncs = []
100
- if (Object.keys(expandKeys).length === 0) {
101
- // empty object, no special configuration
102
- tidyFuncs.push(complete([x], nullySpec))
103
- } else {
104
- tidyFuncs.push(complete(expandKeys, nullySpec))
105
- }
106
-
107
- output.push(tidy(value, ...tidyFuncs))
108
- }
109
- if (xIsDate) {
110
- let converted = output.flat().map(r => ({...r, [x]: new Date(r[x])}))
111
- if (Array.isArray(_data?._evidenceColumnTypes)) {
112
- converted._evidenceColumnTypes = _data._evidenceColumnTypes
113
- }
114
- return converted
115
- }
116
-
117
- let flattened = output.flat()
118
- if (Array.isArray(_data?._evidenceColumnTypes)) {
119
- flattened._evidenceColumnTypes = _data._evidenceColumnTypes
120
- }
121
- return flattened
122
- }
@@ -1,7 +0,0 @@
1
- import {tidy, summarize, nDistinct} from '@tidyjs/tidy'
2
-
3
- export default function getDistinctCount(data, column) {
4
- let distinctCount = tidy(data, summarize({count: nDistinct(column)}))[0].count
5
-
6
- return distinctCount
7
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * Extracts an array of distinct values from a specified column in a dataset.
3
- *
4
- * This function iterates over the dataset, collecting values from the specified
5
- * column into a Set to ensure uniqueness. It then converts the Set into an array
6
- * of distinct values and returns this array.
7
- *
8
- * @param {Object[]} data - The dataset to process, represented as an array of objects.
9
- * @param {string} column - The name of the column from which to extract distinct values.
10
- * @returns {any[]} An array containing distinct values from the specified column of the dataset.
11
- */
12
- export default function getDistinctValues(data, column) {
13
- let set = new Set(data.map(val => val[column]))
14
- return Array.from(set)
15
- }