Soccer analysis exampleΒΆ

No description has been provided for this image

Binder IPYNB HTML

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'>
No description has been provided for this image
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'>
No description has been provided for this image
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:00End: 2019-01-04 12:00:12.800000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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: >
No description has been provided for this image
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:00End: 2019-01-04 12:00:12.800000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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:00End: 2019-01-03 12:00:09.100000Duration: 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]:

Continue exploring MovingPandasΒΆ

  1. Bird migration analysis
  2. Ship data analysis
  3. Horse collar data exploration
  4. OSM traces
  5. Soccer game
  6. Mars rover & heli
  7. Ever Given
  8. Iceberg
  9. Pollution data