The code in this document generates an interactive scatter plot using the Plotly library. The plot compares the offensive performance of selected players from the 2020 NBA Draft’s first round in the 2022-23 season. The x-axis represents Field Goal Percentage (FG%), showing the accuracy of field goal attempts in tenths of a percentage point (20.00%, 30.00%, etc.), while the y-axis represents Points Per Game (PPG). Each player is represented as a marker on the plot. Hovering over a marker displays information about the player’s name, FG%, and PPG. The plot helps analyze the relationship between shooting efficiency and scoring volume for these players.

# Fetch the web page content
url <- "https://www.basketball-reference.com/leagues/NBA_2023_per_game.html"
page <- read_html(url)

# Extract data from the web page
players_data <- page %>% 
  html_table(fill = TRUE) %>%
  `[[`(1) %>%
  as.data.frame()

# Select the required players
selected_players <- c('LaMelo Ball', 'Anthony Edwards', 'James Wiseman', 'Patrick Williams', 'Isaac Okoro',
                      'Onyeka Okongwu', 'Killian Hayes', 'Obi Toppin', 'Deni Avdija', 'Jalen Smith',
                      'Devin Vassell', 'Tyrese Haliburton', 'Kira Lewis Jr.', 'Aaron Nesmith', 'Cole Anthony', 'Isaiah Stewart',
                      'Aleksej Pokusevski', 'Josh Green', 'Saddiq Bey', 'Precious Achiuwa', 'Tyrese Maxey', 'Zeke Nnaji', 'Leandro Bolmaro',
                      'RJ Hampton', 'Immanuel Quickley', 'Payton Pritchard', 'Udoka Azubuike', 'Jaden McDaniels', 'Malachi Flynn', 'Desmond Bane')


# Filter data for selected players
selected_players_data <- players_data %>%
  filter(Player %in% selected_players)

# Convert columns to numeric data types
numeric_cols <- c('Age', 'G', 'GS', 'MP', 'FG', 'FGA', 'FG%', '3P', '3PA', '3P%', '2P', '2PA', '2P%', 'FT',
                  'FTA', 'FT%', 'ORB', 'DRB', 'TRB', 'AST', 'STL', 'BLK', 'TOV', 'PF', 'PTS')

selected_players_data[numeric_cols] <- lapply(selected_players_data[numeric_cols], as.numeric)

# Manually remove specific rows
rows_to_remove <- c(8, 9, 32, 33)
selected_players_data <- selected_players_data[-rows_to_remove, ]


# Display the data frame
print(selected_players_data)
##     Rk             Player Pos Age  Tm  G GS   MP  FG  FGA   FG%  3P  3PA   3P%
## 1    1   Precious Achiuwa   C  23 TOR 55 12 20.7 3.6  7.3 0.485 0.5  2.0 0.269
## 2   13       Cole Anthony  PG  22 ORL 60  4 25.9 4.6 10.2 0.454 1.3  3.4 0.364
## 3   16        Deni Avdija  SF  22 WAS 76 40 26.6 3.3  7.6 0.437 0.9  3.1 0.297
## 4   18     Udoka Azubuike   C  23 UTA 36  4 10.0 1.6  2.0 0.819 0.0  0.0    NA
## 5   21        LaMelo Ball  PG  21 CHO 36 36 35.2 8.2 20.0 0.411 4.0 10.6 0.376
## 6   24       Desmond Bane  SG  24 MEM 58 58 31.7 7.8 16.2 0.479 2.9  7.0 0.408
## 7   40         Saddiq Bey  SF  23 TOT 77 37 27.6 4.6 10.9 0.422 2.0  5.4 0.361
## 10  48    Leandro Bolmaro  SF  22 UTA 14  0  4.9 0.2  1.4 0.150 0.0  0.3 0.000
## 11 140    Anthony Edwards  SG  21 MIN 79 79 36.0 8.9 19.5 0.459 2.7  7.3 0.369
## 12 147      Malachi Flynn  PG  24 TOR 53  2 13.0 1.6  4.6 0.360 0.9  2.5 0.353
## 13 181         Josh Green  SG  22 DAL 60 21 25.7 3.4  6.4 0.537 1.1  2.8 0.402
## 14 186  Tyrese Haliburton  PG  22 IND 56 56 33.6 7.4 15.0 0.490 2.9  7.2 0.400
## 15 204      Killian Hayes  PG  21 DET 76 56 28.3 4.0 10.7 0.377 1.1  3.8 0.280
## 16 291     Kira Lewis Jr.  PG  21 NOP 25  0  9.4 1.6  3.5 0.455 0.6  1.4 0.441
## 17 316       Tyrese Maxey  SG  22 PHI 60 41 33.6 7.3 15.2 0.481 2.7  6.2 0.434
## 18 322    Jaden McDaniels  SF  22 MIN 79 79 30.6 4.7  9.1 0.517 1.4  3.4 0.398
## 19 358      Aaron Nesmith  SF  23 IND 73 60 24.9 3.5  8.1 0.427 1.6  4.3 0.366
## 20 362         Zeke Nnaji  PF  22 DEN 53  5 13.7 2.1  3.7 0.561 0.3  1.2 0.262
## 21 372     Onyeka Okongwu   C  22 ATL 80 18 23.1 4.0  6.2 0.638 0.1  0.2 0.308
## 22 373        Isaac Okoro  SF  22 CLE 76 46 21.7 2.3  4.7 0.494 0.8  2.3 0.363
## 23 387 Aleksej Pokusevski  PF  21 OKC 34 25 20.6 3.2  7.3 0.434 1.1  3.1 0.365
## 24 400   Payton Pritchard  PG  25 BOS 48  3 13.4 2.1  5.1 0.412 1.2  3.2 0.364
## 25 403  Immanuel Quickley  SG  23 NYK 81 21 28.9 5.2 11.6 0.448 2.1  5.6 0.370
## 26 454        Jalen Smith   C  22 IND 68 31 18.8 3.6  7.5 0.476 0.8  2.8 0.283
## 27 459     Isaiah Stewart   C  21 DET 50 47 28.3 3.9  8.8 0.442 1.3  4.1 0.327
## 28 476         Obi Toppin  PF  24 NYK 67  5 15.7 2.8  6.3 0.446 1.3  3.7 0.344
## 29 486      Devin Vassell  SG  22 SAS 38 32 31.0 6.9 15.7 0.439 2.7  7.0 0.387
## 30 523   Patrick Williams  PF  21 CHI 82 65 28.3 3.8  8.3 0.464 1.4  3.4 0.415
## 31 530      James Wiseman   C  21 TOT 45 22 19.3 4.2  7.5 0.558 0.1  0.4 0.200
##     2P  2PA   2P% eFG%  FT FTA   FT% ORB DRB TRB  AST STL BLK TOV  PF  PTS
## 1  3.0  5.4 0.564 .521 1.6 2.3 0.702 1.8 4.1 6.0  0.9 0.6 0.5 1.1 1.9  9.2
## 2  3.4  6.7 0.500 .516 2.5 2.8 0.894 0.8 4.0 4.8  3.9 0.6 0.5 1.5 2.6 13.0
## 3  2.4  4.6 0.530 .497 1.6 2.2 0.739 1.0 5.4 6.4  2.8 0.9 0.4 1.6 2.8  9.2
## 4  1.6  2.0 0.819 .819 0.2 0.6 0.350 0.9 2.4 3.3  0.3 0.2 0.4 0.5 0.9  3.5
## 5  4.2  9.4 0.450 .510 2.8 3.4 0.836 1.2 5.3 6.4  8.4 1.3 0.3 3.6 3.3 23.3
## 6  4.9  9.2 0.534 .568 3.1 3.5 0.883 0.7 4.3 5.0  4.4 1.0 0.4 2.2 2.6 21.5
## 7  2.6  5.4 0.483 .513 2.7 3.1 0.861 1.3 3.4 4.7  1.5 0.9 0.2 0.9 1.6 13.8
## 10 0.2  1.1 0.188 .150 0.0 0.0    NA 0.3 0.2 0.5  0.5 0.2 0.1 0.5 0.7  0.4
## 11 6.3 12.2 0.513 .528 4.0 5.3 0.756 0.6 5.2 5.8  4.4 1.6 0.7 3.3 2.4 24.6
## 12 0.8  2.1 0.367 .457 0.5 0.6 0.758 0.3 1.2 1.4  1.3 0.4 0.1 0.5 1.2  4.6
## 13 2.3  3.6 0.643 .626 1.1 1.6 0.723 0.9 2.1 3.0  1.7 0.7 0.1 1.2 2.6  9.1
## 14 4.5  7.8 0.572 .586 3.1 3.6 0.871 0.6 3.1 3.7 10.4 1.6 0.4 2.5 1.2 20.7
## 15 3.0  7.0 0.429 .426 1.2 1.5 0.821 0.4 2.5 2.9  6.2 1.4 0.4 2.3 2.9 10.3
## 16 1.0  2.2 0.463 .540 0.8 0.9 0.864 0.2 1.1 1.3  0.9 0.4 0.1 0.4 1.0  4.6
## 17 4.7  9.1 0.513 .568 3.0 3.6 0.845 0.4 2.6 2.9  3.5 0.8 0.1 1.3 2.2 20.3
## 18 3.3  5.7 0.588 .591 1.3 1.8 0.736 1.2 2.7 3.9  1.9 0.9 1.0 1.4 3.4 12.1
## 19 1.9  3.8 0.496 .525 1.6 1.9 0.838 0.8 2.9 3.8  1.3 0.8 0.5 1.0 3.2 10.1
## 20 1.8  2.5 0.710 .605 0.8 1.2 0.645 1.2 1.4 2.6  0.3 0.3 0.4 0.6 2.0  5.2
## 21 3.9  6.1 0.647 .642 1.9 2.5 0.781 2.7 4.5 7.2  1.0 0.7 1.3 1.0 3.1  9.9
## 22 1.5  2.4 0.617 .582 1.0 1.4 0.757 0.7 1.8 2.5  1.1 0.7 0.4 0.6 2.1  6.4
## 23 2.1  4.3 0.483 .510 0.6 1.0 0.629 1.3 3.4 4.7  1.9 0.6 1.3 1.3 1.7  8.1
## 24 0.9  1.9 0.495 .527 0.3 0.3 0.750 0.5 1.3 1.8  1.3 0.3 0.0 0.8 0.8  5.6
## 25 3.1  6.0 0.521 .537 2.5 3.1 0.819 0.7 3.4 4.2  3.4 1.0 0.2 1.2 2.0 14.9
## 26 2.8  4.7 0.593 .530 1.5 2.0 0.759 1.9 3.9 5.8  1.0 0.3 0.9 1.1 2.3  9.4
## 27 2.6  4.7 0.542 .518 2.2 3.0 0.738 2.3 5.8 8.1  1.4 0.4 0.7 1.4 2.7 11.3
## 28 1.5  2.6 0.593 .548 0.6 0.7 0.809 0.4 2.4 2.8  1.0 0.3 0.2 0.6 1.0  7.4
## 29 4.2  8.7 0.480 .525 2.1 2.6 0.780 0.2 3.7 3.9  3.6 1.1 0.4 1.5 1.5 18.5
## 30 2.4  4.9 0.498 .549 1.1 1.3 0.857 1.0 3.0 4.0  1.2 0.9 0.9 1.2 1.8 10.2
## 31 4.1  7.1 0.580 .563 1.5 2.2 0.701 1.6 4.3 5.9  0.7 0.2 0.6 1.1 2.4 10.0

Below, you will find the code for an interactive scatter plot for the first round of the 2020 NBA Draft class from the 2022-23 season.

# Create a named vector of colors for each player
player_colors <- c("#1f77b4", "#ff7f0e", "#2ca02c", "#FFFF00", "#9467bd",
                   "#8c564b", "#e377c2", "#7f7f7f", "#40826D", "lightgreen", "#E52B50",
                   "red4", "purple4", "#FF2400", "darkgreen", "skyblue", "darkblue", "turquoise", 
                   "tan", "gold4", "#AD6F69", "#6495ED", "#007FFF", "cyan", "#563C5C", "#00B7EB", "#7FFF00",
                   "#BEBEBE", "#87421F", "#FA8072")

# Map colors to players
selected_players_data$Color <- player_colors[match(selected_players_data$Player, selected_players)]

# Define a custom tick formatting function for formatting x axis percentages appropriately
custom_tick_format <- function(x) {
  paste0(sprintf("%.2f", x * 100), "%")
}

# Create the scatter plot using Plotly
scatter_plot <- plot_ly(data = selected_players_data, x = ~`FG%`, y = ~PTS,
                         text = ~paste("Player: ", Player, "<br>FG%: ", `FG%`, "<br>Points Per Game: ", PTS),
                         type = 'scatter', name = "ON/OFF", mode = 'markers',
                         marker = list(size = 12, opacity = 0.8, color = ~Color)) %>%
  layout(
    title = "    Scatter Plot: Field Goal % vs. Points Per Game Comparison (2022-23)",
    xaxis = list(
      title = "Field Goal Percentage",
      tickvals = seq(0.2, 0.8, 0.1),
      ticktext = lapply(seq(0.2, 0.8, 0.1), custom_tick_format)
    ),
    yaxis = list(title = "Points Per Game"),
    legend = list(orientation = "h", x = 0.1, y = -0.1),
       annotations = list(
      list(text = "<i>2020 NBA Draft Class (1st Round)</i>",
           showarrow = FALSE,
           xref = "paper",
           yref = "paper",
           x = 0.5,
           y = 1.021,  # Adjust the y value to position the annotation closer to the title
           font = list(size = 12, color = "black"))
    ),
    hoverlabel = list(bgcolor = "white", font = list(family = "Arial", size = 12, color = "black")),
    plot_bgcolor = "rgba(240, 240, 240, 0.7)",
    paper_bgcolor = "rgba(255, 255, 255, 0.9)",
    hovermode = "closest",
    showlegend = TRUE
  ) %>%
  config(displayModeBar = FALSE)  # Hide the display mode bar

# Display the interactive scatter plot
scatter_plot

The goal of this plot is to show a few points: