|
<!doctype html> |
|
<meta charset="utf-8"> |
|
<title>Pitchers</title> |
|
<style> |
|
body { |
|
font-family: sans-serif; |
|
} |
|
#main { |
|
display: flex; |
|
flex-direction: row; |
|
flex-wrap: wrap; |
|
justify-content: flex-start; |
|
margin: 20px 30px 20px 10px; |
|
} |
|
.title { |
|
margin-left: 9px; |
|
font-size: 14px; |
|
} |
|
.bar, .selection { |
|
fill: steelblue; |
|
} |
|
.axis path, |
|
.axis line { |
|
fill: none; |
|
stroke: #666666; |
|
shape-rendering: crispEdges; |
|
} |
|
.axis text { |
|
fill: #666666; |
|
font-size: 14px; |
|
} |
|
#output { |
|
margin: 0 20px 10px 10px; |
|
} |
|
pre { |
|
width: 100%; |
|
height: 300px; |
|
margin: 6px 12px; |
|
tab-size: 30; |
|
font-size: 10px; |
|
overflow: auto; |
|
} |
|
</style> |
|
<body> |
|
<div id="main"></div> |
|
<div id="output"></div> |
|
<script src="https://d3js.org/d3.v4.js"></script> |
|
<script> |
|
|
|
var margin = { |
|
top: 20, |
|
right: 20, |
|
bottom: 20, |
|
left: 10 |
|
}; |
|
|
|
var height = 100 - margin.top - margin.bottom; |
|
var width = 200 - margin.left - margin.right; |
|
|
|
d3.csv("http://dhoboy.github.io/baseball/pitchers.csv", function(data) { |
|
var filteredData = data; |
|
var filters = {}; |
|
|
|
var columnKey = { |
|
'G': 'Games Pitched', |
|
'GS': 'Games Started', |
|
'CG': 'Complete Games', |
|
'SHO': 'Shutouts', |
|
'GF': 'Relief Games Finished', |
|
'SV': 'Saves', |
|
'IP': 'Innings Pitched', |
|
'H': 'Hits Allowed', |
|
'BFP': 'Batters Faced Pitcher', |
|
'HR': 'Home Runs Allowed', |
|
'R': 'Runs Allowed', |
|
'ER': 'Earned Runs Allowed', |
|
'BB': 'Bases On Balls', |
|
'IB': 'Intentional Bases On Balls', |
|
'SO': 'Strikeouts', |
|
'SH': 'Sacrifice Hits Allowed', |
|
'SF': 'Sacrifice Flies Allowed', |
|
'WP': 'Wild Pitches', |
|
'HBP': 'Hit By Pitch', |
|
'BK': 'Balks', |
|
'GDP': 'Grounded in Double Plays', |
|
'W': 'Wins', |
|
'L': 'Losses', |
|
'ERA': 'Earned Run Average', |
|
'RS': 'Run Support', |
|
'PW': 'Pitcher Wins' |
|
}; |
|
|
|
var output = d3.select("#output").append("pre") |
|
.text("Brush along at least one dimension above to see a table of results"); |
|
|
|
var scales = d3.keys(columnKey).reduce(function(prev, next) { |
|
prev[next] = d3.scaleLinear() |
|
.domain(d3.extent(data, function(d) { |
|
return +d[next]; |
|
})) |
|
.range([0, width]); |
|
return prev; |
|
}, {}); |
|
|
|
var reverseScales = d3.keys(columnKey).reduce(function(prev, next) { |
|
prev[next] = d3.scaleLinear() |
|
.domain([margin.left, width + margin.left, height]) |
|
.range(d3.extent(data, function(d) { |
|
return +d[next]; |
|
})); |
|
return prev; |
|
}, {}); |
|
|
|
var axes = d3.keys(columnKey).reduce(function(prev, next) { |
|
prev[next] = d3.axisBottom(scales[next]).ticks(3) |
|
return prev; |
|
}, {}); |
|
|
|
var brushes = d3.keys(columnKey).reduce(function(prev, next) { |
|
prev[next] = d3.brushX().extent([[margin.left, -15], [width + margin.left, height]]); |
|
return prev; |
|
}, {}); |
|
|
|
var graphs = d3.select("#main").selectAll(".graph") |
|
.data(d3.keys(columnKey)) |
|
.enter() |
|
.append("div") |
|
.attr("class", "graph"); |
|
|
|
graphs.append("div") |
|
.attr("class", "title") |
|
.text(function(d) { return columnKey[d] + ": " + d; }); |
|
|
|
var svgs = graphs.append("svg") |
|
.attr("id", function(d) { return d; }) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.attr("width", width + margin.right + margin.left) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
svgs.append("rect") |
|
.attr("class", "bar") |
|
.attr("height", 15) |
|
.attr("width", width) |
|
.attr("rx", 5) |
|
.attr("ry", 5); |
|
|
|
d3.keys(columnKey).forEach(function(key) { |
|
var s = d3.select("svg#" + key); |
|
|
|
s.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(" + margin.left + "," + height + ")") |
|
.call(axes[key]); |
|
|
|
s.append("g") |
|
.attr("class", "brush") |
|
.call(brushes[key]); |
|
|
|
brushes[key].on("brush end", function() { |
|
var brushSection = d3.brushSelection(this); |
|
|
|
if (brushSection === null) { |
|
removeFilter(key); |
|
} else { |
|
var filterInput = [ |
|
reverseScales[key](brushSection[0]), |
|
reverseScales[key](brushSection[1]) |
|
]; |
|
addFilter(key, filterInput); |
|
} |
|
}); |
|
}); |
|
|
|
function addFilter(key, filterInput) { |
|
filters[key] = filterInput; |
|
filterData(); |
|
} |
|
|
|
function removeFilter(key) { |
|
delete filters[key]; |
|
filterData(); |
|
} |
|
|
|
function filterData() { |
|
// reset filteredData |
|
filteredData = data; |
|
|
|
// apply each filter |
|
d3.keys(filters).forEach(function(filterKey) { |
|
filteredData = filteredData.filter(function(d) { |
|
return +d[filterKey] >= filters[filterKey][0] && |
|
+d[filterKey] <= filters[filterKey][1]; |
|
}); |
|
}); |
|
|
|
// only draw result table if you've filtered the dataset somewhat |
|
if (d3.keys(filters).length > 0) { |
|
output.text(d3.tsvFormat(filteredData.slice(0))); |
|
} else { |
|
output.text("Brush along at least one dimension above to see a table of results"); |
|
} |
|
} |
|
}); |
|
</script> |