Soccer analysis exampleΒΆ
This tutorial uses data extracted from video footage of a soccer game that was published in https://github.com/Friends-of-Tracking-Data-FoTD/Last-Row
InΒ [1]:
import numpy as np
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import shapely as shp
import holoviews as hv
import hvplot.pandas
import matplotlib.pyplot as plt
from geopandas import GeoDataFrame, read_file
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
from holoviews import opts, dim
from os.path import exists
from urllib.request import urlretrieve
import warnings
warnings.filterwarnings("ignore")
hvplot_defaults = {
"line_width": 5,
"frame_height": 350,
"frame_width": 700,
"colorbar": True,
"tiles": None,
"geo": False,
}
mpd.show_versions()
MovingPandas 0.23.0 SYSTEM INFO ----------- python : 3.10.19 | packaged by conda-forge | (main, Jan 26 2026, 23:45:08) [GCC 14.3.0] executable : /home/anita/miniforge3/envs/mpd-ex/bin/python machine : Linux-6.8.0-134-generic-x86_64-with-glibc2.39 PROJ INFO ----------- PROJ : 9.6.2 PROJ data dir: /home/anita/miniforge3/envs/mpd-ex/share/proj PYTHON DEPENDENCIES ------------------- numpy : 1.23.1 geopandas : 1.0.1 geopy : 2.4.1 geoviews : 1.15.1 holoviews : 1.22.1 hvplot : 0.12.2 mapclassify: 2.8.1 matplotlib : 3.10.8 pandas : 2.3.3 pyproj : 3.7.1 shapely : 2.1.2 stonesoup : 1.8
Loading soccer dataset from GithubΒΆ
InΒ [2]:
def get_file_from_url(url):
file = url.split("/")[-1]
if not exists(file):
urlretrieve(url, file)
return file
def get_df_from_gh_url(url):
file = get_file_from_url(url)
return pd.read_csv(file)
InΒ [3]:
input_file = "https://raw.githubusercontent.com/Friends-of-Tracking-Data-FoTD/Last-Row/master/datasets/positional_data/liverpool_2019.csv"
df = get_df_from_gh_url(input_file)
df.drop(columns=["Unnamed: 0"], inplace=True)
print(f"Number of records: {len(df)}")
Number of records: 74936
InΒ [4]:
df.head()
Out[4]:
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | NaN | 0.000000 | 0.000000 | NaN | 0 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 46.394558 | 11.134454 | 0.0 |
| 1 | NaN | 0.185745 | 1.217580 | NaN | 1 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 46.580302 | 12.352034 | 0.0 |
| 2 | NaN | 0.178659 | 1.171133 | NaN | 2 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 46.758961 | 13.523166 | 0.0 |
| 3 | NaN | 0.171573 | 1.124685 | NaN | 3 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 46.930535 | 14.647852 | 0.0 |
| 4 | NaN | 0.164488 | 1.078238 | NaN | 4 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 47.095022 | 15.726090 | 0.0 |
From the metadata:
- play: the scoreline after the goal. The team who scored the goal is the one next to the brackets.
- frame: the frame number for the current location. Data provided has 20 frames per second.
- player: the id of the player. The id is consistent within a play but not between plays.
- player_num: the player jersey number. This number is the official one, and did not change for Liverpool in 2019. You can check the corresponding names at this wikipedia link.
- x, y: coordinates for the player/ball. Pitch coordinates go from 0 to 100 on each axis.
- dx, dx: change in (x,y) coordinates from last frame to current frame
- z: height, from 0 to 1.5 (only filled for the ball)
- bgcolor: the main color for the team (used as background color)
- edgecolor the secondary color (used as edge color)
And according to https://en.wikipedia.org/wiki/Football_pitch
the preferred size for many professional teams' stadiums is 105 by 68 metres
InΒ [5]:
plays = list(df.play.unique())
def to_timestamp(row):
# plays to date
day = plays.index(row.play) + 1
start_time = datetime(2019, 1, day, 12, 0, 0)
# frames to time
td = timedelta(milliseconds=1000 / 20 * row.frame)
return start_time + td
# frame: the frame number for the current location. Data provided has 20 frames per second
df["time"] = df.apply(to_timestamp, axis=1)
df.set_index("time", inplace=True)
# the preferred size for many professional teams' stadiums is 105 by 68 metres, accoring to https://en.wikipedia.org/wiki/Football_pitch
pitch_length = 105
pitch_width = 68
df.x = df.x / 100 * pitch_length
df.y = df.y / 100 * pitch_width
df
Out[5]:
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-01 12:00:00.000 | NaN | 0.000000 | 0.000000 | NaN | 0 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 48.714286 | 7.571429 | 0.0 |
| 2019-01-01 12:00:00.050 | NaN | 0.185745 | 1.217580 | NaN | 1 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 48.909318 | 8.399383 | 0.0 |
| 2019-01-01 12:00:00.100 | NaN | 0.178659 | 1.171133 | NaN | 2 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 49.096909 | 9.195753 | 0.0 |
| 2019-01-01 12:00:00.150 | NaN | 0.171573 | 1.124685 | NaN | 3 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 49.277061 | 9.960539 | 0.0 |
| 2019-01-01 12:00:00.200 | NaN | 0.164488 | 1.078238 | NaN | 4 | Liverpool [3] - 0 Bournemouth | 0 | NaN | NaN | 49.449774 | 10.693741 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2019-01-19 12:00:06.000 | blue | 0.000000 | 0.000000 | white | 120 | Leicester 0 - [3] Liverpool | 10267 | NaN | defense | 103.661067 | 36.529840 | 0.0 |
| 2019-01-19 12:00:06.050 | blue | 0.000000 | 0.000000 | white | 121 | Leicester 0 - [3] Liverpool | 10267 | NaN | defense | 103.661067 | 36.529840 | 0.0 |
| 2019-01-19 12:00:06.100 | blue | 0.000000 | 0.000000 | white | 122 | Leicester 0 - [3] Liverpool | 10267 | NaN | defense | 103.661067 | 36.529840 | 0.0 |
| 2019-01-19 12:00:06.150 | blue | 0.000000 | 0.000000 | white | 123 | Leicester 0 - [3] Liverpool | 10267 | NaN | defense | 103.661067 | 36.529840 | 0.0 |
| 2019-01-19 12:00:06.200 | blue | 0.000000 | 0.000000 | white | 124 | Leicester 0 - [3] Liverpool | 10267 | NaN | defense | 103.661067 | 36.529840 | 0.0 |
74936 rows Γ 12 columns
InΒ [6]:
df["team"].value_counts().plot(title="team", kind="bar", figsize=(15, 3))
Out[6]:
<Axes: title={'center': 'team'}, xlabel='team'>
InΒ [7]:
df["player_num"].value_counts().plot(title="player_num", kind="bar", figsize=(15, 3))
Out[7]:
<Axes: title={'center': 'player_num'}, xlabel='player_num'>
InΒ [8]:
df["team"] = df["team"].astype("category").cat.as_ordered()
df["player"] = df["player"].astype("category").cat.as_ordered()
df["player_num"] = df["player_num"].astype("category").cat.as_ordered()
Finally, let's create trajectories:
TrajectoriesΒΆ
InΒ [9]:
%%time
CRS = None
tc = mpd.TrajectoryCollection(df, "player", x="x", y="y", crs=CRS)
mpd.TemporalSplitter(tc).split(mode="day")
print(f"Finished creating {len(tc)} trajectories")
Finished creating 364 trajectories CPU times: user 2.6 s, sys: 12.9 ms, total: 2.61 s Wall time: 2.61 s
InΒ [10]:
pitch = Polygon(
[(0, 0), (0, pitch_width), (pitch_length, pitch_width), (pitch_length, 0), (0, 0)]
)
plotted_pitch = GeoDataFrame(
pd.DataFrame([{"geometry": pitch, "id": 1}]), crs=CRS
).hvplot(color="white", alpha=0.5)
InΒ [11]:
plotted_pitch * tc.filter("player_num", 20).hvplot(**hvplot_defaults)
Out[11]:
PlaysΒΆ
InΒ [12]:
PLAY = 2
title = f"Play {PLAY} {plays[PLAY]}"
play_trajs = tc.filter("play", plays[PLAY])
play_trajs
Out[12]:
TrajectoryCollection with 20 trajectories
Trajectory 15 (No. rows: 440 | Length: 200.0 unknown units)
| Start: 2019-01-03 12:00:00 | End: 2019-01-04 12:00:12.800000 | Duration: 1 day, 0:00:12.800000 |
| Bounds: (6.551567770977525, 3.7750702170347226, 82.09398284322187, 38.26729953820284) | CRS: None | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||
| 2019-01-03 12:00:00.000 | red | -0.043670 | 0.074173 | white | 0 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (35.21733 3.77507) |
| 2019-01-03 12:00:00.050 | red | -0.047653 | 0.070251 | white | 1 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (35.1673 3.82284) |
| 2019-01-03 12:00:00.100 | red | -0.051604 | 0.066492 | white | 2 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (35.11311 3.86806) |
| 2019-01-03 12:00:00.150 | red | -0.055524 | 0.062895 | white | 3 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (35.05481 3.91082) |
| 2019-01-03 12:00:00.200 | red | -0.059413 | 0.059461 | white | 4 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (34.99243 3.95126) |
Trajectory 1417 (No. rows: 183 | Length: 28.3 unknown units)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (2.4067528263372275, 32.64796726872315, 29.011220461407955, 36.247053914056096) | CRS: None | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||
| 2019-01-03 12:00:00.000 | red | -0.166623 | 0.035776 | white | 0 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (29.01122 35.94375) |
| 2019-01-03 12:00:00.050 | red | -0.161728 | 0.028071 | white | 1 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (28.84141 35.96284) |
| 2019-01-03 12:00:00.100 | red | -0.156964 | 0.020572 | white | 2 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (28.67659 35.97683) |
| 2019-01-03 12:00:00.150 | red | -0.152331 | 0.013280 | white | 3 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (28.51665 35.98586) |
| 2019-01-03 12:00:00.200 | red | -0.147829 | 0.006194 | white | 4 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (28.36143 35.99007) |
Trajectory 1726 (No. rows: 183 | Length: 42.1 unknown units)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (5.734167253361569, 17.619044936607835, 38.25362992582764, 32.38861292505991) | CRS: None | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||
| 2019-01-03 12:00:00.000 | red | -0.235714 | 0.157618 | white | 0 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (38.25363 23.11031) |
| 2019-01-03 12:00:00.050 | red | -0.234865 | 0.137702 | white | 1 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (38.00702 23.20395) |
| 2019-01-03 12:00:00.100 | red | -0.234039 | 0.118320 | white | 2 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (37.76128 23.2844) |
| 2019-01-03 12:00:00.150 | red | -0.233236 | 0.099472 | white | 3 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (37.51638 23.35205) |
| 2019-01-03 12:00:00.200 | red | -0.232455 | 0.081157 | white | 4 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (37.2723 23.40723) |
Trajectory 2150 (No. rows: 183 | Length: 49.7 unknown units)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (-0.14078795317397683, 20.167864811566734, 37.73409725043924, 39.63452549724319) | CRS: None | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||
| 2019-01-03 12:00:00.000 | red | 0.035577 | -0.179075 | white | 0 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.6906 39.63453) |
| 2019-01-03 12:00:00.050 | red | 0.024562 | -0.186474 | white | 1 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.71639 39.50772) |
| 2019-01-03 12:00:00.100 | red | 0.013744 | -0.193706 | white | 2 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.73082 39.376) |
| 2019-01-03 12:00:00.150 | red | 0.003124 | -0.200771 | white | 3 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.7341 39.23948) |
| 2019-01-03 12:00:00.200 | red | -0.007300 | -0.207669 | white | 4 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.72643 39.09826) |
Trajectory 2813 (No. rows: 183 | Length: 54.6 unknown units)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (2.7660926033158155, 10.256982134264762, 52.57416878737574, 30.905891049635116) | CRS: None | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| time | |||||||||||
| 2019-01-03 12:00:00.000 | red | -0.133693 | 0.009661 | white | 0 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (52.57417 10.25698) |
| 2019-01-03 12:00:00.050 | red | -0.141654 | 0.016081 | white | 1 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (52.42543 10.26792) |
| 2019-01-03 12:00:00.100 | red | -0.149469 | 0.022388 | white | 2 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (52.26849 10.28314) |
| 2019-01-03 12:00:00.150 | red | -0.157138 | 0.028583 | white | 3 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (52.10349 10.30258) |
| 2019-01-03 12:00:00.200 | red | -0.164663 | 0.034666 | white | 4 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (51.9306 10.32615) |
... and 15 more trajectories
InΒ [13]:
play_trajs.plot(column="team", colormap={"attack": "hotpink", "defense": "turquoise"})
Out[13]:
<Axes: >
InΒ [14]:
generalized = mpd.MinTimeDeltaGeneralizer(play_trajs).generalize(
tolerance=timedelta(seconds=0.5)
)
InΒ [15]:
generalized.add_speed()
Out[15]:
TrajectoryCollection with 20 trajectories
Trajectory 15 (No. rows: 46 | Length: 19228.5 km)
| Start: 2019-01-03 12:00:00 | End: 2019-01-04 12:00:12.800000 | Duration: 1 day, 0:00:12.800000 |
| Bounds: (6.621318386672574, 3.7750702170347226, 82.09398284322187, 38.22377088649229) | CRS: epsg:4326 | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64), speed (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | speed | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-03 12:00:00.000 | red | -0.043670 | 0.074173 | white | 0 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (35.21733 3.77507) | 173009.429041 |
| 2019-01-03 12:00:00.500 | red | -0.082083 | 0.042270 | white | 10 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (34.53424 4.15101) | 173009.429041 |
| 2019-01-03 12:00:01.000 | red | -0.117349 | 0.026626 | white | 20 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (33.46598 4.37082) | 242113.267888 |
| 2019-01-03 12:00:01.500 | red | -0.149470 | 0.027239 | white | 30 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (32.04559 4.54504) | 317629.439724 |
| 2019-01-03 12:00:02.000 | red | -0.178445 | 0.044111 | white | 40 | Fulham 0 - [1] Liverpool | 15 | 10.0 | attack | 0.0 | POINT (30.3061 4.78425) | 389611.812608 |
Trajectory 1417 (No. rows: 20 | Length: 2645.1 km)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (2.4171798590630593, 32.64796726872315, 29.011220461407955, 36.21487965556477) | CRS: epsg:4326 | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64), speed (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | speed | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-03 12:00:00.000 | red | -0.166623 | 0.035776 | white | 0 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (29.01122 35.94375) | 268877.797805 |
| 2019-01-03 12:00:00.500 | red | -0.123573 | -0.031987 | white | 10 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (27.52165 35.92202) | 268877.797805 |
| 2019-01-03 12:00:01.000 | red | -0.093635 | -0.079111 | white | 20 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (26.40839 35.51668) | 220626.580808 |
| 2019-01-03 12:00:01.500 | red | -0.076808 | -0.105597 | white | 30 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (25.53375 34.86809) | 214688.615696 |
| 2019-01-03 12:00:02.000 | red | -0.073093 | -0.111445 | white | 40 | Fulham 0 - [1] Liverpool | 1417 | 11.0 | attack | 0.0 | POINT (24.76008 34.11658) | 219082.498957 |
Trajectory 1726 (No. rows: 20 | Length: 4381.7 km)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (5.734167253361569, 17.692516247713808, 38.25362992582764, 32.329922320985105) | CRS: epsg:4326 | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64), speed (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | speed | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-03 12:00:00.000 | red | -0.235714 | 0.157618 | white | 0 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (38.25363 23.11031) | 504443.403156 |
| 2019-01-03 12:00:00.500 | red | -0.228249 | -0.017532 | white | 10 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (35.82371 23.49713) | 504443.403156 |
| 2019-01-03 12:00:01.000 | red | -0.223058 | -0.139336 | white | 20 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (33.45904 22.89244) | 502341.047061 |
| 2019-01-03 12:00:01.500 | red | -0.220141 | -0.207795 | white | 30 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (31.13574 21.65899) | 551301.696136 |
| 2019-01-03 12:00:02.000 | red | -0.219497 | -0.222910 | white | 40 | Fulham 0 - [1] Liverpool | 1726 | 20.0 | attack | 0.0 | POINT (28.82995 20.15953) | 583426.888212 |
Trajectory 2150 (No. rows: 20 | Length: 5186.7 km)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (-0.11124068481597718, 20.180051254744626, 37.69059626103843, 39.63452549724319) | CRS: epsg:4326 | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64), speed (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | speed | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-03 12:00:00.000 | red | 0.035577 | -0.179075 | white | 0 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.6906 39.63453) | 330032.029258 |
| 2019-01-03 12:00:00.500 | red | -0.065693 | -0.245552 | white | 10 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (37.46222 38.15883) | 330032.029258 |
| 2019-01-03 12:00:01.000 | red | -0.147225 | -0.295339 | white | 20 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (36.2845 36.29351) | 463799.633169 |
| 2019-01-03 12:00:01.500 | red | -0.209018 | -0.328435 | white | 30 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (34.36468 34.15206) | 589859.110405 |
| 2019-01-03 12:00:02.000 | red | -0.251072 | -0.344841 | white | 40 | Fulham 0 - [1] Liverpool | 2150 | 9.0 | attack | 0.0 | POINT (31.91004 31.84798) | 686732.475941 |
Trajectory 2813 (No. rows: 20 | Length: 5785.1 km)
| Start: 2019-01-03 12:00:00 | End: 2019-01-03 12:00:09.100000 | Duration: 0:00:09.100000 |
| Bounds: (2.780061514910607, 10.256982134264762, 52.57416878737574, 30.89351462425568) | CRS: epsg:4326 | |
| Columns: bgcolor (object), dx (float64), dy (float64), edgecolor (object), frame (int64), play (object), player (int64), player_num (category), team (category), z (float64), speed (float64) | ||
Data preview
| bgcolor | dx | dy | edgecolor | frame | play | player | player_num | team | z | geometry | speed | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| time | ||||||||||||
| 2019-01-03 12:00:00.000 | red | -0.133693 | 0.009661 | white | 0 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (52.57417 10.25698) | 407784.977209 |
| 2019-01-03 12:00:00.500 | red | -0.206756 | 0.068807 | white | 10 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (50.73586 10.55018) | 407784.977209 |
| 2019-01-03 12:00:01.000 | red | -0.265280 | 0.116731 | white | 20 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (48.21435 11.20359) | 569995.811624 |
| 2019-01-03 12:00:01.500 | red | -0.309266 | 0.153435 | white | 30 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (45.1623 12.14093) | 697093.847659 |
| 2019-01-03 12:00:02.000 | red | -0.338712 | 0.178918 | white | 40 | Fulham 0 - [1] Liverpool | 2813 | 26.0 | attack | 0.0 | POINT (41.73236 13.2859) | 786909.255594 |
... and 15 more trajectories
InΒ [16]:
generalized.hvplot(
title=title, c="speed", hover_cols=["player", "team"], **hvplot_defaults
)
Out[16]:
InΒ [17]:
(
plotted_pitch
* generalized.hvplot(
title=title, c="speed", hover_cols=["player"], cmap="Viridis", **hvplot_defaults
)
)
Out[17]:
InΒ [18]:
get_file_from_url(
"https://github.com/movingpandas/movingpandas/raw/main/tutorials/data/soccer_field.png"
)
pitch_img = hv.RGB.load_image(
"soccer_field.png", bounds=(0, 0, pitch_length, pitch_width)
)
(
pitch_img
* generalized.hvplot(
title=title,
c="team",
colormap={"attack": "limegreen", "defense": "purple"},
hover_cols=["team"],
**hvplot_defaults
)
* generalized.get_start_locations().hvplot(label="start", color="orange")
)
Out[18]:
InΒ [19]:
(
pitch_img
* generalized.hvplot(title=title, c="team", hover_cols=["team"], **hvplot_defaults)
* generalized.get_start_locations().hvplot(
label="start",
c="team",
hover_cols=["team"],
colormap={"attack": "limegreen", "defense": "purple"},
colorbar=True,
legend=True,
)
)
Out[19]: