{"metadata":{"kernelspec":{"name":"ir","display_name":"R","language":"R"},"language_info":{"name":"R","codemirror_mode":"r","pygments_lexer":"r","mimetype":"text/x-r-source","file_extension":".r","version":"4.0.5"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Player Target Vision (PlayerTV):\n\n## Contents Table:\n* [Brief Description](#section-1)\n* [Why?](#section-2)\n* [Special Team Usage:](#section-3)\n* [How?](#section-6)\n    - [How does this idea work?](#how_1)\n    - [How do you put this into practice?](#how_2)\n* [Comparisons](#section-7)\n    - [ESPN MNF Footage](#comp-subsection-1)\n    - [NFL All-22](#comp-subsection-2)\n    - [All Film Footage](comp-subsection-3)\n    - [Dots](#comp-subsection-4)\n    - [PlayerTV](#comp-subsection-5)\n        - [Andre Roberts](#PTV_NYJ_19)\n* [Appendix (External Link)](https://www.kaggle.com/zacrogersuk/appendix-playertv-by-zacrogers/)\n    - Offence / Defensive Usage\n    - PlayerTV for the other 21 Players\n    - Previous Discussions after publishing on Twitter\n    - Code Review\n    - Final Words\n\n\n<a id=\"section-1\"></a>\n## Brief Description:\n\nMy #BigDataBowl entry for 2022 is all about film studies. Film Review is the main way that NFL teams analyse their performance, scout the opposition and work on their own game. The biggest limitation to this is the camera angles, but I have started solving that with \"PlayerTV\".\n\n<a id=\"section-2\"></a>\n## Why?\n\nThe difference between being a bad team and a good team is minimal, and then the difference between a good team and an elite team is even smaller. This means that any difference that can be found could make a big difference to a team's success. Traditionally, teams evaluate players based on film review; they spend a couple of days collecting the film, looking through it, and reporting their findings. The problem is that (publicly available) camera angles haven't advanced in years. The angles don't show the whole picture and even all-22 doesn't show the player's point of view (POV). \n\n<a id=\"section-3\"></a>\n## Special Team Usage:\n\nThis idea could be used by anyone (NFL teams, broadcast teams and fans) to improve their insight on the game. Keeping with special team plays for time being.\nNFL teams could use this product to evaluate what a player did on each play. In simple terms, cameras are ball magnets: they follow the ball (either proactively by predicting where the ball will go or reactively). This is great for the broadcast and fans as they want to follow the game, but it isn't great when evaluating a player when the ball has gone the complete other side of the field to where he is. With PlayerTV, a coach/scout/analyst could search up the player they want to evaluate and watch everything he saw from his POV.\nBroadcast Teams could use this product to show the brilliance of an individual play by showing how the player dived through gaps that just appeared. One of the questions that I suspect a lot of people will answer is \"why did the player return it?\" or \"why did the player fair catch it?\", the simple answer is typically coaching influence, or he saw a massive gap where he could run into. Broadcast teams would ideally provide an analytics metric to what the player should have done in combination with PlayerTV to provide context.\nThe media could use this product to learn more about the game. Media (both professional and amateur) love to analyse the game into the tiniest of margins. Providing additional context would help provide them with better analysis and go deeper into team schemes, ideas and philosophies. It would help settle debates and create better interactions between players and fans with fans more understanding of what a player is doing.\n\n<a id=\"section-6\"></a>\n## How?\n\nThere are two main How's; 1. How does this idea work? And 2. How do you put this into practice? \n\n<a id=\"how_1\"></a>\n### 1. How does this idea work? \nThe code is below and explains it in a lot of detail. In one sentence: PlayerTV uses coordinate data to pinpoint the whereabouts of all players from the point of view of the selected player.\n\n<a id=\"how_2\"></a>\n### 2. How do you put this into practice? \nMy method of choice would be a desktop application called \"All-22+\". \"All-22+\" is a spin on the All-22 cameras that is the current main cameras for film review.\nThis desktop application would use a powerful graphics engine giving real immersion to the film studies. \nThe user would have the desktop application installed and loaded up. The user can select any game from the Next Gen Stats era (2016-onwards) to download the coordinates for plug-and-play film review. Then, the user would have the choice of a selection of cameras including, but not limited to:\n* PlayerTV (Player Point of View,POV)\n* NFL Camera Angles (both publicly available and private)\n* Free-Roaming (manually controlled by an Xbox controller)\n* Stadium Seats (including the coaches booth)\n\n<a id=\"section-7\"></a>\n## Comparisons:\nAs mentioned when looking at individual plays, there are a range of special team analytical metrics (by individual NFL teams and now more publicly available after the Big Data Bowl) that can help quantify the value of each play. \nBut film review is still a must alongside these metrics. There are currently 3 main ways to look at context, with PlayerTV being the 4th. They are:\n\n* Broadcast Footage\n* All-22\n* Dots\n* PlayerTV\n\nFor a fair comparison, we will be using the same play for all of them. The play is the 2018 Week 1 game between the New York Jets and the Detroit Lions. This play happened in the 3rd Quarter with 7:20 remaining on the clock where Sam Martin (Lions) punted to the returner (Andre Roberts), who returned it 78 yards for a Touchdown.\nI will attempt to analyse these plays from the camera angles provided. I do not study film often and have never been trained on it.\n\n<a id=\"comp-subsection-1\"></a>\n### Broadcast Footage:\n\nThis game was a Monday Night Football (MNF) broadcast production by ESPN ([link](https://youtu.be/Er6FCawLCO4)). The live camera angle is the traditional low angled sideline camera. This angle helps give us some perspective on how crowded it got around the 35-yard line and how there was an attempted tackle. It also shows how Sam Martin (#6 for the Lions and the Punter) attempted a tackle. Another Lions player attempted a tackle and was handed-off. But the second Lions player, we know his number is in the 50s but not precise. In one sentence: We see a lot of chaos but can't dive much more into it. The first highlight we see focuses on the foot of Andre Roberts to see if he kept in bounds. This is vital to show the TV audience but doesn't help much with our film review. It does, however, confirm that the final missed tackle by the Lions is by #59 (Marquis Flowers). The second highlight and third highlight continue to look at Roberts' feet. \n\n<a id=\"comp-subsection-2\"></a>\n### All-22 Footage:\n\nThe NFL shares two All-22 camera angles via Game Pass ([link](https://youtu.be/rm41Tu5j5E8)). The first angle is a high-angled sideline camera (much like the live broadcast camera), but being higher up provides us footage of all-22 players (outside of punts and exceptional plays). The first thing I notice is that we can identify Jets #27 (Darryl Roberts) who's role is Special Teams Safety according to PFF. We can also identify that a Jets player (number in the 40s, precise number unknown) initially makes a mistake but recovers in time for when the returner needs him to block. It continues to show the chaos that happened, but it seems more controlled.\nThe second angle provides a lot more insight, including helping identify players better. Looking to see if the angle helps us with the previous angle, the Jets player in the 40s is #42 (Trenton Cannon). It also looks like as much as a mistake by Jets #42; it was a great move by Lions #32 (Tavon Wilson).\nThe second angle gives us a better understanding of what is happening at the line of scrimmage, as well. It is the first angle (out of the broadcast footage and the first all-22 angle) that has it close enough to identify who had which roles and what they needed to do. You can clearly see that the Jets had no plans to get to the Punter and were more interested in blocking from the get-go. You can also identify that Jets #50 (Frankie Luvu) makes a clear mistake and lets his guy, he is meant to block, Lions #48 (Don Muhlbach), get a free run on the pack. Looking at the return itself, we don't get a clear picture of how much chaos is happening. But it does give us the angle to see how athletic Andre Roberts is.\n\n<a id=\"comp-subsection-3\"></a>\n### Film Footage Analysis:\nWhen you combine all the knowledge you get from each camera angle, you don't understand much of what happens within the chaos. You get a great understanding of the line of scrimmage (from All-22 2nd camera angle) and you can identify the players who have made mistakes (mainly Jets #42 and Jets #50). \nThe big thing is that the film review does not help us understand the chaos that happened - which is very common in special teams. We have to hope that analytics can help solve it. \n\n<a id=\"comp-subsection-4\"></a>\n### The Dots:\n\n![Dots_Example_Play](https://raw.githubusercontent.com/rogers1000/bdb2022/main/Player_TV_code56_v6_dots.gif)\n\nThe Dots is the nickname for putting the coordinate data onto a graph. These are very popular and can be made easily - as it is not part of PlayerTV, I made a quick version. (I'll include the code, but it only took me a couple of minutes).\nThe Dots in blue represent allies to our returner (Jets) and red represents the opposition (Lions).\nThe first thing you notice with the dots is player identification is easy. The numbers are shown within dots representing the players.\nThe second thing you notice is that the chaos identified from the film review happens once Roberts (returner) has made his move and is already going downfield.\nThe cut Roberts made takes out all the defenders for the Lions outside of #35, who doesn't have the speed to keep up with him.\nLions #59 (Marquis Flowers) also tries to impact the play coming from a long way out to make a missed tackle. While the dots identify it, an analytical metric should help identify that and show a quantifiable added value by his play.\nThe mistake / good play by Jets #42 (blue) and Lions #32 (red) is even more impressive on the dots and shows a clear acceleration and cut by the Lions player (Tavon Wilson) to get past his man. The other mistake identified by the film review was on Jets #50, and the dots show that he was never in a position to block his guy (Lions #48).\nThe battle of Lions #43 (Nick Bellore) and Jets #51 (Brandon Copeland) is also super fun to watch on the dots. We can see that the Lions player kept trying to get past, but the Jets player matched him every time. We can also see it ended by the Jets player pushing his opponent to the ground as soon as the returner (Roberts) got close to the duo.\nThe dots show that Roberts may not have taken the best line once he made his original cut. However, this is where the film is still needed because we can see the reason for such a big cut was a missed tackle.","metadata":{"_kg_hide-input":false}},{"cell_type":"code","source":"install.packages(\"nflfastR\")\ninstall.packages(\"nflreadr\")\n\noptions(scipen = 9999)\noptions(warn=-1)\nlibrary(nflfastR)\nlibrary(tidyverse)\nlibrary(nflreadr)\nlibrary(ggrepel)\nlibrary(ggimage)\nlibrary(ggpubr)\nlibrary(lme4)\nlibrary(repr)\nlibrary(gganimate)\nlibrary(cowplot)\nlibrary(ggridges)\nlibrary(stringr)\nlibrary(gifski)\n\ngames <- read_csv(\"../input/nfl-big-data-bowl-2022/games.csv\") \n\nPFF_Scouting <- read_csv(\"../input/nfl-big-data-bowl-2022/PFFScoutingData.csv\") %>%\n  mutate(tracker_join = paste0(gameId,\"_\",playId)) \n\nplayers <- read_csv(\"../input/nfl-big-data-bowl-2022/players.csv\") \n\nplayers <- players %>%\n  filter(str_detect(players$height,\"-\")) %>%\n  separate(col = height, c(\"feet\",\"inches\"), remove = FALSE, convert = TRUE) %>%\n  mutate(height_inches = 12*feet + inches) %>%\n  mutate(height_yards = height_inches / 36) \n\nplays <- read_csv(\"../input/nfl-big-data-bowl-2022/plays.csv\") \n\nTV_guide_tracking_df <- read_csv(\"../input/nfl-big-data-bowl-2022/tracking2018.csv\") %>%\n  ### Getting Tracking Data Info\n  select(gameId,playId,nflId,jerseyNumber,team) %>%\n  mutate(tracker_join = paste0(gameId,\"_\",playId)) %>%\n  select(tracker_join,nflId,jerseyNumber,team) %>%\n  unique()\n\ngc()\n\n\n### USER INPUT\n\nPlayerTV_game <- 2018091000\nPlayerTV_play <- 2626\nPlayerTV <- 35527\n\n### END OF USER INPUT\n\ntracking_df <- read_csv(\"../input/nfl-big-data-bowl-2022/tracking2018.csv\") %>%\n  mutate(game_play = paste0(gameId,\"_\",playId)) %>%\n  filter(gameId == PlayerTV_game, playId == PlayerTV_play)\n\ngc()\n\nnFrames <- max(tracking_df$frameId)\n\ntracking_df_target <- tracking_df %>%\n  filter(nflId == PlayerTV) %>%\n  select(frameId,x,y,dir,o,team) %>%\n  rename(x_target = x) %>%\n  rename(y_target = y) %>%\n  rename(dir_target = dir) %>%\n  rename(o_target = o) %>%\n  rename(team_target = team)\n\n\ntracking_df_target_distance <- tracking_df %>%\n  left_join(tracking_df_target, by = \"frameId\") %>%\n  ### Pythagoras Theorem\n  mutate(a_squared = (x - x_target)*(x - x_target)) %>%\n  mutate(b_squared = (y - y_target)*(y - y_target)) %>%\n  left_join(players, by = \"nflId\") %>%\n  mutate(X_difference_positive = sqrt(a_squared)) %>%\n  mutate(Y_difference_positive = sqrt(b_squared)) %>%\n  mutate(x_difference_real = x - x_target) %>%\n  mutate(y_difference_real = y - y_target) %>%\n  mutate(yards_away = sqrt(a_squared + b_squared)) %>%\n  filter(nflId != PlayerTV) %>%\n  ### People Height Perception\n  mutate(perception_height_rad = atan(height_yards/yards_away)) %>%\n  mutate(height_perception = perception_height_rad * 180/3.14) %>%\n  mutate(height_perception = perception_height_rad * 180/3.14) %>%\n  mutate(grass_gap = height_inches - height_perception) %>%\n  mutate(Observer_Angle_xpos_ypos_rad = ifelse(x_difference_real >= 0 & y_difference_real >= 0, atan((x - x_target)/(y - y_target)),1000)) %>%\n  mutate(xpos_ypos_deg = Observer_Angle_xpos_ypos_rad*180/3.14) %>%\n  mutate(Observer_Angle_xpos_yneg_rad = ifelse(x_difference_real >= 0 & y_difference_real <= 0, atan((y_target - y)/(x - x_target)),1000)) %>%\n  mutate(xpos_yneg_deg = Observer_Angle_xpos_yneg_rad*180/3.14 + 90) %>%\n  mutate(Observer_Angle_xneg_yneg_rad = ifelse(x_difference_real <= 0 & y_difference_real <= 0, atan((x_target - x)/(y_target - y)),1000)) %>%\n  mutate(xneg_yneg_deg = Observer_Angle_xneg_yneg_rad*180/3.141593 + 180) %>%\n  mutate(Observer_Angle_xneg_ypos_rad = ifelse(x_difference_real <= 0 & y_difference_real >= 0, atan((y_target - y)/(x - x_target)),1000)) %>%\n  mutate(xneg_ypos_deg = Observer_Angle_xneg_ypos_rad*180/3.141593+270) %>%\n  #select(nflId,frameId,x_difference_real,y_difference_real,xpos_ypos_deg,xpos_yneg_deg,xneg_yneg_deg,xneg_ypos_deg) %>%\n  mutate(Quad1 = ifelse(xpos_ypos_deg < 360, xpos_ypos_deg,xpos_yneg_deg)) %>%\n  mutate(Quad2 = ifelse(Quad1 < 360, Quad1, xneg_yneg_deg)) %>%\n  mutate(Quad3 = ifelse(Quad2 < 360, Quad2, xneg_ypos_deg)) %>%\n  #mutate(colour_graph = if_else(team == team_target, \"blue\",\"red\")) %>%\n  mutate(observer_angle = o_target - Quad3) %>%\n  mutate(width_yards = 0.5) %>%\n  mutate(perception_width_rad = atan(width_yards/yards_away)) %>%\n  mutate(width_perception = perception_width_rad * 180/3.14) %>%\n  mutate(x1 = observer_angle - width_perception/2) %>%\n  mutate(x2 = observer_angle + width_perception/2) %>%\n  mutate(y1 = if_else(observer_angle > -90 & observer_angle < 90,grass_gap,-1)) %>%\n  mutate(y2 = if_else(observer_angle > -90 & observer_angle < 90,height_inches,0)) %>%\n  mutate(colour_graph = if_else(team == team_target, \"blue\",\"red\")) %>%\n  arrange(yards_away) %>%\n  mutate(yards_away_decimals = yards_away / 100) %>%\n  mutate(alpha_value = 1 - yards_away_decimals) %>%\n  mutate(height_perception1 = if_else(nflId == PlayerTV, -1,height_perception)) %>%\n  arrange(frameId, -yards_away) %>%\n  mutate(description = \"players\") %>%\n  select(nflId,frameId,height_perception,width_perception,yards_away,observer_angle,y1,y2,x1,x2,colour_graph,alpha_value,o_target,description) \n\ndots_coordinates <- tracking_df %>%\n  select(frameId,x,y,team) %>%\n  left_join(tracking_df_target, by = \"frameId\") %>%\n  mutate(colour_graph = if_else(team == team_target, \"blue\",\"red\")) %>%\n  filter(team != \"football\")\n\ntracking_df_football <- tracking_df %>%\n  filter(team == \"football\")\n\ndots_field <- data.frame(x1 = 0, x2 = 120, y1 = 0, y2 = 53.3) %>%\n  view()\n\nPlayerTV_animation <- ggplot() +\n  geom_rect(data = dots_field, aes(xmin = y1, xmax =y2, ymin = x1, ymax = x2), fill = \"forestgreen\") +\n  geom_point(data = dots_coordinates, aes(x = y, y = x, fill = colour_graph, col = \"black\"), size = 6, shape = 21, alpha = 1) +\n  geom_point(data = tracking_df_target, aes(x = y_target, y = x_target, fill = \"black\", col = \"black\"), size = 6, shape = 21, alpha = 1) +\n  geom_text(data = tracking_df,\n            aes(x = y, y = x, label = jerseyNumber),\n            colour = \"white\", \n            vjust = 0.36, size = 3.5) +\n  geom_point(data = tracking_df_football, aes(x = y, y = x, fill = \"#663300\"), size = 4, shape = 25, alpha = 1) +\n  scale_colour_identity() +\n  scale_fill_identity() +\n  theme_bw() +\n  scale_x_reverse() +\n  transition_time(frameId)  +\n  labs(subtitle = \"Frame: {frame_time}\") +\n  ease_aes('linear') + \n  NULL \n\nanim_save('example_play_dots.gif',\n          animate(PlayerTV_animation, width = 720, height = 440,\n                  fps = 10, nframe = nFrames))","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-01-06T13:39:01.536134Z","iopub.execute_input":"2022-01-06T13:39:01.538308Z","iopub.status.idle":"2022-01-06T13:43:21.783515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"comp-subsection-5\"></a>\n### PlayerTV:\nWe have now looked at all the publicly available methods of analysing special team play before the Big Data Bowl to evaluate the play. We can now look at what PlayerTV sees when looking at this play. To do this I'll look at the Kick Returner first and then each player on the return team, followed by all the players on the kicking team.\nBefore we analyse the play using PlayerTV, I want to list the features:\n* Perceived Height\n* Perceived Width\n* Radar Chart\n* Name\n* Speed (mph)\n* Direction Player is Facing\nThese additional features help the coach/scout/analyst to understand the play easier. Using a combination of Facing (Direction of travel with 0 being directly towards the endzone) and Speed (mph), you can identify when the player makes a \"cut\" move.\nPerceived Height and Width immerses you into the play with the other players moving closer (therefore larger) or further away from you and getting smaller.\nUsing the radar chart (the dots), you can identify where the chosen player is in context to other players and the field.\n\n<a id=\"PTV_NYJ_19\"></a>\n#### Andre Roberts:","metadata":{}},{"cell_type":"markdown","source":"![image](https://raw.githubusercontent.com/rogers1000/bdb2022/main/2018_1_NYJ_DET_2626_Andre%20Roberts.gif)\n\n* Team: New York Jets \n* Number: #19\n* Role: Kick Returner\n\n\n\nPlayerTV identified that Roberts runs backwards to the left in order to catch the ball before running right of the first player (using the dots, we identify him as Lions #12) and the second opponent (Lions #52). After taking evasive action which forced Roberts to run 45 degrees to the right, Roberts, then, cuts in 135 degrees to the left. Now the sideline, Roberts, then, used his speed and acceleration to go from around 12mph to 19mph. This speed meant he could just outrun everyone to score the Touchdown.\nYou can see the available space before he cuts back in, which is really good to see. Also, he almost cuts into two opponents, causing a missed tackle attempt by one of them. The punter (Sam Martin) also has a missed tackle, which is really fun to see.","metadata":{"_kg_hide-input":false,"_kg_hide-output":false}},{"cell_type":"markdown","source":"## Appendix:\nI have an [appendix](https://www.kaggle.com/zacrogersuk/appendix-playertv-by-zacrogers/) that contains:\n* Usage for Offence/Defence\n* Previous Discussions about Project on Twitter\n* Code Review\n* Final Words","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}