Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mattrelph/2526cc430c195d1cad2661d503536469 to your computer and use it in GitHub Desktop.
Save mattrelph/2526cc430c195d1cad2661d503536469 to your computer and use it in GitHub Desktop.
FCC - Data Visualization Projects - Visualize Data with a Choropleth Map

FCC - Data Visualization Projects - Visualize Data with a Choropleth Map

User Story #1: My choropleth should have a title with a corresponding id="title". User Story #2: My choropleth should have a description element with a corresponding id="description". User Story #3: My choropleth should have counties with a corresponding class="county" that represent the data. User Story #4: There should be at least 4 different fill colors used for the counties. User Story #5: My counties should each have data-fips and data-education properties containing their corresponding fips and education values. User Story #6: My choropleth should have a county for each provided data point. User Story #7: The counties should have data-fips and data-education values that match the sample data. User Story #8: My choropleth should have a legend with a corresponding id="legend". User Story #9: There should be at least 4 different fill colors used for the legend. User Story #10: I can mouse over an area and see a tooltip with a corresponding id="tooltip" which displays more information about the area. User Story #11: My tooltip should have a data-education property that corresponds to the data-education of the active area.

A Pen by Matthew Relph on CodePen.

License.

<div class = "container">
<div class = "row">
<div class="col">
</div>
<div class="col-10 text-center">
<div class="infoGraphic card">
<div class="card-body">
<h1 id="title" class="card-title h1">United States Educational Attainment</h1>
<h2 id="description" class="card-title h2">Percentage of adults age 25 and older with a bachelor's degree or higher (2010-2014)</h2>
<p id="graph" class="card-text block-center"></p>
<!--<a href="" class="btn btn-primary" target="_blank">More Info</a>-->
</div>
</div>
</div>
<div class="col">
</div>
</div>
</div>
/*Chloropleth Map visualization project*/
//Source Dataset #1 - US Education Data: https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/for_user_education.json
//Source Dataset #2 - US County Data: https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/counties.json
//Font Awesome CSS - https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css
//Bootstrap CSS - https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css
//Bootstrap JS - https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js
//D3 Datavisualization Library - https://d3js.org/d3.v5.min.js
//D3 TopoJSON Library - https://unpkg.com/topojson@3
//Testing JS - https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js
const EDUCATION_URL = "https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/for_user_education.json"
const COUNTY_URL = "https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/counties.json";
const fullwidth = 1000;
const fullheight = 700;
const padding = 25;
const width = fullwidth - 2*padding;
const height = fullheight - 2*padding;
Promise.all([
d3.json(COUNTY_URL), //Load Map Data
d3.json(EDUCATION_URL) //Load Shading Data
])
.then(([countyData, educationData]) => {
//County and State outlines
var usCounties = topojson.feature(countyData, countyData.objects.counties); //convert TopoJSON to GeoJSON.
var usStates = topojson.mesh(countyData, countyData.objects.states, function(a, b) { return a !== b; }); //convert TopoJSON to GeoJSON Mesh Overlay
var path = d3.geoPath();
//Create toolTips DIV
var toolTips = d3.select("body").append("div")
.attr("class", "tooltip")
.attr("id", "tooltip")
.style("background", "Beige")
.style("color", "Black")
.style("opacity", 0); //Hide until mouseover
//Setup Color Scale
var minEducation = d3.min(educationData, (d) => d.bachelorsOrHigher);
var maxEducation = d3.max(educationData, (d) => d.bachelorsOrHigher);
var stepVariance = (Math.abs(maxEducation) - Math.abs(minEducation))/10;
// console.log("minEducation:" + minEducation + " maxEducation:" +maxEducation);
//Create SVG
var svg = d3.select("#graph")
.append("svg")
.attr("width", fullwidth)
.attr("height", fullheight);
var target;
// Draw Counties Map
svg.selectAll("path")
.data(usCounties.features)
.enter()
.append("path")
.style("fill", function(d){
target = educationData.filter(function (object) {
return object.fips == d.id;
});
if (target.length >0)
{
//We use a built in D3 color scale to provide shading
return (d3.interpolateRdYlBu(1-(target[0].bachelorsOrHigher / Math.round(maxEducation))));
}
else
{
return "beige"
}
})
.style("stroke", "grey")
.style("stroke-width", "0.5px")
.attr("class", "county")
.attr("data-fips", (d) => d.id)
.attr("data-education", function(d){
target = educationData.filter(function (object) {
return object.fips == d.id;
});
if (target.length >0)
{
return target[0].bachelorsOrHigher;
}
})
.attr("d", path)
.on("mouseover", function(d,i) {
d3.select(this)
.style("stroke", "black")
.style("stroke-width", 0.9);
target = educationFilter(educationData, d.id);
toolTips.html(target[0].area_name + ", " + target[0].state + "<br/>" + target[0].bachelorsOrHigher + "%")
.attr("data-education",target[0].bachelorsOrHigher)
.style("left", (d3.event.pageX + 15) + "px")
.style("top", (d3.event.pageY - 50) + "px")
.style("background", d3.interpolateRdYlBu(1-(target[0].bachelorsOrHigher / Math.round(maxEducation))))
.style("opacity", 0.9); //Reveal on mouseover
})
.on("mouseout", function(d,i) {
d3.select(this)
.style("stroke", "grey")
.style("stroke-width", 0.5);
toolTips.style("opacity", 0); //Hide until mouseover
});
// Draw States Map Overlay
svg.append("path")
.datum(usStates)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-linejoin", "round")
.attr("class", "states")
.attr("d", path);
//Setup legend gradient
var defs = svg.append("defs");
var numStops = 2;
var numBlocks = 10;
var gradient=[];
for (var n = 0; n< numBlocks; ++n)
{
gradient[n] = defs.append("linearGradient")
.attr("id", "svgGradient"+n)
.attr("x1", "0%")
.attr("x2", "100%")
.selectAll("stop")
.data(d3.range(numStops))
.enter().append("stop")
.attr("offset", (d) => d/numStops)
.attr("stop-color", function(d,i) {
return d3.interpolateRdYlBu(1-(d+n)*0.1);
console.log(1-(d+n)*0.1);
});
}
//Add SVG Legend
var legend = svg.append("g")
.attr("class", "legend")
.attr("id", "legend");
//Add colored rectangles to legend
var legendSize = 20;
var legendLength = 10;
var stopOffset="";
for (var k = 0; k <numBlocks ; ++k)
{
legend.append("rect")
.style("stroke", "black")
.style("stroke-width", 1.5)
.attr("x", 0.1 * fullwidth+k*(legendSize*2+1))
.attr("y", fullheight - padding)
.attr("width", (legendSize*3+1))
.attr("height", legendSize/2)
.style("fill", "url(#svgGradient" + k +")");
}
//Add text to legend
for (var j=0; j<= legendLength; ++j)
{
legend.append("text")
.attr("x", 0.1 * fullwidth +j*(legendSize*2+1))
.attr("y", fullheight - padding - legendSize*0.5)
.text(Math.round((minEducation+(j*stepVariance)) * 100) / 100);
}
});
//Function for retrieving education info by ID
function educationFilter(educationData, targetID)
{
var target = educationData.filter(function (object) {
return object.fips == targetID;
});
return target.slice();
}
<script src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/topojson@3"></script>
body {
margin-top: 50px;
font: 10px sans-serif;
background : LightGray;
}
.infoGraphic{
background : white;
padding: 10px;
box-shadow: 10px 10px;
}
#tooltip{
text-align: center;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment