Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js">
</script>
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<style>
text {
font-size: 11px;
font-weight: 900;
}
text.title {
font-size: 24px;
}
text.mini-title {
font-size: 20px;
font-weight: normal;
}
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<svg width="960" height="80">
<text class="title" x=30 y=40>Jason Witten Scatterplot</text>
<text class="mini-title" x=30 y=70>Win% Added by QB</text>
<script>
var margin = {top: 20, right: 40, bottom: 20, left: 40};
var width = 960 - margin.left - margin.right
var height = 500 - margin.top- margin.bottom
var svg = d3.select("body").append("svg")
.attr('class', 'containerL')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
//resource: https://learnjsdata.com/read_data.html
var wittenData = d3.csv("witten.csv", function(d) {
return{
QB: d.pname,
Season: +d.seas,
Week: +d.wk,
Catches: +d.catches,
Thrown_to: +d.thrown_to,
Yards: +d.yards,
Catch_Rate: parseFloat(d.catch_rate, 10)/100,
Success: parseFloat(d.success, 10)/100,
Points: +d.pts,
YardsPerCatch: +d.yds_per_catch,
WPA_throw: parseFloat(d.wpa_throw, 10)/100,
WPA_catch: parseFloat(d.wpa_catch, 10)/100 //parseFloat will take all numberic value up to a non-numeric character, dropping everything after the non-numberic character
};
},
// function(woop){
// console.log(woop)
// },
main)
console.log(wittenData)
function main(error, data){
if(error){
throw error
};
// console.log(data)
//colors-----------------------------------------------
var colorDomain = data.map(function(d) {
return d.QB
});
var select = d3.select("body")
.append('select')
.attr('class', 'containerR')
.attr('id','colorInput')
.on('change', function() {
var val = this.value;
console.log(this.value, colors[val])
var circles = svg.selectAll("circle")
.attr("fill", function(d){
console.log(d, val, colors[val])
return colors[val](d[val]) //colors[val] selects the colors, d[val] selects data to pass in
})
})
var colors = {
QB: d3.scaleOrdinal()
.range(colorDomain.map((val, i) =>
d3.interpolateYlGnBu(i / (17 - 1)))
),
Season: d3.scaleOrdinal(d3.schemeBlues[9])
}
var colorScale = d3.scaleOrdinal()
.range(colorDomain.map((val, i) =>
d3.interpolateYlGnBu(i / (17 - 1)))
)
//legend----------------------------------------------
console.log(colorDomain) //how do i only get unique values? don't need to d3 scale is smart enouhg
var ordinal = d3.scaleOrdinal()
.domain(colorDomain) //mbostock: domain is option in oridinal scale
.range(colorDomain.map((val, i) =>
d3.interpolateYlGnBu(i / (17 - 1)) //how to replace 17 with a count unique QBs
))
var legendOrdinal = d3.legendColor() //.legendColor = Susie Lu's package
.scale(ordinal)
.shape("path", d3.symbol().type(d3.symbolCircle).size(150)())
.shapePadding(10) //how to get a list of all the QBs/seasons?
d3.select("body").append("svg")
.attr("width", width/4)
.attr("height", height)
.attr("class", "containerR")
.call(legendOrdinal)
// .attr("transform", "translate(" + (width - margin.left - margin.right) + ",0)")
//console.log(xExtent) //make sure to translate Yard in object to number with "+"
//X---------------------------------------------------
var xExtent = d3.extent(data, function(d){
return d.Yards
});
var xScale = d3.scaleLinear()
.domain(xExtent)
.range([0, width]);
var xAxis = d3.axisBottom()
.scale(xScale)
.tickFormat(d3.format("d"))
//Y--------------------------------------------------
var p = d3.format(".1%")
var yExtent = d3.extent(data, function(d){
return (d.WPA_catch)
});
// console.log(yExtent)
var yScale = d3.scaleLinear()
.domain(yExtent)
.range([height, 0]);
var yAxis = d3.axisLeft()
.scale(yScale)
.tickFormat(d3.format(".0%"));
//R-----------------------------------------------------
var rExtent = d3.extent(data, function(d){
return d.Catches
})
var rScale = d3.scaleSqrt()
.domain(rExtent)
.range([2, 20])
svg.append("g")
.attr("class", "axes")
.attr("transform", "translate(0," + height +")")
.call(xAxis);
svg.append("g")
.attr("class", "axes")
.call(yAxis);
var radius = function(d){return rScale(d.Catches)}
var circles = svg.selectAll("circle")
.attr('class', 'bubbles')
.data(data, function(d){return d.Yards}) //function here is the key function (redefine with something unique - may be index position)
.enter()
.append("circle")
.attr('fill', function(d){return colorScale(d.Season)})
.attr('stroke', '#3297AC')
.attr('r', function(d){return rScale(d.Catches)}) //can put this here instead of simulation b/c has nothing to do w/ force
var simulation = d3.forceSimulation(data)
.force('x', d3.forceX(function(d){
return xScale(d.Yards)
}))
.force('y', d3.forceY(function(d){ //change function to 0 to get fish back
return yScale(d.WPA_catch)
}))
.force('collide', d3.forceCollide(radius))
.on('tick', function(){
circles
.attr('cx', function(d){return d.x}) //force simulation creates x & ys. can always just use d.x and d.y even when nothing is called 'x' or 'y'
.attr('cy', function(d){return d.y});
});
var colorOptions = [
{text: "Quarterback", value: "QB"},
{text: "Season", value: "Season"}
]
var options = select
.selectAll('option')
.data(colorOptions)
// .property("selected", function(d){
// return d === "QB"
// })
.enter()
.append('option')
.attr("value", function(option) {
return option.value;
})
.text(function(option) {
return option.text;
})
options.attr('transform', 'translate(' + margin.left + ',' +
margin.top + ')');
// function onchange(){
// console.log("blah")
// var circles = svg.selectAll("circle")
// .attr("fill", function(d){
// return colorScale(d.Season)
// })
// }
};
</script>
</body>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-scale-chromatic.v1.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.js