Merge pull request #11382 from Budibase/feature/frequency-histogram

Added a simple histogram to the supported chart types
This commit is contained in:
deanhannigan 2023-07-31 10:56:13 +01:00 committed by GitHub
commit a77b5e51ac
5 changed files with 336 additions and 1 deletions

View File

@ -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"
]
} }
] ]

View File

@ -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",

View File

@ -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}

View File

@ -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} />

View File

@ -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"