Whats the deal
I wanted to visualize the predominant genres showcased at the Electric Daisy Carnival (EDC), offering valuable insights into trends within the electronic music industry. In doing so, I seek to gain a deeper understanding of market demands and cultural shifts.
Plan
I wanted to build out a project to test my analyst knowledge and build something to combine SQL, Python, Tableau, and Analysis. My aim was to uncover trends within a niche and personally intriguing market. I also wanted to play with the Spotify API and thus decided to analyze trends within the Electronic Music industry.
I wanted to limit my dataset so I decided to focus on artists who have performed at the Electric Daisy Carnival in Las Vegas, believing this selection would encompass both established and emerging talents in the electronic music scene with the barrier to entry that they are somewhat commercially popular. In doing so, I want to acknowledge that my analysis is constrained by various factors that, for a detailed understanding of these limitations and potential solutions, I will provide documentation on analysis limitations below.
I broke down the project into phases, with each phase building functionality on the previous one. Initially, I will develop a rudimentary (I studied accounting, not CS!) Python script to call the Spotify API and retrieve genres and other information for a list of artists. I will then compile a list of artists who have performed at EDC and scrape their year of performance and set time. (The significance of set time lies in its potential correlation with popular genres, but I’ve kept this out of scope for now.) While not entirely necessary due to the small dataset, I aim to populate this data into a database to gain practice. Following this, I will execute SQL queries to pull the final dataset into Tableau Public (Im cheap). The focus of the project is to generate a Tableau dashboard with metrics, with the main metric being the top genres by stage. Visually, I envision the dashboard as an interactive map of the festival, allowing users to filter the data by stage.
Step 1 – The backbone
import pandas as pd
from dotenv import load_dotenv
import os
import base64
from requests import post, get
import json
load_dotenv()
client_id = os.getenv("CLIENT_ID")
client_secret = os.getenv("CLIENT_SECRET")
def get_token():
auth_string = client_id + ":" + client_secret
auth_bytes = auth_string.encode("utf-8")
auth_base64 = str(base64.b64encode(auth_bytes), "utf-8")
url = "https://accounts.spotify.com/api/token"
headers = {
"Authorization": "Basic " + auth_base64,
"Content-Type": "application/x-www-form-urlencoded"
}
data = {"grant_type": "client_credentials"}
result = post(url, headers=headers, data=data)
json_result = json.loads(result.content)
token = json_result["access_token"]
return token
def get_auth_header(token):
return {"Authorization": "Bearer " + token}
def search_for_artist(token, artist_name):
url = "https://api.spotify.com/v1/search"
headers = get_auth_header(token)
query = f"?q={artist_name}&type=artist&limit=1"
query_url = url + query
result = get(query_url,headers=headers)
json_result = json.loads(result.content)["artists"]["items"]
if len(json_result) == 0:
print(f"No artist found for {artist_name}")
return None
return json_result[0]
def get_genres_by_artists(token, artist_id):
url = f"https://api.spotify.com/v1/artists/{artist_id}"
headers = get_auth_header(token)
result = get(url, headers=headers)
json_result = json.loads(result.content)["genres"]
return json_result
def get_genres_for_artists_from_excel(input_file, output_file):
token = get_token()
data = pd.read_excel(input_file, usecols=['Artist'])
genres_list = []
for artist_name in data['Artist']:
artist_result = search_for_artist(token, artist_name)
if artist_result:
genres = get_genres_by_artists(token, artist_result["id"])
genres_list.append(", ".join(genres))
else:
genres_list.append("Not Found")
data['Genres'] = genres_list
data.to_excel(output_file, index=False)
if __name__ == "__main__":
input_file = "/Users/devicente/Desktop/Projects/SpotifyAPI/EDC Artists.xlsx"
output_file = "/Users/devicente/Desktop/Projects/SpotifyAPI/output.xlsx"
get_genres_for_artists_from_excel(input_file, output_file)
print("It worked!")
I wrote the following Python script to take a workbook of artists, access the Spotify API and return information about the artists. This current version only returns the artist’s genre as defined by Spotify. This is the first issue I can see in terms of limitation of analysis. Genres are subjective. It can be argued that in using Spotify’s API, it would perform a baseline determination of genres such that it is not left to the subjectivity of a single person.
Step 2: Database
Data regarding artist rosters is readily available in nice Excel sheets provided by the great people of reddit. So I modified an SEO bot to scrape threads using chat-GPT. No need to over complicate the easy parts. I pulled the rosters from threads and spot checked the rosters (we may be losing a few last minute artist changes, but more on that later). We do want to over-complicate the fun stuff so over lunch I quickly sketched out a Entity Relationship Diagram for my data:
And here it is beautified:
Some considerations on this ERD draft. While I have experience in SQL, I don’t typically build databases from scratch. A few things I will look into that may already identify themselves as I am bringing this into postgreSQL.
-Probably need a relationship between EDC and stage
-Probably need to reconfigure date and year for EDC
-Probably could share some kind of composite key for Set
Need to combine data to have a better visual. Feel like – while this will work, we are losing clarity/flexibility/efficency.
Step 3: API Results
As anticipated, pushing my artist list through the Spotify API has returned some… interesting results. In my research I found the following from the man himself, Glenn McDonald, Spotify’s former data alchemist (I’m a huge fan Glenn, can’t wait for the book to drop!):
The genre tags you see in the API are for artists who we (Spotify) consider representative for those genres. Internally we have a larger mapping of less-representative artists to their probably-relevant genres…. Genre assignments are a combination of human curation and algorithmic extrapolation, so in most genres it’s quite possible for artists to qualify as representative (and thus appear in Sound or Intro playlists) based on listening patterns.
Glenn McDonald, 2022
Limiting the data to the 2024 EDC artist list, of the 236 Artists, 43 are not assigned a genre. The missing genre information for 43 out of 236 artists presents a significant challenge for accurate data analysis and interpretation. While utilizing the API was intended to reduce biases, the gaps in data re-introduces unanticipated biases and limitations. Implementing an effective mitigation strategy and acknowledging these gaps may help in managing the impact and improve the the derived results… if the data was perfect beyond these holes.
Additionally, in completing spot checks there are uh… issues. The “backbone” will only return one artist, which is defaulted to the most popular artist. The issue is that DJ’s love to pick very commonplace names. In a run-through of the data, artists like IVY and Richter are returning popular artists with similar names and VASTLY different Genres.
Because the API did not return a genre for 42 out of a list of 220 artists, a significant data gap that can skew understanding of genre trends and popularity. This missing data limits ability to perform a comprehensive and accurate analysis, as it omits a considerable portion of the artist pool, potentially excluding emerging or niche genres that would be critical to understanding current music trends. Additionally, the current “backbone” approach of returning only the most popular artists may lead to a skewed perspective. Popularity does not necessarily equate to representativeness, as it can disproportionately highlight mainstream artists while neglecting those who may be influential within specific sub-genres or emerging scenes (Go Listen to Richter). I approached this project with the hope to have data-driven insights, so it is crucial for me to have a holistic view of artist and accurately captured genre information. Hopefully to ensure that insights are not biased by popularity metrics and reflect the true dynamics of the analysis I set out to achieve. I am going to resolve the following before continuing (should be around October when busy season ends for me – Where I plan on implementing a few mitigation ideas (searching by related artists or searching genres of several artists and returning by established “category”). Until then, please feel free to review the list below:
Artist | Artist Genre |
Abana | No genres found |
Acraze | pop dance, tech house |
Adam Beyer | dark techno, minimal techno, raw techno, schranz, swedish electronic, swedish techno, techno |
Adam X | dark techno |
Adrenalize | classic hardstyle, euphoric hardstyle, rawstyle |
Adventure Club | brostep, canadian electronic, complextro, edm, electro house, filthstep, pop dance |
Airwolf Paradise | australian house |
Alchimyst | No genres found |
Alesso | dance pop, edm, pop, pop dance, progressive electro house |
Alison Wonderland | aussietronica, edm, electra, electronic trap, escape room, indietronica |
Aly & Fila | dance pop, girl group, post-teen pop |
Andrew Bayer | progressive house, progressive trance, trance, uplifting trance |
Andrew Rayel | edm, moldovan pop, pop dance, progressive house, trance |
Andruss | mexican tech house, tech house |
Angerfist | hardcore techno, tekk, uptempo hardcore |
Argy | No genres found |
Armin Van Buuren | dutch trance, edm, pop dance, progressive house, trance |
Atliens | brostep, dubstep |
Atmozfears | classic hardstyle, euphoric hardstyle, rawstyle |
Audiofreq | classic hardstyle, euphoric hardstyle, rawstyle |
Azzecca | tech house |
Bec | latin pop, latin viral pop, rap latina, reggaeton, trap latino, urbano latino |
Ben Hemsley | uk house |
Ben Sterling | tech house, uk tech house |
Benny Benassi | dutch house, edm, electro house, pop dance |
Blastoyz | psychedelic trance |
Boogie T | brostep |
Bou | connecticut hardcore, metallic hardcore |
Brina Knauss | No genres found |
Bryan Kearney | trance, uplifting trance |
Calussa | afro house |
Camden Cox | stutter house |
Carl Cox | house, schranz, uk tech house |
Caspa | brostep, classic dubstep, filthstep, glitch hop |
Cassian | melodic house |
Chef Boyarbeatz | downtempo bass |
Chelina Manuhutu | dutch tech house |
Clawz | No genres found |
Crankdat | dubstep |
Creeds + Helen Ka | hypertechno |
Cristoph | house, melodic house, progressive house |
D-Sturb | classic hardstyle, euphoric hardstyle, frenchcore, rawstyle, xtra raw |
D. Zeledon | No genres found |
Da Tweekaz | classic hardstyle, euphoric hardstyle |
Dabin | canadian electronic, melodic dubstep, pop edm |
Darksiderz | No genres found |
David Guetta | big room, dance pop, edm, pop, pop dance |
Daxson | progressive trance |
Dead X | gym hardstyle |
Deadly Guns | frenchcore, uptempo hardcore |
Deadmau5 | canadian electronic, complextro, edm, electro house, pop dance, progressive house |
Death Code | No genres found |
Deborah De Luca | electra, italian techno |
Deeper Purpose | bass house, tech house, uk tech house |
Deorro | dutch house, edm, electro house, melbourne bounce, melbourne bounce international, pop dance, progressive electro house |
Devault | vapor twitch |
Devin Wild | classic hardstyle, euphoric hardstyle, rawstyle |
Dillon Francis | brostep, edm, electro house, moombahton, pop dance, progressive electro house, slap house |
Dimension | dancefloor dnb, drum and bass, uk dnb |
Diplo | dance pop, edm, electro house, moombahton, pop dance |
DJ Minx | detroit house |
DJ Snake | edm, electronic trap, pop, pop dance |
Dom Dolla | australian house, deep groove house, house |
Domina | No genres found |
Eli Brown | house, tech house, uk dance |
Emorfik | No genres found |
Eric Prydz | edm, electro house, house, pop dance, progressive electro house, progressive house |
Excision | brostep, canadian electronic, filthstep |
Fallen | No genres found |
Ferry Corsten | dutch trance, progressive house, progressive trance, trance, uplifting trance |
Fisher | australian house, house |
Four Tet | electronica, folktronica, indietronica, intelligent dance music, trip hop |
Fred Again | edm, house, stutter house |
Frosttop | No genres found |
Geo | contemporary country, country, country road |
Ghastly Presents Ghengar | No genres found |
Giuseppe Ottaviani | italian trance, progressive house, trance, uplifting trance |
Gravedgr | No genres found |
Green Velvet | deep disco house, house, minimal techno, tech house |
Gryffin | edm, pop dance |
Habstract | No genres found |
Hamdi | bassline |
Hannah Laing | No genres found |
Hedex | belgian dnb |
Heidi Lawden | No genres found |
Hi-Lo | dutch house, electro house, house |
Hivemind | No genres found |
Hixxy | deep happy hardcore, happy hardcore, hardcore techno |
Hol! | dubstep, gaming dubstep |
Honeyluv | tech house |
Hugel | deep house |
Illenium | edm, melodic dubstep, pop dance |
Indira Paganotto | No genres found |
Infected Mushroom | psychedelic trance |
Ivy | latin hip hop, rap latina, reggaeton, trap latino, urbano latino |
J. Worra | bass house, house, tech house |
Jamie Jones | deep disco house, deep house, house, minimal techno, uk tech house |
Jeanie | dubstep, speed house |
Jerome Isma-Ae | munich electronic, progressive house |
Jessica Audiffred | dubstep, mexican edm |
John 00 Fleming | No genres found |
John Summit | house, pop dance, uk dance |
Joluca | No genres found |
Jon Casey | south african electronic |
Joseph Capriati | italian techno, minimal techno, techno |
Joyryde | bass house, brostep, edm, electro house, electronic trap |
Kai Wachi | brostep, deathstep, dubstep |
Kasablanca | melodic house |
Kaskade | edm, electro house, pop dance, progressive electro house, progressive house, vocal house |
Kayzo | brostep, speed house |
Keltek | No genres found |
Kevin De Vries | dark techno |
Kevin Saunderson | acid house, detroit techno, minimal techno, techno |
Khiva | experimental bass |
Khomha | No genres found |
Klangkuenstler | dark techno, deep euro house, hard techno, raw techno |
Koven | chillstep, melodic dubstep |
Kream | pop dance |
Kreation | No genres found |
Kyle Walker | bass house, tech house |
Lady Faith | hardstyle |
Layz | dubstep |
Level Up | No genres found |
Levenkhan | No genres found |
Lf System | uk dance |
Lil Texas | No genres found |
Lilly Palmer | swiss techno |
Loco Dice | german techno, minimal techno, techno |
Lost Frequencies | belgian edm, edm, pop dance, tropical house |
Lsdream | No genres found |
Luttrell | melodic house, progressive house |
Maddix | big room |
Majestic | christian power metal, melodic metal, power metal, swedish power metal, symphonic metal |
Malóne | No genres found |
Mandy | dance pop, hollywood, neo mellow, post-teen pop |
Marauda | brostep, deathstep, dubstep, tearout |
Marcel Dettmann | microhouse, minimal techno, techno |
Markus Schulz | edm, pop dance, progressive house, progressive trance, trance |
Marsh | brostep, edm, pop, progressive electro house |
Martin Garrix | dutch edm, edm, pop, pop dance, progressive house |
Mary Droppinz | No genres found |
Matroda | bass house, electro house, tech house |
Matt Sassari | french tech house, french techno, tech house |
Mau P | tech house |
Max Styler | brostep, tech house |
Melé | uk house |
Mersiv | experimental bass |
Metta & Glyde | neo-classical |
Mind Against | deep techno, italian techno, melodic techno, minimal techno |
Miss Dre | tech house |
Mitis | chillstep, complextro, filthstep, melodic dubstep, pop edm |
Miyuki | No genres found |
Mk | experimental r&b |
Naz | album rock, classic rock, glam metal, hard rock, rock |
Nghtmre | brostep, edm, electro house |
Nicole Moudaber | arab electronic, deep minimal techno, electra, minimal techno, techno |
Nifra | progressive trance |
Nightstalker | No genres found |
Ninajirachi | aussietronica |
Noizu | bass house, house, tech house |
Odd Mob X Omnom: Hyperbeam | aussietronica, bass house, tech house |
Odd Mob | aussietronica, bass house, tech house |
Omar Santana | gabber |
Orjan Nilsen & Mark Sixma | progressive electro house, progressive house, trance, uplifting trance |
Ownboss | brazilian edm |
Paul Oakenfold | trance |
Paul Van Dyk | german techno, trance, uplifting trance |
Peggy Gou | electra, float house |
neo grime | |
Pryda | progressive electro house, progressive house |
Purple Disco Machine | deep house, house |
Rated R | dubstep, gaming dubstep |
Rayben | urbano mexicano |
Remk | No genres found |
Richter | classical, classical performance, classical piano, russian classical piano |
Riordan | tech house |
San Pacho | tech house |
Sara Landry | dark techno |
Seven Lions | brostep, complextro, dubstep, edm, electro house, melodic dubstep, pop dance, progressive trance |
Shiba San | bass house, fidget house, french tech house, house, tech house |
Shlømo | french techno, minimal dub |
Sicaria | No genres found |
Slander | dubstep |
Sofi Tukker | edm |
Soren | No genres found |
Sosa | chicago bop, chicago drill, chicago rap, drill, hip hop, rap, trap |
Sound Rush | classic hardstyle, euphoric hardstyle, rawstyle |
Steve Aoki | edm, electro house, pop dance |
Sub Focus | dancefloor dnb, drum and bass, uk dance |
Sub Zero Project | euphoric hardstyle, rawstyle |
Subtronics | brostep |
Svdden Death | deathstep, dubstep, riddim dubstep |
Talla 2Xlc | bubble trance, frankfurt electronic, german techno, trance |
Tape B | No genres found |
Taylor Torrence | No genres found |
Tiësto | big room, brostep, dutch edm, edm, house, pop dance, progressive electro house, slap house, trance |
Timmy Trumpet | australian dance, big room, melbourne bounce, melbourne bounce international |
Tobehonest | No genres found |
Troyboi | bass trap, electronic trap |
Trym | french techno |
Valentino Khan | brostep, edm, electro house, electronic trap, moombahton |
Vintage Culture | brazilian edm |
Virtual Riot | brostep, complextro, dubstep, filthstep, gaming dubstep |
VULLLGUR | riddim dubstep |
Wade | classic texas country, outlaw country, red dirt, texas country |
Warface | rawstyle, xtra raw |
Wasted Penguinz | classic hardstyle, euphoric hardstyle |
Water Spirit | speed house |
Wilkinson | dancefloor dnb, drum and bass, uk dance |
Will Clarke | bass house, house, tech house |
Wooli | brostep, dubstep |
Worship | roots worship, worship |
Wuki | No genres found |
Yosuf | gym hardstyle |
Yotto | finnish edm, melodic house, progressive house |
Zedd | complextro, edm, german techno, pop, pop dance |
Zingara | No genres found |
Zof | No genres found |
Zomboy | brostep, edm, glitch |
Zuezeu | No genres found |
Step 4: Pressing forward (for Database Practice)
Despite the data issues above, I want to get the database practice in. I used PostgresSQL to build my database. Review my PostgresSQL ERD (wonky lines included!) and my SQL to populate the data. I want to provide a write up on the lessons learned in this practice, such as how we change methodology from the sketch above and how i’m not sure if we are implementing best practices as it relates to constraints. As mentioned in the previous chapter, project will be on hold until October while I file my 3rd busy season client (always the auditors-maid, never the Analyst).
CREATE TABLE Artists (
ArtistID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
ArtistName VARCHAR(100) NOT NULL
);
-- Create Genres Table
CREATE TABLE Genres (
GenreID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
GenreName VARCHAR(100) NOT NULL
);
CREATE TABLE ArtistGenres (
ArtistID INT,
GenreID INT,
PRIMARY KEY (ArtistID, GenreID),
FOREIGN KEY (ArtistID) REFERENCES Artists(ArtistID),
FOREIGN KEY (GenreID) REFERENCES Genres(GenreID)
);
CREATE TABLE Stages (
StageID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
StageName VARCHAR(50) NOT NULL
);
CREATE TABLE Sets (
SetID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
ArtistID INT,
StageID INT,
SetTime TIME,
Date DATE,
FOREIGN KEY (ArtistID) REFERENCES Artists(ArtistID),
FOREIGN KEY (StageID) REFERENCES Stages(StageID)
);
INSERT INTO Stages (StageName) VALUES
('Stereobloom'),
('Kinetic Field'),
('Neon Garden'),
('Wasteland'),
('Basspod'),
('Circuit Grounds');
INSERT INTO Artists (ArtistName) VALUES
('Abana'), ('Acraze').....
INSERT INTO Genres (GenreName) VALUES
('acid house'),
('afro house'),
('album rock'),
('arab electronic').......
INSERT INTO Sets (ArtistID, StageID, SetTime, Date) VALUES
((SELECT ArtistID FROM Artists WHERE ArtistName = 'Abana'), (SELECT StageID FROM Stages WHERE StageName = 'Stereobloom'), '04:45', '2024-05-19'),
((SELECT ArtistID FROM Artists WHERE ArtistName = 'Acraze'), (SELECT StageID FROM Stages WHERE StageName = 'Kinetic Field'), '04:13', '2024-05-18').......