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",
|
||||
"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": {
|
||||
"name": "Form",
|
||||
"icon": "Form",
|
||||
|
@ -3965,6 +4106,10 @@
|
|||
"label": "Bar",
|
||||
"value": "bar"
|
||||
},
|
||||
{
|
||||
"label": "Histogram",
|
||||
"value": "histogram"
|
||||
},
|
||||
{
|
||||
"label": "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,
|
||||
"name": "Line Chart",
|
||||
|
|
|
@ -46,6 +46,9 @@
|
|||
export let lowColumn
|
||||
export let dateColumn
|
||||
|
||||
// Histogram
|
||||
export let bucketCount
|
||||
|
||||
let dataProviderId
|
||||
|
||||
$: colors = c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null
|
||||
|
@ -92,6 +95,7 @@
|
|||
highColumn,
|
||||
lowColumn,
|
||||
dateColumn,
|
||||
bucketCount,
|
||||
}}
|
||||
/>
|
||||
{/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 area } from "./AreaChart.svelte"
|
||||
export { default as candlestick } from "./CandleStickChart.svelte"
|
||||
export { default as histogram } from "./HistogramChart.svelte"
|
||||
|
|
Loading…
Reference in New Issue