Skip to content

Instantly share code, notes, and snippets.

@chrisrzhou
Last active April 26, 2019 06:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisrzhou/078d39d91acf95d59cd8 to your computer and use it in GitHub Desktop.
Save chrisrzhou/078d39d91acf95d59cd8 to your computer and use it in GitHub Desktop.
D3 Inflation Explorer

D3 Inflation Explorer

bl.ocks.org link

image-inflation

Explores inflation by visualizing relative prices in two different years.

Mouseover to view details on relative CPI and prices. Click on a tile to freeze details. 2015 years are highlighted in gold.

The project is created using D3.js.


Description

This project is based on the CPI Inflation Calculator provided by the Bureau of Labor Statistics.

This calculator measures the buying power of the dollar based on the Consumer Price Index (CPI). In general, the relative price formula is:

targetPrice = basePrice x (targetCPI / baseCPI)

A specific example given the 1980 price and calculating the 2011 price:

The average CPI for 1980 = 82.4
The average CPI for 2011 = 224.9

2011 Price = 1980 Price x (2011 CPI / 1980 CPI)
           = $20.00 x (82.4 / 224.9)
           = $7.33

Files

  • index.html: Main HTML file.

  • app.js: All D3 drawing logic is contained in this file.

  • inflation.tsv: tsv data file of year and CPI values

  • style.css: stylesheet


Analytics

