Skip to content

Instantly share code, notes, and snippets.

@j450h1
Forked from nikolay-shenkov/create_vis.js
Last active September 20, 2015 11:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save j450h1/4846a5a62defddb139f7 to your computer and use it in GitHub Desktop.
Save j450h1/4846a5a62defddb139f7 to your computer and use it in GitHub Desktop.
Comparing Revenue & Attendance Across Leagues (NHL, NBA, MLB, NFL)
function createScatter(error, data, current_year) {
// output error message, if any:
if (error) { console.log(error); }
// use a global variable to store parsed_data
// so that we have access to it for other functions
data_parsed = data;
// set a default year:
// if current year is undefined, set it to 2006
current_year = current_year || "2006";
// Create a subset of the data to be used to draw scatter points
var data_subset = [];
for (var i = 0; i < data.length; i++) {
var new_elem = {
"uniqueid": data[i]["uniqueid"],
"Year": data[i]["Year"],
"League": data[i]["League"],
"Revenue": data[i]["Revenue"],
"Attendance": data[i]["Attendance"]
};
//Only going to add the data points for the selected year to the stage
if (data[i]["Year"] == current_year) {
data_subset.push(new_elem);
}
}
// renderLineVis(data_subset, current_year);
renderCircleVis(data_subset, current_year);
}
//just simpy refreshes the page
function resetVis() {
window.location.reload();
}
function renderCircleVis(data, current_year) {
// bind data to html elements - circles
var selection = bodyG.selectAll("circle.uniqueid")
.data(data, function(d) {return d.uniqueid;});
// Function to color points based on league type
function colorPoints(d) {
if (d.League == "NHL")
return "#c2e487";
else if (d.League == "NBA")
return "#ebb980";
else if (d.League == "MLB")
return "#ebbbb5";
else //NFL
return "#95b8d1";
}
//Each year has a higher opacity, when each year is clicked successively the trend is apparent
//Ended up not using this function below because it wasn't required.
function opacityYear(d) {
if (d.Year == "2006")
return 1.0;
else if (d.Year == "2007")
return 0.85;
else if (d.Year == "2008")
return 0.68;
else if (d.Year == "2009")
return 0.51;
else if (d.Year == "2010")
return 0.34;
else //2011
return 0.17;
}
selection.enter().append("circle")
.attr("class", "uniqueid") //would make only that specific years circles show if uncommented
.attr("fill", colorPoints)
//.style("opacity",opacityYear);
selection.exit().remove();
// update selection handles animation so we use the duration()
// to specify a 2 second transition
selection.transition().duration(2000)
// we use the linear scales to go from
// data elements to pixel locations cx and cy
.attr("cx", function(d) {return xlinear(d["Revenue"])})
.attr("cy", function(d) {return ylinear(d["Attendance"])})
.attr("r", radius)
.attr("fill", colorPoints);
}
//Didn't end up using below because doesn't show much information
function renderLineVis(data, current_year) {
// bind data to html elements - circles
/*var line_selection = bodyP.selectAll("path")
.data(data);
*/
var lineFunction = d3.svg.line()
.x(function(d) {return xlinear(d["Revenue"])})
.y(function(d) {return ylinear(d["Attendance"])})
.interpolate("linear");
var lineGraph = svg.append("path")
.attr("d", lineFunction(data))
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("opacity",0.25)
.attr("transform", translator(margin,margin));
}
function initializeTreemap(data) {
var height = 600, width = 850,
margin = 25, radius = 11;
var attributes = [
{"League": "NFL", "hex": "#95b8d1"},
{"League": "MLB", "hex": "#ebbbb5"},
{"League": "NBA", "hex": "#ebb980"},
{"League": "NHL", "hex": "#c2e487"}
]
var visualization2 = d3plus.viz()
.container("#viz2")
.data(data)
.type("tree_map")
.id("League")
.size("ARPF")
.time({"value": "nYear", "solo": 2006})
.attrs(attributes)
.color("hex")
.height(height + margin)
.width(width + margin)
.legend({"value":false})
.draw()
}
function initializeLinechart(data) {
data = data.filter(function(d){
return d.Year != "2006";
})
clickedOnceChart3 = true;
var height = 600, width = 850,
margin = 25, radius = 11;
var attributes = [
{"League": "NFL", "hex": "#95b8d1"},
{"League": "MLB", "hex": "#ebbbb5"},
{"League": "NBA", "hex": "#ebb980"},
{"League": "NHL", "hex": "#c2e487"}
]
//Left Chart - half the width of visualization 1 and 2.
var visualization3 = d3plus.viz()
.container("#viz3")
.data(data)
.type("bar")
.id("League")
.y({"value": "RGrowth", "label": "Yearly Revenue Growth (Percentage)"})
.x("Year")
.attrs(attributes)
.color("hex")
.height(height + margin)
.width(width/2)
.draw()
//Right Chart - half the width of visualization 1 and 2.
var visualization4 = d3plus.viz()
.container("#viz4")
.data(data)
.type("line")
.id("League")
.y({"value": "AGrowth", "label": "Yearly Attendance Growth (Percentage)"})
.x("Year")
.attrs(attributes)
.color("hex")
.height(height + margin)
.width(width/2)
.draw()
}
uniqueid Year League Attendance AGrowth Revenue RGrowth Ratio nYear
MLB2006 2006 MLB 76.3 0.00 5111 0.00 66.99 2006
MLB2007 2007 MLB 79.6 4.33 5489 7.40 68.96 2007
MLB2008 2008 MLB 79 -0.75 5819 6.01 73.66 2008
MLB2009 2009 MLB 73.6 -6.84 5898 1.36 80.14 2009
MLB2010 2010 MLB 73.2 -0.54 6137 4.05 83.84 2010
MLB2011 2011 MLB 73.7 0.68 6464 5.33 87.71 2011
NBA2006 2006 NBA 21.6 0.00 3367 0.00 155.88 2006
NBA2007 2007 NBA 21.8 0.93 3573 6.12 163.9 2007
NBA2008 2008 NBA 21.4 -1.83 3768 5.46 176.07 2008
NBA2009 2009 NBA 21.5 0.47 3786 0.48 176.09 2009
NBA2010 2010 NBA 21.1 -1.86 3805 0.50 180.33 2010
NBA2011 2011 NBA 21.3 0.95 3960 4.07 185.92 2011
NFL2006 2006 NFL 17.6 0.00 6539 0.00 371.53 2006
NFL2007 2007 NFL 17.6 0.00 7090 8.43 402.84 2007
NFL2008 2008 NFL 17.5 -0.57 7575 6.84 432.86 2008
NFL2009 2009 NFL 17.3 -1.14 8016 5.82 463.35 2009
NFL2010 2010 NFL 17.1 -1.16 8345 4.10 488.01 2010
NFL2011 2011 NFL 17.2 0.58 8867 6.26 515.52 2011
NHL2006 2006 NHL 20.9 0.00 2267 0.00 108.47 2006
NHL2007 2007 NHL 20.9 0.00 2436 7.45 116.56 2007
NHL2008 2008 NHL 21.3 1.91 2747 12.77 128.97 2008
NHL2009 2009 NHL 21.5 0.94 2819 2.62 131.12 2009
NHL2010 2010 NHL 21 -2.33 2929 3.90 139.48 2010
NHL2011 2011 NHL 21.1 0.48 3090 5.50 146.45 2011
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title align = "left">Annual Revenue &amp; Attendance for Major Sports Leagues</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="http://www.d3plus.org/js/d3plus.js"></script>
</head>
<body>
<header id="title-container">
<h1 id="title">Annual Revenue &amp; Attendance for Major Sports Leagues
<div id="logos-container">
<!--These logos act as a legend, each league is represented by a different colored circle -->
<div class="div_NFL"><img src="nfl-on.png" alt="NFL"></div>
<div class="div_MLB"><img src="mlb-on.png" alt="MLB"></div>
<div class="div_NBA"><img src="nba-on.png" alt="NBA"></div>
<div class="div_NHL"><img src="nhl-on.png" alt="NHL"></div>
</div>
</h1>
</header>
<div id="graphbuttons-container">
<button id="graph1" class="graphbuttons">1. Revenue & Attendance Comparison</button>
<button id="graph2" class="graphbuttons">2. Avg Revenue/Fan</button>
<button id="graph3" class="graphbuttons">3. Revenue & Attendance - % Growth YOY</button>
</div>
<section id="scatter-container"></section>
<div id ="viz-container">
<div id="viz2"></div>
<div id="viz3"></div>
<div id="viz4"></div>
</div>
<div id="text-container">
<text id="caption"> The NFL has the lowest attendance, but earns the most Revenue, while MLB has at least 3X more fans compared to each of the other leagues, yet is still 2nd in Revenue. <break>
<p>Click through to see if this pattern has changed over the years.</p></text>
</div>
<div id="buttons-container">
<br class = "break">
<!--When these buttons are pressed, the data points for that year appear -->
<button id="Y2006" class="buttons">2006</button>
<br class = "break">
<button id="Y2007" class="buttons">2007</button>
<br class = "break">
<button id="Y2008" class="buttons">2008</button>
<br class = "break">
<button id="Y2009" class="buttons">2009</button>
<br class = "break">
<button id="Y2010" class="buttons">2010</button>
<br class = "break">
<button id="Y2011" class="buttons">2011</button>
<br class = "break">
</div>
<footer><h2>References:</h2>
<ol>
<li>Data from <a href="https://www.wrhambrecht.com/wp-content/uploads/2013/09/SportsMarketReport_2012.pdf">THE U.S. PROFESSIONAL SPORTS MARKET &amp; FRANCHISE VALUE REPORT 2012</a></li>
<li><a href="http://bl.ocks.org/weiglemc/6185069">Scatterplot example in d3</a></li>
<li><a href="http://bl.ocks.org/nikolay-shenkov/raw/3c05dd0ec4b86cdbb968/">Gender inequality in primary school completion</a></li>
<li><a href="http://bl.ocks.org/WilliamQLiu/bd12f73d0b79d70bfbae">D3 Scatterplot (Animations)</a></li>
<li><a href="http://d3plus.org">http://d3plus.org</a></li>
</ol>
</footer>
<script src="create_chart1.js"></script>
<script src="create_chart2and3.js"></script>
<script src="initialize_figure.js"></script>
</body>
<script>
d3.csv("dataset_ratio_growth.csv", function(d) {
d["Attendance"] = +d["Attendance"];
d["Revenue"] = +d["Revenue"];
d["AGrowth"] = +d["AGrowth"];
d["RGrowth"] = +d["RGrowth"];
d["ARPF"] = +d["Ratio"];
d["nYear"] = +d["nYear"];
return d;
}, createScatter);
</script>
</html>
// global variable to hold data once we load it with d3.csv
var data_parsed;
var height = 600, width = 850,
margin = 25, radius = 11;
// create the svg element that contains visualization
var svg = d3.select("#scatter-container").append("svg")
.attr("id", "scatter")
.attr("width", width + 2*margin)
.attr("height", height);
// keep scale ranges constant
var minX = 0, minY = 0, maxX = 9000, maxY = 80;
// create two linear scales
var xlinear = d3.scale.linear()
.domain([minX - 100, maxX])
.range([0, width - 2*margin]);
var ylinear = d3.scale.linear()
.domain([minY - 5, maxY + 10])
.range([height - 2*margin, 0]);
// a "g" element to hold axes
var axesG = svg.append("g").attr("class", "axes");
// create axis elements
var commasFormatter = d3.format(",.0f")
var xAxis = d3.svg.axis().scale(xlinear).orient("bottom")
.tickValues([1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000])
.tickFormat(function(d) { return "$" + commasFormatter(d); });
var yAxis = d3.svg.axis().scale(ylinear).orient("left");
// helper function to create the "translate(x, y)" string
function translator(x, y) {
return "translate(" + x + "," + y + ")";
}
// append axes elements to axesG container
axesG.append("g")
.attr("class", "y-axis all-axis")
// location for the y-axis: margin, margin
.attr("transform", translator(margin, margin))
.call(yAxis)
// add y-axis label
.append("text")
.attr("id", "y-axis")
.attr("class", "axis-label")
// rotate text so that it is vertical
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
// position text appropriately along the axis
.style("text-anchor", "end")
// finally, specify the actual label
.text("Annual Combined Attendance of all Stadiums (Millions of Spectators)");
axesG.append("g")
.attr("class", "x-axis all-axis")
.attr("transform", translator(margin, height - margin))
.call(xAxis)
.append("text")
.attr("id", "x-label")
.attr("class", "axis-label")
.attr("x", width - 2*margin)
.attr("y", -6)
.style("text-anchor", "end")
.text("Annual League Revenue from All Sources ($ Millions USD - $1,000 Million = $1 Billion)");
// add grid-lines for the x-axis
d3.selectAll("g.x-axis g.tick")
.append("line")
.classed("grid-line", true)
// they start at (0, 0) and go to (0, height - 2*margin)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", - (height - 2*margin));
// add grid-lines for the y-axis
d3.selectAll("g.y-axis g.tick")
.append("line")
.classed("grid-line", true)
// they start at (0, 0) and go to (0, height - 2*margin)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", (width - 2*margin))
.attr("y2", 0);
// container for the scatter points
var bodyG = svg.append("g")
.attr("class", "scatter-g")
.attr("transform", translator(margin, margin));
// --------------------------------------
// Creating buttons and binding data to them
var buttonsData = [{"text": "2006", "display_year": "2006"},
{"text": "2007", "display_year": "2007"},
{"text": "2008", "display_year": "2008"},
{"text": "2009", "display_year": "2009"},
{"text": "2010", "display_year": "2010"},
{"text": "2011", "display_year": "2011"}];
// bind all the buttons to data
var buttons_selection = d3.selectAll(".buttons").data(buttonsData)
// Creating graph buttons and binding data to them
var graphbuttonsData = [{"text": "graph1", "display_graph": "graph1"},
{"text": "graph2", "display_graph": "graph2"},
{"text": "graph3", "display_graph": "graph3"}];
// bind all the buttons to data
var graph_buttons_selection = d3.selectAll(".graphbuttons").data(graphbuttonsData)
// make 2006 button look active (pressed)
// we are using a 1 sec (1000 ms) transition for a smooth effect
d3.select("#Y2006").transition().duration(1000).
style("background", "steelBlue").style("color", "white");
// make Revenue and Attendance button look active (pressed)
d3.select("#graph1").transition().duration(1000).
style("background", "steelBlue").style("color", "white");
// make graph buttons look inactive (not pressed)
d3.select("#graph2").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
// note that it is partially transparent
.style("opacity", 0.6);
d3.select("#graph3").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
// note that it is partially transparent
.style("opacity", 0.6);
// and the rest of the button look inactive (not pressed)
d3.select("#Y2007").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
// note that it is partially transparent
.style("opacity", 0.6);
d3.select("#Y2008").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
d3.select("#Y2009").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
d3.select("#Y2010").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
d3.select("#Y2011").transition().duration(1000)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
// declare a click handler for ALL of the year buttons
buttons_selection.on("click", function(d) {
// make all buttons look inactive
d3.selectAll(".buttons").transition().duration(500)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
// make the button that is pressed ("this")look pressed
d3.select(this).transition().duration(500)
.style("background", "steelBlue").style("color", "white")
.style("opacity", 1);
createScatter(null, data_parsed, d.display_year);
});
// declare a click handler for ALL three of the graph selection buttons
graph_buttons_selection.on("click", function(d) {
// make all buttons look inactive
d3.selectAll(".graphbuttons").transition().duration(500)
.style("background", "rgb(240, 232, 226)").style("color", "black")
.style("opacity", 0.6);
// make the button that is pressed (we can access it using the this parameter)
// look pressed
d3.select(this).transition().duration(500)
.style("background", "steelBlue").style("color", "white")
.style("opacity", 1);
var text;
if (d.display_graph == "graph1")
{
window.location.reload();
};
if (d.display_graph == "graph2")
{
if (d3.select("#viz2").empty()==true)
{
d3.select("#viz-container").append("div").attr("id", "viz2")
}
d3.select("#viz3").remove();
d3.select("#viz4").remove();
d3.select("#scatter-container").remove();
d3.select("#buttons-container").remove();
d3.select("#caption").remove();
text = "Earlier we mentioned that the NFL earns the most compared to the other leagues. If we break it down by the Average Revenue Per Fan (ARPF), the NFL makes more than other 3 leagues combined! See if this trend persists over the years.";
d3.select('#text-container')
.append("text")
.attr("id", "caption")
.text(text);
initializeTreemap(data_parsed);
};
if (d.display_graph == "graph3"){
d3.select("#viz2").remove();
if (d3.select("#viz3").empty()==true)
{
d3.select("#viz-container").append("div").attr("id", "viz3")
}
if (d3.select("#viz4").empty()==true)
{
d3.select("#viz-container").append("div").attr("id", "viz4")
}
d3.select("#scatter-container").remove();
d3.select("#buttons-container").remove();
d3.select("#caption").remove();
text = "Although the NFL has looked the most impressive thus far, investors are usually interested in percentage growth as well (not that you are necessarily one). In terms of Revenue, the NFL has been growing at about the same rate as the other leagues. However, it has still been leading the pack (except for '08 when the NHL grew at 2X the rate of the others). In terms of Attendence, '09 was a bad year for the MLB, but the numbers have remained consistently stable for the other years and the other leagues. This suggests that this overall Revenue growth across all leagues is being fueled by other sources outside of ticket sales.";
d3.select('#text-container')
.append("text")
.attr("id", "caption")
.text(text);
initializeLinechart(data_parsed);
};
});
#scatter-container {
width: 62%;
float: left;
margin-left: 50px;
margin-right: 25px;
}
#viz2 {
width: 62%;
float: left;
margin-left: 50px;
margin-top: 10px;
margin-right: 25px;
}
#viz3 {
width: 62%;
float: left;
margin-left: 50px;
margin-top: 10px;
margin-right: 25px;
}
#viz4 {
width: 62%;
float: left;
margin-top: 10px;
margin-right: 25px;
}
#buttons-container {
float: center;
margin-left: 50px;
}
#graphbuttons-container {
margin-top: 10px;
margin-left: 50px;
}
#text-container {
float: center;
margin-bottom: 10px;
margin-left: 50px;
margin-top: 10px;
}
#logos-container {
float: left;
margin-left: 50px;
}
.buttons {
font-size: 22px;
margin-bottom: 30px;
font-family: Verdana;
border-radius: 10px;
}
.resetbuttons {
font-size: 22px;
margin-bottom: 30px;
font-family: Verdana;
border-radius: 10px;
}
.graphbuttons {
font-size: 16px;
margin-bottom: 0px;
font-family: Verdana;
border-radius: 0px;
}
#title {
font-family: Verdana;
font-size: 30px;
font-weight: normal;
margin-left: 50px;
}
footer {
width: 100%;
float: left;
display: block;
}
.all-axis path,
.all-axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.country {
opacity: 0.6;
}
.grid-line {
opacity: 0.05 ;
}
.tooltip {
position: absolute;
width: 350px;
font-size: 20px;
font-family: sans-serif;
pointer-events: none;
text-align: center;
}
.metrics, ol {
font-size: 18px;
font-family: Helvetica;
}
h2 {
font-family: Verdana;
font-weight: normal;
font-size: 20px;
}
footer {
margin-left: 50px;
margin-bottom: 20px;
}
.div_NHL {
background-color: #c2e487;
float:right;
margin-right: 25px;
}
.div_NBA {
background-color: #ebb980;
float:right;
margin-right: 25px;
}
.div_MLB {
background-color: #ebbbb5;
float:right;
margin-right: 25px;
}
.div_NFL {
background-color: #95b8d1;
float:right;
margin-right: 25px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment