{"cells":[{"metadata":{"_uuid":"badf9b9796b7f3fb397f04cfa0ac71e06567d5a0"},"cell_type":"markdown","source":"# NFL EDA\n\n <font color='red' size=6> Due to a large number of animations, this notebook may take a minute or two to display fully! </font> \n\nSo this is the first data analytics style competition that Kaggle has run, and what a way to start it! I think there will be numerous benefits to running competitions like these mainly the fact that your avoiding data leaks, your opening the competitive aspect of kaggle to people who may not have a large amount of knowledge or interest in the machine learning side of things and finally I think the noticebly short timeframe is also a positive in my opinon. I often monitor the competitions running on Kaggle and the process is quite long. Shorter competitions like this one could be a game changer (pun intended!).\n\nNow that I have finished my brief rant, I must confess that I know almost nothing about American football. I have watched two or three superbowl finals and found them to be quite a spectacle but never really understood anything about the game itself. Hopefully partaking in this competition will change that.\n\n### Table of Contents\n[1. Basic NFL Rules](#1.-Basic-NFL-Rules) <br>\n[2. What Causes Concussion](#2.-What-Causes-Concussion) <br>\n[3. The Punt](#3.-The-Punt) <br>\n[4. EDA](#4.-EDA) <br>\n[4.1 Concussion EDA](#4.1) <br>\n[4.2 Punt Returner Analysis](#4.2) <br>\n[4.2.1 First Rule Change](#4.2.1) <br>\n[4.2.2 Second Rule Change](#4.2.2) <br>\n[4.3 PRG & PLG Analysis](#4.3) <br>\n[4.3 Third Rule Change](#4.3.1) <br>"},{"metadata":{"_uuid":"dcf71613b284b8f660b9ad46f4c7933368fa3d6e"},"cell_type":"markdown","source":"## 1. Basic NFL Rules\nAs I previously mentioned I know almost nothing about American football. To address this I found a video on youtube (https://www.youtube.com/watch?v=Ddwp1HyEFRE) that gives a brief outline of the rules which I will now document.\n\n    A Team Consists of 46 players. 11 players for each team on the field at any time.\n    \n    Field is 100 yards long by 53 yards wide.\n    \n    Game starts with kickoff.\n    \n    Offence is given 4 chances (4 downs) to make 10 yards after which they regain possesion and the process repeats.\n    \n    If offence doesn't move the ball 10 yards after 4 downs the defensive team is then given the ball at that point.\n    \n    Offence often kicks the ball at 4th down so the defensive team gets possesion further down the field.\n    \n    The quarterback is the main player. They orchestrate every play by throwing or running with the ball.\n    \n    The wide receivers run and try to catch the ball thrown to them by the quarterback.\n    \n    The tight end is responsible for blocking and catching the ball in the middle of the field.\n    \n    The running back and fullback are responsible for running with the ball up the field.\n    \n    The outside tackle (x2), outside gaurd(x2) and outside center are responsible for protecting the quarterback from getting sacked.\n    \n    Sacked: when the defensive team tackles the quarterback before he can throw or run the ball.\n    \n    The defensive end(x2) and defensive tackle(x2) try to get by the offensive line to sack the quarterback.\n    \n    Linebackers(x3) stop running backs coming through the defensive line. Also responsible for attacking the quarterback.\n    \n    Cornerbacks(x2) try stop the wide receivers.\n    \n    The safeties(x2) try stop passes up the center of the field.\n    \n    A punter or kicker is used when a team is on the offensive and a punt returner is used by the defense.\n    \n    A touchdown is worth 6 points. The offensive team can then choose two ways of getting extra points; kick the ball between the posts for an extra point or run the ball in for another touchdown worth 2 points.\n    \n    At any time the offensive team can opt to attempt a field goal. A field goal is worth 3 points.\n    \n    The final method to gain points occurs when a defensive player tackles an offensive player behind their goal line. This scores 2 points.\n    \n    The game consists of 4 15 minute quarters.\n    \n    If a ball carrier drops a ball its called a fumble. Whichever team gathers and controls the ball gains possesion at that point.\n    \n    The defensive team can gain possesion of the ball by intercepting the quarterbacks pass.\n    \n    An incomplete pass occurs when a pass hits the ground before its intended player or is thrown out of bounds. This means a down is wasted for the offensive team.\n    \n    Referees can throw yellow flags on the field indicating a penalty. They review the incident and determine which team is penalised and by how many yards. Coaches can contest the decision by throwing red flags on the field.\n    \n    If the coaches challenge is unsuccessful the lose one of their 3 timeouts they get per half of the game. Each timeout is 60 seconds long.\n\nI will now move on by summarising the information I can get from some links posted in the discussion forum by JohnM: https://www.kaggle.com/c/NFL-Punt-Analytics-Competition/discussion/73791\n"},{"metadata":{"_uuid":"5e592d505a1f9ea3ee2c6db0f9d11a3170b78320"},"cell_type":"markdown","source":"## 2. What Causes Concussion\n\nDr. David Gehir [1] discusses the results of a previous analysis of concussions during the 2010/2011 and 2013/2014 seasons. He states that a higher percentage of concussions occur in the second half. Could fatigue be a driving factor? This is something I will look to answer as part of this analysis.\n\nThe author also states that ~57% of players anticipated the blow. This is something I found quite intrigueing. The fact that the players anticipated the blow suggests to me that their method of tackling is not optimal. A good example of where a safe and properly executed tackle can be used to great affect is rugby, which I know a little bit more about. The primary method to tackle in Rugby which is taught to kids from day 1 in the sport is to keep your head at either side of the opposing players body and let your shoulder take the impact. Now some people will say that your just going to cause more shoulder injuries. No. If the tackle is performed correctly a small player can bring a much larger player to ground quite easily without pyhsical damage.\n\nThe following image sourced from dreamstime.com [2] illustrates how to perform the rugby tackle safely. As of writing this I am unaware if this method of tackling is taught to people playing American football. If its not I think it should be considered.\n\n![Rugby Tackle](https://thumbs.dreamstime.com/z/rugby-player-tackling-2706447.jpg)\n\nThe author also states that the concussions were evenly distributed between helmet to helmet collisions, helmet to body and helmet to ground impacts."},{"metadata":{"_uuid":"baf10c88fc08b74fcdd86c38bd1a03af6cd0e4a3"},"cell_type":"markdown","source":"## 3. The Punt\n\n\n"},{"metadata":{"_uuid":"7a7c7f1fe6e991325a770d248a2f37d868e9ae9b"},"cell_type":"markdown","source":"There are several types of punt kicks, several of which are documented on wikipedia [3]:\n\n    1. Spiral Punt: ball spirals through the air. Same a spiral kick in rugby.\n    \n    2. Pooch Punt: when the quarterback performs a kick, normally on a 4th down but are too close to their opponents endline for a normal punt. Rarely done.\n    \n    3. Fake Punt: the team lines up in a punt formation but uses a different play e.g. attempts to run the ball.\n    \n    4. Rugby Style Punt: a standard kick.\n    \n    5. Drop Punt: akin to a drop kick in rugby where the ball spins end over end.\n    \n\nA punt return is when an opposing player catches the ball from a punt and attempts to run the ball. Alternatively they can choose to catch the ball and begin their offense from that position using a fair catch requiring the rest of the team to line up in their offensive formation.\n\nThe kicking team cannot score directly from a punt.\n"},{"metadata":{"_uuid":"da2254eb124545f5b8ae0de9c3d213488b8192cd"},"cell_type":"markdown","source":"### 4. General EDA"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"bb6a5fb33c866efe29f153f09654281a217e79d4"},"cell_type":"code","source":"import os\nimport gc\nimport pandas as pd\nimport numpy as np\nfrom IPython.display import HTML\nimport seaborn as sns\nimport squarify\nimport matplotlib.pyplot as plt\nfrom matplotlib import colors as mcolors\nimport plotly.plotly as py\nfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot,iplot\nimport plotly.figure_factory as ff\n#Always run this the command before at the start of notebook\ninit_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport cufflinks as cf\ncf.set_config_file(offline=True, world_readable=True, theme='ggplot')\nimport warnings\nwarnings.filterwarnings('ignore')\nsns.set_style(\"whitegrid\")\n#plt.style.use('seaborn')\n\n\nfrom random import shuffle\nimport matplotlib.animation as animation\n#%matplotlib notebook","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"e9a64333fc241d5018d821bb5550f8fa5cc1fba1"},"cell_type":"code","source":"pd.set_option('display.max_columns', 100)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"e6dbcbb96addd4c344e7b3abf2955441c0bd42e7"},"cell_type":"code","source":"def game_data():\n    dir_path = os.getcwd()\n    game_data =  pd.read_csv('../input/' + 'game_data.csv')\n        \n    return game_data\n\ndef get_NGS_data_pre():\n    dir_path = os.getcwd()\n    files = os.listdir('../input/')\n    substring = 'pre'\n    \n    NGS_files = []\n    for item in files:\n        if substring in item:\n            NGS_files.append(item)\n    \n    data = pd.read_csv('../input/' + NGS_files[0], memory_map=True)\n    data['x'].astype(np.float16, inplace=True)\n    data['y'].astype(np.float16, inplace=True)\n    \n    chunksize = 1000000\n    for file in NGS_files[1:]:\n        for chunk in pd.read_csv('../input/' + file, memory_map=True, chunksize = chunksize):\n            chunk['x'] = chunk['x'].astype(np.float16, inplace=True)\n            chunk['y'] = chunk['y'].astype(np.float16, inplace=True)\n            data = data.append(chunk)\n        \n    return data.round(1)\n\n\ndef get_NGS_data_post():\n    dir_path = os.getcwd()\n    files = os.listdir('../input/')\n    substring = 'post'\n    \n    NGS_files = []\n    for item in files:\n        if substring in item:\n            NGS_files.append(item)\n    \n    data = pd.read_csv('../input/' + NGS_files[0], memory_map=True)\n    data['x'].astype(np.float16, inplace=True)\n    data['y'].astype(np.float16, inplace=True)\n    \n    chunksize = 1000000\n    for file in NGS_files[1:]:\n        for chunk in pd.read_csv('../input/' + file, memory_map=True, chunksize = chunksize):\n            chunk['x'] = chunk['x'].astype(np.float16, inplace=True)\n            chunk['y'] = chunk['y'].astype(np.float16, inplace=True)\n            data = data.append(chunk)\n        \n    return data.round(1)\n\n\ndef get_NGS_data_reg16(usecols):\n    dir_path = os.getcwd()\n    files = os.listdir('../input/')\n    substring = 'reg'\n    \n    NGS_files = []\n    for item in files:\n        if substring in item and '16' in item:\n            NGS_files.append(item)\n    \n    data = pd.read_csv('../input/' + NGS_files[0], memory_map=True, usecols=usecols)\n    data['x'].astype(np.float16, inplace=True)\n    data['y'].astype(np.float16, inplace=True)\n    data['Season_Year'] = data['Season_Year'].astype(np.int16, inplace=True)\n    data['GameKey'] = data['GameKey'].astype(np.int32, inplace=True)\n            \n    data['PlayID'] = data['PlayID'].astype(np.int32, inplace=True)\n    #data['GSISID'] = data['GSISID'].astype(np.int32, inplace=True)\n    \n    chunksize = 1000000\n    for file in NGS_files[1:]:\n        for chunk in pd.read_csv('../input/' + file, memory_map=True, chunksize = chunksize, usecols=usecols):\n            chunk['x'] = chunk['x'].astype(np.float16, inplace=True)\n            chunk['y'] = chunk['y'].astype(np.float16, inplace=True)\n            \n            chunk['Season_Year'] = chunk['Season_Year'].astype(np.int16, inplace=True)\n            chunk['GameKey'] = chunk['GameKey'].astype(np.int32, inplace=True)\n            \n            chunk['PlayID'] = chunk['PlayID'].astype(np.int32, inplace=True)\n            #chunk['GSISID'] = chunk['GSISID'].astype(np.int32, inplace=True)\n            data = data.append(chunk)\n        \n    return data.round(1)\n\n\ndef get_NGS_data_reg17(usecols):\n    dir_path = os.getcwd()\n    files = os.listdir('../input/')\n    substring = 'reg'\n    \n    NGS_files = []\n    for item in files:\n        if substring in item and '17' in item:\n            NGS_files.append(item)\n    \n    data = pd.read_csv('../input/' + NGS_files[0], memory_map=True, usecols=usecols)\n    data['x'].astype(np.float16, inplace=True)\n    data['y'].astype(np.float16, inplace=True)\n    data['Season_Year'] = data['Season_Year'].astype(np.int16, inplace=True)\n    data['GameKey'] = data['GameKey'].astype(np.int32, inplace=True)\n            \n    data['PlayID'] = data['PlayID'].astype(np.int32, inplace=True)\n    #data['GSISID'] = data['GSISID'].astype(np.int32, inplace=True)\n    \n    chunksize = 1000000\n    for file in NGS_files[1:]:\n        for chunk in pd.read_csv('../input/' + file, memory_map=True, chunksize = chunksize, usecols=usecols):\n            chunk['x'] = chunk['x'].astype(np.float16, inplace=True)\n            chunk['y'] = chunk['y'].astype(np.float16, inplace=True)\n            \n            chunk['Season_Year'] = chunk['Season_Year'].astype(np.int16, inplace=True)\n            chunk['GameKey'] = chunk['GameKey'].astype(np.int32, inplace=True)\n            \n            chunk['PlayID'] = chunk['PlayID'].astype(np.int32, inplace=True)\n            #chunk['GSISID'] = chunk['GSISID'].astype(np.int32, inplace=True)\n            data = data.append(chunk)\n        \n    return data.round(1)\n\n\ndef vid_review_data():\n    dir_path = os.getcwd()\n    vid_data =  pd.read_csv('../input/' + 'video_review.csv')\n        \n    return vid_data\n\n\ndef vid_injury_data():\n    dir_path = os.getcwd()\n    vid_data =  pd.read_csv('../input/' + 'video_footage-injury.csv')\n        \n    return vid_data\n\n\ndef player_role_data():\n    dir_path = os.getcwd()\n    role_data =  pd.read_csv('../input/' + 'play_player_role_data.csv')\n        \n    return role_data\n\n\ndef player_punt_data():\n    dir_path = os.getcwd()\n    punt_data =  pd.read_csv('../input/' + 'player_punt_data.csv')\n        \n    return punt_data\n\n\ndef play_info_data():\n    dir_path = os.getcwd()\n    play_data =  pd.read_csv('../input/' + 'play_information.csv')\n        \n    return play_data\n\n\ndef generate_table(data):\n    \n    trace = go.Table(\n    header=dict(values=[data.columns[0], data.columns[1]],\n                fill = dict(color='#C2D4FF'),\n                align = ['left'] * 5),\n    cells=dict(values=[data[data.columns[0]], data[data.columns[1]]],\n               fill = dict(color='#F5F8FF'),\n               align = ['left'] * 5))\n    layout = go.Layout(\n     autosize=True)\n\n    data = [trace]\n    filename = 'pandas_table'\n    \n    fig = go.Figure(data=data, layout=layout)\n    return [fig, filename]\n\n\ndef generate_table3(data):\n    \n    trace = go.Table(\n    header=dict(values=[data.columns[0], data.columns[1], data.columns[2]],\n                fill = dict(color='#C2D4FF'),\n                align = ['left'] * 5),\n    cells=dict(values=[data[data.columns[0]], data[data.columns[1]], data[data.columns[2]]],\n               fill = dict(color='#F5F8FF'),\n               align = ['left'] * 5))\n    layout = go.Layout(\n     autosize=True)\n\n    data = [trace]\n    filename = 'pandas_table'\n    \n    fig = go.Figure(data=data, layout=layout)\n    return [fig, filename]\n\n\ndef generate_bar_plot(x_data, y_data, data, pal, xaxis_title, yaxis_title, title, hue):\n    fig, axes = plt.subplots(1,1,figsize=(10,10))\n    ax = sns.barplot(x = x_data, y=y_data, data=data, palette=pal, hue = hue)\n    ax.set_ylabel(yaxis_title,fontsize=15)\n    ax.set_xlabel(xaxis_title,fontsize=15)\n    ax.set_title(title ,fontsize=15)\n    ax.tick_params(labelsize=12.5)\n    try:\n        plt.setp(ax.get_legend().get_texts(), fontsize='15') # for legend text\n        plt.setp(ax.get_legend().get_title(), fontsize='15') # for legend title\n        \n        plt.show()\n    except:\n        plt.show()\n        \n\ndef generate_line_plot(x_data, y_data, data, xaxis_title, yaxis_title, title):\n    fig, axes = plt.subplots(1,1,figsize=(10,10))\n    ax = sns.lineplot(x = x_data, y=y_data, data=data)\n    ax.set_ylabel(yaxis_title,fontsize=15)\n    ax.set_xlabel(xaxis_title,fontsize=15)\n    ax.set_title(title ,fontsize=15)\n    ax.tick_params(labelsize=12.5)\n    try:\n        plt.setp(ax.get_legend().get_texts(), fontsize='15') # for legend text\n        plt.setp(ax.get_legend().get_title(), fontsize='15') # for legend title\n        \n        plt.show()\n    except:\n        plt.show()\n\n\ndef pie_chart(data, x, y, colour, title):    \n    data.iplot(kind='pie', labels = y, values = x, pull=.1, hole=.1,  \n          colorscale = colour, textposition='outside', \n        title = title)    \n\n    \ndef scatter_plot(x, y, label, colour, xaxis_title, yaxis_title, title):\n    \n    fig,ax = plt.subplots(1,1,figsize=(10, 10))\n    plt.scatter(x, y, color= colour, alpha=1, label= label)\n    ax.set_ylabel(yaxis_title,fontsize=15)\n    ax.set_xlabel(xaxis_title,fontsize=15)\n    ax.set_title(title ,fontsize=15)\n    ax.tick_params(labelsize=10)\n    plt.legend()\n    plt.show()\n    \n    \ndef bubble_plot(data, x, y, colour, xaxis_title, yaxis_title, title, size, categories):\n    data.iplot(kind ='bubble', colorscale = colour, categories= categories, x = x, y = y, size = size,\n                xTitle = xaxis_title, yTitle = yaxis_title, title = title)\n    \n    \ndef plotly_stacked_bar(data, categories, x_data, y_data, x_title, y_title, title):\n    temp_data = []\n   \n    for index, item in enumerate(categories):\n        trace = go.Bar(\n        x = data[index][x_data],\n        y = data[index][y_data],\n        name=item)\n        temp_data.append(trace)\n\n    data = temp_data\n    layout = go.Layout(\n    barmode='stack',\n    title=title,\n    xaxis=go.layout.XAxis(title=x_title),\n    yaxis=go.layout.YAxis(title=y_title)\n    )\n\n    fig = go.Figure(data=data, layout=layout)\n    iplot(fig, filename='stacked-bar')\n    \n\ndef pyramid_plot(data_1, data_2, name_1, name_2, x_title, title, category, category_2):\n\n    values = data_2['Percentage'] * -1\n    values = values.append(data_1['Percentage'])\n    values = values.sort_values(ascending=True)\n\n    min_v = int(values.min())\n    max_v = int(values.max())\n    values = [int(i) for i in values]\n\n    labels = data_2['Percentage'] * -1\n    labels = labels.append(data_1['Percentage'])\n    labels = labels.sort_values(ascending=True)\n    labels = [int(i) for i in labels]\n\n    new_labels =[]\n    for item in labels:\n        if item < 0:\n            item = item * -1\n            new_labels.append(item)\n        else:\n            new_labels.append(item)\n\n    data_2['Percentage'] = data_2['Percentage'] * -1\n\n\n    layout = go.Layout(title=title,\n                       yaxis=go.layout.YAxis(tickangle=-15),\n                       xaxis=go.layout.XAxis(\n                           tickangle=-55,\n                           range=[min_v, max_v],\n                           tickvals= [int(i) for i in values],\n                           ticktext= new_labels,\n                           title=x_title),\n                       barmode='overlay',\n                       bargap=0.5,\n                       height=500,\n                      width=900, \n                      margin=go.layout.Margin(l=225, r=0))\n\n    data = [go.Bar(y=data_1[category],\n                   x=data_1['Percentage'],\n                   orientation='h',\n                   name=name_1,\n                   marker=dict(color='green')\n                   ),\n            go.Bar(y=data_1[category],\n                   x=data_2['Percentage'],\n                   orientation='h',\n                   name=name_2,\n                   marker=dict(color='orange')\n                   )]\n\n    iplot(dict(data=data, layout=layout), filename='EXAMPLES/bar_pyramid')\n    \n    \ndef draw_pitch(data, col1, col2, title, poss_team, oppostion):\n    #layout sourced from https://fcpython.com/visualisation/drawing-pitchmap-adding-lines-circles-matplotlib\n    #pitch is 53 yards by 100 yards excluding two 10 yard touchdown zones.\n    labels = ['Goal','10','20','30','40','50','40','30','20','10','Goal']\n    fig = plt.figure(facecolor='white', figsize=(12.5,5))\n    ax = fig.add_subplot(1,1,1)\n    ax.set_facecolor('green')\n    plt.yticks([]) # disable yticks\n    \n    start_x = -10\n    bottom_y = 0\n    top_y = 53\n    \n    ticks = [item * 10 for item in range(0,11)]\n    #(x1,x2) (y1,y2)\n    \n    plt.plot([-10, 110],[0, 0], color='white', linewidth=4)\n    plt.plot([-10, 110],[53, 53], color='white', linewidth=4)\n\n    \n    for item in range(0,28):\n        if item == 0:\n            plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n        \n        if item >=1  and item <= 28:\n            if item % 2 == 1:\n                if item == 0 or item == 27:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5\n                else:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linestyle=\"dashed\")\n                    start_x = start_x + 5\n                \n            else:\n                if start_x >=0 and start_x < 110:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5 \n                    \n    y_value = []\n    for i in range(len(data)):\n        y_value.append(10 + i * 5)\n                    \n    for item in range(len(data)):\n        plt.scatter(data[col1][item], y_value[item], s=80, color=\"red\")\n        plt.scatter(data[col2][item], y_value[item], s=80, color=\"yellow\")\n        ax.text(data[col1][item], y_value[item], poss_team[item], ha='left', size=12.5, color='black')\n        ax.text(data[col2][item], y_value[item], oppostion[item], ha='left', size=12.5, color='black')\n\n    plt.xticks(ticks, labels, size=15)\n    plt.title(title, fontsize=20)\n    plt.show()\n    \n    \ndef draw_heatmap(data, col1, col2, title, levels):\n    #layout sourced from https://fcpython.com/visualisation/drawing-pitchmap-adding-lines-circles-matplotlib\n    #pitch is 53 yards by 100 yards excluding two 10 yard touchdown zones.\n    labels = ['Goal','10','20','30','40','50','40','30','20','10','Goal']\n    fig = plt.figure(facecolor='white', figsize=(12.5,5))\n    ax = fig.add_subplot(1,1,1)\n    ax.set_facecolor('darkgreen')\n    plt.yticks([]) # disable yticks\n    \n    start_x = -10\n    bottom_y = 0\n    top_y = 53\n    \n    ticks = [item * 10 for item in range(0,11)]\n    #(x1,x2) (y1,y2)\n    \n    ax = sns.kdeplot(shade=True, n_levels=levels, data=data, cmap='Greens_r')\n    #ax = sns.scatterplot(col1,col2, data=data, alpha=.4)\n    \n    plt.plot([-10, 110],[0, 0], color='white', linewidth=4)\n    plt.plot([-10, 110],[53, 53], color='white', linewidth=4)\n\n    \n    for item in range(0,28):\n        if item == 0:\n            plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n        \n        if item >=1  and item <= 28:\n            if item % 2 == 1:\n                if item == 0 or item == 27:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5\n                else:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linestyle=\"dashed\")\n                    start_x = start_x + 5\n                \n            else:\n                if start_x >=0 and start_x < 110:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5 \n\n    \n    plt.ylim(0, 53)\n    plt.xlim(-10, 110)\n    plt.xticks(ticks, labels, size=15)\n    plt.title(title, fontsize=20)\n    plt.show()\n    \n    \n    \ndef plotly_scatter(x, y, mode, categories, xaxis, yaxis, title, data ):\n    data.iplot(kind='scatter', mode=mode, categories=categories, x=x, y=y, xTitle=xaxis_title,\n               yTitle=yaxis_title, title=title, filename='cufflinks/simple-scatter')\n    \n\ndef plotly_line_graph(data, x_data, y_data, names, xaxis, yaxis, title):\n    temp = []\n    for index, item in enumerate(data):\n        trace = go.Scatter(x=item[x_data],\n                          y=item[y_data],\n                          name = names[index])\n        temp.append(trace)\n        \n    layout = go.Layout(title=title,\n                       yaxis=go.layout.YAxis(tickangle=-15, title=yaxis),\n                       xaxis=go.layout.XAxis(tickangle=-45, title=xaxis))\n\n    fig = dict(data=temp, layout=layout)\n    iplot(fig, filename='simple-connectgaps')\n    \n    \ndef perform_merge(data1, data2, columns):\n    merged_data = pd.merge(data1, data2, left_on=columns, right_on=columns, suffixes=['','_1'], how='left')\n    return merged_data\n\n\ndef punt_received(data):\n    yards_gained = []\n    \n    for row in data['PlayDescription']:\n        temp = row.split('punts')[1].split(' ')[1]\n        yards_gained.append(int(temp))\n    \n    data['kicked_to'] = yards_gained\n    data['kicked_to'] = data['kicked_to'] + data['kicked_from']\n    return data\n\n\ndef punt_from(data):\n    yardline = []\n    \n    for row in data['YardLine']:\n        temp = row.split(' ')[1]\n        yardline.append(int(temp))\n    \n    data['kicked_from'] = yardline\n    return data\n\n\ndef opposition_team(data): \n    opposition = []\n    \n    for item in data.iterrows():\n        teams = item[1]['Home_Team_Visit_Team'].split('-')\n        poss_team = item[1]['Poss_Team']\n        for element in teams:\n            if poss_team != element:\n                opposition.append(element)\n    data['oppostion'] = opposition\n\n    return data\n\n\ndef visiting_data(data):\n    score_away = []\n    away_team = []\n    for item in data['Score_Home_Visiting']:\n        scores = item.split('-')\n        temp =  int(scores[1])\n        score_away.append(temp)\n        \n    for item in data['Home_Team_Visit_Team']:\n        teams = item.split('-')\n        temp =  teams[1].strip()\n        away_team.append(temp)\n        \n    data['visiting_team'] = away_team    \n    data['visit_score'] = score_away\n    \n    return data\n\n\ndef home_data(data):\n    home_score = []\n    home_team = []\n    for item in data['Score_Home_Visiting']:\n        scores = item.split('-')\n        temp =  int(scores[0])\n        home_score.append(temp)\n        \n    for item in data['Home_Team_Visit_Team']:\n        teams = item.split('-')\n        temp =  teams[0].strip()\n        home_team.append(temp)\n\n    data['home_team'] = home_team     \n    data['home_score'] = home_score\n    \n    return data\n\n\ndef score_difference(data):\n    data['score_diff'] = abs(data['home_score'] - data['visit_score'])\n    \n    return data\n\n\ndef check_winning(data):\n    win_or_lose = []\n    for row in data.iterrows():\n        items = row[1]\n        if items['Poss_Team'] == items['home_team']:\n            if items['home_score'] < items['visit_score']:\n                win_or_lose.append('Losing')\n            if items['home_score'] > items['visit_score']:\n                win_or_lose.append('Winning')\n                \n        elif items['Poss_Team'] == items['visiting_team']:\n            if items['visit_score'] < items['home_score']:\n                win_or_lose.append('Losing')\n            if items['visit_score'] > items['home_score']:\n                win_or_lose.append('Winning')\n                \n        if items['home_score'] == items['visit_score']:\n            win_or_lose.append('Draw Game')\n    \n    data['Poss_Team_Status'] = win_or_lose\n    \n    return data\n\n\ndef missing_data(data):\n    missing = pd.DataFrame(data.isnull().sum()).reset_index()\n    missing.columns = ['Column', 'Count']\n    missing['Percentage_Observations_Missing'] =  missing['Count'] / len(data) * 100\n    return missing\n\n\ndef count_agg(group_columns, data):\n    temp_data = data.groupby(group_columns, as_index=False).size()\n    agg = pd.DataFrame(temp_data.reset_index())\n    group_columns.append('Count')\n    agg.columns = group_columns\n    agg['Percentage'] = agg['Count'] / agg['Count'].sum() * 100\n    \n    return agg\n\n\ndef merge_all(play_data, dataframes):\n    for item in dataframes:\n        cols = list(play_data.columns.intersection(item.columns))\n        play_data = perform_merge(play_data, item, cols)\n    \n    return play_data\n\n\ndef get_merged():\n    game = game_data() #general game data, date, time, location etc.\n    play = play_info_data()\n    video_data = vid_review_data() #concussion data, how it happened etc.\n    role = player_role_data() #players role during the pun\n    punt = player_punt_data() #player postion\n    injury = vid_injury_data()\n\n    injury = injury.rename(columns={'gamekey':'GameKey', 'playid':'PlayID'})\n\n    dataframes = [role, punt]\n    all_data = merge_all(game, dataframes)\n    all_data = perform_merge(all_data, play, columns=['GameKey', 'PlayID','Season_Year'])\n\n    del(game)\n    del(play)\n    del(role)\n    del(punt)\n    gc.collect()\n    \n    return all_data\n\n\ndef get_NGS_data(data):\n    usecols = None\n    \n    NGS = get_NGS_data_pre()\n    cols = list(data.columns.intersection(NGS.columns))\n    pre = data.merge(NGS, on = cols)\n    \n    NGS = get_NGS_data_reg16(usecols)\n    cols = list(data.columns.intersection(NGS.columns))\n    reg16 = data.merge(NGS, on = cols)\n    \n    NGS = get_NGS_data_reg17(usecols)\n    cols = list(data.columns.intersection(NGS.columns))\n    reg17 = data.merge(NGS, on = cols)\n    \n    NGS = get_NGS_data_post()\n    cols = list(data.columns.intersection(NGS.columns))\n    post = data.merge(NGS, on = cols)\n\n    pre = pre.append(reg16)\n    pre = pre.append(reg17)\n    pre = pre.append(post)\n    \n    return pre\n\n\ndef group_interactive_data(data):\n    grouped = data.groupby(by=['GameKey', 'GSISID', 'PlayID'])\n    return grouped\n\n\ndef interactive_plot_visible(visible, total_items):\n    vis = []\n    \n    if visible == 0:\n        vis = [True]\n        for item in range(total_items - 1):\n            vis.append(False)\n    else:\n        for index, item in enumerate(range(total_items)):\n            if index == visible:\n                vis.append(True)\n            else:\n                vis.append(False)\n    \n    return vis\n\n\ndef gen_interactive_plot(button_labels, dataframes, col1, col2):\n    traces = []\n    menu_items = []\n    buttons = []\n    list_buttons = dict(active=0)\n    \n    for index, item in enumerate(dataframes):\n        item = item.sort_values('Time')\n        item = item.drop_duplicates(subset=['x', 'y'])\n        item = assign_colours(item)\n        #each trace contains all coordinates for entire dataframe\n        trace = go.Scatter(x=list(item[col1]),\n                            y=list(item[col2]),\n                            #name=button_labels[index],\n                           text = item['Event'],\n                            mode = 'lines+markers',\n                          marker = dict(\n                            size = 10,\n                            color = item['Colour']))\n        traces.append(trace)\n        \n    data = traces\n    \n    button = dict(label = 'All Plays',\n                 method = 'update',\n                 args = [{'visible': [True for item in range(len(button_labels)) ]},\n                         {'title': 'Player Movement: '}])\n    buttons.append(button)\n    \n    for index, item in enumerate(button_labels):\n        button = dict(label = item,\n                 method = 'update',\n                 args = [{'visible': interactive_plot_visible(index, len(button_labels)) },\n                         {'title': 'Player Movement: ' + item}])\n        buttons.append(button)\n    \n                      \n    list_buttons.update({'buttons':buttons, 'direction':'down',\n        'pad': {'r': 10, 't': 10},\n        'showactive': True,\n        'x': 0.1,\n        'xanchor': 'left',\n        'y': 1.15,\n        'yanchor': 'top'})\n    \n    updatemenus = [list_buttons]\n    \n    #Generate field lines\n    x0 = 10\n    x1 = 10\n    y0 = 0\n    y1 = 53\n    \n    #the two side lines\n    lines = []\n    \n    sideline1 = {'type': 'line', 'x0': 0, 'y0': 0, 'x1': 120, 'y1': 0,'line': {'color': 'white','width': 5,},}\n    \n    sideline2 = {'type': 'line', 'x0': 0, 'y0': 53, 'x1': 120, 'y1': 53,'line': {'color': 'white','width': 5,},}\n\n    \n    for item in range(0,22):        \n        if item >=1  and item <= 21:\n            if item % 2 == 1:\n                if item == 0 or item == 21:\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3,},}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n                else:\n                    #dashed lines\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3, },}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n                \n            else:\n                if x0 >=0 and x0 < 110:\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3, 'dash': 'dashdot'},}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n    \n    lines.append(sideline1)\n    lines.append(sideline2)\n\n    layout = dict(title= 'Movements Leading To Injury', showlegend=False,\n                  width=900,\n                  height=520,\n                  margin=dict(t=0, b=60, l=0, r=0),\n                  updatemenus=updatemenus,\n                  plot_bgcolor='MediumSeaGreen',\n                  xaxis=dict(\n                    title='',\n                      range = [0,120],\n                      tickmode='array',\n                      showgrid=False,\n                      tickangle=45,\n                    tickvals=[10,20, 30, 40, 50, 60, 70, 80, 90, 100, 110],\n                    ticktext=['End Zone', 10, 20, 30, 40, 50, 40, 30, 20, 10, 'End Zone'],\n                    showticklabels=True\n                  ),\n                  yaxis=dict(\n                    title='',\n                      showgrid=False,\n                      range = [0,53]\n                  ),\n                 shapes = lines,\n                 annotations=[\n        dict(\n            x=5,\n            y=25,\n            showarrow=False,\n            text='End Zone',\n            textangle=-90,\n            font=dict(\n                family='Overpass',\n                size=22,\n                color='yellow'\n            ),\n            xref='x',\n            yref='y'\n        ),\n        dict(\n            x=115,\n            y=25,\n            showarrow=False,\n            text='End Zone',\n            textangle=-90,\n            font=dict(\n                family='Overpass',\n                size=22,\n                color='yellow'\n            ),\n            xref='x',\n            yref='y'\n        )\n        \n    ])\n    \n\n    fig = dict(data=data, layout=layout)\n    filename='update_dropdown'\n    return [fig, filename]\n\n\ndef assign_colours(dataframe):\n    colours = \"\"\"aliceblue, antiquewhite, aqua, aquamarine, azure,\n            beige, bisque, black, blanchedalmond, blue,\n            blueviolet, brown, burlywood, cadetblue,\n            chartreuse, chocolate, coral, cornflowerblue,\n            cornsilk, crimson, cyan, darkblue, darkcyan,\n            darkgoldenrod, darkgray, darkgrey, darkgreen,\n            darkkhaki, darkmagenta, darkolivegreen, darkorange,\n            darkorchid, darkred, darksalmon, darkseagreen,\n            darkslateblue, darkslategray, darkslategrey,\n            darkturquoise, darkviolet, deeppink, deepskyblue,\n            dimgray, dimgrey, dodgerblue, firebrick,\n            floralwhite, forestgreen, fuchsia, gainsboro,\n            ghostwhite, gold, goldenrod, gray, grey, green,\n            greenyellow, honeydew, hotpink, indianred, indigo,\n            ivory, khaki, lavender, lavenderblush, lawngreen,\n            lemonchiffon, lightblue, lightcoral, lightcyan,\n            lightgoldenrodyellow, lightgray, lightgrey,\n            lightgreen, lightpink, lightsalmon, lightseagreen,\n            lightskyblue, lightslategray, lightslategrey,\n            lightsteelblue, lightyellow, lime, limegreen,\n            linen, magenta, maroon, mediumaquamarine,\n            mediumblue, mediumorchid, mediumpurple,\n            mediumseagreen, mediumslateblue, mediumspringgreen,\n            mediumturquoise, mediumvioletred, midnightblue,\n            mintcream, mistyrose, moccasin, navajowhite, navy,\n            oldlace, olive, olivedrab, orange, orangered,\n            orchid, palegoldenrod, palegreen, paleturquoise,\n            palevioletred, papayawhip, peachpuff, peru, pink,\n            plum, powderblue, purple, red, rosybrown,\n            royalblue, saddlebrown, salmon, sandybrown,\n            seagreen, seashell, sienna, silver, skyblue,\n            slateblue, slategray, slategrey, snow, springgreen,\n            steelblue, tan, teal, thistle, tomato, turquoise,\n            violet, wheat, white, whitesmoke, yellow,\n            yellowgreen\"\"\"\n\n    colour = []\n    for item in colours.split(','):\n        item = str(item.strip())\n        colour.append(item)\n    \n\n    shuffle(colour)\n    dataframe['Event'] = dataframe['Event'].replace(np.nan, 'General Play')\n    dataframe['Colour'] = 'blue'\n    colour.remove('blue')\n    colour.remove('green')\n    \n    for index, event in enumerate(pd.unique(dataframe['Event'])):\n        dataframe.loc[dataframe['Event'] == event, 'Colour'] = colour[index]\n        colour.remove(colour[index]) #stop colours being duplicated\n\n    return dataframe\n\n\ndef assign_matplot_colours(dataframe):\n    colour_list = []\n    for key in mcolors.CSS4_COLORS:\n        colour_list.append(key)\n    \n    shuffle(colour_list)\n    dataframe['Event'] = dataframe['Event'].replace(np.nan, 'General Play')\n    dataframe['Colour'] = 'blue'\n    colour_list.remove('blue')\n    colour_list.remove('green')\n    colour_list.remove('white')\n    colour_list.remove('red')\n    \n    for index, event in enumerate(pd.unique(dataframe['Event'])):\n        dataframe.loc[dataframe['Event'] == event, 'Colour'] = colour_list[index]\n        colour_list.remove(colour_list[index])#stop colours being duplicated\n        \n\n    return dataframe\n\n\ndef plot_play(dataframe):\n    dataframe = dataframe.sort_values('Time')\n    dataframe = assign_colours(dataframe)\n    dataframe = dataframe.drop_duplicates(subset=['x', 'y'])\n    list_coords = []\n    coordinates = {}\n\n    title = list(dataframe['Home_Team'])[0] + ' vs. ' + list(dataframe['Visit_Team'])[0]\n\n\n    ####################################################\n     #Generate field lines\n    x0 = 10\n    x1 = 10\n    y0 = 0\n    y1 = 53\n\n    #the two side lines\n    lines = []\n\n    sideline1 = {'type': 'line', 'x0': 0, 'y0': 0, 'x1': 120, 'y1': 0,'line': {'color': 'white','width': 5,},}\n\n    sideline2 = {'type': 'line', 'x0': 0, 'y0': 53, 'x1': 120, 'y1': 53,'line': {'color': 'white','width': 5,},}\n\n\n    for item in range(0,22):        \n        if item >=1  and item <= 21:\n            if item % 2 == 1:\n                if item == 0 or item == 21:\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3,},}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n                else:\n                    #dashed lines\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3, },}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n\n            else:\n                if x0 >=0 and x0 < 110:\n                    line = {'type': 'line', 'layer':'below', 'x0': x0, 'y0': y0, 'x1': x1, 'y1': y1,\n            'line': {'color': 'white','width': 3, 'dash': 'dashdot'},}\n                    lines.append(line)\n                    x0 = x0 + 5\n                    x1 = x1 + 5\n\n    lines.append(sideline1)\n    lines.append(sideline2)\n    \n\n    for item in dataframe.iterrows():\n        data = item[1]\n        list_coords.append({'data' : [{'x': [data['x']], 'y':[data['y']], 'type':'scattergl', 'text': data['Event'], 'name': data['Event'], 'mode':'lines+markers', 'marker': {'size' : 15, 'color': data['Colour']}}]})\n        \n    \n    figure = {'data': list_coords[0]['data'],\n              'layout': {'shapes' : lines,\n                         'showlegend' :True,\n                        'plot_bgcolor' :'MediumSeaGreen',\n                  'xaxis': {'range': [0, 120], 'autorange': False,\n                            'tickvals' :[10,20, 30, 40, 50, 60, 70, 80, 90, 100, 110],\n                            'ticktext' : ['End Zone', 10, 20, 30, 40, 50, 40, 30, 20, 10, 'End Zone'],\n                           'showgrid' : False,\n                          'tickangle' : 45},\n                  'yaxis': {'range': [0, 53], 'autorange': False, 'showgrid' : False},\n                         'updatemenus': [{'type': 'buttons',\n                                          'active':-1,  \n                                          'buttons': [\n                                              {\n                                        'args': [None, {'frame': {'duration': 200, 'redraw': False}, 'mode': \"immediate\",\n                                                 'fromcurrent': True, 'transition': {'duration': 200, 'easing': 'quadratic-in-out',}}],\n                                        'label': 'Play',\n                                        'method': 'animate',\n                                        \"execute\": True,\n                                    },\n                                    {\n                                        'args': [[None],{'frame': {'duration': 10, 'redraw': False}, 'mode': 'immediate',\n                                        'transition': {'duration': 0}}],\n                                        'label': 'Pause',\n                                        'method': 'animate',\n                                        \"execute\": True\n                                    }\n                                              ]}],\n                         \n                         'annotations' :[\n                                            dict(\n                                                x=5,\n                                                y=25,\n                                                showarrow=False,\n                                                text='End Zone',\n                                                textangle=-90,\n                                                font=dict(\n                                                    family='Overpass',\n                                                    size=22,\n                                                    color='yellow'\n                                                ),\n                                                xref='x',\n                                                yref='y'\n                                            ),\n                                            dict(\n                                                x=115,\n                                                y=25,\n                                                showarrow=False,\n                                                text='End Zone',\n                                                textangle=-90,\n                                                font=dict(\n                                                    family='Overpass',\n                                                    size=22,\n                                                    color='yellow'\n                                                ),\n                                                xref='x',\n                                                yref='y'\n                                            )],\n                         'title': title},\n              'frames': list_coords}\n    return figure\n\n\ndef animate_play(data, title):\n    %matplotlib inline\n\n    #layout sourced from https://fcpython.com/visualisation/drawing-pitchmap-adding-lines-circles-matplotlib\n    #pitch is 53 yards by 100 yards excluding two 10 yard touchdown zones.\n    labels = ['Goal','10','20','30','40','50','40','30','20','10','Goal']\n    fig = plt.figure(facecolor='white', figsize=(12.5,8))\n    ax = fig.add_subplot(1,1,1)\n    ax.set_facecolor('MediumSeaGreen')\n    plt.xlim(-15, 115)\n    plt.ylim(-5, 58)\n    plt.yticks([]) # disable yticks\n    \n    start_x = -10\n    bottom_y = 0\n    top_y = 53\n    \n    ticks = [item * 10 for item in range(0,11)]\n    #(x1,x2) (y1,y2)\n    \n    plt.plot([-10, 110],[0, 0], color='white', linewidth=4)\n    plt.plot([-10, 110],[53, 53], color='white', linewidth=4)\n\n    \n    for item in range(0,28):\n        if item == 0:\n            plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n        \n        if item >=1  and item <= 28:\n            if item % 2 == 1:\n                if item == 0 or item == 27:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5\n                else:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linestyle=\"dashed\")\n                    start_x = start_x + 5\n                \n            else:\n                if start_x >=0 and start_x < 110:\n                    plt.plot([start_x, start_x],[bottom_y, top_y], color='white', linewidth=4)\n                    start_x = start_x + 5 \n    \n    \n    data = home_data(data)\n    data = visiting_data(data)\n    data = check_winning(data)\n    data['x'] = data['x'] - 10\n    \n    data = data.sort_values('Time')\n    \n    data = data.drop_duplicates(subset=['x','y','Event'])\n   \n    partners_data = partner_data(data)\n    data = assign_matplot_colours(data)\n    \n    play = data.iloc[0] #select data range\n\n    title = 'Home Team: ' + str(play['home_team']) + '. Visiting Team: ' + str(play['visiting_team']) + '.\\n Home Score: ' + str(play['home_score']) + ' Visiting Team Score: ' + str(play['visit_score'])\n    title = title + '.\\n Possession Team: ' + str(play['Poss_Team']) + '. Possession Team Status: ' +  str(play['Poss_Team_Status'])\n    plt.title(title, fontsize=20)\n    \n    x = play['x']\n    y = play['y']\n    label = play['Event'] # Event\n    colour = play['Colour'] # Event colour\n    p1 = plt.scatter(x=x, y=y, s=100, c=colour, label=label, alpha=0.4)\n    \n    if len(partners_data) > 0:\n        \n        partner_play = partners_data.iloc[0] #select data range\n        partner_x = partner_play['x']\n        partner_y = partner_play['y']\n        p2 = plt.scatter(x=partner_x, y=partner_y, s=100, c='red', alpha=0.4)\n        annotate = 'Primary Partner'\n        plt.text(partner_x, partner_y, annotate, ha='left', size=12.5, color='black')\n    \n    annotate = 'Player'\n    plt.text(x, y, annotate, ha='left', size=12.5, color='black')\n    plt.legend(fontsize=15)\n    \n    \n    def animate(i):\n        if i > 1:\n            play = data.iloc[int(i+1)] #select data range\n            x = play['x']\n            y = play['y']\n                        \n                \n            if i+1 < len(partners_data):\n                partner_play = partners_data.iloc[int(i+1)] #select data range\n                partner_x = partner_play['x']\n                partner_y = partner_play['y']\n                \n            label = play['Event']\n            if label != 'General Play':\n                colour = play['Colour']\n                \n                p1 = plt.scatter(x=x, y=y, s=100, c=colour, label=label, alpha=0.4)\n                \n                if i+1 < len(partners_data):\n                    p2 = plt.scatter(x=partner_x, y=partner_y, s=100, c='red', alpha=0.4)\n                    \n                plt.legend(fontsize=15)\n            else:\n                colour = play['Colour']\n                \n                p1 = plt.scatter(x=x, y=y, s=100, c=colour, alpha=0.4)\n                if i+1 < len(partners_data):\n                    p2 = plt.scatter(x=partner_x, y=partner_y, s=100, c='red', alpha=0.4)\n\n                \n                plt.legend(fontsize=15)\n                \n        if i == 1:\n            play = data.iloc[int(i+1)] #select data range\n            x = play['x']\n            y = play['y']\n            \n            label = play['Event']\n            colour = play['Colour']\n            p1 = plt.scatter(x=x, y=y, s=100, c=colour, label=label, alpha=0.4)\n            if i+1 < len(partners_data):\n                partner_play = partners_data.iloc[int(i+1)] #select data range\n                partner_x = partner_play['x']\n                partner_y = partner_play['y']\n                p2 = plt.scatter(x=partner_x, y=partner_y, s=100, c='red', alpha=0.4)\n                \n            plt.legend(fontsize=15)\n            \n    \n    plt.xticks(ticks, labels, size=15)\n    ax.legend(bbox_to_anchor=(1.1, 1.05))\n            \n    myAnimation = animation.FuncAnimation(fig, animate, frames=len(data)-1, interval=100, repeat=False)\n    \n    return HTML(myAnimation.to_jshtml(fps=5)) \n\n\ndef partner_data(data):\n    temp = data[['Season_Year', 'GameKey', 'PlayID', 'Primary_Partner_GSISID', 'Season_Type', 'Week', 'Game_Date']]\n    temp = temp.rename(columns={'Primary_Partner_GSISID': 'GSISID'})\n    temp['GSISID'] = temp['GSISID'].astype(np.float32)\n    \n    usecols = None    \n    \n    if temp['Season_Type'].iloc[0] == 'Pre':\n        NGS = get_NGS_data_pre()\n        cols = list(temp.columns.intersection(NGS.columns))\n        temp = temp.merge(NGS, on = cols)\n            \n    if temp['Season_Type'].iloc[0] == 'Reg':\n        if temp['Season_Year'].iloc[0] == 2016:\n            NGS = get_NGS_data_reg16(usecols)\n            cols = list(temp.columns.intersection(NGS.columns))\n            temp = temp.merge(NGS, on = cols)\n        else:\n            NGS = get_NGS_data_reg17(usecols)\n            cols = list(temp.columns.intersection(NGS.columns))\n            temp = temp.merge(NGS, on = cols)\n           \n    elif temp['Season_Type'].iloc[0] == 'Post':\n        NGS = get_NGS_data_post()\n        cols = list(temp.columns.intersection(NGS.columns))\n        temp = temp.merge(NGS, on = cols)\n            \n    \n    temp = temp.rename(columns={'GSISID':'Primary_Partner_GSISID'})\n    temp['x'] = temp['x'] - 10 \n    temp['Event'] = temp['Event'].replace(np.nan, 'General Play')\n    temp = temp.sort_values('Time')\n    temp = temp.drop_duplicates(subset=['x','y','Event'])\n\n    return temp","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1c3345250d99d39404e1bb4c509487fb447b7a46"},"cell_type":"markdown","source":"Given that the emphasis of the competition is on punt plays lets have an overview of them now. Where on the field are punts most used?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"3a769cb2e4b7a54d2855ccd68abb52da7fe1d419"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'P']\nNGS = get_NGS_data_pre() #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True)\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\ntemp = all_data[all_data['Season_Type'] == 'Pre']\npunts = temp.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\n\npunts_2016 = punts[punts['Season_Year_x'] == 2016]\npunts_2017 = punts[punts['Season_Year_x'] == 2017]\n\nlevels = 50\ndraw_heatmap(punts_2016[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in the 2016 Pre-Season?', levels)\ndraw_heatmap(punts_2017[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in 2017 Pre-Season?', levels)\n\ndel(punts_2016)\ndel(punts_2017)\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"af982c0ee419197d792720d13c39e8ecbc6a5468"},"cell_type":"markdown","source":"Ok so we see here that the usage of punts in the 2016 and 2017 pre season is almost idententical. We can see that the punt play was often deployed quite evenly accross the field with a slight emphasis in deeper areas around the 10 and 20 yard lines."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"19a0a26fa485a25b1b2439d39c4b53eb60a43168"},"cell_type":"code","source":"usecols = ['Season_Year', 'GameKey', 'PlayID', 'GSISID', 'Time', 'x', 'y']\nNGS = get_NGS_data_reg16(usecols) #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True) \n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\ntemp = all_data[(all_data['Season_Type'] == 'Reg') & (all_data['Season_Year'] == 2016)]\npunts = temp.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\n\npunts = count_agg(['X', 'Y'], punts)\npunts.sort_values(by='Count', inplace=True, ascending=False)\n\nlevels = 50\ndraw_heatmap(punts[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in the 2016 Regular Season?', levels)\n\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ec14ddf8ea377888d3ac6dc161a13ac192f13d79"},"cell_type":"markdown","source":"The 2016 regular season shows us that punts were used extensively between the both 10 yard lines in each half. Looking closely at the figure we see the punt being used marginally more in mid-field areas."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"daf0cbad4168823c57ade72b7ad0ae29add64941"},"cell_type":"code","source":"usecols = ['Season_Year', 'GameKey', 'PlayID', 'GSISID', 'Time', 'x', 'y']\nNGS = get_NGS_data_reg17(usecols) #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True)\n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\npunts = all_data.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\n\npunts = count_agg(['X', 'Y'], punts)\npunts.sort_values(by='Count', inplace=True, ascending=False)\n\nlevels = 50\ndraw_heatmap(punts[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in 2017 Regular Season?', levels)\n\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"703288f9232eb1d59e4bf8d6fd4c0d752b37dca8"},"cell_type":"markdown","source":"The 2017 regular season is almost an exact replica of the 2016 regular season. Again we see the punt being used broadly in the mid-field area."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"efb73044a10d7d884b0fbe2c0a7998b9174b6141"},"cell_type":"code","source":"NGS = get_NGS_data_post() #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\npunts = all_data.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\n\npunts_2017 = punts[punts['Season_Year_x'] == 2017] \npunts_2016 = punts[punts['Season_Year_x'] == 2016] \n\nlevels = 50\ndraw_heatmap(punts_2016[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in the 2016 Post Season?', levels)\ndraw_heatmap(punts_2017[['X', 'Y']], 'X', 'Y', 'Where were punts taken from in 2017 Post Season?', levels)\n\ndel(punts_2016)\ndel(punts_2017)\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ea82bd24bbe8aa2df07e8812195322addc4c1e24"},"cell_type":"markdown","source":"So theres a slight difference in the 2016 and 2017 post season punt heatmaps. In 2016 the punts are used a lot between the 40 yard line and opposite 10 yard line. In 2017 punts appeared to be taken more around the 30 and 35 yard lines.\n\nNow lets look at where the punts are received."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"cfe4888adcb37c35d093a5dd6a3f337ef8b20867"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'PR']\nNGS = get_NGS_data_pre() #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True)\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\ntemp = all_data[all_data['Season_Type'] == 'Pre']\npunts = temp.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\npunts = punts[punts['Event'] == 'punt_received']\n\npunts_2016 = punts[punts['Season_Year_x'] == 2016]\npunts_2017 = punts[punts['Season_Year_x'] == 2017]\n\nlevels = 50\ndraw_heatmap(punts_2016[['X', 'Y']], 'X', 'Y', 'Where were punts received in the 2016 Pre-Season?', levels)\ndraw_heatmap(punts_2017[['X', 'Y']], 'X', 'Y', 'Where were punts received in 2017 Pre-Season?', levels)\n\ndel(punts_2016)\ndel(punts_2017)\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3beb730174e5a5058fe94acf071af813729d2fcb"},"cell_type":"markdown","source":"So here we see how useful a punt can be. In the above figures we see similar patterns for the 2016 and 2017 pre seasons where punts are being received close around the 20 yard lines. This shows how useful punt plays can be to force the oppostion deep into their own halves and relieve pressure on the team taking the punt."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"5d1c34fe4a59bfd66b9aaaf59466c1d2d8949d7f"},"cell_type":"code","source":"usecols = ['Season_Year', 'GameKey', 'PlayID', 'GSISID', 'Time', 'x', 'y', 'Event']\nNGS = get_NGS_data_reg16(usecols) #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True)\n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\ntemp = all_data[(all_data['Season_Type'] == 'Reg') & (all_data['Season_Year'] == 2016)]\npunts = temp.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\npunts = punts[punts['Event'] == 'punt_received']\n\n\npunts = count_agg(['X', 'Y'], punts)\npunts.sort_values(by='Count', inplace=True, ascending=False)\n\nlevels = 50\ndraw_heatmap(punts[['X', 'Y']], 'X', 'Y', 'Where were punts received in the 2016 Regular Season?', levels)\n\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e8670753b70369d008b633d5f4fe82805f4f2736"},"cell_type":"markdown","source":"Again we see in the 2016 regular season how useful the punt can be to pressurise the returning team as they are receiving the ball deep in their own half."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"119746a730c4d292e97c6a200202575d3e02e5c2"},"cell_type":"code","source":"usecols = ['Season_Year', 'GameKey', 'PlayID', 'GSISID', 'Time', 'x', 'y', 'Event']\nNGS = get_NGS_data_reg17(usecols) #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n#NGS.drop_duplicates(subset=['x', 'y'], inplace=True)\n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\npunts = all_data.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\npunts = punts[punts['Event'] == 'punt_received']\n\n\npunts = count_agg(['X', 'Y'], punts)\npunts.sort_values(by='Count', inplace=True, ascending=False)\n\nlevels = 50\ndraw_heatmap(punts[['X', 'Y']], 'X', 'Y', 'Where were punts received in 2017 Regular Season?', levels)\n\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ab3edcf28d7e013a282a83a9201f51cd087da8f9"},"cell_type":"markdown","source":"Similarly we see in the 2017 regular season that the punt is received in simalar positions to the 2016 regular season. "},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"538fa6bc0e13cdfc518b465040c9c4e93789eec9"},"cell_type":"code","source":"NGS = get_NGS_data_post() #player position, direction etc.\nNGS['x'] = NGS['x'] - 10\n\ncolumns = ['GameKey' , 'GSISID', 'PlayID']\npunts = all_data.merge(NGS, on= columns)\n\ndel(NGS)\ngc.collect()\n\npunts = punts.rename(columns = {'x':'X', 'y':'Y'})\npunts = punts[(punts['X'] >= -10) | (punts['X'] <= 110)]\npunts = punts[(punts['Y'] >= 0) | (punts['Y'] <= 53)]\npunts = punts[punts['Event'] == 'punt_received']\n\npunts_2017 = punts[punts['Season_Year_x'] == 2017] \npunts_2016 = punts[punts['Season_Year_x'] == 2016]\n\n\nlevels = 50\ndraw_heatmap(punts_2016[['X', 'Y']], 'X', 'Y', 'Where were punts received in the 2016 Post Season?', levels)\ndraw_heatmap(punts_2017[['X', 'Y']], 'X', 'Y', 'Where were punts received in 2017 Post Season?', levels)\n\ndel(punts_2016)\ndel(punts_2017)\ndel(punts)\ngc.collect()\nprint('')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"346001b3ff8e563efddb87589b2a51b32e6fc163"},"cell_type":"markdown","source":"The 2016 Post season showed punts were received in roughly the same areas as the pre season. In 2017 however the punts are predominantly received on the 25 - 30 yard line.\n\nAt this stage I think I can say that the punt play should be kept in the game given how useful it can be to go from being in a high pressure scenario to putting the opposition in a similar scenario with one kick of a ball.\n\nI will now look at the distrution of punts by type of season."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"07ee047fa7c81267ad217059d1ba9456d525c524"},"cell_type":"code","source":"merged_data = get_merged()\ntemp = merged_data[merged_data['Role'] == 'PR']\npunts_per_game = count_agg(['Play_Type', 'Season_Year', 'Season_Type'], temp)\n\nx_data = 'Season_Type' \ny_data = 'Percentage'\nhue = 'Season_Year'\n\npal = 'Greens_r'\nxaxis_title = 'Football Season'\nyaxis_title = 'Percentage'\ntitle = 'Distribution of punts per football season'\n\ngenerate_bar_plot(x_data, y_data, punts_per_game, pal, xaxis_title, yaxis_title, title, hue)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"46781815a96721d77595bb3a82b0b8f745464697"},"cell_type":"markdown","source":"Given the number of games that take place in the regular season its no surprise that most of the punts occur here. Interestingly there is very little reliance on punts in the post season. Again I believe this to be the result of the post season being a high pressure tournament and teams tightening up offensively and defensively."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"be480c69835e722c6aed0897ef001cc23cdc7933"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'P']\ntemp = all_data\npunts_per_game = count_agg(['Poss_Team', 'Play_Type', 'Season_Year'], temp)\npunts_per_game['Season_Year'] = punts_per_game['Season_Year'].astype(str)\n\n_2016_Data = punts_per_game[punts_per_game['Season_Year'] == '2016'].sort_values('Poss_Team', ascending=False)\n_2017_Data = punts_per_game[punts_per_game['Season_Year'] == '2017'].sort_values('Poss_Team', ascending=False)\n_2017_Data = _2017_Data[_2017_Data['Poss_Team'] != 'LAC']\n\nx_data = 'Poss_Team'\ny_data = 'Count'\nxaxis = 'Team'\nyaxis = 'Count of Punts Per Year'\ntitle = 'Teams Utilising the Punt the most.'\n\nnames = ['2016', '2017']\nplotly_line_graph([_2016_Data, _2017_Data], x_data, y_data, names, xaxis, yaxis, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"588e09a4298300004118f15013348469a9e02d8b"},"cell_type":"markdown","source":"**Note** there is no data for the Los Angeles Chargers (LAC) in 2016 due to their rebranding so they are excluded from this plot.\n\nIn 2016 it appears the Minnesota Vikings (MIN) and the Carolina Panthers (CAR) were most relliant on the punt. In comparison the Atlanta Falcons (AL), the New Orleans Saints (NO) and the Washington Redskins (WAS) were least reliant\n\nIn 2017 the Indianapolis Colts (IND) and the Carolina Panthers (CAR) were most reliant on punts. In comparison the Tampa Bay Buccaneers (TB), the New England Patriots (NE) and the Dallas Cowboys (DAL) performed the fewest punts in 2017.\n\nSo we know who's using punts and roughly where they are using them, but we don't know why. To address this I want to look at what stage of the game punts are usually taken and what the possession teams status is in terms of whether they are winning or losing the game."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"3842b1370961e849f87fd6771eb27d7d3dc69bcd"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'PR']\ntemp = all_data\npunts_per_game = count_agg(['Poss_Team', 'Play_Type', 'Season_Year'], temp)\npunts_per_game['Season_Year'] = punts_per_game['Season_Year'].astype(str)\n\n_2016_Data = punts_per_game[punts_per_game['Season_Year'] == '2016'].sort_values('Poss_Team', ascending=False)\n_2017_Data = punts_per_game[punts_per_game['Season_Year'] == '2017'].sort_values('Poss_Team', ascending=False)\n_2017_Data = _2017_Data[_2017_Data['Poss_Team'] != 'LAC']\n\nx_data = 'Poss_Team'\ny_data = 'Count'\nxaxis = 'Team'\nyaxis = 'Count of Punts Per Year'\ntitle = 'Teams Receiving the most Punts.'\n\nnames = ['2016', '2017']\nplotly_line_graph([_2016_Data, _2017_Data], x_data, y_data, names, xaxis, yaxis, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eed5984a83c7980878ee570b01041b37233b5216"},"cell_type":"markdown","source":"**Note** there is no data for the Los Angeles Chargers (LAC) in 2016 due to their rebranding so they are excluded from this plot.\n\nIn 2016 it appears the Oaklan Raiders (OAK) and the Los Angeles Rams (LA) received the most punts. In comparison the Atlanta Falcons (AL) and the New Orleans Saints (NO) received the least amount.\n\nIn 2017 the Miami Dolphins (MIA) and the Washington Redskins (WAS) appeared to receive the most punts by a fairly small margin. In comparison the Tampa Bay Buccaneers (TB) and Seattle Seahawks (SEA) received the fewest punts in 2017.\n\nSo we know who's using punts and roughly where they are using them, but we don't know why. To address this I want to look at what stage of the game punts are usually taken and what the possession teams status is in terms of whether they are winning or losing the game."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"3393b9e8ef99057e1375c844c53eb52072c9ed01"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'P']\n\npunt_usage = all_data\npunt_usage = punt_usage.dropna(subset=['Score_Home_Visiting']) # remove 4 rows containing nan in this column\npunt_usage = home_data(punt_usage)\npunt_usage = visiting_data(punt_usage)\npunt_usage = check_winning(punt_usage)\n\n\npunt_usage['Quarter'] = punt_usage['Quarter'].astype(np.int8)\npunt_usage['Quarter'] = punt_usage['Quarter'].astype(str)\npunt_usage['Quarter'] = punt_usage['Quarter'].replace('5.0', 'Extra Time')\n\n\npunt_usage = count_agg(['Quarter', 'Poss_Team_Status'], punt_usage)\n\nx_data = 'Quarter'\ny_data = 'Count'\ncategories = pd.unique(punt_usage['Poss_Team_Status'])\nx_title = 'Quarter'\ny_title = 'Count'\ntitle = 'When are punt plays predominantly used and whats the Possession teams status?'\ntemp = []\ndata = []\nfor row in punt_usage.iterrows():\n    for cat in categories:\n        item = row[1]\n        temp = punt_usage[punt_usage['Poss_Team_Status'] == cat]\n        data.append(temp)\n        temp = []\n    \nplotly_stacked_bar(data, categories, x_data, y_data, x_title, y_title, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1dae0ee7a2d86c4bcd7c921e1f023e43ff1f42f0"},"cell_type":"markdown","source":"**NOTE The label 5 on the x axis represents the extra time period**\n\nSo there are a few points we can take away here:\n\n1. Overall, the second quarter has the largest number of punt plays.\n\n\n2. In the first quarter the majority of punts taken by the possession team are done so when they are level on scores with their openents.\n\n\n3. In the second quarter the majority of punts taken by the possession team are done so when they are losing to  their openents. The fact that the possession team are losing indicates they are finding themselves in pressure scenarios such as a 4th down in their own half and having to punt the ball.\n\n\n4. In the third quarter the majority of punts taken by the possession team are done so when they are losing. This is likely for the same reason explained previously.\n\n\n5. In the fourth quarter the majority of punts taken by the possession team are done so when they are winning. My guess is that the possession team is trying to protect their lead by forcing the opposion deep into their own half.\n\n\nThere are some trends to note here, the further into the game you go the more likely the possession team are to be winning and thus less likely to be losing. As I already stated I believe teams utilise the punt play when the are winning to protect their lead by forcing the opposition deep in their own halves.\n\nIn summary we see the punt being used in high pressure scenario's when the team is losing and being pressurised deep in their own half or when the possession team is winning and try desperately to protect their lead."},{"metadata":{"_uuid":"cbc7ce056cdd405fb20e4f267b1e949554f12b42"},"cell_type":"markdown","source":"So we know when punts are used on a relatively granular level, what is the weekly distribution like within each season."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"dfc7547ab7f1806ca688456b5d5dcfd0e540b6fc"},"cell_type":"code","source":"merged_data = get_merged()\nall_data = merged_data[merged_data['Role'] == 'P']\npunts_per_game = count_agg(['Season_Type', 'Week'], all_data)\npunts_per_game['Week'] = punts_per_game['Week'].astype(str)\npunts_per_game\n\n\nx_data = 'Week'\ny_data = 'Count'\ncategories = pd.unique(punts_per_game['Season_Type'])\nx_title = 'Week'\ny_title = 'Count'\ntitle = 'Weekly punt distribution per Season Type'\ntemp = []\ndata = []\nfor row in punts_per_game.iterrows():\n    for cat in categories:\n        item = row[1]\n        temp = punts_per_game[punts_per_game['Season_Type'] == cat]\n        data.append(temp)\n        temp = []\n    \nplotly_stacked_bar(data, categories, x_data, y_data, x_title, y_title, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3fe9a7e3a8c1d1af84562841b0a962790e057f56"},"cell_type":"markdown","source":"In general the number of punts per week in the regular season stays fairly uniform. In the pre season we see a sharp increase between the first week and the remaining 4 weeks of the pre season. Finally the longer the post season goes on the less punt plays appear to be used.\n\nI stated previously we had looked at the punt distribution on a relatively granular level by looking at the number of punts taking place in each quarter. I am going to go a step further with this at look at what minute of each quarter were punt plays used."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"67d8764ae8007a0c0111ee7a3e422966f2566d0c"},"cell_type":"code","source":"all_data['Game_Clock'] = all_data['Game_Clock'].astype(str)\nall_data['Game_Clock_Minute'] = all_data['Game_Clock'].apply(lambda x: x.split(':')[0])\n\npunts_per_min = count_agg(['Quarter', 'Game_Clock_Minute'], all_data)\n\npunts_per_min\n\n\nx_data = 'Game_Clock_Minute'\ny_data = 'Count'\ncategories = pd.unique(punts_per_min['Quarter'])\nx_title = 'Game Clock Minute'\ny_title = 'Count'\ntitle = 'Game Clock Minute at time of Punt per Quarter'\ntemp = []\ndata = []\nfor row in punts_per_min.iterrows():\n    for cat in categories:\n        item = row[1]\n        temp = punts_per_min[punts_per_min['Quarter'] == cat]\n        data.append(temp)\n        temp = []\n    \nplotly_stacked_bar(data, categories, x_data, y_data, x_title, y_title, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c87513117b126b26a103e8777c44e499867315b8"},"cell_type":"markdown","source":"**NOTE The label 5 on the legend represents the extra time period**\n\nFor the most part the distribution of punts per minute per game quarter remains fairly stable with the second minute of the second quarter seeing a slight spike in punt plays. Also the last two minutes see a significant drop in punt plays in all quarters with no punts happening in the last two minutes of extra time at all."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"7f6cbbe537dfb090815550fbe781b54e7e7743ca"},"cell_type":"code","source":"game = game_data() #general game data, date, time, location etc.\nvideo_data = vid_review_data() #concussion data, how it happened etc.\nrole = player_role_data() #players role during the pun\npunt = player_punt_data() #player postion\ninjury = vid_injury_data()\nplay = play_info_data()\n\ninjury = injury.rename(columns={'gamekey':'GameKey', 'playid':'PlayID'})","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"442e7e60b5ff52f03f7d8ecf31ad637687628899"},"cell_type":"markdown","source":"#### 4.1 Video Data EDA <a class=\"anchor\" id=\"4.1\"></a>\nGiven the competition is based on preventing concussions a natural starting point is to look at what activities lead to them happening and more specifically what impacts are associated with them."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"d26d0dfe365d2191215b76df83e42fa7f9ea941a"},"cell_type":"code","source":"print('The number of concussion observations is: ', len(video_data))\nvideo_data.head()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"35a0d644737a7297d8d42eb6c8048a25a8cb923c"},"cell_type":"code","source":"columns = ['Player_Activity_Derived']\ndata = count_agg(columns, video_data)\n\nx_data = 'Player_Activity_Derived' \ny_data = 'Percentage'\nhue = 'Player_Activity_Derived'\n\npal = 'Greens_r'\nxaxis_title = 'Player Activity'\nyaxis_title = 'Percentage'\ntitle = 'Activities Causing Concussion'\n\n\ngenerate_bar_plot(x_data, y_data, data, pal, xaxis_title, yaxis_title, title, hue)\n\n\ncolumns = ['Primary_Impact_Type']\ndata = count_agg(columns, video_data)\n\nx_data = 'Primary_Impact_Type' \ny_data = 'Percentage'\nhue = 'Primary_Impact_Type'\n\npal = 'Oranges_r'\nxaxis_title = 'Type of Impact'\nyaxis_title = 'Percentage'\ntitle = 'Impacts Causing Concussion'\n\ngenerate_bar_plot(x_data, y_data, data, pal, xaxis_title, yaxis_title, title, hue)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e1d406531f65c35e75b8c8670869bfd68b541750"},"cell_type":"markdown","source":"It is no surprise to see Tackling being the biggest cause of concussion although I thought it would be more dominant. Getting blocked also appears to cause over a quarter of concussions. This suggests to me that both of these activities need to be addressed with regards to punts. \n\nHelmet-to-helmet and Helmet-to-body are the most dominant which is to be expected really. Observations marked unclear occurs when one particular impact cannot be identified as the primary reason for the concussion. Helmet-to-ground impacts are not applicable for primary partners. \n\nWe will now dig a little deeper to see what the primary impact was for each of these player activities. But firstly lets check the integrity of the impact data."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"ad9f3c092e0ce5872da2a777c34cf532dba8d450"},"cell_type":"code","source":"data = video_data[['Player_Activity_Derived', 'Primary_Partner_Activity_Derived']]\nresult = generate_table(data)\n\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"77afa416513469c6d5160882929977601272a336"},"cell_type":"markdown","source":"So there are some observations that will need further analysis. Why are two of the of the partner activities null and why do some of them mimic the actions of the primary player."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"e264285ba45846e98ad098b6895d225614ddfb44"},"cell_type":"code","source":"temp = video_data[video_data['Primary_Partner_Activity_Derived'].isnull()]\ntemp","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ccca25e3b2d4edea5a52a6919f31060cb0debf1f"},"cell_type":"markdown","source":"Interestingly the two observations marked null have no partner data are caused by helment-to-ground impacts. Are these the only two helmet-to-ground impacts?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"6dc19c942ab961ecb93f72be42bb22a8f9cbf0d3"},"cell_type":"code","source":"temp = video_data[video_data['Primary_Impact_Type'] == 'Helmet-to-ground']\ntemp","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c7fee508205d099fcc83bfb9079da61ec7160606"},"cell_type":"markdown","source":"And the answer to that question is yes. These appear to be considered more accidental or like \"freak accidents\". I will now check for any reasons why the player and primary partner activities mimic each other."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"0d9912e907c8d6139ba93fe10065791f80f5ca5d"},"cell_type":"code","source":"temp = video_data[video_data['Player_Activity_Derived'] == video_data['Primary_Partner_Activity_Derived']]\nprint('The number of observations where player and primary partner activities are the same is: ', len(temp))\ntemp","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"28921cb47f85ea6dfdbcfb11e8f2440dc1dc01e3"},"cell_type":"markdown","source":"So a brief look indicates that all these observations where the activities match are not turnover related but most importantly is that they are all labelled as friendly fire meaning the impacts are caused by two people on the same team i.e. two players attempting to block or tackle. Hence why some player and primary partner activities match.\n\nLets look at how the player and primary partners activities differ by impact type."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"e6d17b776bbf46d5643c6d429595cb944ec694e0"},"cell_type":"code","source":"columns = ['Primary_Impact_Type', 'Player_Activity_Derived']\ndata = count_agg(columns, video_data)\n\nx_data = 'Player_Activity_Derived' \ny_data = 'Percentage'\nhue = 'Primary_Impact_Type'\n\npal = 'viridis'\nxaxis_title = 'Player Activity'\nyaxis_title = 'Percentage'\ntitle = 'Player Activity by Impact Type'\n\ngenerate_bar_plot(x_data, y_data, data, pal, xaxis_title, yaxis_title, title, hue)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fa82749ae7c20c1c8e42f929e7a1802ee623aebd"},"cell_type":"markdown","source":"    1. Helmet to helmet impacts cause the mosts concussions when the player has been blocked.\n    \n    2. Helmet to helmet and helmet to body impacts causing concussion are most common when a player is trying to block their opponent.\n    \n    3. Helmet to helmet concussions are most common when a player has been tackled.\n    \n    4. Helmet to body impacts causing concussion are most common when the player is performing the tackle. Is the player adequetly positioned?\n    \nMy initial thoughts with helmet to body impacts causing concussions is the players on the receiving end of the concussion are not expecting the impact or are not adequetly positioned for it. \n\nIn my limited knowledge of NFL I have always questioned the tackling process overall. I always note that players appear to lead with their head when they are making a tackle which I never understood. Helmet or no helmet thats going to cause long term damage."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"46247992927287ab470c9ec3834e16f736683960"},"cell_type":"code","source":"columns = ['Primary_Impact_Type', 'Primary_Partner_Activity_Derived']\nprimary = count_agg(columns, video_data)\n\nx_data = 'Primary_Partner_Activity_Derived' \ny_data = 'Percentage'\nhue = 'Primary_Impact_Type'\n\npal = 'viridis'\nxaxis_title = 'Primary Partner Activity'\nyaxis_title = 'Percentage'\ntitle = 'Primary Partner Activity by Impact Type'\n\ngenerate_bar_plot(x_data, y_data, primary, pal, xaxis_title, yaxis_title, title, hue)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"01a56a58c766e7cec98ad2f8f608d6aa31690b1e"},"cell_type":"markdown","source":"Given that helmet-to-ground impacts are not included for primary partner its no surprise that helmet-to-helmet and helmet-to-body are dominant.\n\nIn summary:\n\n       1. The primary partner causes/is involved in EQUAL volumes of helmet-to-helmet and helmet-to-body impacts when being blocked.\n       \n       2. The primary partner causes/is involved in MORE volumes of helmet-to-helmet impacts than helmet-to-body impacts when performing a block.\n       \n       3. The primary partner causes/is involved in LESS volumes of helmet-to-helmet impacts than helmet-to-body impacts when being tackled.\n       \n       4. The primary partner causes/is involved in EQUAL volumes of helmet-to-helmet impacts and helmet-to-body impacts when performing a tackle.\n       \nSo we know what games the concussions happened in. Lets check if any had more than one concussion maybe a particularly heated rivalry for example. "},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"c89efbd6dd9b54e1b4e8188f45abb9c41b907838"},"cell_type":"code","source":"columns = ['GameKey']\nplay_counts = count_agg(columns, video_data)\nprint('Number of games with more than one concussion: ', len(play_counts[play_counts['Count'] >= 2]))\nplay_counts[play_counts['Count'] >= 2]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ac82aed10f5d7c711e9133cdcebb69183683076"},"cell_type":"markdown","source":"3 games had more than 1 concussion. Lets now look at the position each player that suffers a concussion plays.\n\n#### 4.2 Punt Returner (PR) Analysis <a class=\"anchor\" id=\"4.2\"></a>\n\nSo to look at the position a player plays when they get a concussion we need to merge the video review data and player role data by GameKey (unique game identifier across all seasons), GSISID (unique player id) and by PlayID( a non unique play id)."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"622cf6cee70885c62af10096526a896e0dd4b38e"},"cell_type":"code","source":"columns = ['GameKey', 'GSISID' ,'PlayID']\nconcussion_role = perform_merge(video_data, role, columns)\n\ncolumns = ['Role', 'Player_Activity_Derived']\ndata = count_agg(columns, concussion_role)\ndata\nx = 'Role'\ny = 'Percentage'\nsize = 'Percentage'\ncategories = 'Role'\n\n\ncolour = None\nxaxis_title = 'Player Role'\nyaxis_title = 'Percentage of Concussions'\ntitle = 'Player Role vs. Percentage of Concussions'\n\nbubble_plot(data, x, y, colour, xaxis_title, yaxis_title, title, size, categories)  \n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"82d839432ad216d95f6be01e1c4b29e05abbf832"},"cell_type":"markdown","source":"Unsurprisingly Punt Returners (PR) receive the large percentage of concussions at ~13.5 percent. How can a PR protect themselves? They can utilise the already existing fair catch rule for one. But why is it not used more. As previously mentioned a possession team will often punt the ball on a 4th down meaning the opposition (in this case the PR specifically) recieves the ball closer to their end line. Ideally the receiving team will not want to claim a fair catch close to their own end line because it makes gaining yards towards the opposition end line harder so they normally run the ball to both move away from their own end line and closer to the oppositions one.\n\nLets focus on the PR's, PLG's and PRG's for now given that the suffer more concussions than any other postitions. More specifically lets look at what data is missing."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"aef686d80ac70211eaccb4e14acffb7133be3a44"},"cell_type":"code","source":"missing = missing_data(game)\ndata = missing[['Column', 'Percentage_Observations_Missing']]\nresult = generate_table(data)\n\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"88d96fe0fd9ab93685cb1c8247a63189ebe2bac2"},"cell_type":"markdown","source":"Ok so most of the missing data is related to weather, venue and surface type which shouldn't have much impact on concussions in the first place.\n\nWhat stage of the season were punt returners receiving concussions and what impacts and activities were causing them?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"28b511227df0c89b8978a1dd8632486ac140cb6f"},"cell_type":"code","source":"punt_returners = concussion_role[concussion_role['Role'] == 'PR']\n\ncolumns = ['GameKey']\npunt_returners = perform_merge(punt_returners, game, columns)\n\ncolumns = ['Season_Type']\nPR_season = count_agg(columns, punt_returners)\n\ndata = PR_season[['Season_Type', 'Percentage']]\nresult = generate_table(data)\n\niplot(result[0], result[1])\n\ncolumns = ['Season_Year']\nPR_season = count_agg(columns, punt_returners)\n\ndata = PR_season[['Season_Year', 'Percentage']]\nresult = generate_table(data)\n\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"0893ff84df8e1c63fa479b9cd8f67b30f26252ab"},"cell_type":"code","source":"columns = ['Player_Activity_Derived', 'Primary_Impact_Type']\nPR_Concussions = count_agg(columns, punt_returners)\n\nx_data = 'Player_Activity_Derived' \ny_data = 'Percentage'\nhue = 'Primary_Impact_Type'\n\npal = 'viridis'\nxaxis_title = 'Player Activity'\nyaxis_title = 'Percentage'\ntitle = 'Punt Returner Activity and Impacts Causing Concussion'\n\ngenerate_bar_plot(x_data, y_data, PR_Concussions, pal, xaxis_title, yaxis_title, title, hue)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"786dff1d355e8c80e5e55392f0ae94ddf11faedc"},"cell_type":"markdown","source":"So we see that all punt returners received their concussions in the regular season with 60 percent of them happening in 2017 and 40 percent happening in 2016.\n\nMore interestingly is that they are on the receiving end of a tackle on all ocassions with 60 percent of the concussions being caused by helmet-to-helmet impacts and the other 40 percent being caused by helmet-to-body impacts.\n\nWhat stage of the regular season are punt returners receiving the concussions?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"7d9e9391b8f7ddd97aa0aa97ca8fd8a9fd938518"},"cell_type":"code","source":"data = punt_returners[['Primary_Impact_Type', 'Week']]\nresult = generate_table(data.sort_values(by=['Week']))\n\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"14cd2ffc037f78c302cb7460b26572118168a2af"},"cell_type":"markdown","source":"So theres not much we can say here other than most punt returner concussions happen from the middle of the regular season towards the end of the regular season when the competition starts to \"heat up\". Is this actually the case, are punters being used in situations where the score is close at the end of the game?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"2f27c3733ffb964c2ddbf61c28e6e12dd6a53487"},"cell_type":"code","source":"columns = ['GameKey', 'PlayID']\nPR = perform_merge(punt_returners, play, columns)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"b91fd6d7b234fb2b67c8f1a4cfb5e4bf17612d56"},"cell_type":"code","source":"PR = visiting_data(PR)\nPR = home_data(PR)\nPR = score_difference(PR)\n\ndata = PR[['Quarter','score_diff' ]]\n\nx_data = 'Quarter'\ny_data = 'score_diff'\nmode='markers'\ncategories=''\nxaxis_title = 'Score defecit'\nyaxis_title = 'Quarter'\ntitle = 'Score defecit vs Quarter'\n\nplotly_scatter(y_data, x_data, mode, categories, xaxis_title, yaxis_title, title, data)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5e9ec460e8cc14fa9d281fd2707d2c272247ffe5"},"cell_type":"markdown","source":"So there appears to be no major relationship between the difference in score at the time the punt returner receives concussion and the stage of the game."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"0bad2af351a098625deaf1dfba4e8ae9ed691b57"},"cell_type":"code","source":"columns = ['Quarter']\nPR_quarter = count_agg(columns, PR)\n\ny = 'Quarter'\nx = 'Count'\ncolour = 'Spectral'\ntitle = 'What Quarter Punt Returners Receive Concussions'\n\npie_chart(PR_quarter, x, y, colour, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f7497328d683ffd0cf30107d5e2664884ea0e386"},"cell_type":"markdown","source":"80 percent of punt returner concussions happen in the 3rd and 4th quarter. Where on the pitch are the punts kicked and recieved? The following interactive plotly figure shows the movements that all concussed PR's made before and during the play. By selecting from the dropdown menu you can view each individual PR's movements. By hovering over each data point you can see the event that occurred at that time of the play. As there are so many data points for each, I suggest zooming in when looking at them in detail."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"8cc840b5ae3c1747b0e04476cee35ca375829c92"},"cell_type":"code","source":"columns = PR.columns\nPR = get_NGS_data(PR)\ngrouped = group_interactive_data(PR)\ndropdown = []\ndataframes = []\n\nfor key, value in grouped:\n\n    key = str(key).strip('(').strip(')').split(',')\n    temp = 'GameKey: ' + str(key[0]) #+ '  GSISID: ' + str(key[1]) + '  PlayID: ' + str(key[2])\n    dropdown.append(temp)\n    dataframes.append(value)\n\nresult = gen_interactive_plot(dropdown, dataframes, 'x', 'y')\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6da6a2f4ef4cbb60eda882f7ca4ff9b568853307"},"cell_type":"markdown","source":"A better way of viewing the concussions is two animate both the PR's movements and the primary partner movements during each play. Note the title which gives details of each game. The primary partner represents the team currently in possession, i.e the team that is taking the punt. The player represents the PR who is receiving the punt.\n\n**Please note, due to the number of ngs data instances per player per play, I have had to drop some duplicate data points. This means that on some occassions the player and primary partner do not meet when there is a tackle for example as the number of data points differs slightly for both. Despite this the location of all the events is correct.**"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"1f978c42139f994c2b7b8d5787c44798795db1c6"},"cell_type":"code","source":"dataframes[0] = dataframes[0].reset_index(drop=True)\nanimated_play = animate_play(dataframes[0],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"28b2c265558b80993b74ca3cfd9cd698cccda5e2"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[0]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[0]['Role'][0])\nprint('Impact: ' , dataframes[0]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"24f5d72be413fcaca66cbb1f4626e0599e742344"},"cell_type":"markdown","source":"So here we see the Kansas City Chiefs (KC) versus the Jacksonville Jaguars (JAX). KC are the home team in possession of the ball (punting  the ball to JAX) and are currently leading by 12 points. Notice where the KC were forced to use the punt on approximatly their 13 yard line!\n\nOne of the main points to note here is the distance the primary partner travels to tackle the PR. Think of the speed that can be achieved over this distance and how heavy the impact could be."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"6c9baf6ca465b48fa0ae75d7a048ac28dbea0ca7"},"cell_type":"code","source":"dataframes[1] = dataframes[1].reset_index(drop=True)\nanimated_play = animate_play(dataframes[1],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"73ae8afa230aecc3aa24687eefae7de35d6eb850"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[1]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[1]['Role'][0])\nprint('Impact: ' , dataframes[1]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"41178ab556e3ccc3cac8d734745b200645f6d697"},"cell_type":"markdown","source":"So here we see the Philadelphia Eagles (PHI) versus the Washington Redskins (WAS). PHI are the home team. WAS are in possession of the ball (punting the ball to PHI) and are currently leading by 2 points. Notice where the WAS were forced to use the punt on approximatly their 30 yard line which is quite high up the field. I presume this was a fourth down.\n\nOne of the main points to note here again is the distance the primary partner travels to tackle the player, from his own 29 yard line to the PR's 28 yard line. "},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"f6f287b657e33588bf2ef79dfea6e5b2913b4eba"},"cell_type":"code","source":"dataframes[2] = dataframes[2].reset_index(drop=True)\nanimated_play = animate_play(dataframes[2],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"f0039255cc4b0badce9ff9d73765d24bbe9ea4d1"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[2]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[2]['Role'][0])\nprint('Impact: ' , dataframes[2]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e7c3ef64621e887706471a9af580824c86f74a10"},"cell_type":"markdown","source":"Here we see the New England Patriots (NE) versus the Kansas City Chiefs (KC). NE are the home team. KC are in possession of the ball (punting the ball to NE) and are currently losing by 3 points. Notice where KC were forced to use the punt on their 10 yard line which is quite deep in their own half. This highlights how useful a punt can be to force the opposition away from the KC end line.\n\nNote again the distance the primary partner travels to tackle the player, from his own 10 yard line to his own ~45 yard line. This animation is a prime example of where the number of data points for each player do not match up. You may have noticed that the primary partner is still a good distance away from the player when the tackle occurs this due to the discrepencies in number of data points per player and the fact that I drop duplicates based on the subset of the player and primary partners x, y and Event parameters as there are so many animations in this notebook. Regardless, we still see where the the tackle occurs and where their paths collide."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"7a78cb599dabede0bc1eb9832f2c1cd49cbf7048"},"cell_type":"code","source":"dataframes[3] = dataframes[3].reset_index(drop=True)\nanimated_play = animate_play(dataframes[3],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"7fa05352cba257636ed2fecd1488273f62b3719e"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[3]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[3]['Role'][0])\nprint('Impact: ' , dataframes[3]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6d5715170e85406ba3c14481949df6848bdd127b"},"cell_type":"markdown","source":"**Note: No primary partner data is visible as there was no primary partner GSISID. The player received a concussion via a helmet to helmet impact caused by the primary partner tackling the player (PR). On this occassion the PR is on the winning team.**"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"f9c97d795faabc2d5be93c6a2904ee100c8ce140"},"cell_type":"code","source":"dataframes[4] = dataframes[4].reset_index(drop=True)\nanimated_play = animate_play(dataframes[4],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"2b9bfa082371e7626488caf003f1fa60045c3399"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[4]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[4]['Role'][0])\nprint('Impact: ' , dataframes[4]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3835c098b34a7537f35937a16cb8c229d0b1ccb8"},"cell_type":"markdown","source":"Here we see the New Tennessee Titans (TEN) versus the Houstan Texans (HST). TEN are the home team and are in possession of the ball (punting to HST) and are currently level with their opposition. Notice where TEN were forced to use the punt on their 20 yard line which is quite deep in their own half.\n\nNote again the distance the primary partner travels after the punt to tackle the player (PR), from his own 20 yard line to the PR's 31 yard line and appears to collide with the player beyond the sideline. A late tackle perhaps?\n\n\nThe above graphs shows us roughly where on the pitch the ball is being received and also highlights the distances between the player and primary partners.\n\nWe can also see that the ball is **mostly** being received between the punt returners 31 yard line and 18 yard line. These kicks appeared to push the receiving team deep into their own half. These are prime examples of why the punt is useful. Although the kicking team may lose possesion they force the opposion away from their end zone.\n\nWe can also see that 2 of the kicks were between the Kansas Cities 10 and 15 yard line which is relatively close to their own goal line. These kicks were possibly the result of a 4th down. Kansas City kicks the ball on both occassions forcing the New England Patriots and Jacksonville Jaguars away from the end zone.\n\n##### 4.2.1 Rule Change #1 : Tackling <a class=\"anchor\" id=\"4.2.1\"></a>\nMy first suggested rule change relates to the method of tackling used not just on punt plays but in the NFL in general. As I previously stated I could never understand why players attempted tackles in a head first manner or why they attempt to hit the head of their opponent in the first place. Not only are they seriously endangering themselves but their opponent also. Fortunately the NFL have already imposed rule changes to prevent head to head tackling as outlined to me by PeterSorensen. Thanks Peter.\n\nDespite this I still propose that a rugby style tackle, again mentioned in section 2 be implemented. This will allow both the player performing the tackle and the player on the receiving end of the tackle to do so in a safer and more controlled manner. Implementing a style of tackle such as this would also allow the NFL to retain the **speed** and **physicality** of the game which provides the entertainment value.\n\nI have added a video that demonstrates a player performing a tackle on the PR, again, diving (no control over the tackle) at the PR, this time his shoulder makes contact with the PR's head. On this occassion the PR is not so lucky and takes a very heavy impact. "},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"d6cdad81971c7bc1d9acfa638980550fb187ec5f"},"cell_type":"code","source":"HTML('<video width=\"560\" height=\"315\" controls> <source src=\"https://nfl-vod.cdn.anvato.net/league/5691/18/11/25/284956/284956_12D27120C06E4DB994040750FB43991D_181125_284956_way_punt_3200.mp4\" type=\"video/mp4\"></video>')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ece8fb10e3207c96431cd93fbb87c7b02d28e418"},"cell_type":"markdown","source":"#####  4.2.2 Rule Change #2 :  <a class=\"anchor\" id=\"4.2.2\"></a>\n\nIn most scenario's where friendly fire is not an issue, there is a significant distance between the PR and the primary partner before the play begins. In my mind that means there is a significant amount of speed and force between any type of collision regardless of whether it causes concussion or not. How can this be altered? The main alteration I would make is maximise the distance a punt can be valid for beyond the line of scrimmage (30 yards for example). For example if the line of scrimmage is on the 50 yard line that means the punting team can only punt as far as the receiving teams 20 yard line. This would mean the PR's are closer to the line of scrimmage which could possibly reduce the speed and force the PR's opposition have in the tackle by the time they get to him. \n\nIt would also add another dimension to the punt as it would become a more specialist move as the punter has to be much more accurate when the take the punt. Defensively the receiving team also has to be much more accurate and efficient to stop the PR from being tackled. In the event a punt is kicked beyond the maximal distance the possession is turned over and the play starts at the previous line of scimmage. "},{"metadata":{"_uuid":"a208455fd5f612ccf2553d61281421d56d57ddb5"},"cell_type":"markdown","source":"#### 4.3 Punt Right Guard (PRG) AND Punt Left Guard Analysis  <a class=\"anchor\" id=\"4.3\"></a>\nSo in a normal play a guard is used to block opposition players to protect and allow the punter to kick the ball beyond the opposition. This is clearly a physically intense position so its no surprise that these players have the second highest number of concussions.\n\nSo like we did for the punt returners, when did PRG and PLG's get concussed and what impacts caused them?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"da942456eb4c3341a60d110fc1748bcab7f53ba4"},"cell_type":"code","source":"prlg = concussion_role[(concussion_role['Role'] == 'PRG') | (concussion_role['Role'] == 'PLG')]\n\ncolumns = ['GameKey']\nprlg = perform_merge(prlg, game, columns)\n\ncolumns = ['Role', 'Season_Type']\nPRLG_season = count_agg(columns, prlg)\n\ndata = PRLG_season[['Role', 'Season_Type', 'Count']]\ngenerate_bar_plot('Role', 'Count', data, 'viridis', 'Player Role', 'Count', 'Number of Concussions per Role by Season Type', 'Season_Type')\n\n\ncolumns = ['Role', 'Season_Year']\nPRLG_season = count_agg(columns, prlg)\n\ndata = PRLG_season[['Role', 'Season_Year', 'Count']]\ngenerate_bar_plot('Role', 'Count', data, 'viridis', 'Player Role', 'Count', 'Number of Concussions per Role by Year', 'Season_Year')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"866de23d0346556d5cd682603c1791e007441031"},"cell_type":"markdown","source":"So what do we learn here? In comparison to PR's, PLG's and PRG's both have 1 concussion that occurs in the pre season. Both PLG's and PRG's record 3 concussions each in the regular season.\n\nNoticeably PRG's recorded 3 of their 4 concussions in 2017 whereas PLG's recorded 3 of their 4 concussions in 2016.\n\nWhat impacts are they sufferring from?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"77624b1d1045e6894898b980356c329db3e19eaf"},"cell_type":"code","source":"data = prlg[['Role','Primary_Impact_Type']]\ncolumns = ['Role','Primary_Impact_Type']\ndata = count_agg(columns, data)\n\ny = 'Primary_Impact_Type'\nx = 'Count'\ncolour = 'Spectral'\ntitle = \"What Impacts are causing PRG's and PLG's to get concussions?\"\n\npie_chart(data, x, y, colour, title)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a91c0de549a2ba7828dad4ec77a9e86f462b959b"},"cell_type":"markdown","source":"Over 60 percent of impacts causing concussion between **both** PRG's and PLG's are caused by helmet-to-body impacts. Lets look at them individually and see what activity is causing these impacts"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"80d965dd6ff1aba4c1dbd23d65113da556f5101c"},"cell_type":"code","source":"data = prlg[['Role','Player_Activity_Derived', 'Primary_Impact_Type']]\ncolumns = ['Role','Player_Activity_Derived', 'Primary_Impact_Type']\ndata = count_agg(columns, data)\n\ngenerate_bar_plot('Player_Activity_Derived', 'Percentage', data, 'viridis', 'Player Activity', 'Percentage of Concussions', 'Percentage of Concussions per Player Activity coloured by Impact Type', 'Primary_Impact_Type')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"aa99565e367f1e136b3963c53d20ff29b16457d1"},"cell_type":"markdown","source":"50 percent of concussions got by **both** PLG's and PRG's are helmet to body impacts caused by tackling. Tackling clearly needs to be addressed. Players being blocked by helmet-to-helmet impacts is also a cause for concern as it caused ~25 percent of the concussions to PLG's and PRG's.\n\nIndividually how do impacts compare for both positions?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"cb004b40dd4a835020d23f9306c7e91863ac74bd"},"cell_type":"code","source":"data = prlg[['Role','Primary_Impact_Type']]\ncolumns = ['Role','Primary_Impact_Type']\ndata = count_agg(columns, data)\n\ndata = data[data['Role'] == 'PRG']\n\ny = 'Primary_Impact_Type'\nx = 'Count'\ncolour = 'PiYG'\ntitle = \"What Impacts are causing PRG's to get concussions?\"\n\npie_chart(data, x, y, colour, title)\n\n\ndata = prlg[['Role','Primary_Impact_Type']]\ncolumns = ['Role','Primary_Impact_Type']\ndata = count_agg(columns, data)\n\ndata = data[data['Role'] == 'PLG']\n\ny = 'Primary_Impact_Type'\nx = 'Count'\ncolour = 'Spectral'\ntitle = \"What Impacts are causing PLG's to get concussions?\"\n\npie_chart(data, x, y, colour, title)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"95845ae6203ddc958c98321967bc78acf6372b35"},"cell_type":"markdown","source":"Wow **100 percent** of PRG concussions are caused by helmet-to-body impacts! PLG's on the other hand seem to suffer more from helmet-to-helmet concussions at ~50 percent. Helmet-to-body impacts is largely due to the player not performing a tackle correctly as such I believe my first suggestion could address this problem.\n\nWhat stage of the **regular** season are they getting their concussions?"},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"ab665dc3e2399129b46cadb2838302c1ea5a1e45"},"cell_type":"code","source":"data = prlg[['Role','Week','Season_Type']]\ndata = data[data['Season_Type'] == 'Reg']\n\nresult = generate_table3(data)\niplot(result[0], result[1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dca1f351bd352de1ad14f5365cc92b6db6015c72"},"cell_type":"markdown","source":"Like punt returners PLG's and PRG concussions occur in the mid to late regular season. Where on the field are the players positioned when the ball is kicked to where they receive their injury?"},{"metadata":{"scrolled":true,"_kg_hide-input":true,"trusted":false,"_uuid":"84b912e6e680950a66c02809f3f4fb864dff5146"},"cell_type":"code","source":"play = play_info_data()\ncolumns = ['GameKey', 'PlayID']\nprlg = perform_merge(prlg, play, columns)\n\ncolumns = prlg.columns\nprlg = get_NGS_data(prlg)\ngrouped = group_interactive_data(prlg)\ndropdown = []\ndataframes = []\n\nfor key, value in grouped:\n\n    key = str(key).strip('(').strip(')').split(',')\n    temp = 'GameKey: ' + str(key[0]) #+ '  GSISID: ' + str(key[1]) + '  PlayID: ' + str(key[2])\n    dropdown.append(temp)\n    dataframes.append(value)\n\nresult = gen_interactive_plot(dropdown, dataframes, 'x', 'y')\niplot(result[0], result[1]) ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"98ad84aa0e10efa567ae987d632ffa4532b275aa"},"cell_type":"markdown","source":""},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"83220deb3dce2a7b6cad92c43d5dd4f4518999eb"},"cell_type":"code","source":"dataframes[0] = dataframes[0].reset_index(drop=True)\nanimated_play = animate_play(dataframes[0],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"783137a3dc0ca6c4a23a29e383f696e49bc9224d"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[0]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[0]['Role'][0])\nprint('Impact: ' , dataframes[0]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"235e435954a8be6d6e4ec544a24da74e9109f606"},"cell_type":"markdown","source":"Here we see the Indianapolis Colts (IND) versus the Tennessee Titans (TEN). The TEN are the possession team having punted the ball to the Indinanapolis Colts. The PLG is blocked on his own 45 yard line and suffers a **Helmet-to-ground impact meaning there is no primary partner data.** "},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"b17cae21d8aadfcd2e04228f035392a8da43e8a2"},"cell_type":"code","source":"dataframes[1] = dataframes[1].reset_index(drop=True)\nanimated_play = animate_play(dataframes[1],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"090353139ca3c1cbc6178a475ecca9d22eaa379d"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[1]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[1]['Role'][0])\nprint('Impact: ' , dataframes[1]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"87293403bf67fc248ed43b4f88af1a7a179f77fc"},"cell_type":"markdown","source":"In this scenario we have the Baltimore Ravens (BLT) versus the Cincinnati Bengals (CIN). The CIN are the possession team having punted the ball to BLT(D. Hester from BLT muffs the punt) who are currently leading by 10 points. Again the distances covered by both players is significant. Notice the primary partner starts behind the player. This injury was caused by two players on the same team colliding."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"c534d95fc4df824eb2a6ccae6b56aa4fcf2f8084"},"cell_type":"code","source":"dataframes[2] = dataframes[2].reset_index(drop=True)\nanimated_play = animate_play(dataframes[2],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"d677ff1c09b1988c2f8016868b1e6c72258b8e80"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[2]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[2]['Role'][0])\nprint('Impact: ' , dataframes[2]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e75829269f529acf24e3724f28ab450882761bb7"},"cell_type":"markdown","source":"Here we see the New York Giants (NYG) versus the Cleveland Browns (CLV). NYG are the possession team having punted the ball to CLV. NYG are leading the game by 8 points. They have used the ball to pin CLV deep into their half. The PRG receives a concussion by making a tackle. Again notice the distance covered by the PRG before he gets injured."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"245c66bd9db3194e71a1e69c6e18f866352eba32"},"cell_type":"code","source":"dataframes[3] = dataframes[3].reset_index(drop=True)\nanimated_play = animate_play(dataframes[3],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"d8bc2bbce5f83d2b5e90a8500af0a25deeb19ec8"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[3]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[3]['Role'][0])\nprint('Impact: ' , dataframes[3]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0fe0136c97a5f81001855afcc61a7e6b6e4eaea7"},"cell_type":"markdown","source":"Again we see two players on the same team colliding and causing concussion. The Kansas City Chiefs (KC) are playing the Tennessee Titans (TEN). The TEN are the punting team and are trailing by 7 points. Again we see how useful a punt can be to get a team away from their own end line where the opposition can do less damage. In this situation the player (PLG) is blocked and the primary partner is tackling. A collision causes concussion to the PLG."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"4429d9eefa4853595965a6b6af2868ad1a9610d8"},"cell_type":"code","source":"dataframes[4] = dataframes[4].reset_index(drop=True)\nanimated_play = animate_play(dataframes[4],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"1513d147468e33b7a73cb17eb26d4b4ad66e102d"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[4]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[4]['Role'][0])\nprint('Impact: ' , dataframes[4]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2011223292c7a8b870c86259c34a19820f90cf00"},"cell_type":"markdown","source":"Here we have the Miami Dolphins (MIA) punting to the Baltimore Ravens (BLT). MIA are the possession team and are losing by 21 points. The PRG is injured while performing a tackle in this scenario as a result of a helmet to body impact."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"01935eafa6982d12d7b202678ceb7e8e2fe2ed97"},"cell_type":"code","source":"dataframes[5] = dataframes[5].reset_index(drop=True)\nanimated_play = animate_play(dataframes[5],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"377c0115b5d5de0f825b9b126b0bbdc4f97e21c4"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[5]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[5]['Role'][0])\nprint('Impact: ' , dataframes[5]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"10b33351f177cf19f9d37c4c1e1aadde6dab0ed7"},"cell_type":"markdown","source":"Here we have the Washington Redskins (WAS) receiving a punt from the Green Bay Packers (GB). GB are the possession team and are winning by 4 points. The PLG is injured while being blocked in this scenario as a result of a helmet to helmet impact."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"4807943efc0ac6d7299e33bd8f0210a2ebc96deb"},"cell_type":"code","source":"dataframes[6] = dataframes[6].reset_index(drop=True)\nanimated_play = animate_play(dataframes[6],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"a7b1f8cc8b43c6bfab893b38173be3edf6f01346"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[6]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[6]['Role'][0])\nprint('Impact: ' , dataframes[6]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3d9dd01a2c787cc02372f7ff65c0d04cfbc83134"},"cell_type":"markdown","source":"Here we have the Oakland Raiders (OAK) versus the Baltimore Ravens (BLT). Oak are the possession team and punting to the BLT. In this case the PRG is performing a tackle and receives a concussion as a result of a helmet-to-body impact with a player on his own team. The PRG travels a significant distance to make the tackle but unfortunately comes out the worst."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"531419b0813df29192166079e853f52c560f829f"},"cell_type":"code","source":"dataframes[7] = dataframes[7].reset_index(drop=True)\nanimated_play = animate_play(dataframes[7],'')\nplt.close()\nanimated_play","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"d2d78121718b2433934cec3c268b8b75bb41e53d"},"cell_type":"code","source":"print('Player Activity: ' , dataframes[7]['Player_Activity_Derived'][0])\nprint('Player Role: ' , dataframes[7]['Role'][0])\nprint('Impact: ' , dataframes[7]['Primary_Impact_Type'][0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"eb7496d40ddc9cb0fb27859a2107044f4ae0d632"},"cell_type":"markdown","source":"Here we have the Seattle Seahawks (SEA) versus the Los Angeles Rams (LA). SEA are the possession team and are punting to LA who have a massive lead of 40 points. In this instance the PRG receives a concussion from a helmet to body impact. As you will have noticed the two players do not meet in this animation. The only reason I can think of that caused this is my previously outlined measures to ensure all animations would fit in the notebook. (I previously tried with all data points in the animations but the loading time for a kernel to display (not the run time) was not acceptable in my opinion)"},{"metadata":{"_uuid":"82a2ad6c9353afbba4f1fef214587d24c65faabd"},"cell_type":"markdown","source":"Given that PLG's and PRG's are used to defend the punter we can see that they are largely being used deep within their own defences (with the exception of the New York Giants). As they are so deep in their own defences they are being used in high pressure scenario's.\n\nAgain we see how important the punt is in NFL. Teams kicking the ball can move the play to the opposite end of the field relatively easily.\n\n**4.3.1 Rule Change #3 : Blocking / Getting Blocked using a \"Shoulder charge\"** <a class=\"anchor\" id=\"4.3.1\"></a>\n\nHaving already proposed a tackling rule change I will now propose a change to the method of blocking as 40% of both PRG and PLG's total concussions arose from the player being blocked. In open play, players tackling and blocking appear to prefer leading with the head or their shoulder. As the NFL Have already addressed helmet to helemt tackles my suggestion is again akin to rugby where hitting a player directly to the upper body or head with your **shoulder and without wrapping your arms around them** in the tackle/block and taking them to the ground is an illegal play and should result in a penalty.\n\nAs such I propose that a \"shoulder charge\" be removed from blocking and replaced with a rugby style challenge that forces them hold onto/wrap around the player during it and bring them to ground as safe as possible. Again this is a change I feel could be implemented very easily by the NFL whilst also **preserving the speed and physicality of the game.**\n\nI have included a video which illustrates the type of blocking I think should be changed. In the following video a Baltimore Ravens player blocks a Cincinnati Bengals player using a shoulder charge causing concussion (0:12 of the video). This tackle is labeled as a helmet-to-helmet impact but appears more like the Baltimore Ravens player hits the upper body of the Cincinnati Bengals player with his shoulder."},{"metadata":{"_kg_hide-input":true,"trusted":false,"_uuid":"4036a50d9aaf0187b8d314498cb1d38fca6a7059"},"cell_type":"code","source":"HTML('<video width=\"560\" height=\"315\" controls> <source src=\"https://nfl-vod.cdn.anvato.net/league/5691/18/11/25/284954/284954_75F12432BA90408C92660A696C1A12C8_181125_284954_huber_punt_3200.mp4\" type=\"video/mp4\"></video>')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"75b9f1ac4afc983826b271eea827c461e075e9e0"},"cell_type":"markdown","source":"### References\n[1]\t‘Head injuries in football: How and when concussions occur in the NFL’, Dr. David Geier - Sports Medicine Simplified, 02-Feb-2017. .\n\n[2]\t‘Rugby player tackling stock illustration. Illustration of retro - 2706447’. [Online]. Available: https://www.dreamstime.com/royalty-free-stock-photography-rugby-player-tackling-image2706447. [Accessed: 05-Dec-2018].\n\n[3]\t‘Punt (gridiron football)’, Wikipedia. 11-Nov-2018.\n"},{"metadata":{"_uuid":"334236f072af2d59eb7b2a3497af13164be05e7c"},"cell_type":"markdown","source":"## Feedback is Welcomed:)"},{"metadata":{"trusted":false,"_uuid":"4b4a478696a5b2d7893411d702af322c805f784b"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"dccc165429ac15d808592d20a70cad233a39ad7d"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"6fd259c453edd14831d2ad40c26a498b2c4b56b9"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"5e41eea98c012b57e919ba126533ec41482f8ff1"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"715ebbbff5ac5a7aaf03aab12d0c2708775595bd"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"531dcebf2c98fa4951f49a48312277316f5ccc05"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"96c63c35a5455be1a3283b45dc0ce0491339e33f"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"6d72455e12caf3024201284c945a588c456c76d1"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":false,"_uuid":"5a853580fca55f39ff3aa3c0fb4331cba59af7e5"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}