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
				 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