Skip to content

Instantly share code, notes, and snippets.

@pbeshai pbeshai/README.md
Last active Feb 4, 2016

Embed
What would you like to do?
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>
@timelyportfolio

This comment has been minimized.

Copy link

commented Jan 9, 2015

thanks so much for sharing the code behind these beautiful and magical creations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.