{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport calendar\nfrom datetime import datetime, timedelta\nfrom collections import Counter\nimport base64\nfrom datetime import datetime\nfrom datetime import timedelta\n\nimport seaborn as sns\n#pal_hls = sns.hls_palette(100, l=.3, s=.8).as_hex() # Seaborn Color Palette for colors\nimport matplotlib as mpl\nimport matplotlib.pyplot as plt\n#sns.set_style('darkgrid')\n\nimport plotly.express as px\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nfrom plotly.offline import init_notebook_mode\nimport plotly.graph_objects as go\ninit_notebook_mode()\n\n# Ignore Warnings\nimport warnings\n#warnings.filterwarnings(\"ignore\")\n\nfrom PIL import Image\nfrom wordcloud import WordCloud, STOPWORDS, ImageColorGenerator\n\n############################################################\n### https://www.kaggle.com/c/nfl-big-data-bowl-2022/data ###\n############################################################","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:07.847349Z","iopub.execute_input":"2021-12-08T16:21:07.848130Z","iopub.status.idle":"2021-12-08T16:21:10.509855Z","shell.execute_reply.started":"2021-12-08T16:21:07.847871Z","shell.execute_reply":"2021-12-08T16:21:10.508415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Welcome to my Kaggle notebook\n\n\nIf you like what you see please give it an upvote, and if you don't feel free to leave any constructive criticism you may have about it =)\n\nThe graphs are done with Plotly, which means that they are interactive, hover over the graph to get more details\n\n## Data inspection\n\nWe are given quite a bit of data to play with and we can join the files in different ways:\n\n* \"game\", \"PFF Scouting data\" and \"play\" csv can be joined with gameId\n* \"play\" and \"player\" on kickerId = nflId\n* \"player\" and \"tracking\" on nflId\n\nThere are probably other ways too, we should be able to find lots of insights with those different combinations","metadata":{}},{"cell_type":"markdown","source":"# 1. Games\n\nLet's start by looking at the games.csv file, check for missing values etc..","metadata":{}},{"cell_type":"code","source":"games_df = pd.read_csv(\"../input/nfl-big-data-bowl-2022/games.csv\")\n\nprint(f\"NaN check:\\n\\n{games_df.isna().sum()} \\n\\nData shape :\\n{games_df.shape}\")\n\n# Renaming the columns, casting the Date & Time ones as DateTime objects\n\ngames_df.rename(columns={'gameDate' : \"Date\", 'gameTimeEastern' : \"Time\", 'homeTeamAbbr' : \"Home Team\", 'visitorTeamAbbr' : \"Visitor Team\"}, inplace=True)\ngames_df.columns = [i.title() for i in games_df.columns]\n\ngames_df[\"Date\"] = pd.to_datetime(games_df[\"Date\"])\ngames_df[\"Day\"] = games_df[\"Date\"].apply(lambda x : calendar.day_name[x.weekday()])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:10.512113Z","iopub.execute_input":"2021-12-08T16:21:10.513035Z","iopub.status.idle":"2021-12-08T16:21:10.570003Z","shell.execute_reply.started":"2021-12-08T16:21:10.512976Z","shell.execute_reply":"2021-12-08T16:21:10.569232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"visitors = sorted(dict(games_df[\"Visitor Team\"].value_counts()).items())\nhome = sorted(dict(games_df[\"Home Team\"].value_counts()).items())\n\nfor a, b, c, d in zip((i[0] for i in visitors), (i[1] for i in visitors), (i[0] for i in home), (i[1] for i in home)):\n    if b > d:\n        print(f\"{a} played {abs(b-d)} more game as a visitor\")\n    elif b < d:\n        print(f\"{a} played {abs(b-d)} more game at home\")        \n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:10.571743Z","iopub.execute_input":"2021-12-08T16:21:10.572355Z","iopub.status.idle":"2021-12-08T16:21:10.589492Z","shell.execute_reply.started":"2021-12-08T16:21:10.572301Z","shell.execute_reply":"2021-12-08T16:21:10.588457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Not all teams have played an equal amount of games at home and as visitors\n\nLet's look at the games distrbution time, what day and time is NFL usually on?","metadata":{}},{"cell_type":"code","source":"fig = px.histogram(data_frame=games_df, \n        x=\"Day\", \n        color=games_df[\"Time\"].apply(lambda x : x[:-3]),\n        labels={\"color\" : \"Time :\"}    # to change the legend title\n        )\n\nfig.update_traces(hovertemplate='<br>Total : <b>%{y:.0f}<br></b>' +\n                                '<br>Date : <b>%{x}<br></b>',\n                  )\n\nfig.update_yaxes(title=\"Count\")                                                                                  \nfig.update_xaxes(categoryorder='total descending')\n\nfig.update_layout(\n    title=f\"<b> Game day distribution and their start time </b><br><sup>{len(games_df['Gameid'].unique())} games in total<sup>\",\n    title_x=0.5,\n    showlegend=True,\n    paper_bgcolor=\"darkgray\", \n    barmode=\"stack\"\n    )\n\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:10.592532Z","iopub.execute_input":"2021-12-08T16:21:10.593137Z","iopub.status.idle":"2021-12-08T16:21:12.066411Z","shell.execute_reply.started":"2021-12-08T16:21:10.593090Z","shell.execute_reply":"2021-12-08T16:21:12.065203Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Over 50% of all games (401 precisely) happened on Sundays at 1PM, 119 on Sundays at 4.25 PM and those 2 slots gather already 68% of all games","metadata":{}},{"cell_type":"markdown","source":"# 2. Players\n\nI don't know anything about American Football, there are much more players on the field at a time that i thought, what are the different positions and what kind of player occupies that position?\n\nIn order to do that i'll change all imperial system values to metric ones, calculations will be easier that way. I'll also change the positions names from abbreviations to their full names","metadata":{}},{"cell_type":"code","source":"players_df = pd.read_csv(\"../input/nfl-big-data-bowl-2022/players.csv\")\n\nplayers_df[\"birthDate\"] = pd.to_datetime(players_df[\"birthDate\"])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:12.068033Z","iopub.execute_input":"2021-12-08T16:21:12.068313Z","iopub.status.idle":"2021-12-08T16:21:12.093438Z","shell.execute_reply.started":"2021-12-08T16:21:12.068279Z","shell.execute_reply":"2021-12-08T16:21:12.092714Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Some of the heights are in inches only, some in foot / inch\n\nfor i in range(len(players_df)):\n    _height = players_df[\"height\"][i][:]\n    if '-' in _height:\n        _height_split = _height.split('-')\n        new_height = (int(_height_split[0]) * 30.48 +  int(_height_split[1]) * 2.54)\n    else:\n        new_height = int(_height) * 2.54\n    \n    players_df.loc[i, \"height\"] = new_height  # PROPER WAY OF INSERTING DATA TO AVOID SETTING SLICE COPY WARNING\n\nplayers_df[\"weight\"] = round(players_df[\"weight\"] * 0.453592, ndigits=2)\nplayers_df[\"height\"] = players_df[\"height\"].astype(\"float\")\n\nposition_dic = {\"T\" : \"Tackle\", \"OT\" : \"Offensive tackle\",\n                \"TE\" : \"Tight end\", \"G\" : \"Guard\",\n                \"OG\" : \"Offensive guard\", \"DE\" :\"Defensive ends\", \n                \"C\" : \"Center\", \"QB\" : \"QuarterBack\", \n                \"DT\" : \"Defensive tackle\", \"NT\" : \"Nose tackle\", \n                \"LS\" : \"Long snapper\", \"OLB\" : \"Outside linebacker\", \n                \"P\" : \"Punter\", \"LB\" : \"Linepacker\", \n                \"ILB\" : \"Inside linebacker\", \"MLB\" : \"Middle linebacker\", \n                \"FB\" : \"Fullback\", \"WR\" : \"Wide receiver\", \n                \"DB\" : \"Defensive back\", \"SS\" : \"Strong safety\",\n                \"FS\" : \"Free safety\", \"S\" : \"Safety\", \"K\" : \"Kicker\", \n                \"CB\" : \"Cornerback\", \"RB\" : \"Running back\", \"HB\" : \"Halfback\"\n                 }\n\nplayers_df[\"Position\"] = players_df[\"Position\"].apply(lambda x : position_dic[x])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:12.094467Z","iopub.execute_input":"2021-12-08T16:21:12.095398Z","iopub.status.idle":"2021-12-08T16:21:12.890658Z","shell.execute_reply.started":"2021-12-08T16:21:12.095360Z","shell.execute_reply":"2021-12-08T16:21:12.889432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Some D.O.B are missing, i gotta use try / except to avoid having my code crash on NaN values\n\nfor i in range(len(players_df)):\n    try:\n        _d_o_b = players_df[\"birthDate\"][i]\n        _delta = datetime.now() - _d_o_b\n        _year_old = int(_delta.total_seconds() // (365.25*24*60*60))\n        players_df.loc[i, \"age\"]  = _year_old\n    except:\n        pass","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:12.892370Z","iopub.execute_input":"2021-12-08T16:21:12.892597Z","iopub.status.idle":"2021-12-08T16:21:13.838795Z","shell.execute_reply.started":"2021-12-08T16:21:12.892571Z","shell.execute_reply":"2021-12-08T16:21:13.837732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_weight_mean = round(players_df.pivot_table(values='weight', index='Position', aggfunc='mean').reset_index(), ndigits=2)\n_height_mean = round(players_df.pivot_table(values='height', index='Position', aggfunc='mean').reset_index(), ndigits=2)\n_age_mean = round(players_df.pivot_table(values='age', index='Position', aggfunc='mean').reset_index(), ndigits=2)\n\nh_w_df = pd.concat(\n    (_each_df.set_index('Position') for _each_df in [_height_mean, _weight_mean, _age_mean]),\n    axis=1, join='inner').reset_index()\n\nh_w_df.sort_values(by=\"height\", ascending=False, inplace=True)\nh_w_df.reset_index(drop=True, inplace=True)\nh_w_df[\"age\"] = h_w_df[\"age\"].apply(lambda x : round(x))\nh_w_df.rename(columns={\"height\" : \"Height mean (cm)\", \"weight\" : \"Weight mean (kg)\", \"age\" : \"Age mean\"}, inplace=True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:13.840273Z","iopub.execute_input":"2021-12-08T16:21:13.840491Z","iopub.status.idle":"2021-12-08T16:21:13.889593Z","shell.execute_reply.started":"2021-12-08T16:21:13.840465Z","shell.execute_reply":"2021-12-08T16:21:13.888556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = go.Figure(data=[\n    go.Bar(\n        x=h_w_df[\"Position\"], \n        y=h_w_df[\"Height mean (cm)\"], \n        name='Height (cm)',\n        customdata=h_w_df[\"Age mean\"],\n        hovertemplate=\"<br>\".join([\n                \"Position : <b>%{x}</b>\",\n                \"Height : <b>%{y}</b> cm\",\n                \"Age : <b>%{customdata}</b>\" \n            ]),\n\n        texttemplate='%{customdata}', #h_w_df[\"Position\"],\n        textposition=\"inside\"\n    ),\n    go.Bar(\n        x=h_w_df[\"Position\"], \n        y=h_w_df[\"Weight mean (kg)\"], \n        name=\"Weight (kg)\", \n        customdata=h_w_df[\"Age mean\"],\n        hovertemplate=\"<br>\".join([\n                \"Position : <b>%{x}</b>\",\n                \"Weight : <b>%{y}</b> kg\",\n                \"Age : <b>%{customdata}</b>\" \n            ]),\n    )\n])\n\nfig.update_layout(\n    title_text=\"<b>Players mean weight, height and age by field position</b><br><sup>sorted by height descending<sup>\",\n    title_x=0.5, \n    yaxis_title=\"Cm - Kg\",\n    barmode='group',\n    showlegend=True, \n    paper_bgcolor=\"darkgray\", \n    bargap=0.2,\n    bargroupgap=0.1\n)\n\ndisplay(fig, h_w_df.head(5))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:13.891417Z","iopub.execute_input":"2021-12-08T16:21:13.892327Z","iopub.status.idle":"2021-12-08T16:21:13.941498Z","shell.execute_reply.started":"2021-12-08T16:21:13.892284Z","shell.execute_reply":"2021-12-08T16:21:13.940335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Waoh some big boys out there ! We can find some useful informations for a guy like me who knows nothing about NFL:\n\n* I'd hate being chased by one Tackler ! \n* Halfback players are on average the lightest, shortest and youngest players of the team.\n* Quarterbacks and Punters need to be both tall and light !\n* Defensive and Nose Tacklers are on the other hand tall and heavy (about the same weight than Tacklers but 8 cm shorter)\n\nAnother thing that could be fun is looking at the first name frequency amongst the players","metadata":{}},{"cell_type":"code","source":"_first_names = [_name.split()[0] for _name in players_df[\"displayName\"]]\n\n_name_counter = Counter(_first_names) \n\n_text = \" \".join([i[0] for i in _name_counter.most_common() if 4 <= len(i[0]) <= 8])\n\nicon_path = '../input/picture/clipart1905967.png'\nicon = Image.open(icon_path)\n\n_mask = Image.new(\"RGB\", icon.size, (255, 255, 255))\n_mask.paste(icon,icon)\n_mask = np.array(_mask)\n\nwc = WordCloud(\n        background_color=\"black\", \n        max_words=300, \n        mask=_mask,\n        max_font_size=150)\n\nwc.generate_from_text(_text)\n\nplt.figure(figsize=(25,18))\nplt.imshow(wc, interpolation=\"bilinear\")\nplt.axis(\"off\")\nplt.margins(x=0, y=0)\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:13.944191Z","iopub.execute_input":"2021-12-08T16:21:13.944486Z","iopub.status.idle":"2021-12-08T16:21:16.280433Z","shell.execute_reply.started":"2021-12-08T16:21:13.944456Z","shell.execute_reply":"2021-12-08T16:21:16.279507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.DataFrame(_name_counter.most_common(10), columns=[\"Name\", \"Count\"])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:16.281758Z","iopub.execute_input":"2021-12-08T16:21:16.282020Z","iopub.status.idle":"2021-12-08T16:21:16.294949Z","shell.execute_reply.started":"2021-12-08T16:21:16.281987Z","shell.execute_reply":"2021-12-08T16:21:16.294009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plays_df = pd.read_csv(\"../input/nfl-big-data-bowl-2022/plays.csv\")\ngames_df2 = pd.read_csv(\"../input/nfl-big-data-bowl-2022/games.csv\")\npffs_df = pd.read_csv(\"../input/nfl-big-data-bowl-2022/PFFScoutingData.csv\")\n\ndf_2018 = pd.read_csv(\"../input/nfl-big-data-bowl-2022/tracking2018.csv\")\ndf_2019 = pd.read_csv(\"../input/nfl-big-data-bowl-2022/tracking2019.csv\")\ndf_2020 = pd.read_csv(\"../input/nfl-big-data-bowl-2022/tracking2020.csv\")\n\ndf_2018_games = df_2018[\"gameId\"].unique()\ndf_2019_games = df_2019[\"gameId\"].unique()\ndf_2020_games = df_2020[\"gameId\"].unique()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:21:16.296285Z","iopub.execute_input":"2021-12-08T16:21:16.296608Z","iopub.status.idle":"2021-12-08T16:23:32.027640Z","shell.execute_reply.started":"2021-12-08T16:21:16.296577Z","shell.execute_reply":"2021-12-08T16:23:32.026587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def game_df_generator(game_id : int):\n\n    _game_info = games_df2[games_df2[\"gameId\"] == game_id].reset_index(drop=True)\n    _plays = plays_df[plays_df[\"gameId\"] == game_id].reset_index(drop=True)\n    _pffs = pffs_df[pffs_df[\"gameId\"] == game_id].reset_index(drop=True)\n\n    if game_id in df_2018_games:\n        _tracking = df_2018[df_2018[\"gameId\"] == game_id].reset_index(drop=True)\n    elif game_id in df_2019_games:\n        _tracking = df_2019[df_2019[\"gameId\"] == game_id].reset_index(drop=True)\n    elif game_id in df_2020_games:\n        _tracking = df_2020[df_2020[\"gameId\"] == game_id].reset_index(drop=True)        \n\n    game_moves = pd.merge(_plays, _pffs, on=[\"gameId\", \"playId\"])\n    game_moves = pd.merge(game_moves, _tracking, on=[\"gameId\", \"playId\"])\n    game_moves[\"time\"] = pd.to_datetime(game_moves[\"time\"])\n\n    unique_players_per_game = game_moves[\"nflId\"].dropna().astype(\"int\").unique()\n    _players_in_game = pd.DataFrame(columns=players_df.columns)\n\n    for _player_id in unique_players_per_game:\n        temp_df = players_df[players_df[\"nflId\"] == _player_id]\n        _players_in_game = pd.concat([_players_in_game, temp_df], axis=0, ignore_index=True)\n\n    if len(game_moves[\"nflId\"].dropna()) != len(game_moves[\"nflId\"]): \n        _missing_players = (f\"\"\"We are missing {len(game_moves['nflId']) - len(game_moves['nflId'].dropna())} moves, that's {round((len(game_moves['nflId']) - len(game_moves['nflId'].dropna())) * 100 / len(game_moves['nflId']), ndigits=2)}% of total\"\"\")\n    else:\n        _missing_players = \"\"\n\n    return _game_info, game_moves, _missing_players, _players_in_game","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:23:32.029265Z","iopub.execute_input":"2021-12-08T16:23:32.029613Z","iopub.status.idle":"2021-12-08T16:23:32.044308Z","shell.execute_reply.started":"2021-12-08T16:23:32.029570Z","shell.execute_reply":"2021-12-08T16:23:32.043269Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"d, e, f, g = game_df_generator(2018101406)\n\n#display(d, e, f, g)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:23:32.046105Z","iopub.execute_input":"2021-12-08T16:23:32.046687Z","iopub.status.idle":"2021-12-08T16:23:32.302183Z","shell.execute_reply.started":"2021-12-08T16:23:32.046641Z","shell.execute_reply":"2021-12-08T16:23:32.301019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. Tracking\n\nWe have plenty of data about the players position at any given moment on the field, we can therefore recreate their movements and analyse them\n\nThe code in the cell below is inspired by the work of [JARON_MICHAL](https://www.kaggle.com/jaronmichal/tracking-data-visualization)\nand [DATAROHITINGOLE](https://www.kaggle.com/datarohitingole/nfl-data-analysis-and-plotly-animation#4.-Tracking-Data) may their names be praised for the generations to come","metadata":{}},{"cell_type":"code","source":"fb_ground_filename = '../input/football-ground/football_ground.png'\nfb_groud_plotly = Image.open(fb_ground_filename)\n\ndef animated_game(gameId, playId, speed):\n\n    _game_info = games_df2[games_df2[\"gameId\"] == gameId].reset_index(drop=True)\n    _home_team = _game_info[\"homeTeamAbbr\"].iloc[0]\n    _visitor_team = _game_info[\"visitorTeamAbbr\"].iloc[0]\n    _date_game = _game_info[\"gameDate\"].iloc[0]\n    _time_game = _game_info[\"gameTimeEastern\"].iloc[0]\n    \t\n\n    var_date = datetime.strptime(_date_game, '%m/%d/%Y')\n    _day = calendar.day_name[var_date.weekday()]\n    _month = calendar.month_name[int(_date_game[:2])]\n    _day_number = _date_game[3:5]\n\n    if str(_day_number[0]) == '0':\n        _day_number = _day_number[1:]\n    \n    if gameId in df_2018_games:\n        _tracking = df_2018[df_2018[\"gameId\"] == gameId].reset_index(drop=True)\n        temp_tracking_mask = (df_2018['gameId'] == gameId) & (df_2018['playId'] == playId)\n        _tracking_df = (df_2018[temp_tracking_mask][['x', 'y', 'time', 'nflId', 'team', 'displayName']]\n        .fillna(0.)\n        .sort_values(['team', 'time'])\n    )\n\n    elif gameId in df_2019_games:\n        _tracking = df_2019[df_2019[\"gameId\"] == gameId].reset_index(drop=True)\n        temp_tracking_mask = (df_2019['gameId'] == gameId) & (df_2019['playId'] == playId)\n        _tracking_df = (df_2019[temp_tracking_mask][['x', 'y', 'time', 'nflId', 'team', 'displayName']]\n        .fillna(0.)\n        .sort_values(['team', 'time'])\n    )\n\n    elif gameId in df_2020_games:\n        _tracking = df_2020[df_2020[\"gameId\"] == gameId].reset_index(drop=True)\n        temp_tracking_mask = (df_2020['gameId'] == gameId) & (df_2020['playId'] == playId)\n        _tracking_df = (df_2020[temp_tracking_mask][['x', 'y', 'time', 'nflId', 'team', 'displayName']]\n        .fillna(0.)\n        .sort_values(['team', 'time'])\n    )\n\n    _tracking_df[\"time\"] = _tracking_df[\"time\"].apply(lambda x : x[14:-2])\n\n    fig = px.scatter(\n        _tracking_df,\n        x='x',\n        y='y',\n        animation_frame='time',\n        color='team',\n        animation_group=\"nflId\",\n        hover_name=\"displayName\"\n    )\n\n    fig.update_traces(marker=dict(size=12,line=dict(width=2,color='DarkSlateGrey')),\n                      selector=dict(mode='markers'))\n\n    fig.update_layout(\n        title=f\"<b>{_home_team} (home) versus {_visitor_team} on {_day} the {_day_number} of {_month} at {str(_time_game)[:-3]}</b><br><sup>Animation of play : {playId} from game : {gameId}<sup><br> pouet\",\n        title_x=0.5, \n        autosize=False,\n        width=1000,\n        height=600,\n        images= [dict(source=fb_groud_plotly,\n                      xref=\"paper\", yref=\"paper\",x=0.01, y=1, sizex=1, sizey=1,\n                      layer=\"below\", opacity=0.8)],\n        xaxis=dict(showgrid=False),\n        yaxis=dict(showgrid=False), \n        showlegend=True, \n        paper_bgcolor=\"darkgray\", \n        margin=dict(\n                    l=20,\n                    r=20,\n                    b=50,\n                    t=50,\n                    pad=0\n                ),\n    )\n\n    fig.update_xaxes(title=\"\")                                                                                  \n    fig.update_yaxes(title=\"\")  \n    \n    fig.layout.updatemenus[0].buttons[0].args[1][\"frame\"][\"duration\"] = speed\n    \n    #print(_date_game, type(_date_game), _day, _month)\n\n    return fig #.show(\"notebook\")  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-08T16:23:32.303666Z","iopub.execute_input":"2021-12-08T16:23:32.303910Z","iopub.status.idle":"2021-12-08T16:23:32.335941Z","shell.execute_reply.started":"2021-12-08T16:23:32.303881Z","shell.execute_reply":"2021-12-08T16:23:32.334964Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_gameId = 2018090907\n_playId = 522\n_speed = 60\n\nanimated_game(_gameId, _playId, _speed)","metadata":{"execution":{"iopub.status.busy":"2021-12-08T16:23:32.337092Z","iopub.execute_input":"2021-12-08T16:23:32.337997Z","iopub.status.idle":"2021-12-08T16:23:34.583530Z","shell.execute_reply.started":"2021-12-08T16:23:32.337954Z","shell.execute_reply":"2021-12-08T16:23:34.582568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## more to come !","metadata":{}}]}