From fc6c30ec32f488c33c0f3e2114886c5de8b19af9 Mon Sep 17 00:00:00 2001 From: Chris Shyi Date: Sat, 30 Jun 2018 17:59:34 -0400 Subject: [PATCH 1/2] Refactor audio feat graph Fixes #51. Instead of passing in an array of hard coded values as the interval end points, an object specifying the beginning, the end, and the step size is used. Categories can be more easily defined and modified this way. --- api/utils.py | 2 +- api/views.py | 3 +- .../static/graphs/scripts/audio_feat_graph.js | 29 +++++++++++++------ graphs/templates/graphs/features_graphs.html | 16 +++++----- reset_db.sh | 16 +++++----- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/api/utils.py b/api/utils.py index d9db42e..ef0c99f 100644 --- a/api/utils.py +++ b/api/utils.py @@ -170,7 +170,7 @@ def add_artist_genres(headers, artist_objs): params = {'ids': artist_ids} artists_response = requests.get('https://api.spotify.com/v1/artists/', headers=headers, - params={'ids': artist_ids}, + params=params, ).json()['artists'] for i in range(len(artist_objs)): if len(artists_response[i]['genres']) == 0: diff --git a/api/views.py b/api/views.py index 5a482d2..2f8e96c 100644 --- a/api/views.py +++ b/api/views.py @@ -166,8 +166,9 @@ def get_audio_feature_data(request, audio_feature, user_secret): # get_genre_data {{{ # + def get_genre_data(request, user_secret): - """Return genre data needed to create the graph user. + """Return genre data needed to create the graph TODO """ user = User.objects.get(secret=user_secret) diff --git a/graphs/static/graphs/scripts/audio_feat_graph.js b/graphs/static/graphs/scripts/audio_feat_graph.js index 1fab293..2b3d97e 100644 --- a/graphs/static/graphs/scripts/audio_feat_graph.js +++ b/graphs/static/graphs/scripts/audio_feat_graph.js @@ -3,10 +3,10 @@ * a designated parent element * * @param audioFeature: the name of the audio feature (string) - * @param intervalEndPoints: a sorted array of 5 real numbers defining the intervals (categories) of values, + * @param intervalEndPoints: a object defining the intervals (categories) of values, * for example: - * [0, 0.25, 0.5, 0.75, 1.0] for instrumentalness would define ranges - * (0-0.25), (0.25-0.5), (0.5-0.75), (0.75-1.0) + * {begin: 0, end: 1.0, step: 0.25} for instrumentalness would define ranges + * [0-0.25), [0.25-0.5), [0.5-0.75), [0.75-1.0] * @param parentElem: the DOM element to append the graph to (a selector string) * @param userSecret: the user secret string for identification * @return None @@ -18,11 +18,20 @@ function drawAudioFeatGraph(audioFeature, intervalEndPoints, parentElem, userSec height = 270 - margin.top - margin.bottom; let featureData = {}; + let currentEndPoint = intervalEndPoints.begin; // start at beginning // Create the keys first in order - for (let index = 0; index < intervalEndPoints.length - 1; index++) { - let key = `${intervalEndPoints[index]} ~ ${intervalEndPoints[index + 1]}`; + while (currentEndPoint !== intervalEndPoints.end) { + let startOfRange = currentEndPoint; + let endOfRange = startOfRange + intervalEndPoints.step; + + let key = `${startOfRange} ~ ${endOfRange}`; featureData[key] = 0; + currentEndPoint = endOfRange; } + // for (let index = 0; index < intervalEndPoints.length - 1; index++) { + // let key = `${intervalEndPoints[index]} ~ ${intervalEndPoints[index + 1]}`; + // featureData[key] = 0; + // } // define the vertical scaling function let vScale = d3.scaleLinear().range([height, 0]); @@ -31,12 +40,14 @@ function drawAudioFeatGraph(audioFeature, intervalEndPoints, parentElem, userSec // categorize the data points for (let dataPoint of response.data_points) { dataPoint = parseFloat(dataPoint); - let index = intervalEndPoints.length - 2; + let currLowerBound = intervalEndPoints.end - intervalEndPoints.step; + let stepSize = intervalEndPoints.step; // find the index of the first element greater than dataPoint - while (dataPoint < intervalEndPoints[index]) { - index -= 1; + while (dataPoint < currLowerBound) { + currLowerBound -= stepSize; } - let key = `${intervalEndPoints[index]} ~ ${intervalEndPoints[index + 1]}`; + let upperBound = currLowerBound + stepSize; + let key = `${currLowerBound} ~ ${upperBound}`; featureData[key] += 1; } diff --git a/graphs/templates/graphs/features_graphs.html b/graphs/templates/graphs/features_graphs.html index ea01793..d8273af 100644 --- a/graphs/templates/graphs/features_graphs.html +++ b/graphs/templates/graphs/features_graphs.html @@ -24,14 +24,14 @@ diff --git a/reset_db.sh b/reset_db.sh index b833b8a..b4805d6 100755 --- a/reset_db.sh +++ b/reset_db.sh @@ -1,15 +1,15 @@ # check if in virtual environment # https://stackoverflow.com/questions/15454174/how-can-a-shell-function-know-if-it-is-running-within-a-virtualenv/15454916 -# python -c 'import sys; print(sys.real_prefix)' 2>/dev/null && INVENV=1 || INVENV=0 +python -c 'import sys; print(sys.real_prefix)' 2>/dev/null && INVENV=1 || INVENV=0 # INVENV=$(python -c 'import sys; print ("1" if hasattr(sys, "real_prefix") else "0")') # if $INVENV is 1, then in virtualenv # echo $INVENV -# if [ $INVENV -eq 1 ]; then -rm login/migrations/0* api/migrations/0* -sudo -u postgres psql -f reset_db.sql -python manage.py makemigrations -python manage.py migrate -python manage.py runserver -# fi +if [ $INVENV -eq 1 ]; then + rm login/migrations/0* api/migrations/0* + sudo -u postgres psql -f reset_db.sql + python manage.py makemigrations login api + python manage.py migrate + python manage.py runserver +fi From 01759c59b304cb1faffaf2eb172a56c7d4bccd6e Mon Sep 17 00:00:00 2001 From: Chris Shyi Date: Sat, 30 Jun 2018 18:51:52 -0400 Subject: [PATCH 2/2] Fix floating point precision issue in audio feat The last commit (fc6c30ec32f488c33c0f3e2114886c5de8b19af9) was affected by a floating point addition/subtraction precision bug. The bug caused nonsensical categories to appear on the audio feature bar charts. Now fixed. --- .../static/graphs/scripts/audio_feat_graph.js | 22 ++++++++++++++----- graphs/templates/graphs/features_graphs.html | 14 ++++++------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/graphs/static/graphs/scripts/audio_feat_graph.js b/graphs/static/graphs/scripts/audio_feat_graph.js index 2b3d97e..5be85fb 100644 --- a/graphs/static/graphs/scripts/audio_feat_graph.js +++ b/graphs/static/graphs/scripts/audio_feat_graph.js @@ -20,9 +20,9 @@ function drawAudioFeatGraph(audioFeature, intervalEndPoints, parentElem, userSec let featureData = {}; let currentEndPoint = intervalEndPoints.begin; // start at beginning // Create the keys first in order - while (currentEndPoint !== intervalEndPoints.end) { + while (currentEndPoint < intervalEndPoints.end) { let startOfRange = currentEndPoint; - let endOfRange = startOfRange + intervalEndPoints.step; + let endOfRange = precise(startOfRange + intervalEndPoints.step); let key = `${startOfRange} ~ ${endOfRange}`; featureData[key] = 0; @@ -40,13 +40,14 @@ function drawAudioFeatGraph(audioFeature, intervalEndPoints, parentElem, userSec // categorize the data points for (let dataPoint of response.data_points) { dataPoint = parseFloat(dataPoint); - let currLowerBound = intervalEndPoints.end - intervalEndPoints.step; + let currLowerBound = precise(intervalEndPoints.end - intervalEndPoints.step); let stepSize = intervalEndPoints.step; // find the index of the first element greater than dataPoint - while (dataPoint < currLowerBound) { - currLowerBound -= stepSize; + while (dataPoint < currLowerBound && currLowerBound >= intervalEndPoints.begin) { + currLowerBound = precise(currLowerBound - stepSize); } - let upperBound = currLowerBound + stepSize; + let upperBound = precise(currLowerBound + stepSize); + currLowerBound = precise(currLowerBound); let key = `${currLowerBound} ~ ${upperBound}`; featureData[key] += 1; } @@ -113,4 +114,13 @@ function drawAudioFeatGraph(audioFeature, intervalEndPoints, parentElem, userSec */ function capFeatureStr(audioFeature) { return audioFeature.charAt(0).toUpperCase() + audioFeature.slice(1); +} + +/** + * Converts a number to a floating point value with 2 significant figures + * @param number: the number to be converted + * @returns the input converted to two significant digits + */ +function precise(number) { + return Number.parseFloat(number.toPrecision(2)); } \ No newline at end of file diff --git a/graphs/templates/graphs/features_graphs.html b/graphs/templates/graphs/features_graphs.html index d8273af..cf8f01a 100644 --- a/graphs/templates/graphs/features_graphs.html +++ b/graphs/templates/graphs/features_graphs.html @@ -24,14 +24,14 @@