Skip to content

Instantly share code, notes, and snippets.

@ramnathv
Forked from pbeshai/README.md
Created November 13, 2015 23:46
Show Gist options
  • Save ramnathv/4781c78ff3afbbc095e9 to your computer and use it in GitHub Desktop.
Save ramnathv/4781c78ff3afbbc095e9 to your computer and use it in GitHub Desktop.
Shooting Signatures

Shooting Signatures were designed to give an at-a-glance view of an NBA player's shooting performance. They were developed by Peter Beshai (@pbesh) as part of Buckets, an interactive NBA shot visualization tool.

Shooting Signature Explanation

Sample Shooting Signature usage

Shooting Signatures of NBA Players from the 2013-14 Season
<!DOCTYPE html>
<html>
<head>
<title>Shooting Signature Example</title>
</head>
<body>
<div id="signature"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.min.js"></script>
<script>
// get your data
var data = [{"x":0,"y":0.7984084880636605,"widthValue":158,"colorValue":0.1629224750896936},{"x":1,"y":0.765993265993266,"widthValue":145,"colorValue":0.16595424641159695},{"x":2,"y":0.7241379310344827,"widthValue":74,"colorValue":0.14788844079931118},{"x":3,"y":0.6082191780821917,"widthValue":36,"colorValue":0.09604064011114222},{"x":4,"y":0.45348837209302323,"widthValue":35,"colorValue":0.0205093443427537},{"x":5,"y":0.37333333333333335,"widthValue":39,"colorValue":-0.015647382920110142},{"x":6,"y":0.3744075829383886,"widthValue":39,"colorValue":-0.012850902701298128},{"x":7,"y":0.3926940639269407,"widthValue":37,"colorValue":0.0016039868744902042},{"x":8,"y":0.4619047619047619,"widthValue":22,"colorValue":0.07160931036145685},{"x":9,"y":0.4788135593220339,"widthValue":45,"colorValue":0.0874320387619314},{"x":10,"y":0.4979423868312757,"widthValue":45,"colorValue":0.10551911317398666},{"x":11,"y":0.4542253521126761,"widthValue":42,"colorValue":0.06070052516549129},{"x":12,"y":0.4503311258278146,"widthValue":44,"colorValue":0.05378653654579513},{"x":13,"y":0.4110787172011662,"widthValue":66,"colorValue":0.009121101429431566},{"x":14,"y":0.4196185286103542,"widthValue":61,"colorValue":0.01780232246319491},{"x":15,"y":0.42819148936170215,"widthValue":64,"colorValue":0.02163884827966278},{"x":16,"y":0.41988950276243087,"widthValue":71,"colorValue":0.016918338868285643},{"x":17,"y":0.45425867507886436,"widthValue":50,"colorValue":0.04975728463782164},{"x":18,"y":0.4141791044776119,"widthValue":45,"colorValue":0.015415540872963762},{"x":19,"y":0.4752475247524752,"widthValue":37,"colorValue":0.07919199741203164},{"x":20,"y":0.41830065359477125,"widthValue":20,"colorValue":0.030376008752275918},{"x":21,"y":0.4928571428571429,"widthValue":13,"colorValue":0.10821499731174294},{"x":22,"y":0.45592705167173253,"widthValue":18,"colorValue":0.07432771905345104},{"x":23,"y":0.43107221006564544,"widthValue":39,"colorValue":0.05587993676927633},{"x":24,"y":0.4125364431486881,"widthValue":221,"colorValue":0.041212020305431696},{"x":25,"y":0.3859060402684564,"widthValue":127,"colorValue":0.023158322960854794},{"x":26,"y":0.36511156186612576,"widthValue":60,"colorValue":0.00876771640727797},{"x":27,"y":0.32627118644067793,"widthValue":22,"colorValue":-0.017285514590249906},{"x":28,"y":0.25555555555555554,"widthValue":3,"colorValue":-0.07036667774454414},{"x":29,"y":0.34375,"widthValue":2,"colorValue":0.043655332912590716},{"x":30,"y":0.2,"widthValue":0,"colorValue":-0.06235399820305482}];
// initialize SVG
var width = 600, height = 200;
var svg = d3.select("#signature").append("svg")
.attr("width", width)
.attr("height", height);
// x = distance in shooting signatures
var x = d3.scale.linear()
.domain([0, 30])
.range([0, width]);
// for gradient offset (needs % - so map x domain to 0-100%)
var offset = d3.scale.linear()
.domain(x.domain())
.range([0, 100]);
// y = Field Goal % in shooting signatures
var y = d3.scale.linear()
.domain([0, 1])
.range([height, 0]);
// scale for the width of the signature
var minWidth = 1;
var maxWidth = height / 4;
var w = d3.scale.linear()
.domain([0, 250])
.range([minWidth, maxWidth]);
// NOTE: if you want maxWidth to truly be the maximum width of the signature,
// you'll need to add .clamp(true) to w.
// need two area plots to make the signature extend in width in both directions around the line
var areaAbove = d3.svg.area()
.x(function(d) { return x(d.x); })
.y0(function (d) { return y(d.y) - w(d.widthValue); })
.y1(function(d) { return Math.ceil(y(d.y)); }) // ceil and floor prevent line between areas
.interpolate("basis");
var areaBelow = d3.svg.area()
.x(function(d) { return x(d.x); })
.y0(function (d) { return y(d.y) + w(d.widthValue); })
.y1(function(d) { return Math.floor(y(d.y)); }) // ceil and floor prevent line between areas
.interpolate("basis");
// add the areas to the svg
var gArea = svg.append("g").attr("class", "area-group");
gArea.append("path")
.datum(data)
.attr("class", "area area-above")
.attr("d", areaAbove)
.style("fill", "url(#area-gradient)"); // specify the linear gradient #area-gradient as the colouring
// NOTE: the colouring won't work if you have multiple signatures on the same page.
// In this case, you'll need to generate unique IDs for each gradient.
gArea.append("path")
.datum(data)
.attr("class", "area area-below")
.attr("d", areaBelow)
.style("fill", "url(#area-gradient)");
/*
// you can draw the line the signature is based around using the following code:
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); })
.interpolate("basis");
gArea.append("path")
.datum(data)
.attr("d", line)
.style("stroke", "#fff")
.style("fill", "none")
*/
// set-up colours
var colorSchemes = {
buckets: {
domain: [-0.15, 0.15],
range: ["#405A7C", "#7092C0", "#BDD9FF", "#FFA39E", "#F02C21", "#B80E05"]
},
goldsberry: {
domain: [-0.15, 0.15],
range: ["#5357A1", "#6389BA", "#F9DC96", "#F0825F", "#AE2A47"]
}
};
var activeColorScheme = colorSchemes.goldsberry;
// Note that the quantize scale does not interpolate between colours
var colorScale = d3.scale.quantize()
.domain(activeColorScheme.domain)
.range(activeColorScheme.range);
// generate colour data
var colorData = [];
var stripe = false; // set stripe to true to prevent linear gradient fading
for (var i = 0; i < data.length; i++) {
var prevData = data[i - 1];
var currData = data[i];
if (stripe && prevData) {
colorData.push({
offset: offset(currData.x) + "%",
stopColor: colorScale(prevData.colorValue)
});
}
colorData.push({
offset: offset(currData.x) + "%",
stopColor: colorScale(currData.colorValue)
});
}
// generate the linear gradient used by the signature
gArea.append("linearGradient")
.attr("id", "area-gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("y1", 0)
.attr("y2", 0)
.selectAll("stop")
.data(colorData)
.enter().append("stop")
.attr("offset", function(d) { return d.offset })
.attr("stop-color", function (d) { return d.stopColor; });
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment