Improve Histogram.svelte

- Add bold axis labels
- Labels defined as element props xlabel and ylabel
- Label offset dynamic to plot height (10 percent)
- Add adjustable gaps between bars
This commit is contained in:
Christoph Kluge 2022-09-30 17:00:15 +02:00
parent 46baa6e534
commit d1c47f4359
2 changed files with 36 additions and 14 deletions

View File

@ -152,7 +152,8 @@
<Histogram <Histogram
width={colWidth1 - 25} height={300} width={colWidth1 - 25} height={300}
data={$mainQuery.data.topUsers.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))} data={$mainQuery.data.topUsers.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))}
label={(x) => x < $mainQuery.data.topUsers.length ? $mainQuery.data.topUsers[Math.floor(x)].name : '0'} /> label={(x) => x < $mainQuery.data.topUsers.length ? $mainQuery.data.topUsers[Math.floor(x)].name : '0'}
xlabel="User Name" ylabel="Number of Jobs" />
{/key} {/key}
</div> </div>
</Col> </Col>
@ -173,7 +174,8 @@
<Histogram <Histogram
width={colWidth1 - 25} height={300} width={colWidth1 - 25} height={300}
data={$mainQuery.data.topProjects.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))} data={$mainQuery.data.topProjects.sort((a, b) => b.count - a.count).map(({ count }, idx) => ({ count, value: idx }))}
label={(x) => x < $mainQuery.data.topProjects.length ? $mainQuery.data.topProjects[Math.floor(x)].name : '0'} /> label={(x) => x < $mainQuery.data.topProjects.length ? $mainQuery.data.topProjects[Math.floor(x)].name : '0'}
xlabel="Project Code" ylabel="Number of Jobs" />
{/key} {/key}
</Col> </Col>
<Col class="px-4 py-2"> <Col class="px-4 py-2">
@ -192,7 +194,8 @@
{#key $mainQuery.data.stats} {#key $mainQuery.data.stats}
<Histogram <Histogram
width={colWidth2 - 25} height={300} width={colWidth2 - 25} height={300}
data={$mainQuery.data.stats[0].histDuration} /> data={$mainQuery.data.stats[0].histDuration}
xlabel="Current Runtime in Hours [h]" ylabel="Number of Jobs" />
{/key} {/key}
</div> </div>
</Col> </Col>
@ -201,7 +204,8 @@
{#key $mainQuery.data.stats} {#key $mainQuery.data.stats}
<Histogram <Histogram
width={colWidth2 - 25} height={300} width={colWidth2 - 25} height={300}
data={$mainQuery.data.stats[0].histNumNodes} /> data={$mainQuery.data.stats[0].histNumNodes}
xlabel="Allocated Nodes" ylabel="Number of Jobs" />
{/key} {/key}
</Col> </Col>
</Row> </Row>

View File

@ -1,4 +1,4 @@
<!-- <!--
@component @component
Properties: Properties:
- width, height: Number - width, height: Number
@ -20,6 +20,8 @@
export let data export let data
export let width export let width
export let height export let height
export let xlabel
export let ylabel
export let min = null export let min = null
export let max = null export let max = null
export let label = formatNumber export let label = formatNumber
@ -72,9 +74,11 @@
} }
function render() { function render() {
const h = height - paddingTop - paddingBottom const labelOffset = Math.floor(height * 0.1)
const h = height - paddingTop - paddingBottom - labelOffset
const w = width - paddingLeft - paddingRight const w = width - paddingLeft - paddingRight
const barWidth = Math.ceil(w / (maxValue + 1)) const barGap = 5
const barWidth = Math.ceil(w / (maxValue + 1)) - barGap
if (Number.isNaN(barWidth)) if (Number.isNaN(barWidth))
return return
@ -83,9 +87,14 @@
const getCanvasY = (count) => (h - (count / maxCount) * h) + paddingTop const getCanvasY = (count) => (h - (count / maxCount) * h) + paddingTop
// X Axis // X Axis
ctx.font = `${fontSize}px ${fontFamily}` ctx.font = `bold ${fontSize}px ${fontFamily}`
ctx.fillStyle = 'black' ctx.fillStyle = 'black'
if (xlabel != '') {
let textWidth = ctx.measureText(xlabel).width
ctx.fillText(xlabel, Math.floor((width / 2) - (textWidth / 2) + barGap), height - Math.floor(labelOffset / 2))
}
ctx.textAlign = 'center' ctx.textAlign = 'center'
ctx.font = `${fontSize}px ${fontFamily}`
if (min != null && max != null) { if (min != null && max != null) {
const stepsizeX = getStepSize(max - min, w, 75) const stepsizeX = getStepSize(max - min, w, 75)
let startX = 0 let startX = 0
@ -94,19 +103,28 @@
for (let x = startX; x < max; x += stepsizeX) { for (let x = startX; x < max; x += stepsizeX) {
let px = ((x - min) / (max - min)) * (w - barWidth) + paddingLeft + (barWidth / 2.) let px = ((x - min) / (max - min)) * (w - barWidth) + paddingLeft + (barWidth / 2.)
ctx.fillText(`${formatNumber(x)}`, px, height - paddingBottom + 15) ctx.fillText(`${formatNumber(x)}`, px, height - paddingBottom - Math.floor(labelOffset / 2))
} }
} else { } else {
const stepsizeX = getStepSize(maxValue, w, 120) const stepsizeX = getStepSize(maxValue, w, 120)
for (let x = 0; x <= maxValue; x += stepsizeX) { for (let x = 0; x <= maxValue; x += stepsizeX) {
ctx.fillText(label(x), getCanvasX(x), height - paddingBottom + 15) ctx.fillText(label(x), getCanvasX(x), height - paddingBottom - Math.floor(labelOffset / 2))
} }
} }
// Y Axis // Y Axis
ctx.fillStyle = 'black' ctx.fillStyle = 'black'
ctx.strokeStyle = '#bbbbbb' ctx.strokeStyle = '#bbbbbb'
ctx.font = `bold ${fontSize}px ${fontFamily}`
if (ylabel != '') {
ctx.save()
ctx.translate(15, Math.floor(h / 2))
ctx.rotate(-Math.PI / 2)
ctx.fillText(ylabel, 0, 0)
ctx.restore()
}
ctx.textAlign = 'right' ctx.textAlign = 'right'
ctx.font = `${fontSize}px ${fontFamily}`
ctx.beginPath() ctx.beginPath()
const stepsizeY = getStepSize(maxCount, h, 50) const stepsizeY = getStepSize(maxCount, h, 50)
for (let y = stepsizeY; y <= maxCount; y += stepsizeY) { for (let y = stepsizeY; y <= maxCount; y += stepsizeY) {
@ -130,10 +148,10 @@
// Fat lines left and below plotting area // Fat lines left and below plotting area
ctx.strokeStyle = 'black' ctx.strokeStyle = 'black'
ctx.beginPath() ctx.beginPath()
ctx.moveTo(0, height - paddingBottom) ctx.moveTo(0, height - paddingBottom - labelOffset)
ctx.lineTo(width, height - paddingBottom) ctx.lineTo(width, height - paddingBottom - labelOffset)
ctx.moveTo(paddingLeft, 0) ctx.moveTo(paddingLeft, 0)
ctx.lineTo(paddingLeft, height- paddingBottom) ctx.lineTo(paddingLeft, height - Math.floor(labelOffset / 2))
ctx.stroke() ctx.stroke()
} }
@ -207,4 +225,4 @@
max: max max: max
} }
} }
</script> </script>