block by ramnathv 4781c78ff3afbbc095e9

Shooting Signatures

Full Screen

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

index.html

<!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>