Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend for Heat Map #75

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
60 changes: 60 additions & 0 deletions client/css/bar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.hero {
display: grid;
align-content: center;
justify-items: center;
width: 100%; /* don't use 100vw, that will cause horizontal scrollbar */
height: 100vh;
}

.svg {
width: 100%;
height: 100%;
}
gracetian6 marked this conversation as resolved.
Show resolved Hide resolved

#vis {
display: flex;
align-items: stretch;
width: 50vh;

height: 60vh;
margin-left: 0;

background-color: #222425;
}

#graph {
display: inline-block;
width: 70%;
}

.bar {
cursor: pointer;

transition: fill .3s ease;

fill: var(--color-accent-primary-2);
}

.bar:hover, .bar:focus {
fill: var(--color-accent-special);
}

#bar-text {
display: flex;
flex-flow: column nowrap;
width: 25%;
height: 100%;

text-align: right;
vertical-align: top;
}

.category {
display: flex;
flex-basis: 0;
flex-direction: column;
flex-grow: 1;
justify-content: center;

text-align: right;
}
62 changes: 62 additions & 0 deletions client/js/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @file constructs bar graph from scratch
*/

// hard coded data for bar chart for now
const CHART_VALUES = [1, 3, 1, 2];
const CHART_CATEGORIES = [
'Pop Music',
'Other Music',
'Electronic Music',
'Music of Latin America',
];

const GRAPH_HEIGHT = 100;
// each bar container is composed of bar padding and fill
const BAR_PERCENT_FILL = 0.7;
const BAR_PERCENT_PADDING = 1 - BAR_PERCENT_FILL;

const GRAPH_LEFT_PADDING = 2.5;

/**
* creates SVG bar chart given chart values and categories
* @param {number[]} chartValues array of bar values/lengths
* @param {string[]} chartCategories array of bar categories/labels
*/
function createBarChart(chartValues, chartCategories) {
const maxChartValues = Math.max(...chartValues);
const barContainerHeight = GRAPH_HEIGHT / chartValues.length;

const barThickness = BAR_PERCENT_FILL * barContainerHeight;
const barUnitLength = 100 / maxChartValues;

// top graph padding depends on bar padding
const graphTopPadding = (BAR_PERCENT_PADDING / 2) * barContainerHeight;

const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 100 100');
svg.setAttribute('preserveAspectRatio', 'none');
svg.setAttribute('class', 'svg');
document.getElementById('graph').appendChild(svg);

for (let i = 0; i < chartValues.length; i++) {
const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
svg.appendChild(g);
g.setAttribute('class', 'bar');

const bar = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
g.appendChild(bar);
bar.setAttribute('width', barUnitLength * chartValues[i]);
bar.setAttribute('height', barThickness);
bar.setAttribute('x', GRAPH_LEFT_PADDING);
bar.setAttribute('y', graphTopPadding + barContainerHeight * i);

const barTextContainer = document.getElementById('bar-text');
const category = document.createElement('div');
barTextContainer.appendChild(category);
category.setAttribute('class', 'category');
category.textContent = chartCategories[i];
}
}

createBarChart(CHART_VALUES, CHART_CATEGORIES);
1 change: 0 additions & 1 deletion client/js/genre.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ async function displayMusicGenre() {
const genreCount = await response.text();
genreBlock.innerHTML = genreCount;
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.lang.Math;
Expand All @@ -22,6 +23,9 @@ public class YoutubeGenres {
public HashMap<String, Integer> genreData = new HashMap<String, Integer>();
public int totalMusic = 0;
public int maxGenreCount = 0;
// element of value x means xth latest video is music
// needed for heat map
public ArrayList<Integer> likedMusicHistory = new ArrayList<Integer>();

public YoutubeGenres() {

Expand All @@ -30,9 +34,11 @@ public YoutubeGenres() {
/**
* parses through youtube liked videos json array,
* updates hash map to contain frequency count of each music genre
* @param firstVideoCount the number of videos retrieved before this http call
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider renaming firstVideoCount to initialNumVideos. firstVideoCount sounds like it could be the index of the first video, or some count associated with the first video in the list

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Probably something like "currentVideoIndex" will be clearest

* @param videos json array of youtube liked videos
* @return number of videos retrieved so far
*/
protected void calculateMusicCount(JsonArray videos) {
protected int calculateMusicCount(int firstVideoCount, JsonArray videos) {
for (int i = 0; i < videos.size(); i++) {
JsonObject video = videos.get(i).getAsJsonObject();
JsonObject topicDetails = video.getAsJsonObject("topicDetails");
Expand Down Expand Up @@ -68,12 +74,17 @@ protected void calculateMusicCount(JsonArray videos) {
}
}

if (isMusic && totalSubgenres == 0) {
if (isMusic) {
// likedMusicHistory records video numbers that are music
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need this comment, you already have a comment explaining what likedMusicHistory is when you first initialize it

likedMusicHistory.add(firstVideoCount + i);

if (totalSubgenres == 0) {
// video only classified as Music so we update as "Other music"
this.updateGenre("Other music");
this.updateGenre("Other music");
}
}
}
return;
return firstVideoCount + videos.size();
gracetian6 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res)
JsonObject likedVideoRes;
JsonArray videos;
YoutubeGenres genreAnalysis = new YoutubeGenres();
// needed to keep track of likedMusicHistory for heat map
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment doesn't really make sense to me, since it's not "keeping track" of likedMusicHistory but being used by it. likedMusicHistory also isn't part of this file, so that could come of as confusing to someone only looking at this file. consider rephrasing to something like "used to determine the position of a newly retrieved video in comparison to already retrieved videos while obtaining more videos in segments"

int videosRetrieved = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider renaming to numVideosRetrieved, videosRetrieved sounds like a list of the retrieved videos


// next Page Token must be an empty string for first http call
String nextPageToken = "";
Expand All @@ -111,7 +113,8 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res)
}

videos = likedVideoRes.getAsJsonArray("items");
genreAnalysis.calculateMusicCount(videos);
videosRetrieved = genreAnalysis
.calculateMusicCount(videosRetrieved, videos);

nextPageToken = getNextPageToken(likedVideoRes);
}
Expand Down