The Rolling Stones Tour

Po wolnej musi być szybka, takie są zasady muzykowania pada na koncertowej płycie Bolilol Tour zespołu Illusion. Sprawdźmy czy tak jest na koncertach… …ale nie dokładnie to sprawdzimy. Inspiracją dla niniejszego postu jest wpis z 2011 roku o utworach granych przez Metallicę na koncertach, szczególnie infografika, o której ów wpis jest. Infografika przedstawia popularność piosenek granych na koncertach. Skoro ktoś mógł to zrobić, to dlaczego nie ja? Instrukcja jak zrobić to samo poniżej. Za źródło danych posłuży serwis Setlist.fm, w którym znaleźć można całą masę informacji o koncertach - przede wszystkim datę, miejsce i to co najbardziej interesująca - lista utworów. Dane pobierać będziemy przez API, do którego potrzebny jest klucz. Po założeniu konta w serwisie możemy sobie taki wygenerować. Z API rozmawiamy JSONem - dlatego poniżej biblioteka jsonlite oraz RCurl do odpytywania tegoż API.

library(tidyverse)
library(RCurl)
library(jsonlite)
library(lubridate)

Warto opanować te dwie biblioteki - pozwalają na obsługę każdego API. Są oczywiście inne, które w swoich bebechach wykorzystują JSON/curl. Ale wracając do tematu - w zmiennej api_KEY trzymamy klucz API (własnego oczywiście nie zdradzam). Kim się zajmiemy? Czyimi występami? Była mała sonda na facebookowej stronie Dane i Analizy ale bez odzewu. Polubcie tego fanpage, warto! Ja poszedłbym chętnie jeszcze raz na Stonesów (byłem na Służewcu w Warszawie, w 2007 roku) - niech będą oni. Nadają się idealnie. Cała komunukacja z Setlist.fm opiera się o numery ID. Czy to wykonawców, czy to koncertów. Potrzebujemy więc ID dla The Rolling Stones:

artist_name <- "The Rolling Stones" # w zmiennej, żeby było uniwersalnie 

# zapytanie do API
json_page <- getURL(paste0("https://api.setlist.fm/rest/1.0/search/artists?artistName=", gsub(" ", "+", artist_name)),
                    httpheader = c(Accept = "application/json",
                                   "x-api-key" = api_KEY),
                    verbose = FALSE)

# wynik przekształcamy z JSONa na data.frame
df <- fromJSON(json_page, flatten = TRUE)

# potrzebny mbid szukanego artysty
# (w wynikach mamy więcej artystów z szukanym ciągiem znaków)
artist_mbid <- df$artist %>%
   filter(tolower(name) == tolower(artist_name)) %>%
   select(mbid) %>%
   .[1,1]

Mamy numerek ID, możemy pobierać listę koncertów. Odpowiedź z API jest stronicowana, po 20 wyników. Musimy więc przejść przez wszystkie strony - zrobi to poniższa pętla. Dla każdego zwróconego występu (upakowanego w listę - w JSONie wygląda to logicznie, w R potrzeba nieco gimnastyki) mamy kilka informacji, wybierzemy te interesujące. Każdą kolejną stronę wyników wyszukiwania dodajemy do tabeli z pełnymi danymi.

# kilka zmiennych kontrolujących stronicowanie i pętlę
page_no <- 1
totals <- 1
liczba_stron <- totals + 1
tour_info <- tibble()

# pętla
while(totals < liczba_stron) {
   # zapytanie do API o kolejną stronę
   base_url <- paste0("https://api.setlist.fm/rest/1.0/search/setlists?artistMbid=", artist_mbid, "&p=", page_no)
   
   # wywołanie zapytania
   json_page <- getURL(base_url,
          httpheader = c(Accept = "application/json",
                         "x-api-key" = api_KEY),
          verbose = FALSE)
   
   # przekształcenie na data.frame
   df <- fromJSON(json_page, flatten = TRUE)

   # interesujące nas dane o występie
   tour_info_tmp <- df$setlist %>%
      unnest(sets.set) %>%
      select(data = eventDate,
             miejsce = venue.name,
             miasto = venue.city.name, kraj = venue.city.country.name,
             long = venue.city.coords.long, lat = venue.city.coords.lat, song) %>%
      unnest(song) %>%
      select(data, miejsce, miasto, kraj, long, lat, piosenka = name)
   
   # dołączamy do dużej tabeli
   tour_info <- bind_rows(tour_info, tour_info_tmp)

   # liczba koncertów - kontrola ilości wykonań pętli
   liczba_stron <- df$total
   totals <- totals + df$itemsPerPage

   # kolejna strona
   page_no <- page_no + 1
}

# daty w przyjaznym formacie
tour_info$data <- dmy(tour_info$data)

# usuwamy ewentualne duplikaty
# (jeśli piosenka była grana dwa razy na koncercie tracimy tę informację!)
tour_info <- distinct(tour_info)

Na koniec w danych mamy informację o:

  • dacie koncertu
  • miejscu (nazwa stadionu, klubu)
  • mieście i kraju (z niezrozumiałych dla mnie przyczyn są to jakieś niemieckie nazwy - pozostaniemy przy nich)
  • długość i szerokość geograficzną miejsca występu (albo raczej miasta - Sala Kongresowa, gdzie Rolling Stones grali w 1967 roku i Tor na Służewcu z 2007 roku mają te same parametry)
  • tytuł piosenki

Utwory ułożone są w kolejności grania, zatem nie ruszamy kolejności danych w tabeli! Sprawdźmy na początek gdzie odbywały się koncerty The Rolling Stones?

# mapka świata - kontury państw
world_map <- map_data("world") %>%
   ggplot() +
   geom_polygon(aes(long, lat, group=group), fill=NA, color="gray")

# miejsca koncertów
tour_places <- tour_info %>%
   select(data, long, lat, kraj, miasto, miejsce) %>%
   distinct() %>%
   group_by(long, lat) %>%
   mutate(ntimes = n()) %>%
   ungroup()

# mapa
world_map + geom_point(data = tour_places,
                       aes(long, lat, color=ntimes, size=ntimes),
                       alpha = 0.5, show.legend = FALSE) +
   scale_color_gradient(low = "red", high="yellow")

Im większy i bardziej żółty punkt tym więcej koncertów było w tym miejscu. Tak, wiem że tak się nie robi (nie pokazuje się dwoma cechami tej samej wartości na jednym wykresie). Widać, że starsi panowie grali głównie w Europie, Stanach, Australii i Japonii. W Ameryce Południowej na wielkie koncerty można liczyć w Buenos Aires w Argentynie oraz Rio de Janeiro i Sao Paolo w Brazylii. Najwięcej koncertów Stonesi dali w Londynie (48 - właściwie co rok), Nowym Jorku (43), Tokio (29), Chicago (28), Toronto (24), Filadelfii (22) i Paryżu (21). Jeśli zaś chodzi o poszczególne kraje to 541 (to 46.8% wszystkich! pamiętajcie, że zespół jest brytyjski) koncertów odbyło się w USA, 99 (tak, to drugie miejsce na liście! 8.6%) w UK, 92 w Niemczech. Japonia załapała się na 6 miejsce z 39 koncertami. W Polsce jak wiemy były trzy koncerty: dwa już wspomniane w Warszawie oraz trzeci na Stadionie Śląskim w Chorzowie (w 1998 roku). Taką samą mapkę, tyle tylko że interaktywną można zrobić korzystając z biblioteki leaflet. Nie zobaczysz jej, jeśli nie przećwiczysz opublikowanych tutaj kodów źródłowych. Oto kod:

library(leaflet)

leaflet(data = tour_places) %>%
   addTiles() %>%
   addMarkers(~long, ~lat,
              clusterOptions = markerClusterOptions(),
              popup = ~paste0("<strong>", miasto, "</strong><br/>", miejsce, "<br/>", data))

Wiemy gdzie, ale ciekawe jest co było grane? Zobaczmy najpopularniejsze 30 piosenek zagranych na koncertach. Ale nie tylko ich listę, ale też kiedy dany kawałek był grany.

# 30 top piosenek
top_songs <- tour_info %>%
   count(piosenka) %>%
   ungroup() %>%
   top_n(30, wt = n) %>%
   arrange(desc(n))

inner_join(tour_info, top_songs, by = "piosenka") %>%
   group_by(piosenka) %>%
   # data pierwszego wykonania na żywo
   mutate(mdata = min(data)) %>%
   ungroup() %>%
   arrange(desc(mdata), data) %>%
   # kolejność na osi
   mutate(piosenka = factor(piosenka, levels = unique(piosenka))) %>%
   ggplot() +
   geom_jitter(aes(data, piosenka, color=piosenka),
               height = 0.3, show.legend = FALSE)

Piosenki ułożone są według daty pierwszego wykonania live. Widać ciekawostki:

  • moja ulubiona Paint It Black nie była grana na koncertach przez jakieś 20 lat! Do stałego repertuaru weszła na trasach od połowy lat dwutysięcznych. Podobnie Ruby Tuesday

  • Out of Control w drugiej połowie lat ’90 było mocno eksploatowanym hitem (pamiętam teledysk - właśnie koncertowy, Mick Jagger w takiej srebrnej błyszczącej kurteczce)

  • właściwie w top 30 nie ma piosenek nie granych na ostatnich koncertach. Trochę jest tak, że Stonesi w ostatnich latach odcinają kupony i jadą na największych hitach. Ale tak bywa z zespołami z tak długim stażem (i tak dużą średnią wieku).

Zobaczmy to samo, ale dla pełnej listy wykonanych piosenek:

tour_info %>%
   group_by(piosenka) %>%
   mutate(mdata = min(data)) %>%
   ungroup() %>%
   arrange(desc(mdata), data) %>%
   mutate(piosenka = factor(piosenka, levels = unique(piosenka))) %>%
   ggplot() +
   geom_jitter(aes(data, piosenka, color=piosenka),
               height = 0.2, show.legend = FALSE, alpha = 0.4)
   scale_x_date(date_breaks = "5 years", date_labels = "%Y")

Wyraźnie widać, że były trasy promujące konkretne płyty. Na przykład piosenki grane po raz pierwszy w okolicach 1975-1978 roku nie były grane później. Trasa ze wspomnianym Out of Control to trasa promująca płytę Bridges to Babylon zawierającą między innymi utwory (z tych bardziej znanych): Anybody Seen My Baby? czy Saint of Me - te jeszcze się powtarzają póżniej. Ale You Don’t Have to Mean It czy pierwszy na płycie Flip the Switch nie pojawiają się na kolejnych koncertach (trasach). Jak długie są koncerty? Nie uda nam się policzyć czasu trwania w minutach, ale możemy sprawdzić ile piosenek było zagranych na kolejnych koncertach.

tour_info %>%
   count(data) %>%
   ggplot() +
   geom_jitter(aes(data, n), width = 0.4, alpha = 0.4) +
   geom_smooth(aes(data, n), method = "loess", color = "red")

Kiedy Rolling Stones byli już niekwestionowaną gwizadą i mieli jeszcze dużo siły - czyli w latach ’80 i ’90 grali najwięcej utworów. Póżniej ograniczyli się do około 20. Porównując te dane z wykresem poniżej

tour_info %>%
   select(data) %>%
   distinct() %>%
   mutate(rok = year(data)) %>%
   count(rok) %>%
   ggplot() +
   geom_bar(aes(rok, n), stat="identity")

można próbować wysnuć wniosek, że koncertów jest więcej, ale przez to są krótsze - trzeba się oszczędzać. 81 koncertów rocznie to szczyt z 2003 roku. Wychodzi średnio koncert co pięć dni. A jeśli weźmiemy pod uwagę przemieszczanie się (z nie taką wcale małą machiną koncertową) po świecie (2003 to m.in. Europa, Australia, Hongkong, Indie, Japonia, Kanada oraz USA) oraz fakt, że w maju 2003 oraz grudniu nie było żadnego koncertu to robi się niezły wysiłek. A lata już nie te (w 2003 zespół miał już średnią wieku bliską sześćdziesiątki: Jagger oraz Richards po 60 lat, Watts 62, a Wood 56). Sprawdźmy jeszcze czy trasy koncertowe są sezonowe, czyli czy koncerty częściej są grane latem niż zimą? Zobaczymy to po średniej liczbie koncertów w danym miesiącu:

tour_info %>%
   select(data) %>%
   distinct() %>%
   mutate(miesiac = month(data), rok=year(data)) %>%
   count(rok, miesiac) %>%
   ungroup() %>%
   group_by(miesiac) %>%
   summarise(n=mean(n)) %>% 
   ungroup() %>%
   ggplot() +
   geom_bar(aes(miesiac, n), stat="identity") +
   scale_x_continuous(breaks = 1:12)

A może sezonowość ma związek z miejscem, w którym grany jest koncert?

tour_info %>%
   select(data, kraj) %>%
   distinct() %>%
   mutate(miesiac = month(data)) %>%
   count(miesiac, kraj) %>%
   ungroup() %>%
   group_by(kraj) %>%
   mutate(n = 100*n/sum(n)) %>%
   ungroup() %>%
   ggplot() +
   geom_tile(aes(miesiac, kraj, fill=n), color="white", show.legend=FALSE) +
   scale_fill_gradient(low = "red", high="yellow") +
   geom_text(aes(miesiac, kraj, label=sprintf("%.0f%%", n)), color = "black") +
   scale_x_continuous(breaks = 1:12)

Półkula południowa (Australia, Argentyna i Nowa Zelandia) na początku roku ma cieplejszą pogodę, co sprzyja koncertom na stadionach (oraz Nowa Zelandia jest blisko Australii, nie trzeba latać dwa razy; podobnie jest z Singapurem). W Europie koncerty przypadają na miesiące od połowy roku (czyli znowu cieplej). Wrócmy do popularności piosenek na koncertach - w jakiej części koncertów grana była konkretna piosenka? Biorąc pod uwagę wszystkie koncerty (nawet te, przed powstaniem piosenki…) mamy:

# liczba wszystkich koncertów
nevents_all <- tour_info %>% distinct(data) %>% nrow()

# popularność piosenki = procent koncertów, na których została zagrana
song_popularity <- tour_info %>%
   group_by(piosenka) %>%
   summarise(p_song = 100 * n() / nevents_all) %>%
   ungroup() %>%
   select(piosenka, p_song) %>%
   arrange(desc(p_song))
   
song_popularity %>%
   top_n(30, wt = p_song) %>%
   arrange(p_song) %>%
   mutate(piosenka = factor(piosenka, levels=piosenka)) %>%
   ggplot() +
   geom_bar(aes(piosenka, p_song), stat="identity") +
   coord_flip()

Są ewidentne hity, można powiedzieć że to żelazny repertuar. Ale narzućmy ograniczenie, które jest dość oczywiste: piosenka nie mogła być zagrana na koncercie zanim nie powstała (czyli w latach ’70 Out of Control nie mogło być grane). Tak więc na ilu koncertach piosenka była grana licząc od pierwszego wykonania?

# kolejne numery koncertów
tour_info$event_num <- group_indices(tour_info, data)

events_nums <- tour_info %>% select(data, event_num) %>% distinct()

# udział piosenki w koncertach
# na ilu koncertach piosenka była grana licząc od pierwszego wykonania?
song_popularity_corr <- left_join(tour_info %>%
             select(data, piosenka) %>%
             group_by(piosenka) %>%
             mutate(n_song = n()) %>%
             ungroup(),
          events_nums,
          by = "data") %>%
   mutate(n_events = nevents_all - event_num) %>%
   group_by(piosenka) %>%
   filter(n_events == max(n_events)) %>%
   ungroup() %>%
   mutate(p = 100 * n_song / n_events) %>%
   select(piosenka, p) %>%
   arrange(desc(p)) %>%
   filter(p <= 100)

song_popularity_corr %>%
   top_n(30, wt = p) %>%
   arrange(p) %>%
   mutate(piosenka = factor(piosenka, levels = piosenka)) %>%
   ggplot() +
   geom_bar(aes(piosenka, p), stat="identity") +
   coord_flip()

Nastąpiło pewne przetasowanie, ale hity trzymają się mocno. Pierwsze pięć utworów jest prawie pewne na każdym koncercie. Paint it Black grają mniej więcej raz na trzy koncerty - trzeba więc mieć szczęście. Z koncertu w 2007 roku pamiętam, że zaczął się Start Me Up i zakończył Satisfaction. I to było normalne - tak wówczas Stonesi mieli ułożoną setlistę. Klaskanie i wołanie na bis po Satisfaction nie miało sensu. Ale czy to prawda? Policzmy średnią (i przy okazji medianę oraz liczbę koncertów) z kolejności utworu podczas koncertu i na tej podstawie ułóżmy taką teoretyczną setlistę (z 2007 roku):

tour_info %>%
   # bierzemy tylko występy z 2007 roku
   filter(year(data) == 2007) %>%
   select(data, piosenka) %>%
   group_by(data) %>%
   mutate(n = row_number()) %>%
   ungroup() %>%
   group_by(piosenka) %>%
   summarise(mean_n = mean(n), median_n = median(n), lp = n()) %>%
   ungroup() %>%
   # bierzemy tylko utwory, które były zagrane na co najmniej połowie koncertów
   filter(lp >= quantile(lp, 0.5)) %>%
   arrange(mean_n)
piosenkamean_nmedian_nlp
Start Me Up1.000000131
Let’s Spend the Night Together2.000000211
You Got Me Rocking2.750000220
Rough Justice3.357143328
All Down the Line4.000000410
Rocks Off4.00000047
Bitch4.14285747
She’s So Cold4.28571457
Ain’t Too Proud to Beg4.50000046
Ruby Tuesday5.57142967
You Can’t Always Get What You Want5.785714614
Midnight Rambler6.823529717
Can’t You Hear Me Knocking7.000000712
I’ll Go Crazy7.928571828
Tumbling Dice8.806452931
You Got the Silver9.8461541026
Wanna Hold You10.6785711128
Miss You11.5217391223
It’s All Over Now11.666667136
It’s Only Rock ‘n’ Roll (But I Like It)12.0000001330
(I Can’t Get No) Satisfaction14.3870971431
Honky Tonk Women14.8333331530
Sympathy for the Devil15.7666671630
Paint It Black16.8461541726
Jumpin’ Jack Flash17.7096771831
Brown Sugar18.2903231931

Sprawdźmy jak było na Służewcu:

npiosenka
1Start Me Up
2You Got Me Rocking
3Rough Justice
4Ain’t Too Proud to Beg
5Love Is Strong
6You Can’t Always Get What You Want
7Midnight Rambler
8I’ll Go Crazy
9Tumbling Dice
10You Got the Silver
11Wanna Hold You
12Miss You
13It’s Only Rock ‘n’ Roll (But I Like It)
14Get Off of My Cloud
15Honky Tonk Women
16Paint It Black
17Jumpin’ Jack Flash
18Brown Sugar
19(I Can’t Get No) Satisfaction

Części piosenek nie ma (żałuję braku Sympathy for the Devil), a coś co średnio biorąc wygląda na bisy (jest po Satisfaction) zagrane zostało wcześniej. To samo możemy zrobić dla wszystkich lat (wyniku oszczędzę - do przećwiczenia w domu):

tour_info %>%
   select(data, piosenka) %>%
   group_by(data) %>%
   mutate(n = row_number()) %>%
   ungroup() %>%
   mutate(rok = year(data)) %>%
   group_by(rok, piosenka) %>%
   summarise(mean_n = mean(n), median_n = median(n), lp = n()) %>%
   ungroup() %>%
   by(.,
      .$rok,
      function(x) x %>%
         filter(lp > quantile(lp, 0.5)) %>%
         arrange(mean_n)
   )

A czy piosenki zmieniały kolejność z upływem czasu i kolejnymi koncertami? Obserwując reakcję publiczności (i własną bo wiadomo przecież, że kondycja po sześćdziesiątce już nie ta, no i z palmy można spaść…) można sterować zachowaniem - jak się nudzą za bardzo przy nowym materiale to trzeba wstawić w środek ze trzy hity dla podkręcenia. Na koniec też hity, żeby wyszli zadowoleni z koncertu mając w głowie łoooo, ale dali czadu na koniec! i zagrali…. Po wolnej musi być szybka, takie są zasady muzykowania, pamiętacie?

tour_info %>%
   select(data, piosenka) %>%
   group_by(data) %>%
   mutate(l = row_number()/n()) %>%
   ungroup() %>%
   inner_join(top_songs, by = "piosenka") %>%
   mutate(data = as.POSIXct(data)) %>%
   ggplot() +
   geom_point(aes(data, l), alpha = 0.3, show.legend = FALSE) +
   geom_smooth(aes(data, l, color = piosenka),
               show.legend = FALSE, method="loess", se = FALSE) +
   facet_wrap(~piosenka, ncol = 5, scales = "free_x") +
   scale_y_reverse() +
   scale_x_datetime(date_labels = "%m / %Y") +
   theme(axis.text.x = element_text(angle = 90, hjust = 0))

Widać, że Satisfaction grane było głównie na końcu koncertów (w imię tezy łooo… zagrali na koniec Satisfaction i rzeczywiście mało mi!). Ciekawa jest pozycja Start Me Up w latach po 2010: raz na początku (ma to sens ze względu na tekst, podobnie na początek pasuje Let’s Spend the Night Together - obie piosenki otwierają uśrednioną setlitę z 2007 roku), a raz na końcu. Co jeszcze można zrobić z tymi danymi? Z tymi z Setlist.fm już chyba niewiele. Ale można dadać do nich informacje ze Spotify (polecam zerknąć do wpisu o badaniu czy pora roku wpływa na wybór słuchanej muzyki - tak gdzieś od połowy zaczyna się fragment interesujący nas w tym kontekście) o poszczególnych utworach - szczególnie parametry danceability, energy, tempo oraz valence. Na ich podstawie możemy ustalić czy po wolnej jest szybka. Można dodać też informacje o liczbie widzów na poszczególnych koncertach oraz o wpływach (cash, honey, cash!) za bilety. Znalazłem takie dane dla trasy Bridges to Babylon Tour ale nie ma ich dla wszystkich tras. Swoją drogą łączny przychód z tej trasy to prawie 250 milionów dolarów i 4.5 miliona sprzedanych biletów (średnio 55 dolców za bilet). Mając dane o pieniądzach i utworach możemy pokusić się o policzenie ile warta jest każda z piosenek wykonana na koncercie (wartość koncertu dzielona przez liczbę piosenek - tak dla każdego koncertu i każdej piosenki, a później średnia z wartości po piosenkach). W ten sposób można ułożyć setlistę najbardziej dochodowego koncertu. Tylko, że to jest bez sensu (chociaż ciekawe). Przecież koncert jest w danym mieście zazwyczaj tylko raz podczas trasy, a ludzie kupują bilety na zespół a nie na konkretne piosenki. Jeśli przyjdzie Wam do głowy jakieś inne zastosowanie tego typu danych - dajcie znać w komentarzu, podlinkujcie do swoich opracowań. Przedstawiony kod jest na tyle uniwersalny, że pozwoli na przygotowanie podobnych danych dla innych wykonawców. A przygotowane przeze mnie wykresiki znajdziecie zapewne w najbliższym czasie na fanpage’u Dane i Analizy.