Created
April 23, 2016 06:31
-
-
Save JaimeStill/ff35ba291366c51684d1e0b7e9376614 to your computer and use it in GitHub Desktop.
D3 Maps Notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
var createBoundingMap = function () { | |
var height = 600, | |
width = 900; | |
var projection = d3.geo.mercator(); | |
var mexico = void 0; | |
var path = d3.geo.path().projection(projection); | |
var svg = d3.select('#bounding-map') | |
.append('svg') | |
.attr({ | |
'width': width, | |
'height': height, | |
'overflow': 'hidden' | |
}); | |
d3.json('geo-data.json', function (data) { | |
var states = topojson.feature(data, data.objects.MEX_adm1); | |
projection.scale(1).translate([0, 0]); | |
var b = path.bounds(states.features[5]); | |
var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; | |
projection.scale(s).translate(t); | |
var map = svg.append('g') | |
.attr('class', 'boundary'); | |
mexico = map.selectAll('path') | |
.data(states.features); | |
// Enter | |
mexico.enter() | |
.append('path') | |
.attr('d', path); | |
}); | |
}; | |
var createChoroplethMap = function () { | |
var height = 600, | |
width = 900; | |
var projection = d3.geo.mercator(); | |
var mexico = void 0; | |
var path = d3.geo.path().projection(projection); | |
var svg = d3.select('#choropleth-map') | |
.append('svg') | |
.attr({ | |
'width': width, | |
'height': height, | |
'overflow': 'hidden' | |
}); | |
d3.json('geo-data.json', function (data) { | |
var states = topojson.feature(data, data.objects.MEX_adm1); | |
projection.scale(1).translate([0, 0]); | |
var b = path.bounds(states); | |
var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; | |
projection.scale(s).translate(t); | |
var map = svg.append('g') | |
.attr('class', 'boundary'); | |
mexico = map.selectAll('path') | |
.data(states.features); | |
// Enter | |
mexico.enter() | |
.append('path') | |
.attr('d', path); | |
// Update | |
var color = d3.scale.linear().domain([0, 33]).range(['red', 'yellow']); | |
mexico.attr({ | |
'fill': function (d, i) { return color(i); }, | |
'stroke': '#333', | |
'stroke-width': 1 | |
}); | |
}); | |
}; | |
var createClickableMap = function () { | |
var height = 600, | |
width = 900; | |
var projection = d3.geo.mercator(); | |
var mexico = void 0; | |
var geoId = function (d) { | |
return "c" + d.properties.ID_1; | |
}; | |
var click = function (d) { | |
mexico.attr('fill-opacity', 0.2); | |
d3.select('#' + geoId(d)) | |
.attr('fill-opacity', 1); | |
} | |
var path = d3.geo.path().projection(projection); | |
var svg = d3.select('#clickable-map') | |
.append('svg') | |
.attr({ | |
'width': width, | |
'height': height, | |
'overflow': 'hidden' | |
}); | |
d3.json('geo-data.json', function (data) { | |
var states = topojson.feature(data, data.objects.MEX_adm1); | |
projection.scale(1).translate([0, 0]); | |
var b = path.bounds(states); | |
var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; | |
projection.scale(s).translate(t); | |
var map = svg.append('g') | |
.attr('class', 'boundary'); | |
mexico = map.selectAll('path') | |
.data(states.features); | |
// Enter | |
mexico.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'id': geoId | |
}) | |
.on('click', click); | |
// Update | |
var color = d3.scale.linear().domain([0, 33]).range(['red', 'yellow']); | |
mexico.attr({ | |
'fill': function (d, i) { return color(i); }, | |
'stroke': '#333', | |
'stroke-width': 1 | |
}); | |
}); | |
} | |
var createTransitionMap = function () { | |
var height = 600, | |
width = 900; | |
var projection = d3.geo.mercator(); | |
var mexico = void 0; | |
var path = d3.geo.path().projection(projection); | |
var svg = d3.select('#transition-map') | |
.append('svg') | |
.attr({ | |
'width': width, | |
'height': height, | |
'overflow': 'hidden' | |
}); | |
d3.json('geo-data.json', function (data) { | |
var states = topojson.feature(data, data.objects.MEX_adm1); | |
projection.scale(1).translate([0, 0]); | |
var b = path.bounds(states); | |
var s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height); | |
var t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2]; | |
projection.scale(s).translate(t); | |
var map = svg.append('g') | |
.attr('class', 'boundary'); | |
mexico = map.selectAll('path') | |
.data(states.features); | |
// Enter | |
mexico.enter() | |
.append('path') | |
.attr('d', path); | |
// Update | |
var color = d3.scale.linear().domain([0, 33]).range(['red', 'yellow']); | |
mexico.attr({ | |
'fill': function (d, i) { return color(i); }, | |
'stroke': '#333', | |
'stroke-width': 1 | |
}); | |
setInterval(function () { | |
mexico.transition().duration(500) | |
.style('fill', function (d) { | |
return color(Math.floor((Math.random() * 32) + 1)); | |
}); | |
}, 2000); | |
}); | |
}; | |
createBoundingMap(); | |
createChoroplethMap(); | |
createClickableMap(); | |
createTransitionMap(); | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Experiments</title> | |
<meta charset="utf-8" /> | |
<link href="site.css" rel="stylesheet" /> | |
</head> | |
<body> | |
<h2>Experiment 1 - Adjusting the Bounding Box</h2> | |
<div id="bounding-map"></div> | |
<p> | |
For this experiment, we manually zoom in to a state of Mexico using the bounding box. rather than initializing the bounds | |
based on all of the features in the states data, we want to initialize it based ont he sixth element of the features array | |
contained in the states object. | |
</p> | |
<div class="code-container"> | |
<pre>var b = path.bounds(states.features[5]);</pre> | |
</div> | |
<p> | |
This basically reduces the min / max of the boundary box to include the geographic coordinates for one state in mexico, and | |
D3 scales and translates this information automatically based on the scale and translation algorithms used. This can be useful | |
in situations where you might not have the data you need in isolation from the surrounding areas. | |
</p> | |
<h2>Experiment 2 - Creating Choropleths</h2> | |
<div id="choropleth-map"></div> | |
<p> | |
One of the most common uses of D3.js maps is to make choropleths. This visualization gives you the ability to discern between regions, | |
giving them a different color. Normally, this color is associated with some other value, for instance, levels of influenza or a company's | |
sales. | |
</p> | |
<p> | |
The <span class="snippet">color</span> variable uses another valuable D3 function named <span class="snippet">scale</span>. This | |
<span class="snippet">color</span> function looks for any number between 0 and 33 in an input domain. D3 linearly maps these input | |
values to a color between red and yellow in the output range. D3 has included the capability to automatically map colors in a linear | |
range to a gradient. This means that executing the new function, <span class="snippet">color</span>, with 0 will return the color | |
red, <span class="snippet">color(15)</span> will return an orange color, and <span class="snippet">color(33)</span> will return yellow. | |
</p> | |
<p> | |
In the update section, we set the fill property of the path to the new color function. This will provide a linear scale of colors and use the | |
index value <span class="snippet">i</span> to determine what color should be returned. If the color was determined by a different value of the | |
datum, for instance, <span class="snippet">d.sales</span>, then you would have a choropleth where the colors actually represent sales. | |
</p> | |
<div class="code-container"> | |
<pre>var color = d3.scale.linear() | |
.domain([0, 33]) | |
.range(['red', 'yellow']); | |
mexico.attr('fill', function (d, i) { return color(i); });</pre> | |
</div> | |
<h2>Experiment 3 - Adding Click Events</h2> | |
<div id="clickable-map"></div> | |
<p> | |
We need a quick reference to each state in the country. To accomplish this, we will create a new function called <span class="snippet">geoId</span> | |
irght below the <span class="snippet">mexico</span> variable. | |
</p> | |
<div class="code-container"> | |
<pre>var geoId = function (d) { | |
return "c" + d.properties.ID_1; | |
}</pre> | |
</div> | |
<p> | |
This function takes in a <span class="snippet">state</span> data element and generates a new selectable ID based on the <span class="snippet">ID_1</span> | |
property found in the data. The <span class="snippet">ID_1</span> property contains a unique numeric value for every state in the array. If we insert | |
this as an <span class="snippet">id</span> attribute into the DOM, then we would create a quick and easy way to select each state in the country. | |
</p> | |
<p> | |
Next, we need to defne a click function that makes it easy to separate what the click is doing. The <span class="snippet">click</span> method receives | |
the datum and changes the fill opacity value of all the states to 0.2. This is done so that when you click on one state and then on the other, the previous | |
state does not maintain the <em>clicked</em> state. Notice that the function call is iterating through all the elements of the DOM, using the D3 update pattern. | |
After making all the states transparent, we will set a fill-opacity of 1 for the given clicked item. This removes all transparent styling from the selected | |
state. | |
</p> | |
<div class="code-container"> | |
<pre>var click = function (d) { | |
mexico.attr('fill-opacity', 0.2); | |
d3.select('#' + geoId(d)).attr('fill-opacity', 1); | |
}</pre> | |
</div> | |
<p> | |
All that's left is to bind the click event to the click function that we created by updating the <span class="snippet">enter</span> function: | |
</p> | |
<div class="code-container"> | |
<pre>mexico.enter() | |
.append('path') | |
.attr({ | |
'd': path, | |
'id': geoId | |
}) | |
.on('click', click);</pre> | |
</div> | |
<h2>Experiment 4 - Using Updates and Transitions</h2> | |
<div id="transition-map"></div> | |
<p> | |
We will assign a random number between 1 and 32 to the existing <span class="snippet">color</span> function. Then, leverage a D3 method to | |
smoothly transition between the random color changes. Every 2 seconds, the <span class="snippet">mexico</span> update section should be | |
executed and the color set to a random number between 1 and 32. The new transition and duration methods transition from the previous | |
state to the new state over 500 milliseconds (half a second). | |
</p> | |
<div class="code-container"> | |
<pre>setInterval(function () { | |
mexico.transition().duration(500) | |
.style('fill', function (d) { | |
return color(Math.floor((Math.random() * 32) + 1)); | |
}); | |
}, 2000);</pre> | |
</div> | |
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script src="https://d3js.org/topojson.v1.js" type="text/javascript"></script> | |
<script src="experiments.js" type="text/javascript"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font-family: 'Segoe UI', sans-serif; | |
padding-left: 1em; | |
} | |
p, li { | |
max-width: 60em; | |
} | |
pre { | |
color: limegreen; | |
font-weight: bold; | |
font-family: Consolas, monospace; | |
margin: 0; | |
padding: 0; | |
display: inline-block; | |
} | |
.code-container { | |
padding: .5em; | |
background-color: #eee; | |
color: springgreen; | |
display: inline-block; | |
word-wrap: break-word; | |
} | |
.code-block { | |
display: block; | |
} | |
span.snippet{ | |
color: limegreen; | |
font-weight: bold; | |
font-family: Consolas, monospace; | |
margin: 0; | |
padding: 0; | |
} | |
.inline-element { | |
display: inline-block; | |
margin-right: 1em; | |
margin-bottom: 1em; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment