Details for spotify-find-bpm.ipynb

Published by gedankenstuecke


Find songs within a given range of BPM!


Tags & Data Sources

music tempo beats per minute Spotify integration


Please log in to comment.

Last updated 1 month, 1 week ago

Find Spotify tracks with a certain bpm

This Notebook requires you to have data from the Spotify integration in your Open Humans account.

With the notebook we want to look into

  • Which tracks are in a certain beats per minute range?

To get started we import some libraries we need and then access your spotify data

In [1]:
from ohapi import api
import os
import requests
import json
import pandas as pd
import datetime

member = api.exchange_oauth2_member(os.environ.get('OH_ACCESS_TOKEN'))
for f in member['data']:
    if f['source'] == 'direct-sharing-176' and f['basename'] == 'spotify-listening-archive.json':
        sp_songs = requests.get(f['download_url'])
    if f['source'] == 'direct-sharing-176' and f['basename'] == 'spotify-track-metadata.json':
        sp_meta = requests.get(f['download_url'])
sp_data = json.loads(sp_songs.content)
sp_metadata = json.loads(sp_meta.content)

Now that we got all of your data we want to transform the rather complex Spotify JSON format into something that is easier to read, a simple table - also called a dataframe. The lines below do this:

In [2]:
track_title = []
artist_name = []
album_name = []
played_at = []
popularity = []
duration_ms = []
explicit = []
track_id = []

tempo = []


for sp in sp_data:
def parse_timestamp(lst):
    timestamps = []
    for item in lst:
            timestamp = datetime.datetime.strptime(
        except ValueError:
            timestamp = datetime.datetime.strptime(
    return timestamps
played_at = parse_timestamp(played_at)

dataframe = pd.DataFrame(data={
    'track_id': track_id,
    'track': track_title,
    'artist': artist_name,
    'album': album_name,
    'popularity': popularity,
    'duration_ms': duration_ms,
    'explicit': explicit,
    'played_at': played_at,
    'tempo': tempo

dataframe = dataframe.set_index(dataframe['played_at'])

Tempo of the music we listen too

Let's have a look at which tempo the music we listen to plays:

In [18]:
%load_ext rpy2.ipython
The rpy2.ipython extension is already loaded. To reload it, use:
  %reload_ext rpy2.ipython
In [19]:
%%R -i dataframe -w 4 -h 2 --units in -r 200
ggplot(dataframe,aes(tempo)) + 
    geom_histogram(binwidth=5) + 
    scale_x_continuous('tempo') + 
    theme_minimal() + 
    geom_vline(xintercept=mean(dataframe$tempo),color='red') + ggtitle('red bar is average')

Now we can start filtering down the music to our own speed requirements. Change the bpm_range value below to the one you're looking for. The default value is 160 bpm and we will extract all songs within ±2 bpm of this target:

In [24]:
bpm_range = 160

Now we can start downsampling and look at the list of songs:

In [29]:
print('The following songs fall within the range in terms of bpm.\n')

print('The table gives track name, artist and BPM!\n')

k1 = dataframe[(dataframe.tempo >= bpm_range-2) & (dataframe.tempo <= bpm_range+2)]
k1 = k1 = k1[['artist','track', 'tempo']]
k1 = k1.drop_duplicates()
for index,row in k1.iterrows():
    print("{}\t{}\t{}".format(row['artist'], row['track'], row['tempo']))
The following songs fall within the range in terms of bpm.

The table gives track name, artist and BPM!

Radical Face	Always Gold - Acoustic	160.988
Sufjan Stevens	City of Roses	159.927
Bad Religion	All There Is	160.229
Elvis Perkins	While You Were Sleeping	161.889
Mipso	Get Out While You Can	160.097
Johnny Flynn	Tarp in the Prop	161.931
The Lumineers	Pretty Paper	159.613
Fiddler's Green	No Anthem	160.205
King Charles	Love Lust - New Master	159.94
Keaton Henson	You	158.407
The Lonely Heartstring Band	Just A Dream	161.89
Asaf Avidan	Sweet Babylon	159.424
Angus & Julia Stone	Yellow Brick Road	161.987
Mighty Oaks	So Low, So High	161.347
Kishi Bashi	A Sunday Smile (by Beirut)	159.675
Donovan Woods	Our Friend Bobby - Acoustic	159.802
Craig Cardiff	Dirty Old Town	159.764
Bat For Lashes	Feel For You	159.949
Eddie Vedder	Society	160.871
Skids	Desert Dust	159.431
Friendly Savages	Her Locket on a Chain	159.664
FKA twigs	holy terrain	159.832
PJ Harvey	The Whores Hustle And The Hustlers Whore	160.543
The Gaslight Anthem	Keepsake	158.016
The Cave Singers	Absalom	161.604
Bob Dylan	Shelter from the Storm - Live at Nippon Budokan Hall, Tokyo, Japan - February/March 1978	161.883
Matthew Perryman Jones	Can’t Get It Right	160.075
Of The Valley	Ride Alone	158.795
Fish & Bird	The Lake	161.973
Jack White	Freedom at 21	160.267
James Vincent McMorrow	We Don't Eat - Acoustic Version	158.838
Or, The Whale	Call and Response	160.636
Flogging Molly	Devil's Dance Floor - Live	158.765
Bad Religion	Queen Of The 21st Century	160.624
Patch and The Giant	Love and War	158.837