Well, I’ve been trying to get different versions of this program to work for a while, but it’s not perfect yet. It’s far from it actually. I’m going to walk you through my thought process and show you my code, any suggestions would be much appreciated!
So, for this week, I noticed that Spotify allows users to access their own data as well as the charts from every day in CSV format (which is very cool). Unfortunately, personal data takes a long time to be prepared and sent to you, so even after asking for it on Thursday, I didn’t receive it so I couldn’t use it. Honestly, that was kind of a relief, I’m not ready to share my Spotify stats with you guys yet…a lot of embarrassing guilty pleasures on there.
Anyways, I decided to use the top 20 songs from the first week in September, and then create a data visualization of how well these songs were doing throughout the month. I downloaded all four CSV files that contain the Top 200 and recorded the values relevant to me (streams for week 1 top 20) in my own CSV file.
Process
Using a multi-row/column CSV file meant I needed different functions than the ones we used in class (loadStrings). I looked up loadTable() and watched a bunch of tutorials on it.
For my visualization, I wanted to achieve to main things. One, present the data using musical symbolism. Two, use user text input to “search” one of the top 20 songs.
For one, I came up with a system where each note value represents a range of streams, and hence if the data in the CSV file corresponds to a certain range a certain note will be displayed on the staff I drew on screen.
So, through looking at a display of 4 notes on the screen one can evaluate how a certain song did throughout the month. which week had the most streams etc.
Then, for 2, I looked in the processing reference for an input function and didn’t find anything relevant to what I needed. I ended up finding a very helpful code on learningprocessing.com, which allowed me to save the user input in a variable. However, my main struggle and the reason my code isn’t complete is that I am unable to compare the string in this variable with the song titles. I tried doing it through a for loop in the keypressed function and a for loop in the draw function, but it did not work. However, when I access a specific song and a specific week, it displays the corresponding note.
Song Class
For this program, I created a song class that takes the song title and the 4-week streaming values as arguments. The functions of this class consist mainly of display functions for different weeks and different kinds of notes.
Alternatives
I considered alternative options, such as simply clicking on the song title to display its data or pressing a number on the keyboard that corresponds to the song number on the chart, but I felt like I’ve already used these methods in previous assignments and was very stubborn about wanting user input to work.
Demonstration
Here’s a clip of my code failing :-(( :
Here’s an example of my program displaying the streams for a song after I specifically called the display function in draw() (not user input):
Take a look at my main code:
// text input code from http://learningprocessing.com/examples/chp18/example-18-01-userinput //Treble Clef png by Vasily Gedzun from the Noun Project //loading image for treble clef PImage treble; PFont f; // Variable to store text currently being typed String typing = ""; // Variable to store saved text when enter is hit String searchInput = ""; Table top20; //creating table Song[] allSongs; //object list void setup() { size(1024,768); f = createFont("Kayak Sans Bold (Italic).otf",20); textFont(f); top20 = loadTable("TOP 20.csv", "header"); //loading table excluding the first row, which are the headers treble = loadImage("Treble Clef.png"); allSongs = new Song[20]; //creating the list for (int i=0; i<19; i++){ allSongs[i] = new Song(top20.getString(i,0), top20.getFloat(i,1),top20.getFloat(i,2),top20.getFloat(i,3),top20.getFloat(i,4)); //creating the object list, the arguments get their vals from acessing CSV file data } } int indent = 25; // indentation for text void draw() { background(255); fill(0); // Display initial text textSize(20); text("Type a Top 10 Song Title to View September Streams \n Hit enter ", indent, 40); text("Typing: " + typing,indent,190); text("Searching: " + searchInput,indent,230); displayMusicStaff(); // calling the function that draws the staff textSize(15); //displaying the search options text("WAP (feat. Megan Thee Stallion) \n Hawaii \n Mood (feat. Iann Dior) \n Dynamite \n Ice Cream (with Selena Gomez) \n Savage Love (Laxed - Siren Beat) \n Watermelon Sugar \n Blinding Lights \n ROCKSTAR (feat. Roddy Ricch) \n Laugh Now Cry Later (feat. Lil Durk)", width/2, 550); text("Roses - Imanbek Remix \n Mood Swings (feat. Lil Tjay) \n Breaking Me \n Ay, DiOs MÃo! \n For The Night (feat. Lil Baby & DaBaby) \n UN DIA (One Day) (Feat. Tainy) \n Head & Heart (feat. MNEK) \n Heather \n La Curiosidad", width/2 + 250, 550); // loop that compares user input to song list for (int i = 0; i<19; i++){ if (searchInput == allSongs[i].songTitle){ allSongs[i].week1Display(); allSongs[i].week2Display(); allSongs[i].week3Display(); allSongs[i].week4Display(); } } } void keyPressed() { //Code for user input // If the enter key is pressed, the user input is saved in a variable called searchInput if (key == '\n' ) { searchInput = typing; //the user is no longer typing, so we clear the typing variable typing = ""; } else { // if enter isn't pressed keep adding characters to the typing variable typing = typing + key; } } void displayMusicStaff(){ //drawing the staff strokeWeight(2); line(250,250,840,250); line(250,300,840,300); line(250,350,840,350); line(250,400,840,400); line(250,450,840,450); image(treble,250,250); }
My Song Class:
class Song{ //declaring variables String songTitle; float streams; int locX, locY; int ellipseW, ellipseH; float wk1Streams, wk2Streams, wk3Streams, wk4Streams; Song(String tempTitle, float tempwk1Streams, float tempwk2Streams, float tempwk3Streams, float tempwk4Streams){ locX = 380; locY = 450; ellipseW = 35; ellipseH = 25; songTitle = tempTitle; wk1Streams = tempwk1Streams; wk2Streams = tempwk2Streams; wk3Streams = tempwk3Streams; wk4Streams = tempwk4Streams; } //function checks the value of week 1 streams and displays the note shape accordingly by calling that note shape's function void week1Display(){ if (wk1Streams > 10000000 && wk1Streams < 20000000){ thrityTwoNote(locX,locY); } else if ((wk1Streams > 20000000 && wk1Streams < 25000000)){ sixteenNote(locX,locY); } else if (wk1Streams> 25000000 && wk1Streams < 30000000){ eightNote(locX,locY); } else if (wk1Streams > 30000000 && wk1Streams < 35000000){ quarterNote(locX,locY); } else if (wk1Streams > 35000000 && wk1Streams < 40000000){ halfNote(locX,locY); } else if (wk1Streams > 40000000 && wk1Streams < 46000000){ wholeNote(locX,locY); } } //week2 void week2Display(){ //x and y values here are dependent on the week 1 x and y, to keep the code dynamic if (wk2Streams > 10000000 && wk2Streams < 20000000){ thrityTwoNote(locX+100,locY-50); } else if ((wk2Streams > 20000000 && wk2Streams < 25000000)){ sixteenNote(locX+100,locY-50); } else if (wk2Streams> 25000000 && wk2Streams < 30000000){ eightNote(locX+100,locY-50); } else if (wk2Streams > 30000000 && wk2Streams < 35000000){ quarterNote(locX+100,locY-50); } else if (wk2Streams > 35000000 && wk2Streams < 40000000){ halfNote(locX+100,locY-50); } else if (wk2Streams > 40000000 && wk2Streams < 46000000){ wholeNote(locX+100,locY-50); } } //week3 void week3Display(){ if (wk3Streams > 10000000 && wk3Streams < 20000000){ thrityTwoNote(locX+200,locY-100); } else if ((wk3Streams > 20000000 && wk3Streams < 25000000)){ sixteenNote(locX+200,locY-100); } else if (wk3Streams> 25000000 && wk3Streams < 30000000){ eightNote(locX+100,locY-100); } else if (wk3Streams > 30000000 && wk3Streams < 35000000){ quarterNote(locX+200,locY-100); } else if (wk3Streams > 35000000 && wk3Streams < 40000000){ halfNote(locX+200,locY-100); } else if (wk3Streams > 40000000 && wk3Streams < 46000000){ wholeNote(locX+200,locY-100); } } void week4Display(){ //week4 if (wk4Streams > 10000000 && wk4Streams < 20000000){ thrityTwoNote(locX+300,locY-150); } else if ((wk4Streams > 20000000 && wk4Streams < 25000000)){ sixteenNote(locX+300,locY-150); } else if (wk4Streams> 25000000 && wk4Streams < 30000000){ eightNote(locX+300,locY-150); } else if (wk4Streams > 30000000 && wk4Streams < 35000000){ quarterNote(locX+300,locY-150); } else if (wk4Streams > 35000000 && wk4Streams < 40000000){ halfNote(locX+300,locY-150); } else if (wk4Streams > 40000000 && wk4Streams < 46000000){ wholeNote(locX+300,locY-150); } } //smallest stream range note shape void thrityTwoNote(int x, int y){ fill(0); ellipse(x,y,ellipseW,ellipseH); line(x+17.5, y, x+17.5, y -70); line(x+17.5, y-70, x+35, y-60); line(x+17.5, y-60, x+35, y-50); line(x+17.5, y-50, x+35, y-40); } void sixteenNote(int x, int y){ fill(0); ellipse(x,y,ellipseW,ellipseH); line(x+17.5, y, x+17.5, y -70); line(x+17.5, y-70, x+35, y-60); line(x+17.5, y-60, x+35, y-50); } void eightNote(int x, int y){ fill(0); ellipse(x,y,ellipseW,ellipseH); line(x+17.5, y, x+17.5, y -70); line(x+17.5, y-70, x+35, y-60); } void quarterNote(int x, int y){ fill(0); ellipse(x,y,ellipseW,ellipseH); line(x+17.5, y, x+17.5, y -70); } void halfNote (int x, int y){ noFill(); ellipse(x,y,ellipseW,ellipseH); line(x+17.5, y, x+17.5, y -70); line(x+17.5, y-70, x+35, y-60); } void wholeNote(int x, int y){ noFill(); ellipse(380,450,35,25); } }
This is great work Sarah. Looking forward to seeing it working as you imagine!