@graphenedata/cli 0.0.1

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 (123) hide show
  1. package/LICENSE.md +100 -0
  2. package/THIRD_PARTY_NOTICES.md +12 -0
  3. package/cli.ts +157 -0
  4. package/dist/cli/cli.js +43 -0
  5. package/dist/docs/data_apps/components/charts/annotations.md +673 -0
  6. package/dist/docs/data_apps/components/charts/area-chart.md +202 -0
  7. package/dist/docs/data_apps/components/charts/bar-chart.md +317 -0
  8. package/dist/docs/data_apps/components/charts/box-plot.md +190 -0
  9. package/dist/docs/data_apps/components/charts/bubble-chart.md +151 -0
  10. package/dist/docs/data_apps/components/charts/calendar-heatmap.md +112 -0
  11. package/dist/docs/data_apps/components/charts/custom-echarts.md +308 -0
  12. package/dist/docs/data_apps/components/charts/echarts-options.md +217 -0
  13. package/dist/docs/data_apps/components/charts/funnel-chart.md +106 -0
  14. package/dist/docs/data_apps/components/charts/heatmap.md +180 -0
  15. package/dist/docs/data_apps/components/charts/histogram.md +107 -0
  16. package/dist/docs/data_apps/components/charts/line-chart.md +265 -0
  17. package/dist/docs/data_apps/components/charts/mixed-type-charts.md +240 -0
  18. package/dist/docs/data_apps/components/charts/sankey-diagram.md +301 -0
  19. package/dist/docs/data_apps/components/charts/scatter-plot.md +134 -0
  20. package/dist/docs/data_apps/components/charts/sparkline.md +68 -0
  21. package/dist/docs/data_apps/components/data/big-value.md +153 -0
  22. package/dist/docs/data_apps/components/data/delta.md +89 -0
  23. package/dist/docs/data_apps/components/data/table.md +470 -0
  24. package/dist/docs/data_apps/components/data/value.md +97 -0
  25. package/dist/docs/data_apps/components/inputs/button-group.md +154 -0
  26. package/dist/docs/data_apps/components/inputs/checkbox.md +52 -0
  27. package/dist/docs/data_apps/components/inputs/date-input.md +131 -0
  28. package/dist/docs/data_apps/components/inputs/date-range.md +124 -0
  29. package/dist/docs/data_apps/components/inputs/dimension-grid.md +67 -0
  30. package/dist/docs/data_apps/components/inputs/dropdown.md +199 -0
  31. package/dist/docs/data_apps/components/inputs/index.md +3 -0
  32. package/dist/docs/data_apps/components/inputs/slider.md +126 -0
  33. package/dist/docs/data_apps/components/inputs/text-input.md +86 -0
  34. package/dist/docs/data_apps/components/maps/area-map.md +397 -0
  35. package/dist/docs/data_apps/components/maps/base-map.md +269 -0
  36. package/dist/docs/data_apps/components/maps/bubble-map.md +361 -0
  37. package/dist/docs/data_apps/components/maps/point-map.md +326 -0
  38. package/dist/docs/data_apps/components/maps/us-map.md +167 -0
  39. package/dist/docs/data_apps/components/ui/accordion.md +116 -0
  40. package/dist/docs/data_apps/components/ui/alert.md +37 -0
  41. package/dist/docs/data_apps/components/ui/big-link.md +19 -0
  42. package/dist/docs/data_apps/components/ui/details.md +58 -0
  43. package/dist/docs/data_apps/components/ui/download-data.md +41 -0
  44. package/dist/docs/data_apps/components/ui/embed.md +47 -0
  45. package/dist/docs/data_apps/components/ui/grid.md +45 -0
  46. package/dist/docs/data_apps/components/ui/image.md +61 -0
  47. package/dist/docs/data_apps/components/ui/info.md +47 -0
  48. package/dist/docs/data_apps/components/ui/last-refreshed.md +28 -0
  49. package/dist/docs/data_apps/components/ui/link-button.md +20 -0
  50. package/dist/docs/data_apps/components/ui/link.md +40 -0
  51. package/dist/docs/data_apps/components/ui/modal.md +57 -0
  52. package/dist/docs/data_apps/components/ui/note.md +32 -0
  53. package/dist/docs/data_apps/components/ui/print-format-components.md +85 -0
  54. package/dist/docs/data_apps/components/ui/tabs.md +122 -0
  55. package/dist/docs/graphene.md +129 -0
  56. package/dist/ui/app.css +332 -0
  57. package/dist/ui/assets/favicon.ico +0 -0
  58. package/dist/ui/component-utilities/autoFormatting.js +301 -0
  59. package/dist/ui/component-utilities/builtInFormats.js +482 -0
  60. package/dist/ui/component-utilities/chartContext.js +12 -0
  61. package/dist/ui/component-utilities/chartWindowDebug.js +21 -0
  62. package/dist/ui/component-utilities/checkInputs.js +95 -0
  63. package/dist/ui/component-utilities/convert.js +15 -0
  64. package/dist/ui/component-utilities/dateParsing.js +57 -0
  65. package/dist/ui/component-utilities/dropdownContext.ts +1 -0
  66. package/dist/ui/component-utilities/echarts.js +262 -0
  67. package/dist/ui/component-utilities/echartsThemes.js +453 -0
  68. package/dist/ui/component-utilities/formatTitle.js +24 -0
  69. package/dist/ui/component-utilities/formatting.js +258 -0
  70. package/dist/ui/component-utilities/getColumnExtents.js +79 -0
  71. package/dist/ui/component-utilities/getColumnSummary.js +67 -0
  72. package/dist/ui/component-utilities/getCompletedData.js +114 -0
  73. package/dist/ui/component-utilities/getDistinctCount.js +7 -0
  74. package/dist/ui/component-utilities/getDistinctValues.js +15 -0
  75. package/dist/ui/component-utilities/getSeriesConfig.js +236 -0
  76. package/dist/ui/component-utilities/getSortedData.js +7 -0
  77. package/dist/ui/component-utilities/getStackPercentages.js +43 -0
  78. package/dist/ui/component-utilities/getStackedData.js +17 -0
  79. package/dist/ui/component-utilities/getYAxisIndex.js +15 -0
  80. package/dist/ui/component-utilities/globalContexts.js +1 -0
  81. package/dist/ui/component-utilities/helpers/getCompletedData.helpers.js +119 -0
  82. package/dist/ui/component-utilities/inputUtils.ts +25 -0
  83. package/dist/ui/component-utilities/replaceNulls.js +14 -0
  84. package/dist/ui/component-utilities/tableUtils.ts +120 -0
  85. package/dist/ui/component-utilities/themeStores.ts +116 -0
  86. package/dist/ui/components/Area.svelte +174 -0
  87. package/dist/ui/components/AreaChart.svelte +150 -0
  88. package/dist/ui/components/Bar.svelte +326 -0
  89. package/dist/ui/components/BarChart.svelte +194 -0
  90. package/dist/ui/components/BigValue.svelte +69 -0
  91. package/dist/ui/components/Chart.svelte +1070 -0
  92. package/dist/ui/components/Column.svelte +172 -0
  93. package/dist/ui/components/DateRange.svelte +324 -0
  94. package/dist/ui/components/Dropdown.svelte +738 -0
  95. package/dist/ui/components/DropdownOption.svelte +21 -0
  96. package/dist/ui/components/ECharts.svelte +77 -0
  97. package/dist/ui/components/ErrorChart.svelte +54 -0
  98. package/dist/ui/components/GrapheneQuery.svelte +12 -0
  99. package/dist/ui/components/InlineDelta.svelte +150 -0
  100. package/dist/ui/components/Line.svelte +210 -0
  101. package/dist/ui/components/LineChart.svelte +178 -0
  102. package/dist/ui/components/PieChart.svelte +36 -0
  103. package/dist/ui/components/QueryLoad.svelte +82 -0
  104. package/dist/ui/components/Row.svelte +14 -0
  105. package/dist/ui/components/SortIcon.svelte +32 -0
  106. package/dist/ui/components/Table.svelte +19 -0
  107. package/dist/ui/components/TableCell.svelte +75 -0
  108. package/dist/ui/components/TableGroupRow.svelte +136 -0
  109. package/dist/ui/components/TableGroupToggle.svelte +42 -0
  110. package/dist/ui/components/TableHeader.svelte +242 -0
  111. package/dist/ui/components/TableRow.svelte +283 -0
  112. package/dist/ui/components/TableSubtotalRow.svelte +62 -0
  113. package/dist/ui/components/TableTotalRow.svelte +88 -0
  114. package/dist/ui/components/TextInput.svelte +92 -0
  115. package/dist/ui/components/_Table.svelte +516 -0
  116. package/dist/ui/internal/clientCache.ts +43 -0
  117. package/dist/ui/internal/queryEngine.ts +169 -0
  118. package/dist/ui/internal/telemetry.ts +28 -0
  119. package/dist/ui/internal/theme.ts +88 -0
  120. package/dist/ui/layout.svelte +3 -0
  121. package/dist/ui/playwright.config.ts +30 -0
  122. package/dist/ui/web.js +106 -0
  123. package/package.json +71 -0
