Created
October 21, 2019 20:23
-
-
Save JackyLiu97/2d30057f2ed1481cde4917b774a14c28 to your computer and use it in GitHub Desktop.
JS Bin Lab 4 with Extra Credit // source https://jsbin.com/kaxamad
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> | |
<html> | |
<head> | |
<meta name="description" content="Lab 4 with Extra Credit"> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin<style id="jsbin-css"> | |
.title { | |
font-family: Helvetica; | |
font-size: 20px; | |
fill: black; | |
text-anchor: middle; | |
} | |
.dot { | |
stroke: black; | |
} | |
.legend--frame { | |
stroke: black; | |
fill: LightGray; | |
} | |
.legend--item--box { | |
stroke: black; | |
} | |
.legend--item--label { | |
font-family: Helvetica; | |
font-size: 14px; | |
fill: black; | |
alignment-baseline: central; | |
} | |
.label { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 14px; | |
text-anchor: middle; | |
} | |
</style> | |
</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script> | |
<body> | |
<div id="chart"></div> | |
<script id="jsbin-javascript"> | |
d3.csv("https://raw.githubusercontent.com/hvo/datasets/master/nyc_grads.csv") | |
.then(function(grads) { | |
var data = grads | |
.filter(row => ((row.Type=='Borough Total') && | |
(row.Cohort%2===0))) | |
.map(row => [row.Advanced/row.Total*100, | |
row.DroppedOut/row.Total*100, | |
row.Cohort, | |
row.Borough]); | |
createPlot(data); | |
}); | |
function createPlot(data) { | |
var canvasSize = [500, 500]; | |
var tickSize = 5; | |
var pArea = [50, 30, 390, 370]; | |
var pSize = [pArea[2]-pArea[0], pArea[3]-pArea[1]]; | |
// Used dictionary | |
var palette = {'Bronx': 'SteelBlue', 'Brooklyn': 'LightSalmon', 'Queens': 'SeaGreen', 'Manhattan': 'Gold', 'Staten Island': 'IndianRed'}; | |
var canvas = d3.select("#chart") | |
.append("svg") | |
.attr('width', canvasSize[0]) | |
.attr('height', canvasSize[1]); | |
var x = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[0], pArea[2]]); | |
// We need to invert our y-values because our grid goes from top to bottom, not bottom to enter | |
var y = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[3], pArea[1]]); | |
var g = canvas.append('g'); | |
g.append('text') | |
.attr('class', 'title') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 25) | |
.text('NYC High School Graduate Statistics'); | |
g.append('g') | |
.attr('class', 'axis axis--x') | |
.attr('transform', `translate(0, ${pArea[3]})`) | |
.call(d3.axisBottom(x).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 35) | |
.text('Advanced Regents (%)'); | |
g.append('g') | |
.attr('class', 'axis axis--y') | |
.attr('transform', `translate(${pArea[0]},0)`) | |
.call(d3.axisLeft(y).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('transform', 'rotate(-90)') | |
.attr('x', -(y.range()[0]+y.range()[1])*0.5) | |
.attr('y', -25) | |
.text('Dropped Out (%)'); | |
// To draw the dots | |
var dots = g.selectAll('.dot') | |
.data(data); | |
drawDots(g, x, y, palette, data); | |
// The 'g' that we are appending refers to a group that will be our legend items | |
// We use the back-tick notation to evaluate whatever is inside of the | |
var legend = g.append('g') | |
.attr('transform', | |
`translate(${pArea[2]-60},${pArea[1]+10})`); | |
legend.append('rect') | |
.attr('class', 'legend--frame') | |
.attr('x', -5) | |
.attr('y', -5) | |
.attr('width', 110) | |
.attr('height', 100) | |
.on('click', function (d) { | |
drawDots(g, x, y, palette, data); | |
}); | |
var legendItems = legend.selectAll('.legend--item--line') | |
.data(['Bronx', 'Brooklyn', 'Queens', 'Manhattan', 'Staten Island']) | |
.enter().append('g'); | |
legendItems.append('rect') | |
.attr('class', 'legend--item--box') | |
.attr('x', 0) | |
.attr('y', (d,i) => (i*20)) | |
.attr('width', 10) | |
.attr('height', 10) | |
.style('fill', (d,i) => palette[d]) | |
.on('click', function (d) { | |
let filteredData = data.filter(item => item[3]==d) | |
console.log(filteredData) | |
// when this function is called, there are 15 visual elements in dots, but only 5 data points from filtered data | |
drawDots(g, x, y, palette, filteredData); | |
}); | |
// so this checks if there are any dot visual elements and assigns them to a variable | |
// if there are, then it updates the data that is already there | |
// another way of doing the same thing is by completely removing all data / viz | |
// and then drawing the new elements, but that is slow and inefficient | |
// so instead we just keep track of the old data | |
function drawDots(g, x, y, palette, data) { | |
var dots = g.selectAll('.dot') // selects all visual elements with .dot | |
.data(data, d => [d[2], d[3]]); // joins visual elements with data; second part is a key function (need to understand this for hw 2) | |
// looks at all visual elements | |
dots.enter() | |
.append('circle') | |
.attr('class', 'dot') | |
.attr('cx', d => x(d[0])) | |
.attr('cy', d => y(d[1])) | |
.attr('r', 5) | |
.style('fill', d => palette[d[3]]) | |
.merge(dots) // applies everything after to new points and old points (same effect as dots.attr() code below) | |
.transition().duration(1000) | |
.style('opacity', 1); | |
// To see why all the dots overlap, just inspect the element | |
// looks at all visual elements with data | |
// dots.attr() | |
// .attr('cx', d => x(d[0])) | |
// .attr('cy', d => y(d[1])) | |
// .attr('r', 5) | |
// .style('fill', d => palette[(d[2]-2002)/2]); | |
// looks at visual elements without data | |
dots.exit() | |
.transition().duration(1000) | |
.style('opacity', 0) | |
} | |
legendItems.append('text') | |
.attr('class', 'legend--item--label') | |
.attr('x', 20) | |
.attr('y', (d,i) => (5+i*20)) | |
.text(d => d); | |
} | |
</script> | |
<script id="jsbin-source-css" type="text/css">.title { | |
font-family: Helvetica; | |
font-size: 20px; | |
fill: black; | |
text-anchor: middle; | |
} | |
.dot { | |
stroke: black; | |
} | |
.legend--frame { | |
stroke: black; | |
fill: LightGray; | |
} | |
.legend--item--box { | |
stroke: black; | |
} | |
.legend--item--label { | |
font-family: Helvetica; | |
font-size: 14px; | |
fill: black; | |
alignment-baseline: central; | |
} | |
.label { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 14px; | |
text-anchor: middle; | |
}</script> | |
<script id="jsbin-source-javascript" type="text/javascript">d3.csv("https://raw.githubusercontent.com/hvo/datasets/master/nyc_grads.csv") | |
.then(function(grads) { | |
var data = grads | |
.filter(row => ((row.Type=='Borough Total') && | |
(row.Cohort%2===0))) | |
.map(row => [row.Advanced/row.Total*100, | |
row.DroppedOut/row.Total*100, | |
row.Cohort, | |
row.Borough]); | |
createPlot(data); | |
}); | |
function createPlot(data) { | |
var canvasSize = [500, 500]; | |
var tickSize = 5; | |
var pArea = [50, 30, 390, 370]; | |
var pSize = [pArea[2]-pArea[0], pArea[3]-pArea[1]]; | |
// Used dictionary | |
var palette = {'Bronx': 'SteelBlue', 'Brooklyn': 'LightSalmon', 'Queens': 'SeaGreen', 'Manhattan': 'Gold', 'Staten Island': 'IndianRed'}; | |
var canvas = d3.select("#chart") | |
.append("svg") | |
.attr('width', canvasSize[0]) | |
.attr('height', canvasSize[1]); | |
var x = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[0], pArea[2]]); | |
// We need to invert our y-values because our grid goes from top to bottom, not bottom to enter | |
var y = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[3], pArea[1]]); | |
var g = canvas.append('g'); | |
g.append('text') | |
.attr('class', 'title') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 25) | |
.text('NYC High School Graduate Statistics'); | |
g.append('g') | |
.attr('class', 'axis axis--x') | |
.attr('transform', `translate(0, ${pArea[3]})`) | |
.call(d3.axisBottom(x).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 35) | |
.text('Advanced Regents (%)'); | |
g.append('g') | |
.attr('class', 'axis axis--y') | |
.attr('transform', `translate(${pArea[0]},0)`) | |
.call(d3.axisLeft(y).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('transform', 'rotate(-90)') | |
.attr('x', -(y.range()[0]+y.range()[1])*0.5) | |
.attr('y', -25) | |
.text('Dropped Out (%)'); | |
// To draw the dots | |
var dots = g.selectAll('.dot') | |
.data(data); | |
drawDots(g, x, y, palette, data); | |
// The 'g' that we are appending refers to a group that will be our legend items | |
// We use the back-tick notation to evaluate whatever is inside of the | |
var legend = g.append('g') | |
.attr('transform', | |
`translate(${pArea[2]-60},${pArea[1]+10})`); | |
legend.append('rect') | |
.attr('class', 'legend--frame') | |
.attr('x', -5) | |
.attr('y', -5) | |
.attr('width', 110) | |
.attr('height', 100) | |
.on('click', function (d) { | |
drawDots(g, x, y, palette, data); | |
}); | |
var legendItems = legend.selectAll('.legend--item--line') | |
.data(['Bronx', 'Brooklyn', 'Queens', 'Manhattan', 'Staten Island']) | |
.enter().append('g'); | |
legendItems.append('rect') | |
.attr('class', 'legend--item--box') | |
.attr('x', 0) | |
.attr('y', (d,i) => (i*20)) | |
.attr('width', 10) | |
.attr('height', 10) | |
.style('fill', (d,i) => palette[d]) | |
.on('click', function (d) { | |
let filteredData = data.filter(item => item[3]==d) | |
console.log(filteredData) | |
// when this function is called, there are 15 visual elements in dots, but only 5 data points from filtered data | |
drawDots(g, x, y, palette, filteredData); | |
}); | |
// so this checks if there are any dot visual elements and assigns them to a variable | |
// if there are, then it updates the data that is already there | |
// another way of doing the same thing is by completely removing all data / viz | |
// and then drawing the new elements, but that is slow and inefficient | |
// so instead we just keep track of the old data | |
function drawDots(g, x, y, palette, data) { | |
var dots = g.selectAll('.dot') // selects all visual elements with .dot | |
.data(data, d => [d[2], d[3]]); // joins visual elements with data; second part is a key function (need to understand this for hw 2) | |
// looks at all visual elements | |
dots.enter() | |
.append('circle') | |
.attr('class', 'dot') | |
.attr('cx', d => x(d[0])) | |
.attr('cy', d => y(d[1])) | |
.attr('r', 5) | |
.style('fill', d => palette[d[3]]) | |
.merge(dots) // applies everything after to new points and old points (same effect as dots.attr() code below) | |
.transition().duration(1000) | |
.style('opacity', 1); | |
// To see why all the dots overlap, just inspect the element | |
// looks at all visual elements with data | |
// dots.attr() | |
// .attr('cx', d => x(d[0])) | |
// .attr('cy', d => y(d[1])) | |
// .attr('r', 5) | |
// .style('fill', d => palette[(d[2]-2002)/2]); | |
// looks at visual elements without data | |
dots.exit() | |
.transition().duration(1000) | |
.style('opacity', 0) | |
} | |
legendItems.append('text') | |
.attr('class', 'legend--item--label') | |
.attr('x', 20) | |
.attr('y', (d,i) => (5+i*20)) | |
.text(d => d); | |
} | |
</script></body> | |
</html> |
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
.title { | |
font-family: Helvetica; | |
font-size: 20px; | |
fill: black; | |
text-anchor: middle; | |
} | |
.dot { | |
stroke: black; | |
} | |
.legend--frame { | |
stroke: black; | |
fill: LightGray; | |
} | |
.legend--item--box { | |
stroke: black; | |
} | |
.legend--item--label { | |
font-family: Helvetica; | |
font-size: 14px; | |
fill: black; | |
alignment-baseline: central; | |
} | |
.label { | |
fill: black; | |
font-family: Helvetica; | |
font-size: 14px; | |
text-anchor: middle; | |
} |
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
d3.csv("https://raw.githubusercontent.com/hvo/datasets/master/nyc_grads.csv") | |
.then(function(grads) { | |
var data = grads | |
.filter(row => ((row.Type=='Borough Total') && | |
(row.Cohort%2===0))) | |
.map(row => [row.Advanced/row.Total*100, | |
row.DroppedOut/row.Total*100, | |
row.Cohort, | |
row.Borough]); | |
createPlot(data); | |
}); | |
function createPlot(data) { | |
var canvasSize = [500, 500]; | |
var tickSize = 5; | |
var pArea = [50, 30, 390, 370]; | |
var pSize = [pArea[2]-pArea[0], pArea[3]-pArea[1]]; | |
// Used dictionary | |
var palette = {'Bronx': 'SteelBlue', 'Brooklyn': 'LightSalmon', 'Queens': 'SeaGreen', 'Manhattan': 'Gold', 'Staten Island': 'IndianRed'}; | |
var canvas = d3.select("#chart") | |
.append("svg") | |
.attr('width', canvasSize[0]) | |
.attr('height', canvasSize[1]); | |
var x = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[0], pArea[2]]); | |
// We need to invert our y-values because our grid goes from top to bottom, not bottom to enter | |
var y = d3.scaleLinear() | |
.domain([0, 30]) | |
.range([pArea[3], pArea[1]]); | |
var g = canvas.append('g'); | |
g.append('text') | |
.attr('class', 'title') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 25) | |
.text('NYC High School Graduate Statistics'); | |
g.append('g') | |
.attr('class', 'axis axis--x') | |
.attr('transform', `translate(0, ${pArea[3]})`) | |
.call(d3.axisBottom(x).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('x', (x.range()[0]+x.range()[1])*0.5) | |
.attr('y', 35) | |
.text('Advanced Regents (%)'); | |
g.append('g') | |
.attr('class', 'axis axis--y') | |
.attr('transform', `translate(${pArea[0]},0)`) | |
.call(d3.axisLeft(y).ticks(5, "I")) | |
.append('text') | |
.attr('class', 'label') | |
.attr('transform', 'rotate(-90)') | |
.attr('x', -(y.range()[0]+y.range()[1])*0.5) | |
.attr('y', -25) | |
.text('Dropped Out (%)'); | |
// To draw the dots | |
var dots = g.selectAll('.dot') | |
.data(data); | |
drawDots(g, x, y, palette, data); | |
// The 'g' that we are appending refers to a group that will be our legend items | |
// We use the back-tick notation to evaluate whatever is inside of the | |
var legend = g.append('g') | |
.attr('transform', | |
`translate(${pArea[2]-60},${pArea[1]+10})`); | |
legend.append('rect') | |
.attr('class', 'legend--frame') | |
.attr('x', -5) | |
.attr('y', -5) | |
.attr('width', 110) | |
.attr('height', 100) | |
.on('click', function (d) { | |
drawDots(g, x, y, palette, data); | |
}); | |
var legendItems = legend.selectAll('.legend--item--line') | |
.data(['Bronx', 'Brooklyn', 'Queens', 'Manhattan', 'Staten Island']) | |
.enter().append('g'); | |
legendItems.append('rect') | |
.attr('class', 'legend--item--box') | |
.attr('x', 0) | |
.attr('y', (d,i) => (i*20)) | |
.attr('width', 10) | |
.attr('height', 10) | |
.style('fill', (d,i) => palette[d]) | |
.on('click', function (d) { | |
let filteredData = data.filter(item => item[3]==d) | |
console.log(filteredData) | |
// when this function is called, there are 15 visual elements in dots, but only 5 data points from filtered data | |
drawDots(g, x, y, palette, filteredData); | |
}); | |
// so this checks if there are any dot visual elements and assigns them to a variable | |
// if there are, then it updates the data that is already there | |
// another way of doing the same thing is by completely removing all data / viz | |
// and then drawing the new elements, but that is slow and inefficient | |
// so instead we just keep track of the old data | |
function drawDots(g, x, y, palette, data) { | |
var dots = g.selectAll('.dot') // selects all visual elements with .dot | |
.data(data, d => [d[2], d[3]]); // joins visual elements with data; second part is a key function (need to understand this for hw 2) | |
// looks at all visual elements | |
dots.enter() | |
.append('circle') | |
.attr('class', 'dot') | |
.attr('cx', d => x(d[0])) | |
.attr('cy', d => y(d[1])) | |
.attr('r', 5) | |
.style('fill', d => palette[d[3]]) | |
.merge(dots) // applies everything after to new points and old points (same effect as dots.attr() code below) | |
.transition().duration(1000) | |
.style('opacity', 1); | |
// To see why all the dots overlap, just inspect the element | |
// looks at all visual elements with data | |
// dots.attr() | |
// .attr('cx', d => x(d[0])) | |
// .attr('cy', d => y(d[1])) | |
// .attr('r', 5) | |
// .style('fill', d => palette[(d[2]-2002)/2]); | |
// looks at visual elements without data | |
dots.exit() | |
.transition().duration(1000) | |
.style('opacity', 0) | |
} | |
legendItems.append('text') | |
.attr('class', 'legend--item--label') | |
.attr('x', 20) | |
.attr('y', (d,i) => (5+i*20)) | |
.text(d => d); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment