NBA Analytics Tutorial: Using R to Display Player Career Stats
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
It’s time for another basketball analytics tutorial! This is for beginners and intermediate sports analytics enthusiasts. I will show you how to extract and prepare NBA data from basketball-reference.com and create a graph with a player’s career stats.
I know it’s been a while since my last tutorial. To be honest, besides being quite busy with work, raising a baby (I have to admit I have the easy part of that, which is just taking her on walks, making her laugh, and changing diapers :D), and focusing on my Brazilian Jiu-Jitsu training, my sports analytics scope has been around the Fantasy leagues I’ve been taking part in. I manage 3 NBA fantasy teams, 2 UEFA Champions League teams, 2 English Premier League teams, and 1 EuroLeague team. I will likely be posting about some cool fantasy tools I’ve developed soon, so make sure you subscribe to get the updates!
Check out the video tutorial below as well if you’re interested.
Let’s Sweep!
Step 1: Download R Studio
The debate about which programming language is best for data science has been going on for a while. R and Python are the main choices. Both are awesome and it’s rather a matter of preference, as well as what kind of projects you have in mind. For some additional info, check out Step 3 of the article on getting started with sports analytics.
That being said, having a statistical background, I have opted to use R. So, first step, if you have not done so, download the latest version of R and R Studio from the links below.
https://www.rstudio.com/products/rstudio/download/
Step 2: Install packages
R has A LOT of packages you can use. Let’s start by installing the ones we use.
Open R Studio and run the below commands.
##################### # Step 2: Install packages ##################### install.packages("wesanderson") install.packages("plyr") install.packages("tidyverse") install.packages("rvest") install.packages("ggrepel") install.packages("readr") install.packages("RCurl") install.packages("jpeg")
After installing the above packages, you will no longer need to install them on your system.
Step 3: Load libraries
Run the below commands to load the libraries we use. We also increase the vroom connection size to accommodate for the large files we read.
##################### # Step 3: Load libraries ##################### library(plyr) library(tidyverse) library(rvest) library(ggrepel) library(readr) library(RCurl) library(jpeg)
Step 4: Get player stats
In this step, we go to our beloved stats page Basketball Reference. On that page, search for a player we want to analyze.
I’m choosing Purvis Short, the 5th overall pick in the 1978 NBA draft. His son commented on a Reddit post and requested I do an analysis for the Golden State Warriors legend. So, here it is!
What we need from Basketball-Reference is the player slug, i.e. the part in the URL right before the “.html”. Once we have that, we can populate the URLs.
##################### ## Step 4: Get player stats from bballref ##################### # Add player name and player slug player <- "Purvis Short" slug <- "shortpu01" # define player page URL and player image URL url <- paste0("https://www.basketball-reference.com/players/",substr(slug,1,1),"/",slug,".html") image_url <- paste0("https://www.basketball-reference.com/req/202106291/images/players/",slug,".jpg")
Next, let’s read the stats tables. The way to do this is by adding the appropriate HTML node into the read_html function as a parameter. Below, I have selected the #totals and #advanced nodes. I store them, as tables, into the ttl_stat and adv_stat variables. Then, I merge them by Season, Age, Tm, Lg, Pos, G, MP, which are all the common columns (so as not to have duplicates) to have all the data as a single table.
# Read total stats ttl_stat <- url %>% read_html %>% html_node("#totals") %>% html_table() # Read advanced stats adv_stat <- url %>% read_html %>% html_node("#advanced") %>% html_table() # Merge stats tables total_stats <- merge(ttl_stat, adv_stat, by=c("Season","Age", "Tm", "Lg", "Pos", "G", "MP")) View(total_stats)
Step 5: Prepare stats data frame for chart
Next, let’s start preparing the data. First, I’ll use str(all_stats) to see the available stats and then choose the ones I want to display. In this written tutorial, I choose 3-point percentage, free throw percentage, effective field goal percentage, true shooting percentage, and usage. The video tutorial uses other stats.
After selecting the stats, I define a data frame with their values. I rescale them to 100, and then use gather to put them into the format the charts need. A bit extra cleaning is required and we’re done!
#################### # Step 5: Select stats #################### str(all_stats) # make a list of stats we care about shooting_stats <- c("3P%", "FT%", "eFG%", "TS%", "USG%") stats <- shooting_stats # create the data frame for the chart, by using the Season, Team, and the vector of all stats df <- total_stats %>% select(Season, "Team"=Tm, unlist(stats)) # multiply values by 100 to rescale df$'3P%' <- df$'3P%'*100 df$'FT%' <- df$'FT%'*100 df$'eFG%' <- df$'eFG%'*100 df$'TS%' <- df$'TS%'*100 # create the final data frame df_stats <- df %>% gather(Stat_cat, Stat_val, 3:ncol(df)) # clean the data df_stats <- dplyr::filter(df_stats, grepl('-', Season)) df_stats <- dplyr::filter(df_stats, !grepl('TOT', Team)) df_stats <- unique(df_stats) df_stats <- merge(df_stats,data.frame("Season"=total_stats$Season,"GP"=total_stats$G), by="Season") View(df_stats)
Step 6: Create graph
Using the description from the Data to Viz, “A connected scatterplot
displays the evolution of a numeric variable. Data points are represented by a dot and connected by straight line segments. It often shows a trend in data over intervals of time: a time series. Basically it is the same as a line plot in most of the cases, except that individual observation are highlighted.”
Time series scatterplot
#################### # Step 6: Create chart #################### # Get columns and pivot wider p <- df_stats %>% ggplot(aes(x = paste0(Season," ",Team,"\n ",GP, "GP"), y = Stat_val, label=Stat_cat)) + # Add points geom_point(aes(fill = Stat_cat), size = 2, color = 'black', shape = 21)
The graph doesn’t look too good, so let’s make some some modifications.
Add lines, add labels, edit axis
First, let’s add the lines to connect the dots by using geom_line and grouping the stat categories, i.e. Stat_cat.
Next, I want to see labels so that I know at a glance what each line represents. To do this, I use geom_text_repel and use a filter so that only the last season has a label. You can look at what the additional parameters do here. I like using this function to ensure that labels do not overlap.
Last, I edit the y axis. I want it to start at 0 and end at the nearest 5th digit above the maximum value of our stats.
# Add lines p <- p + geom_line(aes(group = Stat_cat), size=0.05) # Add labels p <- p + geom_text_repel(data = filter(df_stats, Season == last(Season)), aes(label = Stat_cat), size = 2.5, box.padding = 0.2, point.padding = 0.2, force = 50, segment.size = 0.2, colour = "black", segment.color = "grey50") # Edit axis p <- p + scale_y_continuous(breaks = seq(0, ceiling(max(df_stats$Stat_val,na.rm = TRUE)), 5))
Add titles, add theme
As you can tell, I still have work to do to present this. I no longer need the legend, since i’ve added the labels to the chart. The axis titles are not needed. The x-axis labels are not readable. There is no chart title. There are too many gridlines.
First, I’ll add the title, the subtitle, remove the axis titles, and add a caption.
Then, I’ll add a theme that removes the legend, formats the title, subtitle, and caption, and also formats the x-axis labels.
# Add title, subtitle and caption p <- p + labs(title = paste0(player," Career Stats"), subtitle = paste0(min(df_stats$Season)," to ",max(df_stats$Season)), x = "", y = "", caption = c("@Sweep_SportsAnalytics\nSweepSportsAnalytics.com", "Source:\nbasketball-reference.com")) # Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10))
Add vertical line breaks
A bit better, but there are still a few tweaks to make.
I want to add lines that indicate when Purvis Short switched teams. To do this, we identify when the player changed teams, save the year to a list, and then add lines to the chart.
## Add team changes lines # Team line breaks team_changes <- NULL i=1 while (i < length(unique(paste0(df_stats$Season,df_stats$Team)))){ team_change <- NULL team_change$year <- i+0.5 team_change$team1 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i] team_change$team2 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i+1] team_change <- as.data.frame(team_change) ifelse(team_change$team1==team_change$team2,"",team_changes <- rbind(team_change,team_changes)) i <- i + 1 } p <- p + geom_vline(xintercept=team_changes$year, colour="grey")
Add custom theme
I want to add lines that indicate when Purvis Short switched teams. To do this, we identify when the player changed teams, save the year to a list, and then add lines to the chart.
##### # Create and add custom theme ##### theme_sweep <- function () { theme_minimal(base_size=14, base_family="Helvetica") %+replace% theme( # get rid of panel grids panel.grid.major = element_line(size = (0.075), colour="grey"), panel.grid.minor = element_blank(), #panel.border = element_blank(), # Change plot and panel background plot.background = element_rect(fill = 'antiquewhite', color = 'antiquewhite'), panel.background = element_rect(fill = "#f7e0c0", color = 'antiquewhite'), plot.title = element_text(size=18, hjust = 0.5), plot.subtitle = element_text(size=13, hjust = 0.5), plot.caption = element_text(size=8, hjust=c(1, 0)) ) } # Add custom theme to the graph p <- p + theme_sweep()
So we added the theme, but it overwrote the previous theme changes we had made. No problem, I’ll just add that theme to the chart again!
# Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10))
Add player image and save graph
We’re really close to the end! What I want to add is the image of the player.
First, I will create a function for reading the JPEG image that’s on basketball-reference. Then, using that function, I read the image from the “image_url” variable we created in Step 4. Last, we add the image to the chart by using the annotation_custom function. We need to define where we want to place the image, using the xmin/xmax and ymin/ymax arguments.
## Add player image # Create JPG functions get_jpg <- function(filename) { grid::rasterGrob(readJPEG(getURLContent(filename)), interpolate = TRUE) } pic <- get_jpg(image_url) # Use below if chart has percentages p <- p+ annotation_custom(pic, xmin = -1, xmax = 3, ymin = max(df_stats$Stat_val,na.rm = T)-2, ymax = max(df_stats$Stat_val,na.rm = T)+12) + coord_cartesian(clip = "off") ##### # Save plot ##### chart_type <- "avg_stats" ggsave(paste0(player,"-",chart_type,".png"), p, width = 7, height = 7, dpi = 400)
Additional stats and graphs
This seemed a bit long, but that’s only because (I think) I took some time to explain each part. I’ll show you how easy it is to create a new chart for a different player below!
##################### # Step 3: Load libraries ##################### library(plyr) library(tidyverse) library(rvest) library(ggrepel) library(readr) library(RCurl) library(jpeg) ##################### ## Step 4: Get player stats from bballref ##################### # Add player name and player slug player <- "Kevin Durant" slug <- "duranke01" # define player page URL and player image URL url <- paste0("https://www.basketball-reference.com/players/",substr(slug,1,1),"/",slug,".html") image_url <- paste0("https://www.basketball-reference.com/req/202106291/images/players/",slug,".jpg") # Read total stats ttl_stat <- url %>% read_html %>% html_node("#totals") %>% html_table() # Read advanced stats adv_stat <- url %>% read_html %>% html_node("#advanced") %>% html_table() # Merge stats tables total_stats <- merge(ttl_stat, adv_stat, by=c("Season","Age", "Tm", "Lg", "Pos", "G", "MP")) View(total_stats) # Get RAPTOR ratings RAPTOR_hist <- read.csv("https://github.com/fivethirtyeight/data/raw/master/nba-raptor/historical_RAPTOR_by_player.csv?raw=true") RAPTOR_mod <- read.csv("https://github.com/fivethirtyeight/data/raw/master/nba-raptor/modern_RAPTOR_by_player.csv") RAPTOR <- rbind.fill(RAPTOR_hist, RAPTOR_mod) RAPTOR <- unique(RAPTOR) # Merge all stats data total_stats$player_name <- player total_stats$season <- paste0(substr(total_stats$Season,1,2),substr(total_stats$Season,6,7)) total_stats$season <- str_replace(total_stats$season, "1900", "2000") all_stats <- merge(total_stats, RAPTOR, by=c("player_name", "season")) all_stats <- unique(all_stats) View(all_stats) #################### # Step 5: Select stats #################### str(all_stats) # use below section for basic stats when u want to use the average main_stats <- c("PTS","TRB","AST","STL","BLK","GP"="G") stats <- main_stats df <- all_stats %>% select(Season, "Team"=Tm, unlist(stats)) df_avg <- df[,3:(ncol(df)-1)]/df$GP df <- cbind(df[,1:2],df_avg) # create the final data frame df_stats <- df %>% gather(Stat_cat, Stat_val, 3:ncol(df)) # clean the data df_stats <- dplyr::filter(df_stats, grepl('-', Season)) df_stats <- dplyr::filter(df_stats, !grepl('TOT', Team)) df_stats <- unique(df_stats) df_stats <- merge(df_stats,data.frame("Season"=total_stats$Season,"GP"=total_stats$G), by="Season") View(df_stats) #################### # Step 6: Create chart #################### # Get columns and pivot wider p <- df_stats %>% ggplot(aes(x = paste0(Season," ",Team,"\n ",GP, "GP"), y = Stat_val, label=Stat_cat)) + # Add points geom_point(aes(fill = Stat_cat), size = 2, color = 'black', shape = 21) # Add lines p <- p + geom_line(aes(group = Stat_cat), size=0.05) # Add labels p <- p + geom_text_repel(data = filter(df_stats, Season == last(Season)), aes(label = Stat_cat), size = 2.5, box.padding = 0.2, point.padding = 0.2, force = 50, segment.size = 0.2, colour = "black", segment.color = "grey50") # Edit axis p <- p + scale_y_continuous(breaks = seq(0, ceiling(max(df_stats$Stat_val,na.rm = TRUE)), 5)) # Add title, subtitle and caption p <- p + labs(title = paste0(player," Career Stats"), subtitle = paste0(min(df_stats$Season)," to ",max(df_stats$Season)), x = "", y = "", caption = c("@Sweep_SportsAnalytics\nSweepSportsAnalytics.com", "Source:\nbasketball-reference.com")) # Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10)) ## Add team changes lines # Team line breaks team_changes <- NULL i=1 while (i < length(unique(paste0(df_stats$Season,df_stats$Team)))){ team_change <- NULL team_change$year <- i+0.5 team_change$team1 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i] team_change$team2 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i+1] team_change <- as.data.frame(team_change) ifelse(team_change$team1==team_change$team2,"",team_changes <- rbind(team_change,team_changes)) i <- i + 1 } p <- p + geom_vline(xintercept=team_changes$year, colour="grey") ##### # Create and add custom theme ##### theme_sweep <- function () { theme_minimal(base_size=14, base_family="Helvetica") %+replace% theme( # get rid of panel grids panel.grid.major = element_line(size = (0.075), colour="grey"), panel.grid.minor = element_blank(), #panel.border = element_blank(), # Change plot and panel background plot.background = element_rect(fill = 'antiquewhite', color = 'antiquewhite'), panel.background = element_rect(fill = "#f7e0c0", color = 'antiquewhite'), plot.title = element_text(size=18, hjust = 0.5), plot.subtitle = element_text(size=13, hjust = 0.5), plot.caption = element_text(size=8, hjust=c(1, 0)) ) } # Add custom theme to the graph p <- p + theme_sweep() # Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10)) ## Add player image # Create JPG functions get_jpg <- function(filename) { grid::rasterGrob(readJPEG(getURLContent(filename)), interpolate = TRUE) } pic <- get_jpg(image_url) # Use below if chart has absolute numbers p <- p + annotation_custom(pic, xmin = -1, xmax = 3, ymin = max(df_stats$Stat_val,na.rm = T)-1, ymax = max(df_stats$Stat_val,na.rm = T)+max(df_stats$Stat_val,na.rm = T)*0.15) + coord_cartesian(clip = "off") p ##### # Save plot ##### chart_type <- "avg_stats" ggsave(paste0(player,"-",chart_type,".png"), p, width = 7, height = 7, dpi = 400)
I hope you enjoyed this tutorial! As I mentioned earlier, check out the YouTube video for a deeper explanation of the code.
Let me know if you have any questions or recommendations in the comments or reach out here.
Stay tuned for my next tutorials!
In the meantime, check out the social media accounts below.
Full Code
##################### # Step 2: Install packages ##################### install.packages("wesanderson") install.packages("plyr") install.packages("tidyverse") install.packages("rvest") install.packages("ggrepel") install.packages("readr") install.packages("RCurl") install.packages("jpeg") ##################### # Step 3: Load libraries ##################### library(plyr) library(tidyverse) library(rvest) library(ggrepel) library(readr) library(RCurl) library(jpeg) ##################### ## Step 4: Get player stats from bballref ##################### # Add player name and player slug player <- "Kevin Durant" slug <- "duranke01" # define player page URL and player image URL url <- paste0("https://www.basketball-reference.com/players/",substr(slug,1,1),"/",slug,".html") image_url <- paste0("https://www.basketball-reference.com/req/202106291/images/players/",slug,".jpg") # Read total stats ttl_stat <- url %>% read_html %>% html_node("#totals") %>% html_table() # Read advanced stats adv_stat <- url %>% read_html %>% html_node("#advanced") %>% html_table() # Merge stats tables total_stats <- merge(ttl_stat, adv_stat, by=c("Season","Age", "Tm", "Lg", "Pos", "G", "MP")) View(total_stats) # Get RAPTOR ratings RAPTOR_hist <- read.csv("https://github.com/fivethirtyeight/data/raw/master/nba-raptor/historical_RAPTOR_by_player.csv?raw=true") RAPTOR_mod <- read.csv("https://github.com/fivethirtyeight/data/raw/master/nba-raptor/modern_RAPTOR_by_player.csv") RAPTOR <- rbind.fill(RAPTOR_hist, RAPTOR_mod) RAPTOR <- unique(RAPTOR) # Merge all stats data total_stats$player_name <- player total_stats$season <- paste0(substr(total_stats$Season,1,2),substr(total_stats$Season,6,7)) total_stats$season <- str_replace(total_stats$season, "1900", "2000") all_stats <- merge(total_stats, RAPTOR, by=c("player_name", "season")) all_stats <- unique(all_stats) View(all_stats) #################### # Step 5: Select stats #################### str(all_stats) ### make a list of stats we care about # one option is below shooting_stats <- c("2P%", "FT%", "eFG%", "TS%", "USG%") stats <- shooting_stats df <- all_stats %>% select(Season, "Team"=Tm, unlist(stats)) df$'3P%' <- df$'3P%'*100 df$'2P%' <- df$'2P%'*100 df$'FT%' <- df$'FT%'*100 df$'eFG%' <- df$'eFG%'*100 df$'TS%' <- df$'TS%'*100 # use below section for basic stats when u want to use the average main_stats <- c("PTS","TRB","AST","STL","BLK","GP"="G") stats <- main_stats df <- all_stats %>% select(Season, "Team"=Tm, unlist(stats)) df_avg <- df[,3:(ncol(df)-1)]/df$GP df <- cbind(df[,1:2],df_avg) # use below section for advanced stats adv_stats <- c("PER","raptor_total","war_total","VORP") stats <- adv_stats df <- all_stats %>% select(Season, "Team"=Tm, unlist(stats)) # gather data df_stats <- df %>% gather(Stat_cat, Stat_val, 3:ncol(df)) # filter data df_stats <- dplyr::filter(df_stats, grepl('-', Season)) df_stats <- dplyr::filter(df_stats, !grepl('TOT', Team)) df_stats <- unique(df_stats) df_stats <- merge(df_stats,data.frame("Season"=total_stats$Season,"GP"=total_stats$G),by="Season") View(df_stats) #################### # Step 6: Create chart #################### # Get columns and pivot wider p <- df_stats %>% ggplot(aes(x = paste0(Season," ",Team,"\n ",GP, "GP"), y = Stat_val, label=Stat_cat)) + # Add points geom_point(aes(fill = Stat_cat), size = 2, color = 'black', shape = 21) # Add lines p <- p + geom_line(aes(group = Stat_cat), size=0.05) # Add labels p <- p + geom_text_repel(data = filter(df_stats, Season == last(Season)), aes(label = Stat_cat), size = 2.5, box.padding = 0.2, point.padding = 0.2, force = 50, segment.size = 0.2, colour = "black", segment.color = "grey50") # Edit axis p <- p + scale_y_continuous(breaks = seq(0, ceiling(max(df_stats$Stat_val,na.rm = TRUE)), 5)) # Add title, subtitle and caption p <- p + labs(title = paste0(player," Career Stats"), subtitle = paste0(min(df_stats$Season)," to ",max(df_stats$Season)), x = "", y = "", caption = c("@Sweep_SportsAnalytics\nSweepSportsAnalytics.com", "Source:\nbasketball-reference.com")) # Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10)) ## Add team changes lines # Team line breaks team_changes <- NULL i=1 while (i < length(unique(paste0(df_stats$Season,df_stats$Team)))){ team_change <- NULL team_change$year <- i+0.5 team_change$team1 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i] team_change$team2 <- substr(unique(paste0(df_stats$Season,df_stats$Team)),8,11)[i+1] team_change <- as.data.frame(team_change) ifelse(team_change$team1==team_change$team2,"",team_changes <- rbind(team_change,team_changes)) i <- i + 1 } p <- p + geom_vline(xintercept=team_changes$year, colour="grey") ##### # Create and add custom theme ##### theme_sweep <- function () { theme_minimal(base_size=14, base_family="Helvetica") %+replace% theme( # get rid of panel grids panel.grid.major = element_line(size = (0.075), colour="grey"), panel.grid.minor = element_blank(), #panel.border = element_blank(), # Change plot and panel background plot.background = element_rect(fill = 'antiquewhite', color = 'antiquewhite'), panel.background = element_rect(fill = "#f7e0c0", color = 'antiquewhite'), plot.title = element_text(size=18, hjust = 0.5), plot.subtitle = element_text(size=13, hjust = 0.5), plot.caption = element_text(size=8, hjust=c(1, 0)) ) } # Add custom theme to the graph p <- p + theme_sweep() # Add theme that removes the legend, modifies title, subtitle, captions, and x-axis p <- p + theme(legend.position = 'none', plot.title = element_text(size = 17, face="bold", hjust = .5), plot.subtitle = element_text(face = 'italic', size = 13, hjust = .5), axis.text.x=element_text(angle=60, hjust=1, size=10), plot.caption = element_text(color = 'gray40'), plot.margin = margin(10, 10, 15, 10)) ## Add player image # Create JPG functions get_jpg <- function(filename) { grid::rasterGrob(readJPEG(getURLContent(filename)), interpolate = TRUE) } pic <- get_jpg(image_url) ### Use below if chart has percentages p <- p+ annotation_custom(pic, xmin = -1, xmax = 3, ymin = max(df_stats$Stat_val,na.rm = T)-2, ymax = max(df_stats$Stat_val,na.rm = T)+12) + coord_cartesian(clip = "off") #### Use below if chart has absolute numbers p <- p + annotation_custom(pic, xmin = -1, xmax = 3, ymin = max(df_stats$Stat_val,na.rm = T)-1, ymax = max(df_stats$Stat_val,na.rm = T)+max(df_stats$Stat_val,na.rm = T)*0.15) + coord_cartesian(clip = "off") p ##### # Save plot ##### # choose one of the below chart_type <- "shoot_stats" chart_type <- "avg_stats" chart_type <- "main_stats" chart_type <- "adv_stats" ggsave(paste0(player,"-",chart_type,".png"), p, width = 7, height = 7, dpi = 400)
The post NBA Analytics Tutorial: Using R to Display Player Career Stats appeared first on Sweep Sports Analytics.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.