Merge pull request #11382 from Budibase/feature/frequency-histogram
Added a simple histogram to the supported chart types
This commit is contained in:
commit
a77b5e51ac
|
@ -75,6 +75,14 @@
|
||||||
{
|
{
|
||||||
"name": "Chart",
|
"name": "Chart",
|
||||||
"icon": "GraphBarVertical",
|
"icon": "GraphBarVertical",
|
||||||
"children": ["bar", "line", "area", "candlestick", "pie", "donut"]
|
"children": [
|
||||||
|
"bar",
|
||||||
|
"line",
|
||||||
|
"area",
|
||||||
|
"candlestick",
|
||||||
|
"pie",
|
||||||
|
"donut",
|
||||||
|
"histogram"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -2212,6 +2212,147 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"histogram": {
|
||||||
|
"name": "Histogram Chart",
|
||||||
|
"description": "Histogram chart",
|
||||||
|
"icon": "Histogram",
|
||||||
|
"size": {
|
||||||
|
"width": 600,
|
||||||
|
"height": 400
|
||||||
|
},
|
||||||
|
"requiredAncestors": ["dataprovider"],
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Title",
|
||||||
|
"key": "title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dataProvider",
|
||||||
|
"label": "Provider",
|
||||||
|
"key": "dataProvider",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"label": "Data column",
|
||||||
|
"key": "valueColumn",
|
||||||
|
"dependsOn": "dataProvider",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Y axis label",
|
||||||
|
"key": "yAxisLabel",
|
||||||
|
"defaultValue": "Frequency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "X axis label",
|
||||||
|
"key": "xAxisLabel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"label": "Bucket count",
|
||||||
|
"key": "bucketCount",
|
||||||
|
"defaultValue": 10,
|
||||||
|
"min": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Data labels",
|
||||||
|
"key": "dataLabels",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Width",
|
||||||
|
"key": "width"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Height",
|
||||||
|
"key": "height",
|
||||||
|
"defaultValue": "400"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Colors",
|
||||||
|
"key": "palette",
|
||||||
|
"defaultValue": "Palette 1",
|
||||||
|
"options": [
|
||||||
|
"Custom",
|
||||||
|
"Palette 1",
|
||||||
|
"Palette 2",
|
||||||
|
"Palette 3",
|
||||||
|
"Palette 4",
|
||||||
|
"Palette 5",
|
||||||
|
"Palette 6",
|
||||||
|
"Palette 7",
|
||||||
|
"Palette 8",
|
||||||
|
"Palette 9",
|
||||||
|
"Palette 10"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "C1",
|
||||||
|
"key": "c1",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "palette",
|
||||||
|
"value": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "C2",
|
||||||
|
"key": "c2",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "palette",
|
||||||
|
"value": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "C3",
|
||||||
|
"key": "c3",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "palette",
|
||||||
|
"value": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "C4",
|
||||||
|
"key": "c4",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "palette",
|
||||||
|
"value": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "C5",
|
||||||
|
"key": "c5",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "palette",
|
||||||
|
"value": "Custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Animate",
|
||||||
|
"key": "animate",
|
||||||
|
"defaultValue": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Horizontal",
|
||||||
|
"key": "horizontal",
|
||||||
|
"defaultValue": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"name": "Form",
|
"name": "Form",
|
||||||
"icon": "Form",
|
"icon": "Form",
|
||||||
|
@ -3965,6 +4106,10 @@
|
||||||
"label": "Bar",
|
"label": "Bar",
|
||||||
"value": "bar"
|
"value": "bar"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Histogram",
|
||||||
|
"value": "histogram"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Line",
|
"label": "Line",
|
||||||
"value": "line"
|
"value": "line"
|
||||||
|
@ -4215,6 +4360,47 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"section": true,
|
||||||
|
"name": "Histogram Chart",
|
||||||
|
"icon": "Histogram",
|
||||||
|
"dependsOn": {
|
||||||
|
"setting": "chartType",
|
||||||
|
"value": "histogram"
|
||||||
|
},
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "field",
|
||||||
|
"label": "Value column",
|
||||||
|
"key": "valueColumn",
|
||||||
|
"dependsOn": "dataSource",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Y axis label",
|
||||||
|
"key": "yAxisLabel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "X axis label",
|
||||||
|
"key": "xAxisLabel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"label": "Horizontal",
|
||||||
|
"key": "horizontal",
|
||||||
|
"defaultValue": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "number",
|
||||||
|
"label": "Bucket count",
|
||||||
|
"key": "bucketCount",
|
||||||
|
"defaultValue": 10,
|
||||||
|
"min": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"section": true,
|
"section": true,
|
||||||
"name": "Line Chart",
|
"name": "Line Chart",
|
||||||
|
|
|
@ -46,6 +46,9 @@
|
||||||
export let lowColumn
|
export let lowColumn
|
||||||
export let dateColumn
|
export let dateColumn
|
||||||
|
|
||||||
|
// Histogram
|
||||||
|
export let bucketCount
|
||||||
|
|
||||||
let dataProviderId
|
let dataProviderId
|
||||||
|
|
||||||
$: colors = c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null
|
$: colors = c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null
|
||||||
|
@ -92,6 +95,7 @@
|
||||||
highColumn,
|
highColumn,
|
||||||
lowColumn,
|
lowColumn,
|
||||||
dateColumn,
|
dateColumn,
|
||||||
|
bucketCount,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
<script>
|
||||||
|
import { ApexOptionsBuilder } from "./ApexOptionsBuilder"
|
||||||
|
import ApexChart from "./ApexChart.svelte"
|
||||||
|
|
||||||
|
export let title
|
||||||
|
export let dataProvider
|
||||||
|
export let valueColumn
|
||||||
|
export let xAxisLabel
|
||||||
|
export let yAxisLabel
|
||||||
|
export let height
|
||||||
|
export let width
|
||||||
|
export let dataLabels
|
||||||
|
export let animate
|
||||||
|
export let palette
|
||||||
|
export let c1, c2, c3, c4, c5
|
||||||
|
export let horizontal
|
||||||
|
export let bucketCount = 10
|
||||||
|
|
||||||
|
$: options = setUpChart(
|
||||||
|
title,
|
||||||
|
dataProvider,
|
||||||
|
valueColumn,
|
||||||
|
xAxisLabel || valueColumn,
|
||||||
|
yAxisLabel,
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
dataLabels,
|
||||||
|
animate,
|
||||||
|
palette,
|
||||||
|
horizontal,
|
||||||
|
c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null,
|
||||||
|
customColor,
|
||||||
|
bucketCount
|
||||||
|
)
|
||||||
|
|
||||||
|
$: customColor = palette === "Custom"
|
||||||
|
|
||||||
|
const setUpChart = (
|
||||||
|
title,
|
||||||
|
dataProvider,
|
||||||
|
valueColumn,
|
||||||
|
xAxisLabel, //freqAxisLabel
|
||||||
|
yAxisLabel, //valueAxisLabel
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
dataLabels,
|
||||||
|
animate,
|
||||||
|
palette,
|
||||||
|
horizontal,
|
||||||
|
colors,
|
||||||
|
customColor,
|
||||||
|
bucketCount
|
||||||
|
) => {
|
||||||
|
const allCols = [valueColumn]
|
||||||
|
if (
|
||||||
|
!dataProvider ||
|
||||||
|
!dataProvider.rows?.length ||
|
||||||
|
allCols.find(x => x == null)
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch data
|
||||||
|
const { schema, rows } = dataProvider
|
||||||
|
const reducer = row => (valid, column) => valid && row[column] != null
|
||||||
|
const hasAllColumns = row => allCols.reduce(reducer(row), true)
|
||||||
|
const data = rows.filter(row => hasAllColumns(row)).slice(0, 100)
|
||||||
|
if (!schema || !data.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise default chart
|
||||||
|
let builder = new ApexOptionsBuilder()
|
||||||
|
.type("bar")
|
||||||
|
.title(title)
|
||||||
|
.width(width)
|
||||||
|
.height(height)
|
||||||
|
.xLabel(horizontal ? yAxisLabel : xAxisLabel)
|
||||||
|
.yLabel(horizontal ? xAxisLabel : yAxisLabel)
|
||||||
|
.dataLabels(dataLabels)
|
||||||
|
.animate(animate)
|
||||||
|
.palette(palette)
|
||||||
|
.horizontal(horizontal)
|
||||||
|
.colors(customColor ? colors : null)
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
builder = builder.setOption(["plotOptions", "bar", "barHeight"], "90%")
|
||||||
|
} else {
|
||||||
|
builder = builder.setOption(["plotOptions", "bar", "columnWidth"], "99%")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull occurences of the value.
|
||||||
|
let flatlist = data.map(row => {
|
||||||
|
return row[valueColumn]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Build range buckets
|
||||||
|
let interval = Math.max(...flatlist) / bucketCount
|
||||||
|
let counts = Array(bucketCount).fill(0)
|
||||||
|
|
||||||
|
// Assign row data to a bucket
|
||||||
|
let buckets = flatlist.reduce((acc, val) => {
|
||||||
|
let dest = Math.min(Math.floor(val / interval), bucketCount - 1)
|
||||||
|
acc[dest] = acc[dest] + 1
|
||||||
|
return acc
|
||||||
|
}, counts)
|
||||||
|
|
||||||
|
const rangeLabel = bucketIdx => {
|
||||||
|
return `${Math.floor(interval * bucketIdx)} - ${Math.floor(
|
||||||
|
interval * (bucketIdx + 1)
|
||||||
|
)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const series = [
|
||||||
|
{
|
||||||
|
name: yAxisLabel,
|
||||||
|
data: Array.from({ length: buckets.length }, (_, i) => ({
|
||||||
|
x: rangeLabel(i),
|
||||||
|
y: buckets[i],
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
builder = builder.setOption(["xaxis", "labels"], {
|
||||||
|
formatter: x => {
|
||||||
|
return x + ""
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
builder = builder.series(series)
|
||||||
|
|
||||||
|
return builder.getOptions()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ApexChart {options} />
|
|
@ -4,3 +4,4 @@ export { default as pie } from "./PieChart.svelte"
|
||||||
export { default as donut } from "./DonutChart.svelte"
|
export { default as donut } from "./DonutChart.svelte"
|
||||||
export { default as area } from "./AreaChart.svelte"
|
export { default as area } from "./AreaChart.svelte"
|
||||||
export { default as candlestick } from "./CandleStickChart.svelte"
|
export { default as candlestick } from "./CandleStickChart.svelte"
|
||||||
|
export { default as histogram } from "./HistogramChart.svelte"
|
||||||
|
|
Loading…
Reference in New Issue