@@ -0,0 +1,236 @@
1
+ import getDistinctValues from './getDistinctValues.js'
2
+ import {fmt} from './formatting.js'
3
+
4
+ export default function getSeriesConfig (
5
+ data,
6
+ x,
7
+ y,
8
+ series,
9
+ swapXY,
10
+ baseConfig,
11
+ name,
12
+ xMismatch, // this checks for scenarios where xType is string and xDataType is number. When this is the case, we need to inject strings into the x axis, or else it will cause echarts to think there are duplicate x-axis values (e.g., "4" and 4)
13
+ columnSummary,
14
+ seriesOrder,
15
+ size = undefined,
16
+ tooltipTitle = undefined,
17
+ y2 = undefined,
18
+ seriesLabelFmt = undefined,
19
+ ) {
20
+ function generateTempConfig (seriesData, seriesName, yAxisIndex, baseConfig) {
21
+ let tempConfig = {
22
+ name: seriesName,
23
+ data: seriesData,
24
+ yAxisIndex: yAxisIndex,
25
+ }
26
+ tempConfig = {...baseConfig, ...tempConfig}
27
+ return tempConfig
28
+ }
29
+
30
+ let i
31
+ let j
32
+ let tempConfig
33
+ let seriesConfig = []
34
+ let seriesData
35
+ let filteredData
36
+ let seriesName
37
+ let seriesDistinct
38
+ let yAxisIndex
39
+
40
+ // y = single, y2 = empty
41
+ // y = single, y2 = single
42
+ // y = single, y2 = array
43
+
44
+ // y = array, y2 = empty
45
+ // y = array, y2 = single
46
+ // y = array, y2 = array
47
+
48
+ // y = empty, y2 = empty
49
+ // y = empty, y2 = single
50
+ // y = empty, y2 = array
51
+
52
+ // colname, yAxisIndex
53
+
54
+ function combineVariables (variable1, variable2) {
55
+ // Returns an array of arrays, where each individual array is [column_name, yAxisIndex], where yAxisIndex is 0 for y and 1 for y2.
56
+ // E.g., [ ['sales', 0 ], ['gross_profit', 1]] - sales on primary axis, gross profit on secondary
57
+ let array = []
58
+
59
+ // Helper function to check if a value is undefined
60
+ function isUndefined (value) {
61
+ return typeof value === 'undefined'
62
+ }
63
+
64
+ // Helper function to add non-undefined values to the array with source indicator
65
+ function addValuesToArray (value, source) {
66
+ if (!isUndefined(value)) {
67
+ if (Array.isArray(value)) {
68
+ value.forEach((item) => array.push([item, source]))
69
+ } else {
70
+ array.push([value, source])
71
+ }
72
+ }
73
+ }
74
+
75
+ addValuesToArray(variable1, 0)
76
+ addValuesToArray(variable2, 1)
77
+
78
+ return array
79
+ }
80
+
81
+ let yList = combineVariables(y, y2)
82
+
83
+ // 1) Series column with single y column
84
+ if (series != null && yList.length === 1) {
85
+ seriesDistinct = getDistinctValues(data, series)
86
+
87
+ for (i = 0; i < seriesDistinct.length; i++) {
88
+ // Filter for specific series:
89
+ filteredData = data.filter((d) => d[series] === seriesDistinct[i])
90
+
91
+ if (swapXY) {
92
+ seriesData = filteredData.map((d) => [d[yList[0][0]], xMismatch ? d[x].toString() : d[x]])
93
+ } else {
94
+ seriesData = filteredData.map((d) => [xMismatch ? d[x].toString() : d[x], d[yList[0][0]]])
95
+ }
96
+
97
+ // Append size column if supplied (for bubble chart):
98
+ if (size) {
99
+ let sizeData = filteredData.map((d) => d[size])
100
+ seriesData.forEach((item, index) => item.push(sizeData[index]))
101
+ }
102
+
103
+ // Append tooltip label if supplied:
104
+ if (tooltipTitle) {
105
+ let tooltipData = filteredData.map((d) => d[tooltipTitle])
106
+ seriesData.forEach((item, index) => item.push(tooltipData[index]))
107
+ }
108
+
109
+ // Set series name:
110
+ seriesName = seriesDistinct[i] ?? 'null'
111
+
112
+ // Set y-axis index (used for multi-y axis charts):
113
+ yAxisIndex = yList[0][1]
114
+
115
+ tempConfig = generateTempConfig(seriesData, seriesName, yAxisIndex, baseConfig)
116
+ seriesConfig.push(tempConfig)
117
+ }
118
+ }
119
+
120
+ // 2) Series column with multiple y columns
121
+ if (series != null && yList.length > 1) {
122
+ seriesDistinct = getDistinctValues(data, series)
123
+ for (i = 0; i < seriesDistinct.length; i++) {
124
+ // Filter for specific series:
125
+ filteredData = data.filter((d) => d[series] === seriesDistinct[i])
126
+
127
+ for (j = 0; j < yList.length; j++) {
128
+ if (swapXY) {
129
+ seriesData = filteredData.map((d) => [
130
+ d[yList[j][0]],
131
+ xMismatch ? d[x].toString() : d[x],
132
+ ])
133
+ } else {
134
+ seriesData = filteredData.map((d) => [
135
+ xMismatch ? d[x].toString() : d[x],
136
+ d[yList[j][0]],
137
+ ])
138
+ }
139
+
140
+ // Append size column if supplied (for bubble chart):
141
+ if (size) {
142
+ let sizeData = filteredData.map((d) => d[size])
143
+ seriesData.forEach((item, index) => item.push(sizeData[index]))
144
+ }
145
+
146
+ // Append tooltip label if supplied:
147
+ if (tooltipTitle) {
148
+ let tooltipData = filteredData.map((d) => d[tooltipTitle])
149
+ seriesData.forEach((item, index) => item.push(tooltipData[index]))
150
+ }
151
+
152
+ // Set series name:
153
+ seriesName = (seriesDistinct[i] ?? 'null') + ' - ' + columnSummary[yList[j][0]].title
154
+
155
+ // Set y-axis index (used for multi-y axis charts):
156
+ yAxisIndex = yList[j][1]
157
+
158
+ tempConfig = generateTempConfig(seriesData, seriesName, yAxisIndex, baseConfig)
159
+ seriesConfig.push(tempConfig)
160
+ }
161
+ }
162
+ }
163
+
164
+ // 3) Multiple y columns without series column
165
+ if (series == null && yList.length > 1) {
166
+ for (i = 0; i < yList.length; i++) {
167
+ if (swapXY) {
168
+ seriesData = data.map((d) => [d[yList[i][0]], xMismatch ? d[x].toString() : d[x]])
169
+ } else {
170
+ seriesData = data.map((d) => [xMismatch ? d[x].toString() : d[x], d[yList[i][0]]])
171
+ }
172
+
173
+ // Append size column if supplied (for bubble chart):
174
+ if (size) {
175
+ let sizeData = data.map((d) => d[size])
176
+ seriesData.forEach((item, index) => item.push(sizeData[index]))
177
+ }
178
+
179
+ // Append tooltip label if supplied:
180
+ if (tooltipTitle) {
181
+ let tooltipData = data.map((d) => d[tooltipTitle])
182
+ seriesData.forEach((item, index) => item.push(tooltipData[index]))
183
+ }
184
+
185
+ seriesName = columnSummary[yList[i][0]].title
186
+
187
+ // Set y-axis index (used for multi-y axis charts):
188
+ yAxisIndex = yList[i][1]
189
+
190
+ tempConfig = generateTempConfig(seriesData, seriesName, yAxisIndex, baseConfig)
191
+ seriesConfig.push(tempConfig)
192
+ }
193
+ }
194
+
195
+ // 4) Single y column without series column
196
+ if (series == null && yList.length === 1) {
197
+ if (swapXY) {
198
+ seriesData = data.map((d) => [d[yList[0][0]], xMismatch ? d[x].toString() : d[x]])
199
+ } else {
200
+ seriesData = data.map((d) => [xMismatch ? d[x].toString() : d[x], d[yList[0][0]]])
201
+ }
202
+
203
+ // Append size column if supplied (for bubble chart):
204
+ if (size) {
205
+ let sizeData = data.map((d) => d[size])
206
+ seriesData.forEach((item, index) => item.push(sizeData[index]))
207
+ }
208
+
209
+ // Append tooltip label if supplied:
210
+ if (tooltipTitle) {
211
+ let tooltipData = data.map((d) => d[tooltipTitle])
212
+ seriesData.forEach((item, index) => item.push(tooltipData[index]))
213
+ }
214
+
215
+ seriesName = columnSummary[yList[0][0]].title
216
+
217
+ // Set y-axis index (used for multi-y axis charts):
218
+ yAxisIndex = yList[0][1]
219
+
220
+ tempConfig = generateTempConfig(seriesData, seriesName, yAxisIndex, baseConfig)
221
+ seriesConfig.push(tempConfig)
222
+ }
223
+
224
+ if (seriesOrder) {
225
+ seriesConfig.sort((a, b) => seriesOrder.indexOf(a.name) - seriesOrder.indexOf(b.name))
226
+ }
227
+
228
+ // format series config:
229
+ if (seriesLabelFmt) {
230
+ seriesConfig.forEach((item) => {
231
+ item.name = fmt(item.name, seriesLabelFmt)
232
+ })
233
+ }
234
+
235
+ return seriesConfig
236
+ }
@@ -0,0 +1,7 @@
1
+ export default function getSortedData (data, col, isAsc) {
2
+ let res = [...data].sort((a, b) => {
3
+ return (a[col] < b[col] ? -1 : 1) * (isAsc ? 1 : -1)
4
+ })
5
+ res._evidenceColumnTypes = data._evidenceColumnTypes
6
+ return res
7
+ }
@@ -0,0 +1,43 @@
1
+ import {tidy, groupBy, sum, mutateWithSummary, mutate, rate, rename} from '@tidyjs/tidy'
2
+
3
+ export default function getStackPercentages (data, groupCol, valueCol) {
4
+ let pctData
5
+ if (typeof valueCol !== 'object') {
6
+ pctData = tidy(
7
+ data,
8
+ groupBy(groupCol, mutateWithSummary({xTotal: sum(valueCol)})),
9
+ mutate({percentOfX: rate(valueCol, 'xTotal')}),
10
+ rename({
11
+ percentOfX: valueCol + '_pct',
12
+ }),
13
+ )
14
+ } else {
15
+ pctData = tidy(
16
+ data,
17
+ mutate({
18
+ valueSum: 0,
19
+ }),
20
+ )
21
+
22
+ for (let i = 0; i < pctData.length; i++) {
23
+ pctData[i].valueSum = 0
24
+ for (let j = 0; j < valueCol.length; j++) {
25
+ pctData[i].valueSum = pctData[i].valueSum + pctData[i][valueCol[j]]
26
+ }
27
+ }
28
+
29
+ pctData = tidy(pctData, groupBy(groupCol, mutateWithSummary({xTotal: sum('valueSum')})))
30
+
31
+ for (let i = 0; i < valueCol.length; i++) {
32
+ pctData = tidy(
33
+ pctData,
34
+ mutate({percentOfX: rate(valueCol[i], 'xTotal')}),
35
+ rename({
36
+ percentOfX: valueCol[i] + '_pct',
37
+ }),
38
+ )
39
+ }
40
+ }
41
+
42
+ return pctData
43
+ }
@@ -0,0 +1,17 @@
1
+ import {tidy, groupBy, summarizeAt, sum} from '@tidyjs/tidy'
2
+
3
+ export default function getStackedData (data, groupCol, valueCol) {
4
+ let stackedData = tidy(data, groupBy(groupCol, [summarizeAt(valueCol, sum)]))
5
+
6
+ // If multiple y columns, iterate through data and add stack total column for sorting:
7
+ if (typeof valueCol === 'object') {
8
+ for (let i = 0; i < stackedData.length; i++) {
9
+ stackedData[i].stackTotal = 0
10
+ for (let j = 0; j < valueCol.length; j++) {
11
+ stackedData[i].stackTotal = stackedData[i].stackTotal + stackedData[i][valueCol[j]]
12
+ }
13
+ }
14
+ }
15
+
16
+ return stackedData
17
+ }
@@ -0,0 +1,15 @@
1
+ // Helper function for multi-series tooltips:
2
+ // Returns the yAxisIndex for a series since we can't currently access that in ECharts' params
3
+ export default function getYAxisIndex (componentIndex, yCount, y2Count) {
4
+ let totalPatternCount = yCount + y2Count
5
+
6
+ // Find the position of the index in the repeating sequence
7
+ let positionInPattern = componentIndex % totalPatternCount
8
+
9
+ // If the position lies within yCount, return 0, otherwise return 1
10
+ if (positionInPattern < yCount) {
11
+ return 0
12
+ } else {
13
+ return 1
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ export const CUSTOM_FORMATTING_SETTINGS_CONTEXT_KEY = 'customFormattingSettings'
@@ -0,0 +1,119 @@
1
+ /**
2
+ * This function is used to find difference between consecutive elements in an array.
3
+ *
4
+ * @param {Array<number>} arr - The array from which differences need to be found.
5
+ * @return {Array<number>} An array containing the differences between consecutive elements.
6
+ */
7
+ export function getDiffs (arr) {
8
+ let diffs = []
9
+ for (let i = 1; i < arr.length; i++) diffs.push(arr[i] - arr[i - 1])
10
+ return diffs
11
+ }
12
+
13
+ /**
14
+ * The function is used to find greatest common divisor (gcd) between two numbers.
15
+ *
16
+ * @param {number} a - The first number to find gcd.
17
+ * @param {number} b - The second number to find gcd.
18
+ * @return {number} The greatest common divisor of the input numbers a and b.
19
+ */
20
+ export function gcd (a, b) {
21
+ // Treat non-numeric types as 0
22
+ if (typeof a !== 'number' || isNaN(a)) a = 0
23
+ if (typeof b !== 'number' || isNaN(b)) b = 0
24
+
25
+ // Handle negative numbers properly
26
+ // Never reaches base case w/o this
27
+ a = Math.abs(a)
28
+ b = Math.abs(b)
29
+
30
+ // base case
31
+ if (b <= 0.01) {
32
+ return a
33
+ } else {
34
+ return gcd(b, a % b)
35
+ }
36
+ }
37
+
38
+ /**
39
+ * This function is used to find the minimum and maximum values in an array.
40
+ *
41
+ * @param {Array} values - An array from which min and max values should be determined.
42
+ * @param {Function} [valueof] - An optional function that defines how to obtain the measuring value.
43
+ * @return {Array} An array containing the minimum and maximum of numbers, respectively.
44
+ */
45
+ export function extent (values, valueof) {
46
+ if (!Array.isArray(values)) throw new TypeError('Cannot calculate extent of non-array value.')
47
+ let min
48
+ let max
49
+ if (valueof === undefined) {
50
+ for (let candidate of values) {
51
+ if (typeof candidate !== 'number' || Number.isNaN(candidate)) continue
52
+
53
+ if (min === undefined || candidate < min) min = candidate
54
+ if (max === undefined || candidate > max) max = candidate
55
+ }
56
+ return [min, max]
57
+ }
58
+
59
+ let index = -1
60
+ for (let original of values) {
61
+ if (typeof original !== 'number') continue
62
+ let candidate = valueof(original, ++index, values)
63
+ if (candidate == null || Number.isNaN(candidate)) continue
64
+
65
+ if (min === undefined || candidate < min) min = candidate
66
+ if (max === undefined || candidate > max) max = candidate
67
+ }
68
+ return [min, max]
69
+ }
70
+
71
+ /**
72
+ * This function generates a sequence of numbers as a vector from minimum to maximum with the given period increment.
73
+ *
74
+ * @param {Array<number>} values - An array containing the data to be sequenced.
75
+ * @param {number} period - The incremental value for each step in the sequence.
76
+ * @return {Array<number>} An array containing the sequenced numbers.
77
+ */
78
+ export function vectorSeq (values, period) {
79
+ let [min, max] = extent(values)
80
+
81
+ let sequence = []
82
+ let value = min
83
+ while (value <= max) {
84
+ sequence.push(Math.round((value + Number.EPSILON) * 100000000) / 100000000)
85
+ value += period
86
+ }
87
+
88
+ return sequence
89
+ }
90
+
91
+ /**
92
+ * This function is used to find the interval distance among numbers in an array.
93
+ *
94
+ * @param {Array<number>} arr - An array containing numbers from which interval is calculated.
95
+ * @return {number|undefined} The interval between numbers in the sorted array, or undefined if the array has only one element.
96
+ */
97
+ export function findInterval (arr) {
98
+ if (arr.length <= 1) {
99
+ return
100
+ }
101
+
102
+ // Sort array ascending
103
+ arr.sort(function (a, b) {
104
+ return a - b
105
+ })
106
+
107
+ // 1. Multiply array by 100
108
+ arr = arr.map(function (x) {
109
+ return x * 100000000
110
+ })
111
+
112
+ // 2. Get diffs
113
+ arr = getDiffs(arr)
114
+
115
+ // 3. Calculate greatest common divisor of diffs and divide by 100
116
+ let interval = arr.reduce((a, b) => gcd(a, b)) / 100000000
117
+ interval = Math.round((interval + Number.EPSILON) * 100000000) / 100000000
118
+ return interval
119
+ }
@@ -0,0 +1,25 @@
1
+
2
+ export function toBoolean (value: any): boolean {
3
+ if (typeof value === 'boolean') return value
4
+ if (typeof value === 'number') return value !== 0
5
+ if (typeof value === 'string') {
6
+ let trimmed = value.trim().toLowerCase()
7
+ if (trimmed === 'true' || trimmed === 'yes' || trimmed === '1') return true
8
+ if (trimmed === 'false' || trimmed === 'no' || trimmed === '0' || trimmed === '') return false
9
+ }
10
+ return Boolean(value)
11
+ }
12
+
13
+ export function ensureArray<T> (value: T | T[] | undefined | null): T[] {
14
+ if (Array.isArray(value)) return value
15
+ if (value === undefined || value === null) return []
16
+ return [value]
17
+ }
18
+
19
+ export function serializeValue (value: unknown): string {
20
+ if (value === null || value === undefined) return 'NULL'
21
+ if (typeof value === 'number' || typeof value === 'bigint') return String(value)
22
+ if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE'
23
+ let str = String(value)
24
+ return `'${str.replace(/'/g, "''")}'`
25
+ }
@@ -0,0 +1,14 @@
1
+ import {tidy, replaceNully} from '@tidyjs/tidy'
2
+
3
+ export default function replaceNulls (data, columns) {
4
+ let colObj = {}
5
+ if (typeof columns === 'object') {
6
+ for (let i = 0; i < columns.length; i++) {
7
+ colObj[columns[i]] = 0
8
+ }
9
+ } else {
10
+ colObj[columns] = 0
11
+ }
12
+ data = tidy(data, replaceNully(colObj))
13
+ return data
14
+ }
@@ -0,0 +1,120 @@
1
+ import {strictBuild} from './chartContext.js'
2
+
3
+ type ColumnSummary = {
4
+ id: string
5
+ type?: string
6
+ format?: any
7
+ columnUnitSummary?: any
8
+ }
9
+
10
+ type ColumnOption = {
11
+ id: string
12
+ }
13
+
14
+ type ColumnLike = ColumnOption & Partial<ColumnSummary>
15
+
16
+ export const safeExtractColumn = <T extends ColumnLike>(column: T, columnSummary: ColumnSummary[]): ColumnSummary => {
17
+ let foundCols = columnSummary.filter(d => d.id === column.id)
18
+ if (!foundCols.length) {
19
+ let error = column.id === undefined
20
+ ? new Error('please add an "id" property to all the <Column ... />')
21
+ : new Error(`column with id: "${column.id}" not found`)
22
+ if (strictBuild) throw error
23
+ console.warn(error.message)
24
+ return {id: column.id ?? ''}
25
+ }
26
+ return foundCols[0]
27
+ }
28
+
29
+ export const weightedMean = (data: Record<string, unknown>[], valueCol: string, weightCol?: string | null): number | null => {
30
+ if (!weightCol) return null
31
+ if (!data.length) return null
32
+
33
+ let totalWeightedValue = 0
34
+ let totalWeight = 0
35
+
36
+ for (let item of data) {
37
+ let value = Number(item[valueCol] ?? 0)
38
+ let weight = Number(item[weightCol] ?? 0)
39
+ totalWeightedValue += value * weight
40
+ totalWeight += weight
41
+ }
42
+
43
+ return totalWeight > 0 ? totalWeightedValue / totalWeight : 0
44
+ }
45
+
46
+ export const median = (data: Record<string, unknown>[], column: string): number => {
47
+ let values = data
48
+ .map(item => item[column])
49
+ .filter(val => val !== undefined && val !== null && !Number.isNaN(Number(val)))
50
+ .map(val => Number(val))
51
+ .sort((a, b) => a - b)
52
+
53
+ if (!values.length) return 0
54
+
55
+ let mid = Math.floor(values.length / 2)
56
+ return values.length % 2 !== 0 ? values[mid] : (values[mid - 1] + values[mid]) / 2
57
+ }
58
+
59
+ export const aggregateColumn = (
60
+ data: Record<string, unknown>[],
61
+ columnName: string,
62
+ aggType: string | undefined,
63
+ columnType?: string,
64
+ weightColumnName?: string | null,
65
+ ): number | string | null => {
66
+ if (!data || !data.length) return null
67
+
68
+ if (!aggType && columnType === 'number') aggType = 'sum'
69
+
70
+ if (
71
+ columnType !== 'number' &&
72
+ ['sum', 'min', 'max', 'mean', 'weightedMean', 'median', undefined].includes(aggType as any)
73
+ ) {
74
+ return '-'
75
+ }
76
+
77
+ let columnValues = data
78
+ .map(row => row[columnName])
79
+ .filter(val => val !== undefined && val !== null)
80
+ .map(val => Number(val))
81
+
82
+ switch (aggType) {
83
+ case 'sum':
84
+ return columnValues.reduce((sum, val) => sum + Number(val), 0)
85
+ case 'min':
86
+ return Math.min(...columnValues)
87
+ case 'max':
88
+ return Math.max(...columnValues)
89
+ case 'mean':
90
+ return columnValues.length
91
+ ? columnValues.reduce((sum, val) => sum + Number(val), 0) / columnValues.length
92
+ : '-'
93
+ case 'count':
94
+ return data.length
95
+ case 'countDistinct':
96
+ return new Set(columnValues).size
97
+ case 'weightedMean':
98
+ if (!weightColumnName) return 'Weight column name required for weightedMean'
99
+ let totalWeight = 0
100
+ let weightedSum = 0
101
+ for (let row of data) {
102
+ let weight = Number(row[weightColumnName] ?? 0)
103
+ totalWeight += weight
104
+ weightedSum += Number(row[columnName] ?? 0) * weight
105
+ }
106
+ return totalWeight > 0 ? weightedSum / totalWeight : null
107
+ case 'median':
108
+ return median(data, columnName)
109
+ case undefined:
110
+ return '-'
111
+ default:
112
+ return aggType ?? '-'
113
+ }
114
+ }
115
+
116
+ export const getFinalColumnOrder = (columns: string[], priorityColumns: Array<string | undefined>): string[] => {
117
+ let priorities = priorityColumns.filter(Boolean) as string[]
118
+ let restColumns = columns.filter(key => !priorities.includes(key))
119
+ return [...priorities, ...restColumns]
120
+ }