Browse Source
Moved script to create genre graph to static file
Moved script to create genre graph to static file
- sorted artists in bar by most to least, bottom to top - wrap x-axis labels by bar width - increased track name length (program crashed on a track name)master
Kevin Mok
7 years ago
5 changed files with 145 additions and 78 deletions
-
2spotifyvis/models.py
-
137spotifyvis/static/spotifyvis/scripts/genre_graph.js
-
80spotifyvis/templates/spotifyvis/test_db.html
-
2spotifyvis/utils.py
-
2spotifyvis/views.py
@ -0,0 +1,137 @@ |
|||||
|
function create_genre_graph(data) { |
||||
|
// convert strings to nums {{{ //
|
||||
|
|
||||
|
data.forEach(function(d) { |
||||
|
d.num_songs = +d.num_songs; |
||||
|
console.log(d.genre, d.num_songs); |
||||
|
var artist_names = Object.keys(d.artists); |
||||
|
artist_names.forEach(function(e) { |
||||
|
d.artists[e] = +d.artists[e]; |
||||
|
console.log(e, d.artists[e]); |
||||
|
//console.log(e, d.artists[e], d.artists[e] + 1);
|
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
// }}} convert strings to nums //
|
||||
|
|
||||
|
// domains {{{ //
|
||||
|
|
||||
|
data.sort(function(a, b) { |
||||
|
return b.num_songs - a.num_songs; |
||||
|
}); |
||||
|
x.domain(data.map(function(d) { |
||||
|
return d.genre; |
||||
|
})); |
||||
|
//y.domain([0, d3.max(data, function(d) { return d.num_songs; }) * 1.25]).nice();
|
||||
|
y.domain([0, d3.max(data, function(d) { |
||||
|
return d.num_songs; |
||||
|
})]).nice(); |
||||
|
|
||||
|
// }}} domains //
|
||||
|
|
||||
|
// setup bar colors {{{ //
|
||||
|
|
||||
|
var max_artists = d3.max(data, function(d) { |
||||
|
return Object.keys(d.artists).length; |
||||
|
}); |
||||
|
var z = d3.scaleOrdinal().range(randomColor({ |
||||
|
count: max_artists, |
||||
|
luminosity: 'light', |
||||
|
})); |
||||
|
|
||||
|
// }}} setup bar colors //
|
||||
|
|
||||
|
for (var genre_dict of data) { |
||||
|
|
||||
|
// process artist breakdown {{{ //
|
||||
|
|
||||
|
var keys = Object.keys(genre_dict.artists); |
||||
|
var stack = d3.stack() |
||||
|
//.order(d3.stackOrderAscending)
|
||||
|
.order(d3.stackOrderDescending) |
||||
|
.keys(keys)([genre_dict.artists]) |
||||
|
//unpack the column
|
||||
|
.map((d, i) => { |
||||
|
return { |
||||
|
key: keys[i], |
||||
|
data: d[0] |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// }}} process artist breakdown //
|
||||
|
|
||||
|
// add bars {{{ //
|
||||
|
|
||||
|
g.append("g") |
||||
|
.selectAll("rect") |
||||
|
.data(stack) |
||||
|
.enter().append("rect") |
||||
|
.attr("x", x(genre_dict.genre)) |
||||
|
.attr("y", function(d) { |
||||
|
return y(d.data[1]); |
||||
|
}) |
||||
|
.attr("height", d => y(d.data[0]) - y(d.data[1])) |
||||
|
.attr("width", x.bandwidth()) |
||||
|
.attr('fill', (d, i) => z(i)) |
||||
|
.append('title').text(d => d.key + ': ' + (d.data[1] - d.data[0])); |
||||
|
|
||||
|
// }}} add bars //
|
||||
|
|
||||
|
// x-axis {{{ //
|
||||
|
|
||||
|
g.append("g") |
||||
|
.attr("class", "axis") |
||||
|
.attr("transform", "translate(0," + height + ")") |
||||
|
.call(d3.axisBottom(x)) |
||||
|
.selectAll(".tick text") |
||||
|
.call(wrap, x.bandwidth()); |
||||
|
|
||||
|
// }}} x-axis //
|
||||
|
|
||||
|
// y-axis {{{ //
|
||||
|
|
||||
|
g.append("g") |
||||
|
.attr("class", "axis") |
||||
|
.call(d3.axisLeft(y).ticks(null, "s")) |
||||
|
.append("text") |
||||
|
.attr("x", 2) |
||||
|
.attr("y", y(y.ticks().pop()) + 0.5) |
||||
|
.attr("dy", "0.32em") |
||||
|
.attr("fill", "#000") |
||||
|
.attr("font-weight", "bold") |
||||
|
.attr("text-anchor", "start") |
||||
|
.text("Songs"); |
||||
|
|
||||
|
// }}} y-axis //
|
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// wrap text {{{ //
|
||||
|
|
||||
|
// https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07#file-index-html
|
||||
|
function wrap(text, width) { |
||||
|
text.each(function() { |
||||
|
var text = d3.select(this), |
||||
|
words = text.text().split(/\s+/).reverse(), |
||||
|
word, |
||||
|
line = [], |
||||
|
lineNumber = 0, |
||||
|
lineHeight = 1.1, // ems
|
||||
|
y = text.attr("y"), |
||||
|
dy = parseFloat(text.attr("dy")), |
||||
|
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em") |
||||
|
while (word = words.pop()) { |
||||
|
line.push(word) |
||||
|
tspan.text(line.join(" ")) |
||||
|
if (tspan.node().getComputedTextLength() > width) { |
||||
|
line.pop() |
||||
|
tspan.text(line.join(" ")) |
||||
|
line = [word] |
||||
|
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(word) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// }}} wrap text //
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue