Graphs and tables for your Spotify account.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
3.9 KiB

  1. function create_genre_graph(data) {
  2. // convert strings to nums {{{ //
  3. data.forEach(function(d) {
  4. d.num_songs = +d.num_songs;
  5. console.log(d.genre, d.num_songs);
  6. var artist_names = Object.keys(d.artists);
  7. artist_names.forEach(function(e) {
  8. d.artists[e] = +d.artists[e];
  9. console.log(e, d.artists[e]);
  10. //console.log(e, d.artists[e], d.artists[e] + 1);
  11. });
  12. });
  13. // }}} convert strings to nums //
  14. // domains {{{ //
  15. data.sort(function(a, b) {
  16. return b.num_songs - a.num_songs;
  17. });
  18. x.domain(data.map(function(d) {
  19. return d.genre;
  20. }));
  21. //y.domain([0, d3.max(data, function(d) { return d.num_songs; }) * 1.25]).nice();
  22. y.domain([0, d3.max(data, function(d) {
  23. return d.num_songs;
  24. })]).nice();
  25. // }}} domains //
  26. // setup bar colors {{{ //
  27. var max_artists = d3.max(data, function(d) {
  28. return Object.keys(d.artists).length;
  29. });
  30. var z = d3.scaleOrdinal().range(randomColor({
  31. count: max_artists,
  32. luminosity: 'light',
  33. }));
  34. // }}} setup bar colors //
  35. for (var genre_dict of data) {
  36. // process artist breakdown {{{ //
  37. var keys = Object.keys(genre_dict.artists);
  38. var stack = d3.stack()
  39. //.order(d3.stackOrderAscending)
  40. .order(d3.stackOrderDescending)
  41. .keys(keys)([genre_dict.artists])
  42. //unpack the column
  43. .map((d, i) => {
  44. return {
  45. key: keys[i],
  46. data: d[0]
  47. }
  48. });
  49. // }}} process artist breakdown //
  50. // add bars {{{ //
  51. g.append("g")
  52. .selectAll("rect")
  53. .data(stack)
  54. .enter().append("rect")
  55. .attr("x", x(genre_dict.genre))
  56. .attr("y", function(d) {
  57. return y(d.data[1]);
  58. })
  59. .attr("height", d => y(d.data[0]) - y(d.data[1]))
  60. .attr("width", x.bandwidth())
  61. .attr('fill', (d, i) => z(i))
  62. .append('title').text(d => d.key + ': ' + (d.data[1] - d.data[0]));
  63. // }}} add bars //
  64. // x-axis {{{ //
  65. g.append("g")
  66. .attr("class", "axis")
  67. .attr("transform", "translate(0," + height + ")")
  68. .call(d3.axisBottom(x))
  69. .selectAll(".tick text")
  70. .call(wrap, x.bandwidth());
  71. // }}} x-axis //
  72. // y-axis {{{ //
  73. g.append("g")
  74. .attr("class", "axis")
  75. .call(d3.axisLeft(y).ticks(null, "s"))
  76. .append("text")
  77. .attr("x", 2)
  78. .attr("y", y(y.ticks().pop()) + 0.5)
  79. .attr("dy", "0.32em")
  80. .attr("fill", "#000")
  81. .attr("font-weight", "bold")
  82. .attr("text-anchor", "start")
  83. .text("Songs");
  84. // }}} y-axis //
  85. }
  86. }
  87. // wrap text {{{ //
  88. // https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07#file-index-html
  89. function wrap(text, width) {
  90. text.each(function() {
  91. var text = d3.select(this),
  92. words = text.text().split(/\s+/).reverse(),
  93. word,
  94. line = [],
  95. lineNumber = 0,
  96. lineHeight = 1.1, // ems
  97. y = text.attr("y"),
  98. dy = parseFloat(text.attr("dy")),
  99. tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em")
  100. while (word = words.pop()) {
  101. line.push(word)
  102. tspan.text(line.join(" "))
  103. if (tspan.node().getComputedTextLength() > width) {
  104. line.pop()
  105. tspan.text(line.join(" "))
  106. line = [word]
  107. tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(word)
  108. }
  109. }
  110. })
  111. }
  112. // }}} wrap text //