class Chart { constructor(opts) { console.log('inside') this.element = opts.element; this.x = opts.x; this.y = opts.y; d3.csv(opts.data, (d) => { this.data = d; this.draw(); }); } draw() { this.margin = { top: 200, bottom: 50, right: 50, left: 100 }; this.width = 800 - this.margin.right - this.margin.left; this.height = this.width / 1.5 - this.margin.top - this.margin.bottom; this.element.innerHTML = ''; const svg = d3.select(this.element).append('svg'); svg.attr('width', this.width + this.margin.right + this.margin.left); svg.attr('height', this.height + this.margin.top + this.margin.bottom); this.plot = svg.append('g') .attr('transform', `translate(${this.margin.left}, ${this.margin.top})`) this.createScales(); this.addAxes(); this.addDensities(); } createScales() { this.categories = this.data.columns.filter(d => !isNaN(this.data[0][d])) this.n = this.categories.length const {min, max} = csvExtent(this.data) this.x = d3.scaleLinear() .domain([min - 15, max + 15]) .range([ 0, this.width ]); // Create a Y scale for densities this.y = d3.scaleLinear() .domain([0, .25]) .range([ this.height, 0]); // Create the Y axis for names this.yName = d3.scaleBand() .domain(this.categories) .range([0, this.height]) .paddingInner(1) console.log(this.yName) }; addAxes() { this.plot.append("g") .attr('class', 'x-axis') .attr("transform", `translate(0, ${this.height})`) .call(d3.axisBottom(this.x)); this.plot.append("g") .attr('class', 'y-axis') .call(d3.axisLeft(this.yName)); }; addDensities() { console.log('r', this.yName) const that = this; // Compute kernel density estimation for each column: var kde = kernelDensityEstimator(kernelEpanechnikov(7), this.x.ticks(40)) // increase this 40 for more accurate density. var allDensity = [] for (var i = 0; i < this.n; i++) { let key = this.categories[i] let density = kde( this.data.map(function(d){ return d[key]; }) ) allDensity.push({key: key, density: density}) } // Add areas this.plot.selectAll("areas") .data(allDensity) .enter() .append("path") // .attr('transform', // d => { // `translate(0, ${(that.yName(d.key)-that.height)})` // }) .attr("transform", function(d){ return("translate(0," + (that.yName(d.key)-that.height) +")" ) }) .datum(d => d.density) .attr("fill", "skyblue") .attr('opacity', 1) .attr("stroke", "azure") .attr("stroke-width", 1) .attr("d", d3.line() .curve(d3.curveStep) .x(function(d) { return that.x(d[0]); }) .y(function(d) { return that.y(d[1]); }) ) }; } function kernelDensityEstimator(kernel, X) { return function(V) { return X.map(function(x) { return [x, d3.mean(V, function(v) { return kernel(x - v); })]; }); }; } function kernelEpanechnikov(k) { return function(v) { return Math.abs(v /= k) <= 1 ? 0.75 * (1 - v * v) / k : 0; }; } function csvExtent(data) { const colNames = data.columns const extents = colNames.map(col => d3.extent(data, d => +d[col])); const csvMin = d3.min(extents, d => d[0]) const csvMax = d3.max(extents, d => d[1]) return {'min': csvMin, 'max': csvMax} };