Я пытаюсь построить простую гистограмму вероятности, используя d3v4 и angular 7, но по какой-то причине мне не удается правильно рассчитать высоту каждого бина.Напротив, когда я запускаю код, я получаю все бины с очень большой высотой и за пределами ожидаемого масштаба.
Вот код, который я использую.
private buildChart() {
this.chartProps = {};
let _this = this;
// Number of bins for the histogram
let numHistBins = 10;
// If true, the number of bins are calculated automatically and numHistBins is overwritten
let calcHistBinsAutmoatic = true;
// calculate the number of histogram bins
if (calcHistBinsAutmoatic) {
numHistBins = Math.ceil(Math.sqrt(this.plotData.length));
}
// Bandwith (smoothing constant) h of the kernel density estimator
let bandwith = 1.06 * this.standardDeviation(this.plotData) * Math.pow(this.plotData.length, - 1 / 5);
// Set the dimensions of the canvas / graph
let margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
// Calculate the range of the b_values
let dist = d3.max(this.plotData) - d3.min(this.plotData);
// Define the bins function
let bins = d3.histogram().thresholds(numHistBins);
// Get the total number of elements ( used because of the probability histogram )
this.chartProps.totalData = this.plotData.length;
// Define the X/Y scales
this.chartProps.x = d3.scaleLinear()
.range([0, width])
.domain([d3.min(this.plotData) - (dist / 2), d3.max(this.plotData) + (dist / 2)]);
this.chartProps.y = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(bins(this.plotData), function (d) {
return d.length/_this.chartProps.totalData;
}) + 0.1]);
this.chartProps.yForHistogram = d3.scaleLinear()
.domain([0, d3.max(bins(this.plotData), function(d) {
return d.length/_this.chartProps.totalData;
})])
.range([height, 0]);
// Define the axes
var xAxis = d3.axisBottom(this.chartProps.x);
var yAxis = d3.axisLeft(this.chartProps.y);
// Calculate Kernel Density Estimator
var kde = this.kernelDensityEstimator(this.gaussianKernel(bandwith), this.chartProps.x.ticks(100));
// Define the line function (Used if KDE is true)
var line = d3.line<any>()
.x( d => { return _this.chartProps.x(d[0]); })
.y( d => { return _this.chartProps.y(d[1]); });
// Prepare the SVG
var svg = d3.select(this.chartElement.nativeElement)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Add the X Axis
svg.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(0,${height})`)
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("Value");
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the bars of histogram
svg.selectAll(".bar")
.data(bins(_this.plotData))
.enter().insert("rect", ".axis")
.attr("class", "bar")
.attr("fill", "#bbb")
.attr("x", d => {
return this.chartProps.x(d.x0) + 1;
})
.attr("y", d => this.chartProps.y(d.length))
.attr("width", d => Math.max(0, this.chartProps.x(d.x1) - this.chartProps.x(d.x0) - 1))
.attr("height", d => {
return this.chartProps.yForHistogram(0) - this.chartProps.yForHistogram(d.length)
});
if (_this.showKDP == true) {
// console.log(kde(_this.plotData));
svg.append("path")
.datum(kde(_this.plotData))
.attr("class", "line")
.attr("stroke", "red")
.attr("fill", "none")
.attr("d", line);
}
...
}
, а также вот как выглядит график
Любая идея о том, что я делаю здесь неправильно, будет очень приветствоваться.