@graphenedata/cli 0.0.15 → 0.0.16

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 +138 -0
  2. package/dist/cli/bigQuery-I3F46SC6.js +75 -0
  3. package/dist/cli/bigQuery-I3F46SC6.js.map +7 -0
  4. package/dist/cli/chunk-OVWODUTJ.js +12849 -0
  5. package/dist/cli/chunk-OVWODUTJ.js.map +7 -0
  6. package/dist/cli/chunk-QAXEOZ43.js +53 -0
  7. package/dist/cli/chunk-QAXEOZ43.js.map +7 -0
  8. package/dist/cli/cli.js +234 -11197
  9. package/dist/cli/clickhouse-ZN5AN2UL.js +64 -0
  10. package/dist/cli/clickhouse-ZN5AN2UL.js.map +7 -0
  11. package/dist/cli/duckdb-IYBIO5KJ.js +87 -0
  12. package/dist/cli/duckdb-IYBIO5KJ.js.map +7 -0
  13. package/dist/cli/serve2-TNN5EROW.js +447 -0
  14. package/dist/cli/serve2-TNN5EROW.js.map +7 -0
  15. package/dist/cli/snowflake-MOQB5GA4.js +128 -0
  16. package/dist/cli/snowflake-MOQB5GA4.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 +150 -96
  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 +72 -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 +763 -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 +80 -17
  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 +102 -117
  72. package/dist/ui/internal/runSocket.ts +32 -12
  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 +28 -11
  77. package/package.json +36 -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,995 +0,0 @@
