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