{"cells":[{"metadata":{"_uuid":"33d910af253e912c94fc35501de5f61f7aec7ca5"},"cell_type":"markdown","source":"# Interactive Plot of Plays with Code\n\n**NOTE: INTERACTIVITY REQUIRES FORKING THE NOTEBOOK AND RUNNING IN EDIT MODE - IT WILL NOT WORK IN KAGGLE'S RENDERED NOTEBOOK**\n\nIn this notebook I'm sharing some code I put together to allow you to interactively scroll through an individual play and see the position of the players on the field as scroll.\n\nIt's still a work in progress but has been helpful in my analysis. Please let me if you have any suggestions. There are a lot of things I still plan to add (players' speed, any event notes, etc).\n\nExample of how it works (it's a little laggy):\n![gif_example](https://media.giphy.com/media/3ouTtaLxVO6vUCgI22/giphy.gif)\n\n*Please upvote if you find this helpful. Please reference this notebook if you use the code elseware.*"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\n\nimport bokeh\nfrom bokeh.io import show, output_notebook, push_notebook\nfrom bokeh.layouts import row, column, widgetbox\nfrom bokeh.plotting import figure\nfrom bokeh.models import CustomJS, ColumnDataSource, Slider\nfrom bokeh.models import ColumnDataSource, Range1d, LabelSet, Label\nfrom bokeh.models import BoxAnnotation\nfrom bokeh.models.glyphs import Text\nfrom bokeh.models.widgets import PreText, Div\n\noutput_notebook()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"45945f729e8c962001d4686de6384151a45d0b1d"},"cell_type":"code","source":"# Read play data\nngs = pd.read_csv('../input/NGS-2016-pre.csv')\nngs.columns = [col.lower() for col in ngs.columns]\npprd = pd.read_csv('../input/play_player_role_data.csv')\npprd.columns = [col.lower() for col in pprd.columns]\nvr = pd.read_csv('../input/video_review.csv')\nvr.columns = [col.lower() for col in vr.columns]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3a70e23c6f5322ef6374436a6b3b4cef4cb8cdd2"},"cell_type":"code","source":"# Take a play as an example\nvr[['season_year','gamekey','playid']].sort_values(['season_year','gamekey','playid']).loc[1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"57c4706ab919a1d8e05d961ef8fdbd518366762e"},"cell_type":"code","source":"# Filter a sepcific play\nseason_year=2016\ngamekey=21\nplayid=2587\n\nplay = ngs[(ngs['season_year'] == season_year) &\n           (ngs['gamekey'] == gamekey) &\n           (ngs['playid'] == playid)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"63cc6bd5b74419724ff6a7a23b19403caf910c11"},"cell_type":"code","source":"# Pull just one play\nplay = pd.merge(play, pprd)\nplayxy = play.drop(['season_year','gamekey'], axis=1) \\\n    .pivot(index='time',\n           columns='role',\n           values=['x','y'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6234f31c693b66e700179d30fd4e8c344fb262b9"},"cell_type":"code","source":"# Create player colors\ncolors = ['red' if x in(vr['gsisid'].values) or x in(vr['primary_partner_gsisid'].values) else 'blue' for x in play.gsisid.unique()]\n\n# Setup Figure\n## Football Field Figure\nfig = figure(plot_width=800, plot_height=400, x_range=(0,120), y_range=(0, 53.3))\nfig.xgrid.grid_line_color = None\nfig.ygrid.grid_line_color = None\n# Green Field\nbox = BoxAnnotation(left=0, right=120, fill_color='green', fill_alpha=0.5)\nendzone1 = BoxAnnotation(left=0, right=10, fill_color='grey', fill_alpha=0.5)\nendzone2 = BoxAnnotation(left=110, right=120, fill_color='grey', fill_alpha=0.5)\nfig.add_layout(box)\nfig.add_layout(endzone1)\nfig.add_layout(endzone2)\n# Add lines|\nfig.line([10,10,20,20,30,30,40,40,50,50,60,60,70,70,80,80,90,90,\n          100,100,110,110,120,120],\n         [55.5,0,0,55.5,55.5,0,0,55.5,55.5,0,0,55.5,55.5,0,0,55.5,\n         55.5,0,0,55.5,55.5,0,0,0], line_color='grey')\n# Line numbers\n\nline_nums = ColumnDataSource(dict(x=[20, 30, 40, 50, 60, 70, 80, 90, 100],\n                                  y=[5, 5, 5, 5, 5, 5, 5, 5, 5],\n                                  text=['10', '20', '30','40','50','40','30','20','10']))\nglyph = Text(x=\"x\", y=\"y\", text=\"text\", angle=0, text_color=\"black\", text_align='center')\nfig.add_glyph(line_nums, glyph)\n\n# Create values used in the initial states\nx_values = playxy.loc[playxy.index[1]]['x'].values\ny_values = playxy.loc[playxy.index[1]]['y'].values\ngsisid = playxy['x'].columns.values\nsource = ColumnDataSource(data=dict(x=x_values,\n                                    y=y_values,\n                                    gsisid=gsisid))\nlabels = LabelSet(x='x', y='y', text='gsisid', level='glyph',\n              x_offset=5, y_offset=5, source=source, render_mode='canvas')\n\n# Add players as circles\nplt = fig.circle(x_values, y_values, size=20, alpha=0.5, color=colors, radius=1)\nfig.add_layout(labels)\n\ndiv = Div(text=\"\"\"....\"\"\",width=200, height=100)\n\ndef plot_time_pos(time_pos):\n    x_values = playxy.loc[playxy.index[time_pos]]['x'].values\n    y_values = playxy.loc[playxy.index[time_pos]]['y'].values\n    gsisid = playxy['x'].columns.values\n    # p = figure(plot_width=800, plot_height=400)\n    # p.circle(x_values, y_values, size=20, color=\"navy\", alpha=0.5)\n    source = ColumnDataSource(data=dict(x=x_values,\n                                    y=y_values,\n                                    gsisid=gsisid))\n    labels = LabelSet(x='x', y='y', text='gsisid', level='glyph',\n               x_offset=5, y_offset=5, source=source, render_mode='canvas')\n    fig.renderers.pop()\n    fig.add_layout(labels)\n    plt.data_source.data['x'] = x_values\n    plt.data_source.data['y'] = y_values\n    div.text = playxy.loc[playxy.index[time_pos]].name\n\n    push_notebook(handle=bokeh_handle)\n\n\nsource = ColumnDataSource(data=dict(x=x_values, y=y_values))\n\n# Using javascript custom code\ncallback = CustomJS(code=\"\"\"\nif (IPython.notebook.kernel !== undefined) {\n    var kernel = IPython.notebook.kernel;\n    cmd = \"plot_time_pos(\" + cb_obj.value + \")\";\n    kernel.execute(cmd, {}, {});\n}\n\"\"\")\n\n\nslider = Slider(start=1,\n                end=len(playxy),\n                value=1,\n                step=1,\n                title=\"position within play\",\n                callback=callback)\n\nlayout = column(\n    widgetbox(slider),\n    fig,\n    div\n)\n\nbokeh_handle = show(layout, notebook_handle=True)","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}