Skip to content

Instantly share code, notes, and snippets.

@JackyLiu97
Created October 21, 2019 20:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JackyLiu97/2d30057f2ed1481cde4917b774a14c28 to your computer and use it in GitHub Desktop.
Save JackyLiu97/2d30057f2ed1481cde4917b774a14c28 to your computer and use it in GitHub Desktop.
JS Bin Lab 4 with Extra Credit // source https://jsbin.com/kaxamad
<!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>
.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;
}
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