In the first notebook you saw how to make static plots of player positions at a given point in time, as well as plots of player tracks over the course of a play. That's cool and all but we all know what you're really here for — animations! ptplot
does not disappoint in this category.
(NOTE: If you are viewing this notebook on GitHub, none of the plots will render due to the way GitHub processes the notebooks. To see the notebook rendered properly, please use nbviewer.)
Starting with imports, as usual.
import numpy as np
import pandas as pd
from ptplot import PTPlot
from ptplot.animation import Animation
from ptplot.hover import Hover
from ptplot.nfl import Aesthetics, Field
from ptplot.plot import Positions, Tracks
from bokeh.plotting import show
from bokeh.io import output_notebook
output_notebook()
Static plots are useful, but where ptplot
really shines is in its ability to easily make animations. We'll use the same play as before, that reverse + WR pass, to demonstrate.
# Load the data file
player_tracking_data = pd.read_csv(
"2018_CLE_2018122305_1246.tsv",
sep="\t", parse_dates=["time"]
)
player_tracking_data.loc[player_tracking_data["displayName"] == "ball", "teamAbbr"] = "ball"
player_tracking_data.loc[player_tracking_data["displayName"] == "ball", "jerseyNumber"] = ""
player_tracking_data.x = player_tracking_data.x - 10
# Just look between the snap and the tackle, to make the tracks clearer
snap_frame = player_tracking_data[player_tracking_data["event"] == "ball_snap"]["frame"].unique()[0]
tackle_frame = player_tracking_data[player_tracking_data["event"] == "tackle"]["frame"].unique()[0]
player_tracking_data = player_tracking_data[
player_tracking_data["frame"].between(snap_frame, tackle_frame)
]
Creating an animation is no harder than making a static plot. Add an Animation layer and supply a frame argument.
plot = (
PTPlot(data=player_tracking_data, pixel_height=400)
+ Field()
+ Positions(
"x", "y", orientation="o", number="jerseyNumber",
name="positions"
)
+ Aesthetics(team_ball_mapping="teamAbbr", home_away_mapping="homeTeamFlag == 1", ball_identifier="ball")
+ Hover([("name", "@displayName")], "positions", ["displayName"])
+ Animation("frame", 10)
)
show(plot.draw())
In addition to standard play/pause controls, ptplot
also automatically generates a slider that gives you fine-grained control over the animation.
Just like for the static plots, you can animate traces as well.
plot = (
PTPlot(
data=player_tracking_data,
pixel_height=400
)
+ Field()
+ Tracks("x", "y", "displayName", line_width=2)
+ Positions(
"x", "y", orientation="o", number="jerseyNumber",
name="positions"
)
+ Aesthetics(team_ball_mapping="teamAbbr", home_away_mapping="homeTeamFlag == 1", ball_identifier="ball")
+ Hover([("name", "@displayName")], "positions", ["displayName"])
+ Animation("frame", 10)
)
show(plot.draw())