Built with blockbuilder.org
Last active
May 4, 2019 18:41
-
-
Save jwilber/77337df96fcd953e6320efbbc19a5433 to your computer and use it in GitHub Desktop.
basic joy plot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
/* .y-axis text, .x-axis text { | |
fill: white; | |
opacity: .85; | |
} | |
.y-axis line, .y-axis path { opacity: 0} | |
.x-axis line, .x-axis path { | |
stroke: white; | |
opacity: .85; | |
} */ | |
.y-axis, .x-axis { | |
font-family: 'arial' | |
} | |
</style> | |
</head> | |
<!-- Load d3.js --> | |
<script src="https://d3js.org/d3.v4.js"></script> | |
<!-- Create a div where the graph will take place --> | |
<body></body> | |
<!-- <script src="joyplot.js"></script> --> | |
<script> | |
// set the dimensions and margins of the graph | |
var margin = {top: 120, right: 30, bottom: 20, left:110}, | |
width = 460 - margin.left - margin.right, | |
height = 400 - margin.top - margin.bottom; | |
// append the svg object to the body of the page | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.style('background-color', 'white') | |
.append("g") | |
.attr("transform", | |
"translate(" + margin.left + "," + margin.top + ")"); | |
//read data | |
d3.csv("https://raw.githubusercontent.com/uiuc-cse/data-fa14/gh-pages/data/iris.csv", function(data) { | |
// Get the different categories and count them | |
var categories = data.columns.filter(d => !isNaN(data[0][d])) | |
var n = categories.length | |
const {min, max} = csvExtent(data) | |
// Add X axis | |
var x = d3.scaleLinear() | |
.domain([min - 15, max + 15]) | |
.range([ 0, width ]); | |
svg.append("g") | |
.attr('class', 'x-axis') | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x)); | |
// Create a Y scale for densities | |
var y = d3.scaleLinear() | |
.domain([0, .25]) | |
.range([ height, 0]); | |
// Create the Y axis for names | |
var yName = d3.scaleBand() | |
.domain(categories) | |
.range([0, height]) | |
.paddingInner(1) | |
svg.append("g") | |
.attr('class', 'y-axis') | |
.call(d3.axisLeft(yName)); | |
// Compute kernel density estimation for each column: | |
var kde = kernelDensityEstimator(kernelEpanechnikov(7), x.ticks(40)) // increase this 40 for more accurate density. | |
var allDensity = [] | |
for (i = 0; i < n; i++) { | |
key = categories[i] | |
density = kde( data.map(function(d){ return d[key]; }) ) | |
allDensity.push({key: key, density: density}) | |
} | |
// Add areas | |
svg.selectAll("areas") | |
.data(allDensity) | |
.enter() | |
.append("path") | |
.attr("transform", function(d){return("translate(0," + (yName(d.key)-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 x(d[0]); }) | |
.y(function(d) { return y(d[1]); }) | |
) | |
}) // end csv load | |
// This is what I need to compute kernel density estimation | |
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} | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Chart { | |
constructor(opts) { | |
this.element = opts.element; | |
this.x = opts.x; | |
this.y = opts.y; | |
d3.csv(opts.data, (d) => { | |
this.data = d; | |
this.draw(); | |
}); | |
} | |
draw() { | |
this.width = 750; | |
this.height = this.width / 1.5; | |
this.margin = { | |
top: 50, | |
bottom: 50, | |
right: 50, | |
left: 50 | |
}; | |
this.element.innerHTML = ''; | |
const svg = d3.select(this.element).append('svg'); | |
svg.attr('width', this.width); | |
svg.attr('height', this.height); | |
this.plot = svg.append('g') | |
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`) | |
this.createScales(); | |
this.addAxes(); | |
// this.addScatter(); | |
} | |
createScales() { | |
var categories = this.data.columns.filter(d => !isNaN(this.data[0][d])) | |
var n = categories.length | |
const {min, max} = csvExtent(this.data) | |
var this.x = d3.scaleLinear() | |
.domain([min - 15, max + 15]) | |
.range([ 0, this.width ]); | |
// Create a Y scale for densities | |
var this.y = d3.scaleLinear() | |
.domain([0, .25]) | |
.range([ this.height, 0]); | |
// Create the Y axis for names | |
var this.yName = d3.scaleBand() | |
.domain(categories) | |
.range([0, this.height]) | |
.paddingInner(1) | |
}; | |
addAxes() { | |
svg.append("g") | |
.attr('class', 'x-axis') | |
.attr("transform", "translate(0," + this.height + ")") | |
.call(d3.axisBottom(this.x)); | |
svg.append("g") | |
.attr('class', 'y-axis') | |
.call(d3.axisLeft(this.yName)); | |
}; | |
addDensities() { | |
this.plot.selectAll('circle') | |
.data(this.data).enter() | |
.append('circle') | |
.attr("cx", d => this.xScale(+d[this.x])) | |
.attr("cy", d => this.yScale(+d[this.y])) | |
.attr("r", 4); | |
}; | |
} | |
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} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment