Skip to content

Instantly share code, notes, and snippets.

@jwilber
Last active October 9, 2018 00:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwilber/219e9d40802c2a33a71958a5d6ab07b7 to your computer and use it in GitHub Desktop.
Save jwilber/219e9d40802c2a33a71958a5d6ab07b7 to your computer and use it in GitHub Desktop.
d3 flexbox table
license: mit

Flexbox table of most popular artist by genre (in skate videos). Click to a column to sort by it.

.table {
display: flex;
flex-flow: column nowrap;
flex: 1 1 auto;
font-size: .9rem;
margin: 0 -5px;
line-height: .5;
width: 50%;
font-family: Gill Sans;
font-weight: 10%;
}
.th {
display: none;
font-weight: bold;
/*background-color: #f2f2f2;*/
border-bottom: 1px solid #d0d0d0;
color: #74a9cf;
}
.th > .td {
white-space: normal;
justify-content: center;
}
.tr {
width: 100%;
display: flex;
flex-flow: row nowrap;
/*border-bottom: .5px solid #d0d0d0;*/
}
/*
.tr:nth-of-type(even) {
background-color: #e8eff9;
}
.tr:nth-of-type(odd) {
background-color: #ffffff;
}*/
.td {
display: flex;
flex-flow: row nowrap;
flex-grow: 1;
flex-basis: 0;
padding: 0.3em;
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0px;
white-space: nowrap;
margin: 0 5px;
}
/* Non-table styling */
.title {
font-weight: bold;
font-size: 200%;
margin-bottom: 14px;
vertical-align: top;
font-family: Gill Sans;
color: #2b8cbe;
/*margin-left: 200px;*/
}
.SearchBar {
font-weight: bold;
font-size: 90%;
margin-bottom: 10px;
font-family: Gill Sans;
color: #2b8cbe;
}
[{"genre2":"Indie Rock","artist":"Joy Division","art_count":32,"percent":0.1609},{"genre2":"Western Hip-Hop/Rap","artist":"Gang Starr","art_count":34,"percent":0.1579},{"genre2":"Punk","artist":"Bad Brains","art_count":19,"percent":0.0629},{"genre2":"70's Rock","artist":"Pink Floyd","art_count":40,"percent":0.0529},{"genre2":"Metal","artist":"Black Sabbath","art_count":47,"percent":0.0432},{"genre2":"Alternative","artist":"The Cure","art_count":15,"percent":0.0423},{"genre2":"60's Rock","artist":"The Beatles","art_count":54,"percent":0.0411},{"genre2":"Mainstream Rock","artist":"The Rolling Stones","art_count":40,"percent":0.0372},{"genre2":"Classic R&B/Soul","artist":"Curtis Mayfield","art_count":25,"percent":0.0349},{"genre2":"Western Pop","artist":"John Lennon","art_count":14,"percent":0.0325},{"genre2":"Downtempo, Lounge & Ambient","artist":"Tommy Guerrero","art_count":19,"percent":0.0226},{"genre2":"Electronica Mainstream","artist":"Moby","art_count":15,"percent":0.0178},{"genre2":"Hard Rock","artist":"David Bowie","art_count":40,"percent":0.0166},{"genre2":"Emo & Hardcore","artist":"Fugazi","art_count":45,"percent":0.0135},{"genre2":"Original Film/TV Music","artist":"Ennio Morricone","art_count":9,"percent":0.0124},{"genre2":"Contemporary R&B/Soul","artist":"Michael Jackson","art_count":9,"percent":0.0122},{"genre2":"Reggae","artist":"Bob Marley","art_count":14,"percent":0.0121},{"genre2":"Garage Rock Revival","artist":"The Greenhornes","art_count":8,"percent":0.0097},{"genre2":"Synth Pop","artist":"New Order","art_count":22,"percent":0.0085},{"genre2":"Alternative Folk","artist":"Devendra Banhart","art_count":12,"percent":0.0085},{"genre2":"Techno","artist":"Squarepusher","art_count":8,"percent":0.0085},{"genre2":"New Wave Pop","artist":"Devo","art_count":32,"percent":0.0078},{"genre2":"House","artist":"Justice","art_count":11,"percent":0.0075},{"genre2":"Bebop & Modern Jazz","artist":"John Coltrane","art_count":4,"percent":0.0074},{"genre2":"Folk","artist":"Donovan","art_count":14,"percent":0.007},{"genre2":"New Wave Rock","artist":"The Velvet Underground","art_count":16,"percent":0.0064},{"genre2":"Dance & Club","artist":"DJ Egadz","art_count":6,"percent":0.0064},{"genre2":"Country","artist":"The Sadies","art_count":4,"percent":0.0064},{"genre2":"Contemporary Jazz & Fusion","artist":"Shawn Lee's Ping Pong Orchestra","art_count":10,"percent":0.006},{"genre2":"Data & Other","artist":"Blvck Ceiling","art_count":5,"percent":0.006},{"genre2":"Folk Rock","artist":"Bob Dylan","art_count":26,"percent":0.0059},{"genre2":"European Pop","artist":"Edith Piaf","art_count":3,"percent":0.0054},{"genre2":"Alternative Roots","artist":"Radical Face","art_count":7,"percent":0.0047},{"genre2":"Brit Rock","artist":"Placebo","art_count":9,"percent":0.0045},{"genre2":"Electric Blues","artist":"Gibb Droll","art_count":3,"percent":0.0044},{"genre2":"Adult Alternative Rock","artist":"Ben Harper","art_count":9,"percent":0.0041},{"genre2":"Electronica Fusion","artist":"Bonobo","art_count":13,"percent":0.004},{"genre2":"Trance","artist":"Gorgeous","art_count":2,"percent":0.004},{"genre2":"Other Classical","artist":"Adeodat Warfield","art_count":2,"percent":0.0039},{"genre2":"Jam Bands","artist":"Sol","art_count":22,"percent":0.0037},{"genre2":"50's Rock","artist":"Elvis Presley","art_count":8,"percent":0.003},{"genre2":"Ska Revival","artist":"Dance Hall Crashers","art_count":6,"percent":0.003},{"genre2":"Brit Pop","artist":"Oasis","art_count":6,"percent":0.003},{"genre2":"Brazilian","artist":"Chorão & Charlie Brown Jr.","art_count":5,"percent":0.0028},{"genre2":"Japanese Pop","artist":"Cornelius","art_count":5,"percent":0.0028},{"genre2":"New Age","artist":"18 Carat Affair","art_count":2,"percent":0.0028},{"genre2":"Jazz Vocals","artist":"Nina Simone","art_count":19,"percent":0.0027},{"genre2":"Easy Listening","artist":"Frank Sinatra","art_count":5,"percent":0.0027},{"genre2":"Disco","artist":"Cheryl Lynn","art_count":2,"percent":0.0027},{"genre2":"Classic Country","artist":"Johnny Cash","art_count":12,"percent":0.0026},{"genre2":"Power Pop","artist":"Cheap Trick","art_count":3,"percent":0.0025},{"genre2":"Spoken Word","artist":"Justin Bates","art_count":2,"percent":0.0025},{"genre2":"Latin Rock","artist":"El Guincho","art_count":3,"percent":0.0024},{"genre2":"African Pop","artist":"The Budos Band","art_count":11,"percent":0.0023},{"genre2":"Latin Traditional","artist":"Buena Vista Social Club","art_count":3,"percent":0.0023},{"genre2":"Japanese Rock","artist":"Mr. E","art_count":4,"percent":0.0022},{"genre2":"New Romantic","artist":"A Flock Of Seagulls","art_count":5,"percent":0.0021},{"genre2":"Smooth Jazz","artist":"Bob James","art_count":3,"percent":0.0019},{"genre2":"Comedy","artist":"Bobby Pickett and The Crypt","art_count":2,"percent":0.0019},{"genre2":"Goth","artist":"HIM","art_count":5,"percent":0.0016},{"genre2":"Industrial","artist":"Lard","art_count":4,"percent":0.0016},{"genre2":"Stage Musicals","artist":"Baron","art_count":4,"percent":0.0015},{"genre2":"Jungle/Drum 'n' Bass","artist":"Hive","art_count":4,"percent":0.0015},{"genre2":"Rockabilly Revival","artist":"The Cramps","art_count":7,"percent":0.0013},{"genre2":"Big Band & Swing","artist":"Enoch","art_count":4,"percent":0.0013},{"genre2":"Latin Hip-Hop/Rap","artist":"Mala Rodriguez","art_count":3,"percent":0.0013},{"genre2":"Latin Pop","artist":"Bronx River Parkway","art_count":2,"percent":0.0013},{"genre2":"Early Jazz","artist":"Louis Armstrong","art_count":4,"percent":0.0012},{"genre2":"Classic Pop Vocals","artist":"456 Productions","art_count":3,"percent":0.0012},{"genre2":"Surf Revival","artist":"Los Tiki Phantoms","art_count":2,"percent":0.0012}]
function makeTable(data, columns) {
// columns MUST be the same length as the number of features in the dataset
var searchBar = d3.select('body').append("div").attr("class", "SearchBar")
var table = d3.select('body').append('div').attr('class', 'table');
var thead = table.append('div').attr('class', 'tr th');
var tbody = table.append('div').attr('class', 'tbody');
// Save column names for column creation
var dataFeatures = d3.keys(data[0]);
// Create dictionary to track true column names for sorting later
// i.e.; {'columns[i] : dataFeatures[i]}
var colDict = {};
for (var i=0; i<columns.length; i++) {
colDict[columns[i]] = dataFeatures[i];
};
// keep track of sort ordenr
var sortAscending = true;
var barScalePercent = d3.scale.linear()
.domain([0,.20])
.range([5,100]);
var barScaleGenre = d3.scale.linear()
.domain([10,2060])
.range([5,100]);
var barScaleArtist = d3.scale.linear()
.domain([0,70])
.range([5,100]);
// append the header row
thead.selectAll('div')
.data(columns).enter()
.append('div')
.attr('class', 'td')
.attr('style', 'justify-content: left;')
.attr('featureName', function (column) { return column; })
.text(function (column) { return column; });
// create a row for each object in the data
var rows = tbody.selectAll('div')
.data(data)
.enter()
.append('div')
.attr('class', 'tr');
// create a cell in each row for each column
var cells = rows.selectAll('div')
.data(function (row) {
return dataFeatures.map(function (columnName) {
return {col: columnName, value: row[columnName]};
});
})
.enter()
.append('div')
.attr('class', 'td')
.attr('style', 'justify-content: left;')
.text(function (d) { return d.value; })
.append('svg')
.attr('height', 10)
.attr('width', 100)
.append("rect")
.attr("height", 8)
.attr('width', function(d) {
if (isNaN(d.value)) {
return 0;
} else {
if (d.col == 'percent'){
return barScalePercent(d.value);
} else if (d.col == 'art_count'){
return barScaleArtist(d.value);
} else if (d.col == 'count') {
return barScaleGenre(d.value);
} else {
return 0;
};
};
})
.attr('fill', 'coral');
// Search
searchBar.append("p")
.attr("class", "SearchBar")
.text("Search By Title:");
d3.select(".SearchBar")
.append("input")
.attr("class", "SearchBar")
.attr("id", "search")
.attr("type", "text")
.attr("placeholder", "Search...");
d3.select("#search")
.on("keyup", function() { // filter according to key pressed
var searched_data = data,
text = this.value.trim();
console.log(text);
var searchResults = searched_data.map(function(r) {
var regex = new RegExp("^" + text + ".*", "i");
if (regex.test(r.artist)) { // if there are any results
return regex.exec(r.artist)[0]; // return them to searchResults
} ;
});
// filter blank entries from searchResults
searchResults = searchResults.filter(function(r){
return r != undefined;
});
// filter dataset with searchResults
searched_data = searchResults.map(function(r) {
return data.filter(function(p) {
return p.artist.indexOf(r) != -1;
});
});
// flatten array
searched_data = [].concat.apply([], searched_data);
console.log(searched_data);
// data bind with new data
rows = rows.data(searched_data, function(d){ return d.genre2});
console.log(rows);
// enter the rows
rows.enter()
.append('div')
.attr('class', 'tr');
// enter td's in each row
var cells = rows.selectAll('div')
.data(function (row) {
return dataFeatures.map(function (columnName) {
return {col: columnName, value: row[columnName]};
});
})
.enter()
.append('div')
.attr('class', 'td')
.attr('style', 'justify-content: left;')
.text(function (d) { return d.value; })
.append('svg')
.attr('height', 10)
.attr('width', 100)
.append("rect")
.attr("height", 8)
.attr('width', function(d) {
if (isNaN(d.value)) {
return 0;
} else {
if (d.col == 'percent'){
return barScalePercent(d.value);
} else if (d.col == 'art_count'){
return barScaleArtist(d.value);
} else if (d.col == 'count') {
return barScaleGenre(d.value);
} else {
return 0;
};
};
})
.attr('fill', 'coral');
// exit
rows.exit().remove();
// })
});
// highlight rows on hover
d3.selectAll('.tbody .tr')
.on('mouseover', function() {
d3.select(this)
// .style('background-color', '#e8eff9');
.style('background-color', '#f1eef6');
})
.on('mouseout', function() {
d3.select(this)
.style('background-color', '#ffffff');
});
// Sort columns on click
d3.selectAll('.th .td')
.on("click", function() {
// Identify column header's true name
var colName = d3.select(this)[0][0]['__data__'];
var dataName = colDict[colName];
if (sortAscending) {
rows.sort(function(a, b) {
if (!isNaN(a[dataName])) { // sort numeric columns
return b[dataName] - a[dataName];
} else { // sort text columns
return d3.ascending(b[dataName], a[dataName]);
};
});
sortAscending = !sortAscending;
} else {
rows.sort(function(a, b) {
if (!isNaN(a[dataName])) { // sort numeric columns
return a[dataName] - b[dataName];
} else { // sort text columns
return d3.ascending(a[dataName], b[dataName]);
};
});
sortAscending = !sortAscending;
};
});
return table;
}
// Throw data into function and create table
d3.json('genre_table_data.json', function (error,data) {
// create table
makeTable(data, ['Genre', 'Top Artist', 'Artist Count', 'Frequency']);
});
<!DOCTYPE html>
<meta charset='utf-8'>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link rel="stylesheet" href="flx.css">
</head>
<body>
<h3 class="title"> Genre Distribution</h3>
<script type='text/javascript' src='genre_table_flex.js'></script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment