This is a table that responds dynamically to given events such as hovering and clicking. The data used is downloaded from http://www.bls.gov/web/laus/laumstrk.htm. This piece of code was completed as part of doing CS171 Visualisation course online (http://www.cs171.org/#!index.md).
Last active
May 2, 2019 08:12
-
-
Save crevoisiersabine/34cef262b6632d82e4a6 to your computer and use it in GitHub Desktop.
Dynamic Table (part of CS171 Harvard Visualisation assignment)
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> | |
<style> | |
table { | |
/*To avoid spaces between the cells*/ | |
border-collapse: collapse; | |
/*To center it*/ | |
margin-left:auto; | |
margin-right:auto; | |
} | |
td, th, caption { | |
/*To add solid lines in the cells*/ | |
border: solid 1px black; | |
/*To add spacing between the text in the cells and the borders*/ | |
padding: 10px; | |
text-align: center; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
//Define click counter | |
var click = 1; | |
// Add a hard coded headline, dynamically with D3 (from http://www.bls.gov/web/laus/laumstrk.htm) | |
var H1 = d3.select("body").append("h1").text("Unemployment Rates for States"); | |
// Center header | |
H1.style({"text-align": "center"}); | |
// This piece of code prints the output of d3.text to the console to check what it looks like | |
// d3.text("unemp_states_us_nov_2013.tsv", function(error, data) { | |
// console.log(d3.tsv.parseRows(data)); | |
// }); | |
// d3.text reads the url file and returns a text file that can then be parsed as a tsv file | |
// We cannot use d3.tsv straight away as this skips the header line which we want to visualise | |
d3.text("unemp_states_us_nov_2013.tsv", function(error, data){ | |
// Creates the DOM elements table, tbody and thead | |
var TABLE = d3.select("body").append("table"), | |
caption = TABLE.append("caption"), | |
thead = TABLE.append("thead") | |
tbody = TABLE.append("tbody"); | |
// Another way to add the caption without using the caption tag | |
// var caption = d3.select("thead").append("tr").append("th").attr("colspan", "3"); | |
// Add a hard coded caption, dynamically with D3 (from http://www.bls.gov/web/laus/laumstrk.html | |
caption.html("<b>Unemployment Rates for States<br>Monthly Rankings<br>Seasonally Adjusted<br>Apr. 2014<sup>p</sup></b>"); | |
var parsedData = d3.tsv.parseRows(data); | |
// .shift() removes the first element of the array parsedData and modifies the array. | |
// It returns this element and I store it into the variable called header | |
var header = parsedData.shift(); | |
// Create the rows to the table based on the number of entries in the parsedData array | |
var rows = tbody.selectAll("tr") | |
.data(parsedData, String) | |
.enter() | |
.append("tr") | |
.on("mouseover", function mouseOver(d, i){ | |
d3.select(this).style({"background-color": "yellow"}); | |
}) | |
.on("mouseout", mouseOut); | |
// Append a child row element "tr" to <thead> where to put the header | |
var rowsH = thead.append("tr"); | |
// Create the cells with <td> for each element of the array of array parsedData | |
var cells = rows.selectAll("td") | |
.data(function(c, i) { | |
return parsedData[i]; | |
}) | |
.enter() | |
.append("td") | |
.text(function(d) { return d; }) | |
// Adding a class element corresponding to the array position for column highlight on mouseover | |
.attr('class', function(d, i){ return "col_" + i; }); | |
// Creates the header cell | |
var cellsH = rowsH.selectAll("th") | |
.data(header) | |
.enter() | |
.append("th") | |
.text(function(d) { return d; }) | |
.attr('class', function(d, i){ return "colH_" + i; }); | |
//The code below creates the header rows without requiring <thead> | |
// var headerCell = rows.select("th") | |
// .data(header) | |
// .enter() | |
// .insert("th", ":first-child") | |
// .order() | |
// .text(function(d) { return d; }); | |
// Make the table zebra coloured | |
tbody.selectAll("tr").style("background-color", function(d, i){ | |
if(i%2 == 0){ | |
return "#D8D8D8"; | |
} | |
}) | |
//Dimensions for the svg where rectange of last column will fit | |
var height = 15; | |
var width = 30; | |
//Add an extra column to the table | |
rows.insert("td").attr("class", "col_3").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
.append("rect") | |
.attr("height", height) | |
.attr("width", function(d) { return parseFloat(d[0]); }); | |
//Add a header to the extra column, add a class and sorting functionality | |
rowsH.insert("th").text("Chart").attr("class", "colH_3"); | |
//Bind the width of the rect bar to the rows DOM element (?no need to do that actually as for sorting I use the value of rate instead of rectangle length...) | |
d3.selectAll("rect").each(function(d, i){ | |
rows.data()[i].push(d3.select(this).attr("width")); | |
}); | |
// Binds this last header cell to cellsH for clicking and hovering events | |
cellsH[0].push(d3.select("th.colH_3")[0][0]); | |
cellsH.on("click", toggle) | |
.on("mouseover", mouse); | |
// Add this last column to the cells to enable hovering over last column as previous ones | |
for(j = 0; j < cells.length; j++){ | |
cells[0, j].push(d3.selectAll("td.col_3")[0][j]); | |
} | |
cells.on("mouseover", function mouseOver(d, i){ | |
d3.selectAll('td.col_' + i) | |
.style('background-color', 'yellow'); | |
}) | |
.on("mouseout", function mouseOver(d, i){ | |
if (i!=2){ | |
d3.selectAll('td.col_' + i) | |
.style('background-color', null); | |
} | |
else{ | |
d3.selectAll('td.col_2').style("background-color", function(d, i){ | |
return colorScale(i); | |
}); | |
} | |
}); | |
//After mouseover, return the cells to their original colour | |
function mouseOut(d, i){ | |
// tbody.selectAll("td").style("background-color", "white"); | |
tbody.selectAll("tr").style("background-color", function(d, i){ | |
if(i%2 == 0){ | |
return "#D8D8D8"; | |
} | |
else{ | |
return "white"; | |
} | |
}) | |
} | |
//On load make the table sorted by rate in increasing order | |
tbody.selectAll("tr").sort(function(a, b) { | |
return (d3.ascending(a[2], b[2]) || d3.ascending(a[1], b[1])); | |
}); | |
function toggle(d, i){ | |
increasing(i, click); | |
if (click == 1){ | |
if(i != 0) { | |
d3.select(".colH_" + i).style("cursor", "s-resize"); | |
} | |
} | |
else{ | |
if(i != 0) { | |
d3.select(".colH_" + i).style("cursor", "n-resize"); | |
} | |
} | |
click*=(-1); | |
} | |
function increasing(i, click){ | |
if (i == 1){ | |
tbody.selectAll("tr").sort(function(a, b) { | |
return click*d3.ascending(a[i], b[i]); | |
}); | |
} | |
else if (i == 2){ | |
tbody.selectAll("tr").sort(function(a, b) { | |
//The statement below will only evaluate the statement after the or is the first statement returns 0 (ie. a tie) | |
return click*(d3.ascending(a[i], b[i]) || d3.ascending(a[i-1], b[i-1])); | |
}); | |
} | |
else if (i == 3){ | |
tbody.selectAll("tr").sort(function(a, b) { | |
return click*d3.ascending(a[i-1], b[i-1]); | |
}); | |
} | |
} | |
//This function causes the cursor to change on hover as per the assignment, however I prefer that the cursor changes upon click, without requiring to hover out of the cell and back in to see the change. Therefore the code is copied into the on.click function. However this is kept because it is nice to get the cursor to change on the first instance prior to any click. | |
function mouse(d, i){ | |
if(click == 1){ | |
if(i != 0) { | |
d3.select(".colH_" + i).style("cursor", "s-resize"); | |
} | |
} | |
else{ | |
if(i != 0) { | |
d3.select(".colH_" + i).style("cursor", "n-resize"); | |
} | |
} | |
} | |
// Visually encode the table as per rate value | |
d3.selectAll('td.col_2').style("background-color", function(d, i){ | |
return colorScale(i); | |
}); | |
function colorScale(i){ | |
var color = d3.scale.linear() | |
.domain([0, tbody.selectAll("tr")[0].length-1]) | |
.interpolate(d3.interpolateRgb) | |
.range(["orangered", "silver"]); | |
return color(i); | |
} | |
}); | |
</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
Rank | State | Rate | |
---|---|---|---|
1 | NORTH DAKOTA | 2.6 | |
2 | SOUTH DAKOTA | 3.6 | |
3 | NEBRASKA | 3.7 | |
4 | UTAH | 4.3 | |
5 | HAWAII | 4.4 | |
5 | IOWA | 4.4 | |
5 | VERMONT | 4.4 | |
5 | WYOMING | 4.4 | |
9 | MINNESOTA | 4.6 | |
10 | KANSAS | 5.1 | |
10 | NEW HAMPSHIRE | 5.1 | |
12 | MONTANA | 5.2 | |
13 | OKLAHOMA | 5.4 | |
13 | VIRGINIA | 5.4 | |
15 | IDAHO | 6.1 | |
15 | MISSOURI | 6.1 | |
15 | TEXAS | 6.1 | |
15 | WEST VIRGINIA | 6.1 | |
19 | ALABAMA | 6.2 | |
20 | LOUISIANA | 6.3 | |
20 | WISCONSIN | 6.3 | |
22 | FLORIDA | 6.4 | |
22 | MAINE | 6.4 | |
22 | MARYLAND | 6.4 | |
22 | NEW MEXICO | 6.4 | |
26 | ALASKA | 6.5 | |
26 | COLORADO | 6.5 | |
26 | DELAWARE | 6.5 | |
29 | WASHINGTON | 6.8 | |
30 | MASSACHUSETTS | 7.1 | |
30 | SOUTH CAROLINA | 7.1 | |
32 | INDIANA | 7.3 | |
32 | OREGON | 7.3 | |
32 | PENNSYLVANIA | 7.3 | |
35 | NEW YORK | 7.4 | |
35 | NORTH CAROLINA | 7.4 | |
35 | OHIO | 7.4 | |
38 | ARKANSAS | 7.5 | |
39 | CONNECTICUT | 7.6 | |
40 | GEORGIA | 7.7 | |
41 | ARIZONA | 7.8 | |
41 | NEW JERSEY | 7.8 | |
43 | TENNESSEE | 8.1 | |
44 | KENTUCKY | 8.2 | |
45 | MISSISSIPPI | 8.3 | |
46 | CALIFORNIA | 8.5 | |
47 | DISTRICT OF COLUMBIA | 8.6 | |
48 | ILLINOIS | 8.7 | |
49 | MICHIGAN | 8.8 | |
50 | NEVADA | 9.0 | |
50 | RHODE ISLAND | 9.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment