library(tidyverse)
library(gt)
This data was extracted from the NBA’s Voting results for 2019 NBA All-Star Game starters using Thomas J. Leeper’s tabulizer package.1
I’m not gonna run through it here, but I used some tricks from a tutorial by Bruno Rodrigues to make getting the PDFs for each of the four categories (Eastern Conference Frontcourt, Eastern Conference Guards, Western Conference Frontcourt, Western Conference Guards) a bit easier.
######### Code in this chunk is not being run ##########
conference <- c("Eastern", "Western")
court <- c("Frontcourt", "Guard")
asg_combos <- crossing(conference, court) %>%
mutate(filename = glue::glue("2019-{conference}-Conference-{court}-NBA-All-Star-Starter-Voting-Results"))
# create vector of filenames
filenames <- asg_combos$filename
# build urls
urls <- glue::glue("https://ak-static.cms.nba.com/wp-content/uploads/sites/46/2019/01/{filenames}.pdf")
# build PDF names
pdf_names <- glue::glue("{filenames}.pdf")
# download PDFs
walk2(urls, pdf_names, download.file, mode = "wb")
# use tabulizer to extract data from pages e.g.
out1 <- extract_tables(pdf_names[4], output = "data.frame", pages = 1)
# and get the contents into a data frame
df_p1 <- out1[[1]]
After a little bit of wrangling, I ended up with a single data frame, asg_votes
(ASG stands for All-Star Game), which looks like this:
asg_votes <- read_csv(here::here("data", "ASG", "asg_votes.csv"))
glimpse(asg_votes)
## Observations: 491
## Variables: 16
## $ player <chr> "Giannis Antetokounmpo", "Kawhi Leonard", "Jo…
## $ team_slug <chr> "MIL", "TOR", "PHI", "BOS", "PHI", "DET", "TO…
## $ player_total_votes <dbl> 269, 189, 186, 19, 51, 50, 16, 11, 21, 17, 18…
## $ player_rank <dbl> 1, 2, 3, 7, 4, 5, 10, 12, 6, 9, 8, 22, 12, 25…
## $ fan_total_votes <dbl> 4375747, 3580531, 2783833, 1002885, 907775, 8…
## $ fan_rank <dbl> 1, 2, 3, 4, 5, 6, 8, 7, 12, 13, 14, 10, 17, 1…
## $ media_total_votes <dbl> 99, 99, 99, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, …
## $ media_rank <dbl> 1, 1, 1, 4, 7, 7, 4, 7, 7, 4, 7, 7, 7, 7, 7, …
## $ weighted_score <dbl> 1.00, 1.75, 2.50, 4.75, 5.25, 6.00, 7.50, 8.2…
## $ conference <chr> "eastern", "eastern", "eastern", "eastern", "…
## $ court <chr> "frontcourt", "frontcourt", "frontcourt", "fr…
## $ conf_court <chr> "eastern frontcourt", "eastern frontcourt", "…
## $ player_name_team <chr> "Antetokounmpo, Giannis -- MIL", "Leonard, Ka…
## $ player_name <chr> "Antetokounmpo, Giannis", "Leonard, Kawhi", "…
## $ last_name <chr> "Antetokounmpo", "Leonard", "Embiid", "Tatum"…
## $ first_name <chr> "Giannis", "Kawhi", "Joel", "Jayson", "Jimmy"…
That player_name_team
variable comes from the original input from the PDF. Using stringr to extract the last three characters for the team slugs, and everything but the last eight characters for the player names worked in most cases.
# get team slug
stringr::str_sub(x, start = -3)
# get player name
stringr::str_sub(x, end = -8)
But, there were a few outliers where players have changed teams during the season (e.g. see Kenneth Faried and Justin Holiday’s entries below), or aren’t currently with a team, so I wanted to keep the original data around just in case.
Atypical data in Eastern Conference Frontcourt voting results for 2019 NBA All-Star Game
Now let’s recreate the top 10 tables they have in the official release, NBA All-Star 2019 starters, captains revealed, using the gt package by Rich Iannone.
asg_votes %>%
filter(conf_court == "western frontcourt") %>%
arrange(weighted_score) %>%
mutate(rank = row_number()) %>%
filter(rank <= 10) %>%
select(rank, player, team_slug, fan_rank, player_rank, media_rank, weighted_score) %>%
gt() %>%
tab_header(
title = md("**Western Conference Frontcourt**"),
subtitle = glue::glue("NBA All-Star Voting 2019 Results")
) %>%
cols_label(rank = md("**Rank**"),
player = md("**Player Name**"),
team_slug = md("**Team**"),
fan_rank = md("**Fan Rank**"),
player_rank = md("**Player Rank**"),
media_rank = md("**Media Rank**"),
weighted_score = md("**Weighted Score**")) %>%
tab_source_note(md("source: [nba.com](http://www.nba.com/article/2019/01/24/2019-nba-all-star-starters-revealed-official-release)")) %>%
tab_footnote(
footnote = "Voted to start",
locations = cells_data(
columns = vars(player),
rows = 1:3)
) %>%
tab_footnote(
footnote = "Team captain",
locations = cells_data(
columns = vars(player),
rows = 1)
) %>%
tab_footnote(
footnote = "Tiebreaker for starting spot is fan rank",
locations = cells_data(
columns = vars(weighted_score),
rows = 3:4)
) %>%
tab_options(footnote.glyph = c("*, †, ‡"))
Western Conference Frontcourt | |||||||
---|---|---|---|---|---|---|---|
NBA All-Star Voting 2019 Results | |||||||
Rank | Player Name | Team | Fan Rank | Player Rank | Media Rank | Weighted Score | |
1 | LeBron James*, † | LAL | 1 | 1 | 1 | 1.00 | |
2 | Kevin Durant* | GSW | 3 | 2 | 2 | 2.50 | |
3 | Paul George* | OKC | 4 | 4 | 4 | 4.00 ‡ | |
4 | Anthony Davis | NOP | 5 | 3 | 3 | 4.00 ‡ | |
5 | Luka Doncic | DAL | 2 | 8 | 6 | 4.50 | |
6 | Nikola Jokic | DEN | 7 | 5 | 5 | 6.00 | |
7 | Steven Adams | OKC | 6 | 7 | 8 | 6.75 | |
8 | Draymond Green | GSW | 9 | 10 | 8 | 9.00 | |
9 | Karl-Anthony Towns | MIN | 11 | 10 | 8 | 10.00 | |
10 | LaMarcus Aldridge | SAS | 13 | 6 | 8 | 10.00 | |
source: nba.com | |||||||
* Voted to start † Team captain ‡ Tiebreaker for starting spot is fan rank |
Western Conference Backcourt | |||||||
---|---|---|---|---|---|---|---|
NBA All-Star Voting 2019 Results | |||||||
Rank | Player Name | Team | Fan Rank | Player Rank | Media Rank | Weighted Score | |
1 | Stephen Curry* | GSW | 1 | 1 | 2 | 1.25 | |
2 | James Harden* | HOU | 3 | 2 | 1 | 2.25 | |
3 | Derrick Rose | MIN | 2 | 4 | 6 | 3.50 | |
4 | Russell Westbrook | OKC | 4 | 3 | 3 | 3.50 | |
5 | Damian Lillard | POR | 6 | 5 | 4 | 5.25 | |
6 | Klay Thompson | GSW | 5 | 11 | 4 | 6.25 | |
7 | DeMar DeRozan | SAS | 7 | 8 | 6 | 7.00 | |
8 | Devin Booker | PHX | 10 | 6 | 6 | 8.00 | |
9 | Lonzo Ball | LAL | 8 | 14 | 6 | 9.00 | |
10 | Chris Paul | HOU | 9 | 14 | 6 | 9.50 | |
source: nba.com | |||||||
* Voted to start |
Eastern Conference Frontcourt | |||||||
---|---|---|---|---|---|---|---|
NBA All-Star Voting 2019 Results | |||||||
Rank | Player Name | Team | Fan Rank | Player Rank | Media Rank | Weighted Score | |
1 | Giannis Antetokounmpo*, † | MIL | 1 | 1 | 1 | 1.00 | |
2 | Kawhi Leonard* | TOR | 2 | 2 | 1 | 1.75 | |
3 | Joel Embiid* | PHI | 3 | 3 | 1 | 2.50 | |
4 | Jayson Tatum | BOS | 4 | 7 | 4 | 4.75 | |
5 | Jimmy Butler | PHI | 5 | 4 | 7 | 5.25 | |
6 | Blake Griffin | DET | 6 | 5 | 7 | 6.00 | |
7 | Pascal Siakam | TOR | 8 | 10 | 4 | 7.50 | |
8 | Vince Carter | ATL | 7 | 12 | 7 | 8.25 | |
9 | Andre Drummond | DET | 12 | 6 | 7 | 9.25 | |
10 | Nikola Vucevic | ORL | 13 | 9 | 4 | 9.75 | |
source: nba.com | |||||||
* Voted to start † Team captain |
Eastern Conference Backcourt | |||||||
---|---|---|---|---|---|---|---|
NBA All-Star Voting 2019 Results | |||||||
Rank | Player Name | Team | Fan Rank | Player Rank | Media Rank | Weighted Score | |
1 | Kyrie Irving* | BOS | 1 | 1 | 1 | 1.0 | |
2 | Kemba Walker* | CHA | 3 | 2 | 2 | 2.5 | |
3 | Dwyane Wade | MIA | 2 | 6 | 6 | 4.0 | |
4 | Ben Simmons | PHI | 4 | 5 | 3 | 4.0 | |
5 | Victor Oladipo | IND | 5 | 4 | 4 | 4.5 | |
6 | Kyle Lowry | TOR | 6 | 7 | 7 | 6.5 | |
7 | Bradley Beal | WAS | 10 | 3 | 5 | 7.0 | |
8 | Zach LaVine | CHI | 7 | 8 | 8 | 7.5 | |
9 | D'Angelo Russell | BKN | 11 | 10 | 8 | 10.0 | |
10 | Eric Bledsoe | MIL | 16 | 8 | 8 | 12.0 | |
source: nba.com | |||||||
* Voted to start. |
Yes, they are barbarians and insist on turning perfectly machine-readable excel sheets into PDFs for reasons unknown.↩