.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/pitch_plots/plot_animation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_pitch_plots_plot_animation.py: ========= Animation ========= This example shows how to animate tracking data from `metricasports `_. .. GENERATED FROM PYTHON SOURCE LINES 9-17 .. code-block:: Python import numpy as np import pandas as pd from matplotlib import animation from matplotlib import pyplot as plt from mplsoccer import Pitch .. GENERATED FROM PYTHON SOURCE LINES 18-19 Load the data .. GENERATED FROM PYTHON SOURCE LINES 19-32 .. code-block:: Python # load away data LINK1 = ('https://raw.githubusercontent.com/metrica-sports/sample-data/master/' 'data/Sample_Game_1/Sample_Game_1_RawTrackingData_Away_Team.csv') df_away = pd.read_csv(LINK1, skiprows=2) df_away.sort_values('Time [s]', inplace=True) # load home data LINK2 = ('https://raw.githubusercontent.com/metrica-sports/sample-data/master/' 'data/Sample_Game_1/Sample_Game_1_RawTrackingData_Home_Team.csv') df_home = pd.read_csv(LINK2, skiprows=2) df_home.sort_values('Time [s]', inplace=True) .. GENERATED FROM PYTHON SOURCE LINES 33-34 Reset the column names .. GENERATED FROM PYTHON SOURCE LINES 34-49 .. code-block:: Python # column names aren't great so this sets the player ones with _x and _y suffixes def set_col_names(df): """ Renames the columns to have x and y suffixes.""" cols = list(np.repeat(df.columns[3::2], 2)) cols = [col+'_x' if i % 2 == 0 else col+'_y' for i, col in enumerate(cols)] cols = np.concatenate([df.columns[:3], cols]) df.columns = cols set_col_names(df_away) set_col_names(df_home) .. GENERATED FROM PYTHON SOURCE LINES 50-51 Subset 2 seconds of data .. GENERATED FROM PYTHON SOURCE LINES 51-56 .. code-block:: Python # get a subset of the data (10 seconds) df_away = df_away[(df_away['Time [s]'] >= 815) & (df_away['Time [s]'] < 825)].copy() df_home = df_home[(df_home['Time [s]'] >= 815) & (df_home['Time [s]'] < 825)].copy() .. GENERATED FROM PYTHON SOURCE LINES 57-58 Split off the ball data, and drop the ball columns from the df_away/ df_home dataframes .. GENERATED FROM PYTHON SOURCE LINES 58-65 .. code-block:: Python # split off a df_ball dataframe and drop the ball columns from the player dataframes df_ball = df_away[['Period', 'Frame', 'Time [s]', 'Ball_x', 'Ball_y']].copy() df_home.drop(['Ball_x', 'Ball_y'], axis=1, inplace=True) df_away.drop(['Ball_x', 'Ball_y'], axis=1, inplace=True) df_ball.rename({'Ball_x': 'x', 'Ball_y': 'y'}, axis=1, inplace=True) .. GENERATED FROM PYTHON SOURCE LINES 66-67 Convert to long form. So each row is a single player's coordinates for a single frame .. GENERATED FROM PYTHON SOURCE LINES 67-87 .. code-block:: Python # convert to long form from wide form def to_long_form(df): """ Pivots a dataframe from wide-form (each player as a separate column) to long form (rows)""" df = pd.melt(df, id_vars=df.columns[:3], value_vars=df.columns[3:], var_name='player') df.loc[df.player.str.contains('_x'), 'coordinate'] = 'x' df.loc[df.player.str.contains('_y'), 'coordinate'] = 'y' df = df.dropna(axis=0, how='any') df['player'] = df.player.str[6:-2] df = (df.set_index(['Period', 'Frame', 'Time [s]', 'player', 'coordinate'])['value'] .unstack() .reset_index() .rename_axis(None, axis=1)) return df df_away = to_long_form(df_away) df_home = to_long_form(df_home) .. GENERATED FROM PYTHON SOURCE LINES 88-89 Show the away data .. GENERATED FROM PYTHON SOURCE LINES 89-91 .. code-block:: Python df_away.head() .. raw:: html
Period Frame Time [s] player x y
0 1 20375 815.0 15 0.52333 0.15093
1 1 20375 815.0 16 0.52972 0.31205
2 1 20375 815.0 17 0.48127 0.45092
3 1 20375 815.0 18 0.38463 0.04628
4 1 20375 815.0 19 0.25890 0.07167


.. GENERATED FROM PYTHON SOURCE LINES 92-93 Show the home data .. GENERATED FROM PYTHON SOURCE LINES 93-95 .. code-block:: Python df_home.head() .. raw:: html
Period Frame Time [s] player x y
0 1 20375 815.0 1 0.18914 0.51216
1 1 20375 815.0 10 0.39725 0.27164
2 1 20375 815.0 11 0.05056 0.44912
3 1 20375 815.0 2 0.18825 0.38918
4 1 20375 815.0 3 0.21617 0.21615


.. GENERATED FROM PYTHON SOURCE LINES 96-97 Show the ball data .. GENERATED FROM PYTHON SOURCE LINES 97-99 .. code-block:: Python df_ball.head() .. raw:: html
Period Frame Time [s] x y
20374 1 20375 815.00 0.24042 0.11311
20375 1 20376 815.04 0.23729 0.11115
20376 1 20377 815.08 0.23415 0.10919
20377 1 20378 815.12 0.23102 0.10723
20378 1 20379 815.16 0.22789 0.10528


.. GENERATED FROM PYTHON SOURCE LINES 100-101 Plot the animation .. GENERATED FROM PYTHON SOURCE LINES 101-138 .. code-block:: Python # First set up the figure, the axis pitch = Pitch(pitch_type='metricasports', goal_type='line', pitch_width=68, pitch_length=105) fig, ax = pitch.draw(figsize=(16, 10.4)) # then setup the pitch plot markers we want to animate marker_kwargs = {'marker': 'o', 'markeredgecolor': 'black', 'linestyle': 'None'} ball, = ax.plot([], [], ms=6, markerfacecolor='w', zorder=3, **marker_kwargs) away, = ax.plot([], [], ms=10, markerfacecolor='#b94b75', **marker_kwargs) # red/maroon home, = ax.plot([], [], ms=10, markerfacecolor='#7f63b8', **marker_kwargs) # purple # animation function def animate(i): """ Function to animate the data. Each frame it sets the data for the players and the ball.""" # set the ball data with the x and y positions for the ith frame ball.set_data(df_ball.iloc[i, [3]], df_ball.iloc[i, [4]]) # get the frame id for the ith frame frame = df_ball.iloc[i, 1] # set the player data using the frame id away.set_data(df_away.loc[df_away.Frame == frame, 'x'], df_away.loc[df_away.Frame == frame, 'y']) home.set_data(df_home.loc[df_home.Frame == frame, 'x'], df_home.loc[df_home.Frame == frame, 'y']) return ball, away, home # call the animator, animate so 25 frames per second anim = animation.FuncAnimation(fig, animate, frames=len(df_ball), interval=50, blit=True) plt.show() # note that its hard to get the ffmpeg requirements right. # I installed from conda-forge: see the environment.yml file in the docs folder # how to save animation - commented out for example # anim.save('example.mp4', dpi=150, fps=25, # extra_args=['-vcodec', 'libx264'], # savefig_kwargs={'pad_inches':0, 'facecolor':'#457E29'}) .. container:: sphx-glr-animation .. raw:: html
.. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 44.723 seconds) .. _sphx_glr_download_gallery_pitch_plots_plot_animation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_animation.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_animation.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_animation.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_