1
- <script lang="ts">
2
- import {setContext, type Snippet} from 'svelte'
3
- import {type Writable, writable, get} from 'svelte/store'
4
- import {propKey, configKey} from '../component-utilities/chartContext.js'
5
- import ECharts from './ECharts.svelte'
6
- import getColumnSummary from '../component-utilities/getColumnSummary.js'
7
- import getDistinctValues from '../component-utilities/getDistinctValues.js'
8
- import getDistinctCount from '../component-utilities/getDistinctCount.js'
9
- import getStackPercentages from '../component-utilities/getStackPercentages.js'
10
- import getSortedData from '../component-utilities/getSortedData.js'
11
- import getYAxisIndex from '../component-utilities/getYAxisIndex.js'
12
- import {standardizeDateColumn} from '../component-utilities/dateParsing.js'
13
- import {formatAxisValue, formatValue, getFormatObjectFromString} from '../component-utilities/formatting.js'
14
- import formatTitle from '../component-utilities/formatTitle.js'
15
- import ErrorDisplay from '../internal/ErrorDisplay.svelte'
16
- import checkInputs from '../component-utilities/checkInputs.js'
17
- import {getThemeStores} from '../component-utilities/themeStores'
18
- import {toBoolean} from '../component-utilities/convert'
19
- import {parseCommaList} from '../component-utilities/inputUtils.ts'
20
- import {logError} from '../internal/telemetry.ts'
21
-
22
- interface Props {
23
- data?: any, chartContext?: any, queryID?: any, x?: any, y?: any, y2?: any, series?: any, size?: any
24
- tooltipTitle?: any, showAllXAxisLabels?: any, swapXY?: boolean | string, title?: string, subtitle?: string
25
- chartType?: string, bubble?: boolean, hist?: boolean, boxplot?: boolean, xType?: string
26
- xAxisTitle?: string, xBaseline?: boolean | string, xTickMarks?: boolean | string
27
- xGridlines?: boolean | string, xAxisLabels?: boolean | string, sort?: boolean | string, xFmt?: any
28
- xMin?: any, xMax?: any, yLog?: boolean | string, yType?: string, yLogBase?: number, yAxisTitle?: string
29
- yBaseline?: boolean | string, yTickMarks?: boolean | string, yGridlines?: boolean | string
30
- yAxisLabels?: boolean | string, yMin?: any, yMax?: any, yScale?: boolean | string, yFmt?: any
31
- yAxisColor?: string, y2AxisTitle?: string, y2Baseline?: boolean | string, y2TickMarks?: boolean | string
32
- y2Gridlines?: boolean | string, y2AxisLabels?: boolean | string, y2Min?: any, y2Max?: any
33
- y2Scale?: boolean | string, y2Fmt?: any, y2AxisColor?: string, sizeFmt?: any, colorPalette?: string
34
- legend?: any, echartsOptions?: any, seriesOptions?: any, seriesColors?: any, stackType?: string
35
- stacked100?: boolean, chartAreaHeight?: any, connectGroup?: string, leftPadding?: any, rightPadding?: any
36
- xLabelWrap?: boolean | string, children?: Snippet
37
- }
38
-
39
- // Note: renamed from 'props' to 'chartProps' to avoid conflict with $props() rune
40
- let chartProps = writable({})
41
- let config: Writable<any> = writable({})
42
-
43
- setContext(propKey, chartProps)
44
- setContext(configKey, config)
45
-
46
- const {theme, resolveColor, resolveColorsObject, resolveColorPalette} = getThemeStores()
47
-
48
- let {
49
- data = undefined, chartContext = undefined, queryID = undefined, x = undefined, y = undefined,
50
- y2 = undefined, series = undefined, size = undefined, tooltipTitle = undefined,
51
- showAllXAxisLabels = undefined, swapXY = false, title = undefined, subtitle = undefined,
52
- chartType = 'Chart', bubble = false, hist = false, boxplot = false, xType = undefined,
53
- xAxisTitle = 'false', xBaseline = true, xTickMarks = false, xGridlines = false, xAxisLabels = true,
54
- sort = true, xFmt = undefined, xMin = undefined, xMax = undefined, yLog = false, yType = undefined,
55
- yLogBase = 10, yAxisTitle = 'false', yBaseline = false, yTickMarks = false, yGridlines = true,
56
- yAxisLabels = true, yMin = undefined, yMax = undefined, yScale = false, yFmt = undefined,
57
- yAxisColor = 'true', y2AxisTitle = 'false', y2Baseline = false, y2TickMarks = false,
58
- y2Gridlines = true, y2AxisLabels = true, y2Min = undefined, y2Max = undefined, y2Scale = false,
59
- y2Fmt = undefined, y2AxisColor = 'true', sizeFmt = undefined, colorPalette = 'default',
60
- legend = undefined, echartsOptions = undefined, seriesOptions = undefined, seriesColors = undefined,
61
- stackType = undefined, stacked100 = false, chartAreaHeight = undefined, connectGroup = undefined,
62
- leftPadding = undefined, rightPadding = undefined, xLabelWrap = false, children,
63
- }: Props = $props()
64
-
65
- // This should be reworked to fit better with svelte's reactivity.
66
-
67
- // We rewrite the x and y values with fallbacks if they aren't present
68
- // the fallback logic *depends* on the values of x and y
69
- // when x and y are replaced by the fallbacks, the fallback logic doesn't reset.
70
- // if the y value isn't set, var y gets populated with a fall back from the data.
71
- // if the data changes, we are now acting as if the fallback from above was entered by the user, and
72
- // then we throw if the fallback column is now missing.
73
-
74
- // This is a hack to get around the above
75
- // Track whether x/y were initially set (not using fallbacks)
76
- // These capture the initial values intentionally - they're set once on mount
77
- // and updated in the effect. Using closure pattern to silence state_referenced_locally warning.
78
- let ySet = $state((() => y ? true : false)())
79
- // const y2Set = y2 ? true : false;
80
- let xSet = $state((() => x ? true : false)())
81
-
82
- // Convert boolean string props to actual booleans
83
- let swapXY_bool = $derived(toBoolean(swapXY))
84
- let xBaseline_bool = $derived(toBoolean(xBaseline))
85
- let xTickMarks_bool = $derived(toBoolean(xTickMarks))
86
- let xGridlines_bool = $derived(toBoolean(xGridlines))
87
- let xAxisLabels_bool = $derived(toBoolean(xAxisLabels))
88
- let sort_bool = $derived(toBoolean(sort))
89
- let yLog_bool = $derived(toBoolean(yLog))
90
- let yBaseline_bool = $derived(toBoolean(yBaseline))
91
- let yTickMarks_bool = $derived(toBoolean(yTickMarks))
92
- let yGridlines_bool = $derived(toBoolean(yGridlines))
93
- let yAxisLabels_bool = $derived(toBoolean(yAxisLabels))
94
- let yScale_bool = $derived(toBoolean(yScale))
95
- let y2Baseline_bool = $derived(toBoolean(y2Baseline))
96
- let y2TickMarks_bool = $derived(toBoolean(y2TickMarks))
97
- let y2Gridlines_bool = $derived(toBoolean(y2Gridlines))
98
- let y2AxisLabels_bool = $derived(toBoolean(y2AxisLabels))
99
- let y2Scale_bool = $derived(toBoolean(y2Scale))
100
- let xLabelWrap_bool = $derived(toBoolean(xLabelWrap))
101
-
102
- let yAxisColorStore = $derived(resolveColor(yAxisColor))
103
- let y2AxisColorStore = $derived(resolveColor(y2AxisColor))
104
- let colorPaletteResolved = $derived(resolveColorPalette(colorPalette))
105
- let seriesColorsResolved = $derived(resolveColorsObject(seriesColors))
106
-
107
- let reqCols
108
- let showAllXAxisLabelsResolved = $state(false)
109
-
110
- let xAxisLabelOverflow = $derived(xLabelWrap_bool ? 'break' : 'truncate')
111
-
112
- // ---------------------------------------------------------------------------------------
113
- // Variable Declaration
114
- // ---------------------------------------------------------------------------------------
115
- // Column Summary:
116
- let columnSummary
117
- let columnNames
118
- let uColNames = []
119
- let unusedColumns = []
120
- let uColType
121
- let uColName
122
- let xDataType
123
- let xMismatch
124
- let xFormat
125
- let yFormat
126
- let y2Format
127
- let sizeFormat
128
- let xUnitSummary
129
- let yUnitSummary
130
- let y2UnitSummary
131
- let xDistinct
132
-
133
- // Individual Config Sections:
134
- let horizAxisConfig
135
- let verticalAxisConfig
136
- let horizAxisTitleConfig
137
- let chartConfig
138
-
139
- // Chart area sizing:
140
- let hasTitle
141
- let hasSubtitle
142
- let hasLegend
143
- let hasTopAxisTitle
144
- let hasBottomAxisTitle
145
- let titleFontSize
146
- let subtitleFontSize
147
- let titleBoxPadding
148
- let titleBoxHeight
149
- let chartAreaPaddingTop
150
- let chartAreaPaddingBottom
151
- let bottomAxisTitleSize
152
- let topAxisTitleSize
153
- let legendHeight
154
- let legendPaddingTop
155
- let legendTop
156
- let chartTop
157
- let chartBottom
158
- let chartContainerHeight
159
- let topAxisTitleTop
160
-
161
- let horizAxisTitle
162
-
163
- // Adjustment to avoid small bars on horizontal bar chart (extend chart height to accomodate):
164
- let maxBars
165
- let barCount
166
- let heightMultiplier
167
-
168
- // Set final chart height:
169
- // Using a separate writable store for dimensions so they're reactive in the template
170
- // without causing infinite effect loops (which $state would cause since the effect reads+writes them).
171
- let dimensions = writable<{height?: string, width?: string}>({})
172
-
173
- let missingCols = []
174
-
175
- let originalRun = true
176
-
177
- // Error Handling:
178
-
179
- let inputCols = []
180
- let optCols = []
181
- let i
182
-
183
- // svelte-ignore non_reactive_update
184
- let error
185
-
186
- // Date String Handling:
187
- let columnSummaryArray
188
- let dateCols
189
-
190
- $effect(() => {
191
- try {
192
- error = undefined
193
- missingCols = []
194
- unusedColumns = []
195
- // Error Handling:
196
- inputCols = []
197
- optCols = []
198
- uColName = []
199
- // Normalize list-like inputs first - use local variables instead of reassigning props
200
- let yLocal = parseCommaList(y)
201
- let y2Local = parseCommaList(y2)
202
- ySet = yLocal.length > 0
203
- xSet = x ? true : false
204
-
205
- checkInputs(data) // check that dataset exists
206
-
207
- // ---------------------------------------------------------------------------------------
208
- // Get column information
209
- // ---------------------------------------------------------------------------------------
210
- // Get column summary:
211
- columnSummary = getColumnSummary(data)
212
-
213
- // Get column names:
214
- columnNames = Object.keys(columnSummary)
215
-
216
- // ---------------------------------------------------------------------------------------
217
- // Make assumptions to complete required props
218
- // ---------------------------------------------------------------------------------------
219
- // If no x column was supplied, assume first column in dataset is x
220
- let xLocal = x
221
- if (!xSet) {
222
- xLocal = columnNames[0]
223
- }
224
-
225
- // If no y column(s) supplied, assume all number columns other than x are the y columns:
226
- if (!ySet) {
227
- uColNames = columnNames.filter(function(col) {
228
- return ![xLocal, series, size].includes(col)
229
- })
230
-
231
- for (let i = 0; i < uColNames.length; i++) {
232
- uColName = uColNames[i]
233
- uColType = columnSummary[uColName].type
234
- if (uColType === 'number') {
235
- unusedColumns.push(uColName)
236
- }
237
- }
238
-
239
- yLocal = unusedColumns // always array; empty handled by required prop checks
240
- }
241
- // Establish required columns based on chart type:
242
- if (bubble) {
243
- reqCols = {
244
- x: xLocal,
245
- y: yLocal,
246
- size: size,
247
- }
248
- } else if (hist) {
249
- reqCols = {
250
- x: xLocal,
251
- }
252
- } else if (boxplot) {
253
- reqCols = {}
254
- } else {
255
- reqCols = {
256
- x: xLocal,
257
- y: yLocal,
258
- }
259
- }
260
-
261
- // Check which columns were not supplied to the chart:
262
- for (let property in reqCols) {
263
- if (reqCols[property] == null) {
264
- missingCols.push(property)
265
- }
266
- }
267
-
268
- if (missingCols.length === 1) {
269
- throw Error(new Intl.ListFormat().format(missingCols) + ' is required')
270
- } else if (missingCols.length > 1) {
271
- throw Error(new Intl.ListFormat().format(missingCols) + ' are required')
272
- }
273
-
274
- // Fix for stacked100 overwriting y variable. Bandaid fix - not a long-term solution:
275
- if (stacked100 === true && Array.isArray(yLocal) && yLocal.some(col => col.includes('_pct')) && originalRun === false) {
276
- yLocal = yLocal.map(col => col.replace('_pct', ''))
277
- originalRun = false
278
- }
279
-
280
- // Check the inputs supplied to the chart:
281
- if (xLocal) {
282
- inputCols.push(xLocal)
283
- }
284
- if (Array.isArray(yLocal)) for (i = 0; i < yLocal.length; i++) inputCols.push(yLocal[i])
285
- if (Array.isArray(y2Local)) for (i = 0; i < y2Local.length; i++) inputCols.push(y2Local[i])
286
- if (size) {
287
- inputCols.push(size)
288
- }
289
- if (series) {
290
- optCols.push(series)
291
- }
292
- if (tooltipTitle) {
293
- optCols.push(tooltipTitle)
294
- }
295
-
296
- checkInputs(data, inputCols, optCols)
297
-
298
- // ---------------------------------------------------------------------------------------
299
- // Aggregate Data if Required
300
- // ---------------------------------------------------------------------------------------
301
- let dataLocal = data
302
- if (stacked100 === true) {
303
- dataLocal = getStackPercentages(dataLocal, xLocal, yLocal)
304
- yLocal = yLocal.map(col => col + '_pct')
305
- originalRun = false
306
- columnSummary = getColumnSummary(dataLocal)
307
- }
308
-
309
- // ---------------------------------------------------------------------------------------
310
- // Define x axis type
311
- // ---------------------------------------------------------------------------------------
312
- xDataType = columnSummary[xLocal].type
313
-
314
- // Get xDataType into ECharts default types:
315
- switch (xDataType) {
316
- case 'number':
317
- xDataType = 'value'
318
- break
319
- case 'string':
320
- xDataType = 'category'
321
- break
322
- case 'date':
323
- xDataType = 'time'
324
- break
325
- default:
326
- break
327
- }
328
-
329
- let xTypeLocal = xType === 'category' ? 'category' : xDataType
330
-
331
- // Set xAxisLabel overflow behaviour based on column type
332
- let showAllXAxisLabelsLocal = showAllXAxisLabels
333
- if (!showAllXAxisLabelsLocal) {
334
- // if user has not set showXAxisLabels
335
- showAllXAxisLabelsLocal = xTypeLocal === 'category'
336
- } else {
337
- // if user has set showXAxisLabels, convert to boolean
338
- showAllXAxisLabelsLocal = showAllXAxisLabelsLocal === 'true' || showAllXAxisLabelsLocal === true
339
- }
340
- showAllXAxisLabelsResolved = showAllXAxisLabelsLocal
341
-
342
- // Throw error if attempting to plot value or time on horizontal x-axis:
343
- if (swapXY_bool && xTypeLocal !== 'category') {
344
- throw Error(
345
- 'Horizontal charts do not support a value or time-based x-axis. You can either change your SQL query to output string values or set swapXY=false.',
346
- )
347
- }
348
-
349
- // Throw error if attempting to plot secondary y-axis on horizontal chart:
350
- if (swapXY_bool && y2Local.length) {
351
- throw Error(
352
- 'Horizontal charts do not support a secondary y-axis. You can either set swapXY=false or remove the y2 prop from your chart.',
353
- )
354
- }
355
-
356
- // Override xType if axes are swapped - only category enabled on horizontal axis
357
- if (swapXY_bool) {
358
- xTypeLocal = 'category'
359
- }
360
-
361
- // Check for x mismatch:
362
- xMismatch = xDataType === 'value' && xTypeLocal === 'category'
363
-
364
- // ---------------------------------------------------------------------------------------
365
- // Sort data based on xType
366
- // ---------------------------------------------------------------------------------------
367
- if (sort_bool) {
368
- let sortColumn = xLocal
369
- if (xDataType === 'category') {
370
- sortColumn = Array.isArray(yLocal) ? (yLocal[0] ?? xLocal) : xLocal
371
- }
372
- let sortAscending = xDataType !== 'category'
373
- dataLocal = getSortedData(dataLocal, sortColumn, sortAscending)
374
- }
375
-
376
- // Always sort time axes by x - this prevents the lines from being drawn out of order
377
- if (xDataType === 'time') {
378
- dataLocal = getSortedData(dataLocal, xLocal, true)
379
- }
380
-
381
- // ---------------------------------------------------------------------------------------
382
- // Standardize date columns
383
- // ---------------------------------------------------------------------------------------
384
-
385
- columnSummaryArray = getColumnSummary(dataLocal, 'array')
386
- dateCols = columnSummaryArray.filter((d) => d.type === 'date')
387
- dateCols = dateCols.map((d) => d.id)
388
-
389
- if (dateCols.length > 0) {
390
- for (let i = 0; i < dateCols.length; i++) {
391
- dataLocal = standardizeDateColumn(dataLocal, dateCols[i])
392
- }
393
- }
394
-
395
- // ---------------------------------------------------------------------------------------
396
- // Get format codes for axes
397
- // ---------------------------------------------------------------------------------------
398
- if (xFmt) {
399
- xFormat = getFormatObjectFromString(xFmt, columnSummary[xLocal].type)
400
- } else {
401
- xFormat = columnSummary[xLocal].format
402
- }
403
-
404
- if (yLocal.length === 0) {
405
- yFormat = 'str'
406
- } else {
407
- if (yFmt) yFormat = getFormatObjectFromString(yFmt, columnSummary[yLocal[0]].type)
408
- else yFormat = columnSummary[yLocal[0]].format
409
- }
410
-
411
- if (y2Local.length) {
412
- if (y2Fmt) y2Format = getFormatObjectFromString(y2Fmt, columnSummary[y2Local[0]].type)
413
- else y2Format = columnSummary[y2Local[0]].format
414
- }
415
-
416
- if (size) {
417
- if (sizeFmt) {
418
- sizeFormat = getFormatObjectFromString(sizeFmt, columnSummary[size].type)
419
- } else {
420
- sizeFormat = columnSummary[size].format
421
- }
422
- }
423
-
424
- xUnitSummary = columnSummary[xLocal].columnUnitSummary
425
-
426
- if (yLocal.length) yUnitSummary = columnSummary[yLocal[0]].columnUnitSummary
427
-
428
- if (y2Local.length) y2UnitSummary = columnSummary[y2Local[0]].columnUnitSummary
429
-
430
- let xAxisTitleLocal = xAxisTitle
431
- if (xAxisTitleLocal === 'true') {
432
- xAxisTitleLocal = formatTitle(xLocal, xFormat)
433
- } else if (xAxisTitleLocal === 'false') {
434
- xAxisTitleLocal = ''
435
- }
436
-
437
- let yAxisTitleLocal = yAxisTitle
438
- if (yAxisTitleLocal === 'true') {
439
- if (yLocal.length === 1) {
440
- yAxisTitleLocal = formatTitle(yLocal[0], yFormat)
441
- } else {
442
- yAxisTitleLocal = ''
443
- }
444
- } else if (yAxisTitleLocal === 'false') {
445
- yAxisTitleLocal = ''
446
- }
447
-
448
- let y2AxisTitleLocal = y2AxisTitle
449
- if (y2AxisTitleLocal === 'true') {
450
- if (y2Local.length === 1) {
451
- y2AxisTitleLocal = formatTitle(y2Local[0], y2Format)
452
- } else {
453
- y2AxisTitleLocal = ''
454
- }
455
- } else if (y2AxisTitleLocal === 'false') {
456
- y2AxisTitleLocal = ''
457
- }
458
-
459
- // ---------------------------------------------------------------------------------------
460
- // Get total series count
461
- // ---------------------------------------------------------------------------------------
462
- let yCount = yLocal.length
463
- let seriesCount = series ? getDistinctCount(dataLocal, series) : 1
464
- let ySeriesCount = yCount * seriesCount
465
-
466
- // y2Count may need to be adjusted to also factor in the series column. For now, we really
467
- // only need to know that it's multi-series, so > 1 is sufficient
468
- let y2Count = y2Local.length
469
- let totalSeriesCount = ySeriesCount + y2Count
470
-
471
- // ---------------------------------------------------------------------------------------
472
- // Set legend flag
473
- // ---------------------------------------------------------------------------------------
474
- let legendLocal = legend
475
- if (legendLocal !== undefined) {
476
- legendLocal = legendLocal === 'true' || legendLocal === true
477
- }
478
-
479
- legendLocal = legendLocal ?? totalSeriesCount > 1
480
-
481
- // ---------------------------------------------------------------------------------------
482
- // Handle errors for log axes (cannot be used with stacked charts)
483
- // ---------------------------------------------------------------------------------------
484
-
485
- if (stacked100 === true && yLog_bool === true) {
486
- throw Error('Log axis cannot be used in a 100% stacked chart')
487
- } else if (stackType === 'stacked' && totalSeriesCount > 1 && yLog_bool === true) {
488
- throw Error('Log axis cannot be used in a stacked chart')
489
- }
490
-
491
- let minYValue
492
- if (yLocal.length) {
493
- minYValue = columnSummary[yLocal[0]].columnUnitSummary.min
494
- for (let i = 0; i < yLocal.length; i++) {
495
- if (columnSummary[yLocal[i]].columnUnitSummary.min < minYValue) {
496
- minYValue = columnSummary[yLocal[i]].columnUnitSummary.min
497
- }
498
- }
499
- }
500
-
501
- if (yLog_bool === true && minYValue <= 0 && minYValue !== null) {
502
- throw Error('Log axis cannot display values less than or equal to zero')
503
- }
504
-
505
- // ---------------------------------------------------------------------------------------
506
- // Compute chartAreaHeight locally
507
- // ---------------------------------------------------------------------------------------
508
- let chartAreaHeightLocal = chartAreaHeight
509
- if (chartAreaHeightLocal) {
510
- // if chartAreaHeight was user-supplied
511
- chartAreaHeightLocal = Number(chartAreaHeightLocal)
512
- if (isNaN(chartAreaHeightLocal)) {
513
- // input must be a number
514
- throw Error('chartAreaHeight must be a number')
515
- } else if (chartAreaHeightLocal <= 0) {
516
- throw Error('chartAreaHeight must be a positive number')
517
- }
518
- } else {
519
- chartAreaHeightLocal = 220
520
- }
521
-
522
- // Compute yType locally
523
- let yTypeLocal = yLog_bool === true ? 'log' : (yType ?? 'value')
524
-
525
- // ---------------------------------------------------------------------------------------
526
- // Add props to store to let child components access them
527
- // ---------------------------------------------------------------------------------------
528
- chartProps.update((d) => {
529
- return {
530
- ...d,
531
- error: undefined,
532
- data: dataLocal,
533
- x: xLocal,
534
- y: yLocal,
535
- y2: y2Local,
536
- series,
537
- swapXY: swapXY_bool,
538
- sort: sort_bool,
539
- xType: xTypeLocal,
540
- xFormat,
541
- yFormat,
542
- y2Format,
543
- sizeFormat,
544
- xMismatch,
545
- size,
546
- yMin,
547
- y2Min,
548
- columnSummary,
549
- xAxisTitle: xAxisTitleLocal,
550
- yAxisTitle: yAxisTitleLocal,
551
- y2AxisTitle: y2AxisTitleLocal,
552
- tooltipTitle,
553
- chartAreaHeight: chartAreaHeightLocal,
554
- chartType,
555
- yCount,
556
- y2Count,
557
- }
558
- })
559
-
560
- // ---------------------------------------------------------------------------------------
561
- // Axis Configuration
562
- // ---------------------------------------------------------------------------------------
563
- xDistinct = getDistinctValues(dataLocal, xLocal)
564
- let secondaryAxis
565
-
566
- if (swapXY_bool) {
567
- horizAxisConfig = {
568
- type: yTypeLocal,
569
- logBase: yLogBase,
570
- position: 'top',
571
- axisLabel: {
572
- show: yAxisLabels_bool,
573
- hideOverlap: true,
574
- showMaxLabel: true,
575
- formatter: function(value) {
576
- return formatAxisValue(value, yFormat, yUnitSummary)
577
- },
578
- margin: 4,
579
- },
580
- min: yMin,
581
- max: yMax,
582
- minInterval: yUnitSummary?.maxDecimals === 0 ? 1 : undefined,
583
- scale: yScale_bool,
584
- splitLine: {
585
- show: yGridlines_bool,
586
- },
587
- axisLine: {
588
- show: yBaseline_bool,
589
- onZero: false,
590
- },
591
- axisTick: {
592
- show: yTickMarks_bool,
593
- },
594
- boundaryGap: false,
595
- z: 2,
596
- }
597
- } else {
598
- horizAxisConfig = {
599
- type: xTypeLocal,
600
- min: xMin,
601
- max: xMax,
602
- tooltip: {
603
- show: true,
604
- position: 'inside',
605
- formatter(p) {
606
- if (p.isTruncated()) {
607
- return p.name
608
- }
609
- },
610
- },
611
- splitLine: {
612
- show: xGridlines_bool,
613
- },
614
- axisLine: {
615
- show: xBaseline_bool,
616
- },
617
- axisTick: {
618
- show: xTickMarks_bool,
619
- },
620
- axisLabel: {
621
- show: xAxisLabels_bool,
622
- hideOverlap: true,
623
- showMaxLabel: xTypeLocal === 'category' || xTypeLocal === 'value', // max label for ECharts' time axis is a stub - default for that is false
624
- formatter:
625
- xTypeLocal === 'time' || xTypeLocal === 'category'
626
- ? false
627
- : function(value) {
628
- return formatAxisValue(value, xFormat, xUnitSummary)
629
- },
630
- margin: 6,
631
- },
632
- scale: true,
633
- z: 2,
634
- }
635
- }
636
-
637
- if (swapXY_bool) {
638
- verticalAxisConfig = {
639
- type: xTypeLocal,
640
- inverse: 'true',
641
- splitLine: {
642
- show: xGridlines_bool,
643
- },
644
- axisLine: {
645
- show: xBaseline_bool,
646
- },
647
- axisTick: {
648
- show: xTickMarks_bool,
649
- },
650
- axisLabel: {
651
- show: xAxisLabels_bool,
652
- hideOverlap: true,
653
- // formatter:
654
- // function(value){
655
- // return formatAxisValue(value, xFormat, xUnitSummary)
656
- // },
657
- },
658
- scale: true,
659
- min: xMin,
660
- max: xMax,
661
- z: 2,
662
- }
663
- } else {
664
- let primaryAxisColor = (() => {
665
- if (!(Array.isArray(y2Local) && y2Local.length)) return undefined
666
- let yColor = get(yAxisColorStore)
667
- if (yColor === 'true') return $colorPaletteResolved?.[0]
668
- if (yColor === 'false') return undefined
669
- return yColor
670
- })()
671
- let secondaryAxisColor = (() => {
672
- let y2Color = get(y2AxisColorStore)
673
- if (y2Color === 'true') return $colorPaletteResolved?.[ySeriesCount]
674
- if (y2Color === 'false') return undefined
675
- return y2Color
676
- })()
677
-
678
- verticalAxisConfig = {
679
- type: yTypeLocal,
680
- logBase: yLogBase,
681
- splitLine: {
682
- show: yGridlines_bool,
683
- },
684
- axisLine: {
685
- show: yBaseline_bool,
686
- onZero: false,
687
- },
688
- axisTick: {
689
- show: yTickMarks_bool,
690
- },
691
- axisLabel: {
692
- show: yAxisLabels_bool,
693
- hideOverlap: true,
694
- margin: 4,
695
- formatter: function(value) {
696
- return formatAxisValue(value, yFormat, yUnitSummary)
697
- },
698
- color: primaryAxisColor,
699
- },
700
- name: yAxisTitleLocal,
701
- nameLocation: 'end',
702
- nameTextStyle: {
703
- align: 'left',
704
- verticalAlign: 'top',
705
- padding: [0, 5, 0, 0],
706
- color: primaryAxisColor,
707
- },
708
- nameGap: 6,
709
- min: yMin,
710
- max: yMax,
711
- minInterval: yUnitSummary?.maxDecimals === 0 ? 1 : undefined,
712
- scale: yScale_bool,
713
- boundaryGap: yUnitSummary?.maxDecimals === 0 ? false : ['0%', '1%'],
714
- z: 2,
715
- }
716
-
717
- secondaryAxis = {
718
- type: 'value',
719
- show: y2Count > 0,
720
- alignTicks: true,
721
- splitLine: {
722
- show: y2Gridlines_bool,
723
- },
724
- axisLine: {
725
- show: y2Baseline_bool,
726
- onZero: false,
727
- },
728
- axisTick: {
729
- show: y2TickMarks_bool,
730
- },
731
- axisLabel: {
732
- show: y2AxisLabels_bool,
733
- hideOverlap: true,
734
- margin: 4,
735
- formatter: function(value) {
736
- return formatAxisValue(value, y2Format, y2UnitSummary)
737
- },
738
- color: secondaryAxisColor,
739
- },
740
- name: y2AxisTitleLocal,
741
- nameLocation: 'end',
742
- nameTextStyle: {
743
- align: 'right',
744
- verticalAlign: 'top',
745
- padding: [0, 0, 0, 5],
746
- color: secondaryAxisColor,
747
- },
748
- nameGap: 6,
749
- min: y2Min,
750
- max: y2Max,
751
- minInterval: y2UnitSummary?.maxDecimals === 0 ? 1 : undefined,
752
- scale: y2Scale_bool,
753
- boundaryGap: y2UnitSummary?.maxDecimals === 0 ? false : ['0%', '1%'],
754
- z: 2,
755
- }
756
-
757
- verticalAxisConfig = [verticalAxisConfig, secondaryAxis]
758
- }
759
-
760
- // ---------------------------------------------------------------------------------------
761
- // Set up chart area
762
- // ---------------------------------------------------------------------------------------
763
-
764
- hasTitle = title ? true : false
765
- hasSubtitle = subtitle ? true : false
766
- hasLegend = legendLocal * (series !== null || (yLocal.length > 1))
767
- hasTopAxisTitle = yAxisTitleLocal !== '' && swapXY_bool
768
- hasBottomAxisTitle = xAxisTitleLocal !== '' && !swapXY_bool
769
-
770
- titleFontSize = 15
771
- subtitleFontSize = 13
772
- titleBoxPadding = 6 * hasSubtitle
773
-
774
- titleBoxHeight =
775
- hasTitle * titleFontSize +
776
- hasSubtitle * subtitleFontSize +
777
- titleBoxPadding * Math.max(hasTitle, hasSubtitle)
778
-
779
- chartAreaPaddingTop = 10
780
- chartAreaPaddingBottom = 10
781
-
782
- bottomAxisTitleSize = 14
783
- topAxisTitleSize = 14 + 0 // font size + padding top
784
-
785
- legendHeight = 15
786
- legendHeight = legendHeight * hasLegend
787
-
788
- legendPaddingTop = 7
789
- legendPaddingTop = legendPaddingTop * Math.max(hasTitle, hasSubtitle)
790
-
791
- legendTop = titleBoxHeight + legendPaddingTop
792
- chartTop =
793
- legendTop + legendHeight + topAxisTitleSize * hasTopAxisTitle + chartAreaPaddingTop
794
- chartBottom = hasBottomAxisTitle * bottomAxisTitleSize + chartAreaPaddingBottom
795
-
796
- // Adjustment to avoid small bars on horizontal bar chart (extend chart height to accomodate)
797
- // Small bars are allowed on normal bar chart (e.g., time series bar chart)
798
- maxBars = 8
799
- heightMultiplier = 1
800
- if (swapXY_bool) {
801
- barCount = xDistinct.length
802
- heightMultiplier = Math.max(1, barCount / maxBars)
803
- }
804
-
805
- chartContainerHeight = chartAreaHeightLocal * heightMultiplier + chartTop + chartBottom
806
-
807
- topAxisTitleTop = legendTop + legendHeight + 7
808
-
809
- // Set final chart height:
810
- dimensions.set({height: chartContainerHeight + 'px', width: '100%'})
811
-
812
- // ---------------------------------------------------------------------------------------
813
- // Set up horizontal axis title (custom graphic)
814
- // ---------------------------------------------------------------------------------------
815
- horizAxisTitle = swapXY_bool ? yAxisTitleLocal : xAxisTitleLocal
816
- if (horizAxisTitle !== '') {
817
- horizAxisTitle = horizAxisTitle + ' →' // u2192 is js escaped version of &rarr;
818
- }
819
-
820
- horizAxisTitleConfig = {
821
- id: 'horiz-axis-title',
822
- type: 'text',
823
- style: {
824
- text: horizAxisTitle,
825
- textAlign: 'right',
826
- fill: $theme.colors['base-content-muted'],
827
- },
828
- cursor: 'auto',
829
- // Positioning (if swapXY, top right; otherwise bottom right)
830
- right: swapXY_bool ? '2%' : '3%',
831
- top: swapXY_bool ? topAxisTitleTop : null,
832
- bottom: swapXY_bool ? null : '2%',
833
- }
834
-
835
- // ---------------------------------------------------------------------------------------
836
- // Build chart config and update config store so child components can access it
837
- // ---------------------------------------------------------------------------------------
838
-
839
- chartConfig = {
840
- title: {
841
- text: title,
842
- subtext: subtitle,
843
- subtextStyle: {
844
- width: '100%',
845
- },
846
- },
847
- tooltip: {
848
- trigger: 'axis',
849
- show: true,
850
- // formatter function is overridden in ScatterPlot, BubbleChart, and Histogram
851
- formatter: function(params) {
852
- let output
853
- let xVal
854
- let yVal
855
- let yCol
856
- if (totalSeriesCount > 1) {
857
- // If multi-series, add series name as title of tooltip
858
- xVal = params[0].value[swapXY_bool ? 1 : 0]
859
- output = `<span id="tooltip" style='font-weight: 600;'>${formatValue(
860
- xVal,
861
- xFormat,
862
- )}</span>`
863
- for (let i = params.length - 1; i >= 0; i--) {
864
- if (params[i].seriesName !== 'stackTotal') {
865
- yVal = params[i].value[swapXY_bool ? 0 : 1]
866
- output =
867
- output +
868
- `<br> <span style='font-size: 11px;'>${params[i].marker} ${
869
- params[i].seriesName
870
- }<span/><span style='float:right; margin-left: 10px; font-size: 12px;'>${formatValue(
871
- yVal,
872
- // Not sure if this will work. Need to check with multi series on both axes
873
- // Check if echarts does the order in the same way - y first, then y2
874
- getYAxisIndex(params[i].componentIndex, yCount, y2Count) === 0
875
- ? yFormat
876
- : y2Format,
877
- )}</span>`
878
- }
879
- }
880
- } else if (xTypeLocal === 'value') {
881
- // If single-series and a numerical x-axis, include x column as a normal column rather than title (so as not to show a number as the title)
882
- xVal = params[0].value[swapXY_bool ? 1 : 0]
883
- yVal = params[0].value[swapXY_bool ? 0 : 1]
884
- yCol = params[0].seriesName
885
- output = `<span id="tooltip" style='font-weight: 600;'>${formatTitle(
886
- xLocal,
887
- xFormat,
888
- )}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
889
- xVal,
890
- xFormat,
891
- )}</span><br/><span style='font-weight: 600;'>${formatTitle(
892
- yCol,
893
- yFormat,
894
- )}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
895
- yVal,
896
- yFormat,
897
- )}</span>`
898
- } else {
899
- // If single series and categorical or date x-axis, use x value as title of tooltip
900
- xVal = params[0].value[swapXY_bool ? 1 : 0]
901
- yVal = params[0].value[swapXY_bool ? 0 : 1]
902
- yCol = params[0].seriesName
903
- output = `<span id="tooltip" style='font-weight: 600;'>${formatValue(
904
- xVal,
905
- xFormat,
906
- )}</span><br/><span>${formatTitle(
907
- yCol,
908
- yFormat,
909
- )}: </span><span style='float:right; margin-left: 10px;'>${formatValue(
910
- yVal,
911
- yFormat,
912
- )}</span>`
913
- }
914
- return output
915
- },
916
- confine: true,
917
- axisPointer: {
918
- // Use axis to trigger tooltip
919
- type: 'shadow', // 'shadow' as default; can also be 'line' or 'shadow'
920
- },
921
- extraCssText:
922
- 'box-shadow: 0 3px 6px rgba(0,0,0,.15); box-shadow: 0 2px 4px rgba(0,0,0,.12); z-index: 1; font-feature-settings: "cv02", "tnum";',
923
- order: 'valueDesc',
924
- },
925
- legend: {
926
- show: legendLocal,
927
- type: 'scroll',
928
- top: legendTop,
929
- padding: [0, 0, 0, 0],
930
- data: [],
931
- },
932
- grid: {
933
- left: leftPadding ?? (swapXY_bool ? '1%' : '0.8%'),
934
- right: rightPadding ?? (swapXY_bool ? '4%' : '3%'),
935
- bottom: chartBottom,
936
- top: chartTop,
937
- containLabel: true,
938
- },
939
- xAxis: horizAxisConfig,
940
- yAxis: verticalAxisConfig,
941
- series: [],
942
- animation: false,
943
- graphic: horizAxisTitleConfig,
944
- color: $colorPaletteResolved,
945
- }
946
-
947
- config.update(() => {
948
- return chartConfig
949
- })
950
- } catch(e) {
951
- // svelte-ignore non_reactive_update
952
- error = e.message
953
- let setTextRed = '\x1b[31m%s\x1b[0m'
954
- console.error(setTextRed, `Error in ${chartType}: ${e.message}`)
955
-
956
- // Build a queryId so it's clear to users/agents exactly which chart caused the error.
957
- let fieldStr = Object.entries(chartContext || {})
958
- .filter(([_, val]) => {
959
- if (Array.isArray(val)) return val.length > 0
960
- if (typeof val === 'string') return val.trim().length > 0
961
- return Boolean(val)
962
- })
963
- .map(([name, val]) => `${name}="${Array.isArray(val) ? val.join(', ') : val}"`)
964
- let queryId = `${title || chartType} (${fieldStr.join(' ')})`
965
- logError(e, {queryId})
966
-
967
- chartProps.update((d) => {
968
- return {...d, error}
969
- })
970
- }
971
- })
972
- </script>
973
-
974
- {#if !$chartProps.error}
975
- {@render children?.()}
976
- <ECharts
977
- config={$config}
978
- height={$dimensions.height}
979
- width={$dimensions.width}
980
- {data}
981
- {queryID}
982
- chartTitle={title}
983
- {echartsOptions}
984
- {seriesOptions}
985
- {connectGroup}
986
- {xAxisLabelOverflow}
987
- showAllXAxisLabels={showAllXAxisLabelsResolved}
988
- swapXY={swapXY_bool}
989
- seriesColors={$seriesColorsResolved}
990
- />
991
- {:else}
992
- <div style="min-height:200px;width:100%;display:grid;align-content:center;padding:8px;box-sizing:border-box">
993
- <ErrorDisplay error={$chartProps.error} />
994
- </div>
995
- {/if}