(function() {
/**
* Initialize D3 by making AJAX call to tsv data
*/
d3.tsv("inflation.tsv", function(error, data) {
data = buildInflation(data);
vis = {}; //init vis object
buildVis(data);
});
/**
* Initiate and build vis
*/
function buildVis(data) {
// vis attributes
vis.margin = {
top: 50,
right: 50,
bottom: 0,
left: 50
};
vis.width = 450 - vis.margin.left - vis.margin.right;
vis.height = 450 - vis.margin.top - vis.margin.bottom;
vis.gridSize = Math.floor(vis.width / Math.sqrt(data.length));
vis.basePrice = 600;
vis.ratio = 1;
// create main svg
vis.svg = d3.select("#vis").append("svg")
.attr("width", vis.width + vis.margin.left + vis.margin.right)
.attr("height", vis.height + vis.margin.top + vis.margin.bottom)
.append("g")
.attr("transform", "translate(" + vis.margin.left + ", " + vis.margin.top + ")");
// create vis colorscale
vis.colorScale = d3.scale.quantile()
.domain([0, d3.max(data, function(d) { return d.value; })])
.range(colorbrewer.RdYlBu[10].reverse());
// create selected tooltip
vis.tooltipSelected = d3.select("body").append("div")
.classed("tooltip", true)
.classed("tooltip-selected", true)
.style("opacity", 0);
// create tooltip
vis.tooltip = d3.select("body").append("div")
.classed("tooltip", true)
.style("opacity", 0);
// add x-label (target year)
vis.svg.append("text")
.classed("x-label", true)
.attr("text-anchor", "middle")
.attr("x", vis.width / 2)
.attr("y", -10)
.text("Base Year");
// add y-label (base year)
vis.svg.append("text")
.classed("y-label", true)
.attr("text-anchor", "middle")
.attr("x", -vis.width / 2)
.attr("y", -15)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Target Year");
// create heatmap tiles
vis.tiles = vis.svg.selectAll(".tiles")
.data(data).enter()
.append("rect").classed("tiles", true)
.attr("x", function(d) { return d.x * vis.gridSize; })
.attr("y", function(d) { return d.y * vis.gridSize; })
.attr("rx", 1)
.attr("ry", 1)
.attr("stroke", function(d) {
return d.targetYear == 2015 || d.baseYear == 2015 ? "orange" : "lightgray";
})
.attr("stroke-width", "1px")
.attr("width", vis.gridSize)
.attr("height", vis.gridSize)
.attr("fill", function(d) { return vis.colorScale(d.value); })
.on("mouseover", function(d) {
tooltipShow(vis.tooltip, d);
d3.select(this).attr("stroke", "red");
})
.on("mouseleave", function(d) {
tooltipHide(vis.tooltip);
d3.select(this)
.attr("stroke", function(d) {
return d.targetYear == 2015 || d.baseYear == 2015 ? "orange" : "lightgray";
});
})
.on("click", function(d) {
tooltipHide(vis.tooltipSelected);
tooltipShow(vis.tooltipSelected, d);
updateYears(d);
});
d3.select("#price").on("input", function() {
updatePrice(+this.value);
});
}
/**
* Helper function to build inflation data from tsv data file
*/
function buildInflation(data) {
result = [];
for (var x = 0; x < data.length; x++) {
baseCPI = +data[x].cpi;
baseYear = +data[x].year;
for (var y = 0; y < data.length; y++) {
targetCPI = +data[y].cpi;
targetYear = +data[y].year;
d = {
baseYear: baseYear,
targetYear: targetYear,
baseCPI: baseCPI,
targetCPI: targetCPI,
value: targetCPI / baseCPI,
x: x,
y: y
};
result.push(d);
}
}
return result;
}
/**
* Helper function to update price
*/
function updatePrice(price) {
vis.basePrice = price;
d3.selectAll(".base-price").text(price.toFixed(2));
d3.selectAll(".target-price").text((vis.ratio * vis.basePrice).toFixed(2));
}
function updateYears(d) {
vis.ratio = +d.value;
d3.select(".base-year").text(+d.baseYear);
d3.select(".target-year").text(+d.targetYear);
d3.select(".target-price").text((+d.value * vis.basePrice).toFixed(2));
}
/**
* Helper function to show tooltip
*/
function tooltipShow(tooltip, d) {
tooltip.style("opacity", 0.9)
.html(
"$<span class='base-price'>" + vis.basePrice.toFixed(2) + "</span>" +
"<sub> " + d.baseYear + " (CPI: " + d.baseCPI.toFixed(2) + ") " + "</sub>" +
"<br />" +
"$<span class='target-price'>" + (vis.basePrice * d.value).toFixed(2) + "</span>" +
"<sub> " + d.targetYear + " (CPI: " + d.targetCPI.toFixed(2) + ") " + "</sub>"
)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) + "px");
}
/**
* Helper function to hide tooltip
*/
function tooltipHide(tooltip) {
tooltip.style("opacity", 0);
}
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Inflation Explorer</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:400,600" />
<link rel="stylesheet" href="style.css" />
</head>
<body class="container">
<!-- header -->
<header class="page-header">
<h1>D3 Inflation Explorer</h1>
</header>
<!-- main content -->
<div class="main container">
<!-- update price -->
<label for="price">Set Price:</label>
<input type="number" step=10 value=600 id="price">
<p class="text-small">
A $<span class="base-price">600.00</span> item in <span class="base-year">2015</span> will cost $<span class="target-price">211.55</span> in <span class="target-year">1980</span>.
</p>
<!-- visualization -->
<div id="vis"></div>
<h2>Instructions</h2>
<p>Mouseover to view details on relative CPI and prices. Click on a tile to freeze details</p>
<p>2015 years are highlighted in gold.</p>
<hr/>
<!-- description -->
<div class="Details">
<h2>Details</h2>
<p>This project is based on the <a href="http://www.bls.gov/data/inflation_calculator.htm">CPI Inflation Calculator</a> provided by the Bureau of Labor Statistics.</p>
<p>This calculator measures the buying power of the dollar based on the Consumer Price Index (CPI). In general, the relative price formula is:</p>
<pre>targetPrice = basePrice x (targetCPI / baseCPI)</pre>
<p>A specific example given the 1980 price and calculating the 2011 price:</p>
<pre>
The average CPI for 1980 = 82.4
The average CPI for 2011 = 224.9
2011 Price = 1980 Price x (2011 CPI / 1980 CPI)
= $20.00 x (82.4 / 224.9)
= $7.33
</pre>
</div>
<hr/>
</div>
<!-- footer -->
<footer>
<p>
<a href="https://gist.github.com/chrisrzhou/078d39d91acf95d59cd8" target="_blank">D3 Inflation Explorer</a> by
<a href="http://chrisrzhou.datanaut.io/projects" target="_blank">chrisrzhou</a>, 2015-03-02
<br />
<a href="http://github.com/chrisrzhou" target="_blank"><i class="fa fa-github"></i></a> |
<a href="http://bl.ocks.org/chrisrzhou" target="_blank"><i class="fa fa-cubes"></i></a> |
<a href="http://www.linkedin.com/in/chrisrzhou" target="_blank"><i class="fa fa-linkedin"></i></a>
</p>
</footer>
<!-- scripts -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/colorbrewer.v1.min.js"></script>
<script src="app.js"></script>
<script>
// Hack to make this example display correctly in an iframe on bl.ocks.org
d3.select(self.frameElement).style("height", "1000px");
</script>
</body>
</html>
year cpi
1980 82.4
1981 90.9
1982 96.5
1983 99.6
1984 103.9
1985 107.6
1986 109.6
1987 113.6
1988 118.3
1989 124
1990 130.7
1991 136.2
1992 140.3
1993 144.5
1994 148.2
1995 152.4
1996 156.9
1997 160.5
1998 163
1999 166.6
2000 172.2
2001 177.1
2002 179.9
2003 184
2004 188.9
2005 195.3
2006 201.6
2007 207.3
2008 215.303
2009 214.537
2010 218.056
2011 224.939
2012 229.594
2013 232.957
2014 236.736
2015 233.707
body {
font-family: "Open Sans", sans-serif;
font-size: 12px;
font-weight: 400;
padding-top: 10px;
padding-bottom: 100px;
}
html {
overflow-y: scroll;
}
h1 {
color: steelblue;
font-weight: 800;
font-size: 1.7em;
}
h2 {
color: steelblue;
font-size: 1.3em;
padding-bottom: 10px;
}
h3 {
color: gray;
font-size: 1.2em;
padding-bottom: 10px;
}
footer a,
footer a:hover, footer a:visited {
color: #D2A000;
}
.text-small {
font-size: 12px;
font-style: italic;
}
footer {
color: white;
padding-top: 5px;
border-top: 1px solid gray;
font-size: 12px;
position: fixed;
left: 0;
bottom: 0;
height: 50px;
width: 100%;
background: black;
text-align: center;
}
pre {
font-size: 11px;
}
.tooltip {
font-size: 15px;
font-weight: bold;
width: auto;
height: auto;
padding: 5px;
background: white;
border: 2px solid gray;
border-radius: 5px;
pointer-events: none;
}
.tooltip-selected {
background: #FFD4C2;
border: 2px solid red;
}
#price {
width: 75px;
height: 35px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment