|
| 1 | +# 🎵 Pop Music Evolution 🎵 |
1 | 2 |
|
2 | | -# Technical Overview |
| 3 | +Project for the COM-480 Data Visualization course at EPFL. |
3 | 4 |
|
4 | | -Our Final workflow was as follows: |
| 5 | +> **Songs are getting shorter — about 13 seconds shorter on average over the last decade. And it is not a coincidence.** |
| 6 | +> **Genres are shifting.** Come interact with the data. |
5 | 7 |
|
6 | | -1. Scrap data from Spotify |
7 | | -2. Extract the relevant statistics to JSON |
8 | | -3. Create the HTML Skeleton for the website |
9 | | -4. Create the JS scripts for the visualization |
| 8 | +<p align="center"> |
| 9 | + <a href="https://com-480-data-visualization.github.io/MusicEnjoyers/">▶️ Go to the website</a> |
| 10 | +</p> |
10 | 11 |
|
| 12 | +## 🔴 Abstract |
11 | 13 |
|
12 | | -## Scrap the data from spotify |
| 14 | +Music listeners today pursue immediate satisfaction. Song intros are shorter than they used to be, artists race to the catchy hook before listeners hit "skip", and short-video platforms reward the most viral few seconds of a track. At the same time, scholars disagree on whether digital platforms are pushing popular music toward *convergence* (everything sounds alike) or *fragmentation* (endless niche genres). |
13 | 15 |
|
14 | | -All relevant scripts are in the folder "Scrapper". The core script is written in python and it connects the spotify data stored in source_files/Billboard_Top_100_songs_of_each_year_1950-2025.csv and connects it to the yearly files in source_files/billboard_data. |
| 16 | +This project turns those questions into an interactive, data-driven story about how pop music has evolved over the past decade. Using the Billboard Hot 100 enriched with Spotify/Deezer audio features, we visualize how the average song has shrunk by more than 10 seconds, how genres have shifted and clustered, and how musical features (energy, danceability, valence, tempo…) relate to one another — so you can explore the trends yourself. |
15 | 17 |
|
16 | | -While generating the data, the script will ignore already matched songs and only look at unmatched songs. We used this feature to run the script repeatedly while adjusting the strictness of the fuzzy matching. |
| 18 | +## 👨👩👧 Target audience |
17 | 19 |
|
18 | | -## Extract the relevant statistics to JSON |
| 20 | +Anyone curious about music and how it has changed: casual listeners who want to *see* why songs feel shorter today, and data-minded readers who want to dig into genre dynamics and audio features. |
19 | 21 |
|
20 | | -In order to serve this data to a website, we extracted the information we want to display in seperate scripts in ./scripts/ and made severable json files stored in ./docs/data. This way the website does not have to do any real computation when loading the page. |
| 22 | +## 🚀 Project structure |
21 | 23 |
|
22 | | -## Create the Website |
| 24 | +``` |
| 25 | +├── basic_statistics.ipynb Exploratory data analysis (Milestone 1) |
| 26 | +├── Scrapper/ Data collection |
| 27 | +│ ├── scrapper.py Matches Billboard songs to Spotify track data (fuzzy matching) |
| 28 | +│ ├── source_files/ Billboard Hot 100 source data |
| 29 | +│ └── results/ Matched / unmatched track ids |
| 30 | +├── scripts/ Build JSON stats served to the website |
| 31 | +├── scripts_billboard_related/ Billboard enrichment helpers |
| 32 | +├── docs/ The website (served via GitHub Pages) |
| 33 | +│ ├── index.html Page skeleton |
| 34 | +│ ├── *.css Styles |
| 35 | +│ ├── scripts/ Visualization JS (such as D3) |
| 36 | +│ └── data/ Pre-computed JSON consumed by the visualizations |
| 37 | +└── Milestones_README.md Detailed milestone write-ups & deliverables |
| 38 | +``` |
23 | 39 |
|
| 40 | +## 💻 Running the website locally |
24 | 41 |
|
25 | | -All files used by our website are in ./docs. It follows a simple layout, where the html and css file are in the first level and all our JS-scripts are in ./docs/scripts and the data used by those scripts are in ./docs/data. |
| 42 | +The website is fully static — everything lives in `docs/`. To run it locally: |
26 | 43 |
|
27 | | -The java script in particular: |
| 44 | +```bash |
| 45 | +cd docs |
| 46 | +python3 -m http.server 8000 |
| 47 | +``` |
| 48 | + |
| 49 | +Then open <http://localhost:8000> in your browser. |
| 50 | + |
| 51 | +> **Tip:** if you changed a JS/CSS file but don't see the update, hard-refresh to bust the cache: |
| 52 | +> `Ctrl + Shift + R` (Linux/Windows) or `Cmd + Shift + R` (macOS). |
| 53 | +
|
| 54 | +Press `Ctrl + C` to stop the server. If port 8000 is stuck in use: |
| 55 | + |
| 56 | +```bash |
| 57 | +lsof -i :8000 |
| 58 | +kill <PID> |
| 59 | +``` |
| 60 | + |
| 61 | +## 💿 Dataset |
| 62 | + |
| 63 | +We build on two main sources: |
| 64 | + |
| 65 | +- **[Billboard Hot 100](https://github.com/mhollingshead/billboard-hot-100)** — a widely-used measure of mainstream popularity, ranking songs by streaming, radio play, and sales. It identifies *which* songs were popular and *when*. |
| 66 | +- **Spotify / Deezer audio features** — release date, duration, genres, and audio attributes (energy, danceability, loudness, valence, tempo, …) used to characterize *how* the music sounds. |
| 67 | + |
| 68 | +Our processed dataset covers Billboard Hot 100 songs over the last decade (2016–2025), each with 16 attributes. |
| 69 | + |
| 70 | +## ⚙️ Technical overview |
| 71 | + |
| 72 | +Our workflow: |
| 73 | + |
| 74 | +1. **Scrape the data.** `Scrapper/scrapper.py` connects the Billboard list (`source_files/Billboard_Top_100_songs_of_each_year_1950-2025.csv`) to the yearly files in `source_files/billboard_data` and enriches each song with Spotify track data. The script skips already-matched songs and only processes unmatched ones, so we could run it repeatedly while loosening the fuzzy-matching strictness. |
| 75 | +2. **Extract statistics to JSON.** The scripts in `scripts/` (and `scripts_billboard_related/`) pre-compute everything the page needs and write JSON files into `docs/data/`. This keeps the website fast — no heavy computation happens in the browser. |
| 76 | +3. **Build the website.** `docs/index.html` provides the skeleton; the CSS files style it; and the visualizations in `docs/scripts/` (`dashboard.js`, `genres.js`, `heatmap.js`, `duration.js`, `dj_knob.js`, `scroll.js`) read from `docs/data/` to render the interactive charts. |
| 77 | + |
| 78 | +## 📍 Milestones |
| 79 | + |
| 80 | +Detailed write-ups, the exploratory data analysis, and all deliverables (PDFs) are in **[Milestones_README.md](Milestones_README.md)**. |
| 81 | + |
| 82 | +- **Milestone 1** — Proposal & EDA: [Milestone 1.pdf](./Milestone%201.pdf) |
| 83 | +- **Milestone 2** — Functional prototype: [Milestone2_MusicEnjoyers.pdf](./Milestone2_MusicEnjoyers.pdf) |
| 84 | +- **Milestone 3** — Final project: [Milestone 3.pdf](./Milestone%203.pdf) |
| 85 | + |
| 86 | +## 📽 Screencast |
| 87 | + |
| 88 | +A screencast of the project is included in the repository: [datavis_cut.mp4](./datavis_cut.mp4). |
| 89 | + |
| 90 | +## 🤝 Authors |
| 91 | + |
| 92 | +| Name | SCIPER | |
| 93 | +| ---- | ------ | |
| 94 | +| Hsieh Wei-En | 341271 | |
| 95 | +| Li An-Jie | 424517 | |
| 96 | +| Rohner Kenji | 425036 | |
| 97 | +</content> |
| 98 | +</invoke> |
0 commit comments