Improve readability
Added additional comments to improve readability of the genre graph related code.
This commit is contained in:
13
api/utils.py
13
api/utils.py
@@ -186,13 +186,11 @@ def add_artist_genres(headers, artist_objs):
|
|||||||
|
|
||||||
# get_artists_in_genre {{{ #
|
# 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.
|
"""Return count of artists in genre.
|
||||||
|
|
||||||
:user: User object to return data for.
|
:user: User object to return data for.
|
||||||
:genre: genre to count artists for. (string)
|
: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
|
:returns: dict of artists in the genre along with the number of songs they
|
||||||
have.
|
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']
|
total_artist_counts = tracks_in_genre.aggregate(counts=Count('artists'))['counts']
|
||||||
|
|
||||||
processed_artist_counts = {}
|
processed_artist_counts = {}
|
||||||
# songs_added = 0
|
|
||||||
for artist in user_artists:
|
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
|
processed_artist_counts[artist.name] = round(artist.track_set
|
||||||
.filter(genre=genre_obj, users=user)
|
.filter(genre=genre_obj, users=user)
|
||||||
.count() * track_count / total_artist_counts, 2)
|
.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
|
return processed_artist_counts
|
||||||
|
|
||||||
# }}} get_artists_in_genre #
|
# }}} get_artists_in_genre #
|
||||||
|
|||||||
22
api/views.py
22
api/views.py
@@ -176,10 +176,30 @@ def get_genre_data(request, user_secret):
|
|||||||
genre_counts = (Track.objects.filter(users__exact=user)
|
genre_counts = (Track.objects.filter(users__exact=user)
|
||||||
.values('genre')
|
.values('genre')
|
||||||
.order_by('genre')
|
.order_by('genre')
|
||||||
|
# annotates each genre and not each Track, due to the earlier values() call
|
||||||
.annotate(num_songs=Count('genre'))
|
.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:
|
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 ***")
|
print("*** Genre Breakdown ***")
|
||||||
pprint.pprint(list(genre_counts))
|
pprint.pprint(list(genre_counts))
|
||||||
return JsonResponse(data=list(genre_counts), safe=False)
|
return JsonResponse(data=list(genre_counts), safe=False)
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ function create_genre_graph(data) {
|
|||||||
x.domain(data.map(function(d) {
|
x.domain(data.map(function(d) {
|
||||||
return d.genre;
|
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) {
|
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();
|
})]).nice();
|
||||||
|
|
||||||
// }}} domains //
|
// }}} domains //
|
||||||
@@ -34,7 +34,7 @@ function create_genre_graph(data) {
|
|||||||
let max_artists = d3.max(data, function(d) {
|
let max_artists = d3.max(data, function(d) {
|
||||||
return Object.keys(d.artists).length;
|
return Object.keys(d.artists).length;
|
||||||
});
|
});
|
||||||
let z = d3.scaleOrdinal().range(randomColor({
|
let colorScale = d3.scaleOrdinal().range(randomColor({
|
||||||
count: max_artists,
|
count: max_artists,
|
||||||
luminosity: 'light',
|
luminosity: 'light',
|
||||||
}));
|
}));
|
||||||
@@ -47,10 +47,9 @@ function create_genre_graph(data) {
|
|||||||
|
|
||||||
let keys = Object.keys(genre_dict.artists);
|
let keys = Object.keys(genre_dict.artists);
|
||||||
let stack = d3.stack()
|
let stack = d3.stack()
|
||||||
//.order(d3.stackOrderAscending)
|
|
||||||
.order(d3.stackOrderDescending)
|
.order(d3.stackOrderDescending)
|
||||||
.keys(keys)([genre_dict.artists])
|
.keys(keys)([genre_dict.artists])
|
||||||
//unpack the column
|
// unpack the column
|
||||||
.map((d, i) => {
|
.map((d, i) => {
|
||||||
return {
|
return {
|
||||||
key: keys[i],
|
key: keys[i],
|
||||||
@@ -72,8 +71,9 @@ function create_genre_graph(data) {
|
|||||||
})
|
})
|
||||||
.attr("height", d => y(d.data[0]) - y(d.data[1]))
|
.attr("height", d => y(d.data[0]) - y(d.data[1]))
|
||||||
.attr("width", x.bandwidth())
|
.attr("width", x.bandwidth())
|
||||||
.attr('fill', (d, i) => z(i))
|
.attr('fill', (d, i) => colorScale(i))
|
||||||
.append('title').text(d => d.key + ': ' + (d.data[1] - d.data[0]));
|
// 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 //
|
// }}} add bars //
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ function create_genre_graph(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wrap text {{{ //
|
// wrap text {{{ //
|
||||||
|
// wrapping long labels
|
||||||
// https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07#file-index-html
|
// https://gist.github.com/guypursey/f47d8cd11a8ff24854305505dbbd8c07#file-index-html
|
||||||
function wrap(text, width) {
|
function wrap(text, width) {
|
||||||
text.each(function() {
|
text.each(function() {
|
||||||
@@ -122,13 +122,13 @@ function wrap(text, width) {
|
|||||||
dy = parseFloat(text.attr("dy")),
|
dy = parseFloat(text.attr("dy")),
|
||||||
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em")
|
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em")
|
||||||
while (word = words.pop()) {
|
while (word = words.pop()) {
|
||||||
line.push(word)
|
line.push(word);
|
||||||
tspan.text(line.join(" "))
|
tspan.text(line.join(" "));
|
||||||
if (tspan.node().getComputedTextLength() > width) {
|
if (tspan.node().getComputedTextLength() > width) {
|
||||||
line.pop()
|
line.pop();
|
||||||
tspan.text(line.join(" "))
|
tspan.text(line.join(" "));
|
||||||
line = [word]
|
line = [word];
|
||||||
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(word)
|
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", `${++lineNumber * lineHeight + dy}em`).text(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<title>Test DB Page</title>
|
<title>Test DB Page</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="{% static 'css/dark_bg.css' %}">
|
{# <link rel="stylesheet" href="{% static 'css/dark_bg.css' %}">#}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<!-- }}} header -->
|
<!-- }}} header -->
|
||||||
@@ -33,7 +33,8 @@
|
|||||||
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||||
let x = d3.scaleBand()
|
let x = d3.scaleBand()
|
||||||
.rangeRound([0, width])
|
.rangeRound([0, width])
|
||||||
.paddingInner(0.05)
|
.paddingInner(0.1)
|
||||||
|
.paddingOuter(0.7)
|
||||||
.align(0.1);
|
.align(0.1);
|
||||||
let y = d3.scaleLinear()
|
let y = d3.scaleLinear()
|
||||||
.rangeRound([height, 0]);
|
.rangeRound([height, 0]);
|
||||||
|
|||||||
Reference in New Issue
Block a user