diff --git a/api/utils.py b/api/utils.py index 5da8c7e..2198ff0 100644 --- a/api/utils.py +++ b/api/utils.py @@ -186,13 +186,11 @@ def add_artist_genres(headers, artist_objs): # get_artists_in_genre {{{ # -def get_artists_in_genre(user, genre, max_songs): +def get_artists_in_genre(user, genre): """Return count of artists in genre. :user: User object to return data for. :genre: genre to count artists for. (string) - :max_songs: max total songs to include to prevent overflow due to having - multiple artists on each track. :returns: dict of artists in the genre along with the number of songs they have. @@ -204,19 +202,10 @@ def get_artists_in_genre(user, genre, max_songs): total_artist_counts = tracks_in_genre.aggregate(counts=Count('artists'))['counts'] processed_artist_counts = {} - # songs_added = 0 for artist in user_artists: - # hacky way to not have total count overflow due to there being multiple - # artists on a track - # if songs_added + artist.num_songs <= max_songs: - # processed_artist_counts[artist.name] = artist.num_songs - # songs_added += artist.num_songs processed_artist_counts[artist.name] = round(artist.track_set .filter(genre=genre_obj, users=user) .count() * track_count / total_artist_counts, 2) - # processed_artist_counts = [{'name': artist.name, 'num_songs': artist.num_songs} for artist in artist_counts] - # processed_artist_counts = {artist.name: artist.num_songs for artist in artist_counts} - # pprint.pprint(processed_artist_counts) return processed_artist_counts # }}} get_artists_in_genre # diff --git a/api/views.py b/api/views.py index 5433080..abb1a59 100644 --- a/api/views.py +++ b/api/views.py @@ -176,10 +176,30 @@ def get_genre_data(request, user_secret): genre_counts = (Track.objects.filter(users__exact=user) .values('genre') .order_by('genre') + # annotates each genre and not each Track, due to the earlier values() call .annotate(num_songs=Count('genre')) ) + # genre_counts is a QuerySet with the format + # [{'genre': 'classical', 'num_songs': 100}, {'genre': 'pop', 'num_songs': 50}...] for genre_dict in genre_counts: - genre_dict['artists'] = get_artists_in_genre(user, genre_dict['genre'], genre_dict['num_songs']) + genre_dict['artists'] = get_artists_in_genre(user, genre_dict['genre']) + ''' + Now genre_counts has the format + [ + {'genre': 'classical', + 'num_songs': 100, + 'artists': { + 'Helene Grimaud': 40.5, + 'Beethoven': 31.2, + 'Mozart': 22... + } + }, + {'genre': 'pop', + 'num_songs': 150, + 'artists': {...} + },... + ] + ''' print("*** Genre Breakdown ***") pprint.pprint(list(genre_counts)) return JsonResponse(data=list(genre_counts), safe=False) diff --git a/graphs/static/graphs/scripts/genre_graph.js b/graphs/static/graphs/scripts/genre_graph.js index 6c5e02e..2d107ea 100644 --- a/graphs/static/graphs/scripts/genre_graph.js +++ b/graphs/static/graphs/scripts/genre_graph.js @@ -22,9 +22,9 @@ function create_genre_graph(data) { 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; }) * 1.25]).nice(); y.domain([0, d3.max(data, function(d) { - return d.num_songs; + return d.num_songs; // returns the maximum number of songs in the genre })]).nice(); // }}} domains // @@ -34,7 +34,7 @@ function create_genre_graph(data) { let max_artists = d3.max(data, function(d) { return Object.keys(d.artists).length; }); - let z = d3.scaleOrdinal().range(randomColor({ + let colorScale = d3.scaleOrdinal().range(randomColor({ count: max_artists, luminosity: 'light', })); @@ -47,10 +47,9 @@ function create_genre_graph(data) { let keys = Object.keys(genre_dict.artists); let stack = d3.stack() - //.order(d3.stackOrderAscending) .order(d3.stackOrderDescending) .keys(keys)([genre_dict.artists]) - //unpack the column + // unpack the column .map((d, i) => { return { key: keys[i], @@ -72,8 +71,9 @@ function create_genre_graph(data) { }) .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])); + .attr('fill', (d, i) => colorScale(i)) + // keep 3 significant figures in the song count label + .append('title').text(d => d.key + ': ' + (d.data[1] - d.data[0]).toPrecision(3)); // }}} add bars // @@ -108,7 +108,7 @@ function create_genre_graph(data) { } // wrap text {{{ // - +// wrapping long labels // https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07#file-index-html function wrap(text, width) { text.each(function() { @@ -122,13 +122,13 @@ function wrap(text, width) { 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(" ")) + 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) + 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); } } }) diff --git a/graphs/templates/graphs/genre_graph.html b/graphs/templates/graphs/genre_graph.html index 7f2ba76..ef41a91 100644 --- a/graphs/templates/graphs/genre_graph.html +++ b/graphs/templates/graphs/genre_graph.html @@ -13,7 +13,7 @@ Test DB Page - +{# #} @@ -33,7 +33,8 @@ g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let x = d3.scaleBand() .rangeRound([0, width]) - .paddingInner(0.05) + .paddingInner(0.1) + .paddingOuter(0.7) .align(0.1); let y = d3.scaleLinear() .rangeRound([height, 0]);