agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
91 lines (78 loc) • 2.96 kB
text/typescript
import ChartJS, { ChartConfiguration } from 'chart.js/auto'
export interface HistogramConstructor {
root: HTMLElement
axisLabels?: { x: string, y: string }
title?: string
width?: number
}
export default class Histogram {
private chart: ChartJS<'bar', number[]>
private width: number
constructor(opts: HistogramConstructor) {
this.width = opts.width || 400
const title = opts.title || 'Histogram'
const axisLabels = opts.axisLabels || { x: 'Bins', y: 'Frequency' }
const canvas = document.createElement('canvas')
const draggable = document.createElement('drag-pane')
draggable.setAttribute('heading', title )
draggable.setAttribute('key', title)
draggable.appendChild(canvas)
opts.root.appendChild(draggable)
canvas.width = this.width
const defaultChartOptions: ChartConfiguration<'bar', number[]> = {
type: 'bar',
data: {
labels: [],
datasets: [{
label: title,
data: [],
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
scales: {
x: {
title: {
display: true,
text: axisLabels.x
}
},
y: {
title: {
display: true,
text: axisLabels.y
},
beginAtZero: true
}
}
}
}
this.chart = new ChartJS<'bar', number[]>(canvas, defaultChartOptions)
}
public applyData(data: number[], binSize: number): void {
const { bins, frequencies } = this.calculateBins(data, binSize)
this.chart.data.labels = bins
this.chart.data.datasets[0].data = frequencies
this.chart.update()
}
private calculateBins(data: number[], binSize: number): { bins: number[], frequencies: number[] } {
const max = Math.max(...data)
const min = Math.min(...data)
// `bins` used as labels for the chart
const bins = []
const frequencies = []
// gets the precision of the bin size float
const precision = binSize.toString().split('.')[1]?.length || 1
for (let start = min; start <= max; start += binSize) {
bins.push(`${+(start).toFixed(precision)}-${ +(start + binSize).toFixed(precision)}`)
frequencies.push(0)
}
data.forEach(value => {
const binIndex = Math.floor((value - min) / binSize)
frequencies[binIndex]++
})
return { bins, frequencies }
}
}