Computing movement speed¶

No description has been provided for this image

Binder IPYNB HTML

MovingPandas offers functions to compute and/or visualize the speed of movement along the trajectory between consecutive points.

In [1]:
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import shapely as shp
import hvplot.pandas

from geopandas import GeoDataFrame, read_file
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
from holoviews import opts

import warnings

warnings.filterwarnings("ignore")

opts.defaults(
    opts.Overlay(active_tools=["wheel_zoom"], frame_width=500, frame_height=400)
)

mpd.show_versions()
MovingPandas 0.20.0

SYSTEM INFO
-----------
python     : 3.10.15 | packaged by conda-forge | (main, Oct 16 2024, 01:15:49) [MSC v.1941 64 bit (AMD64)]
executable : c:\Users\Agarkovam\AppData\Local\miniforge3\envs\mpd-ex\python.exe
machine    : Windows-10-10.0.19045-SP0

GEOS, GDAL, PROJ INFO
---------------------
GEOS       : None
GEOS lib   : None
GDAL       : None
GDAL data dir: None
PROJ       : 9.5.0
PROJ data dir: C:\Users\Agarkovam\AppData\Local\miniforge3\envs\mpd-ex\Library\share\proj

PYTHON DEPENDENCIES
-------------------
geopandas  : 1.0.1
pandas     : 2.2.3
fiona      : None
numpy      : 1.23.1
shapely    : 2.0.6
pyproj     : 3.7.0
matplotlib : 3.9.2
mapclassify: 2.8.1
geopy      : 2.4.1
holoviews  : 1.20.0
hvplot     : 0.11.1
geoviews   : 1.13.0
stonesoup  : 1.4

Basic example¶

In [2]:
df = pd.DataFrame(
    [
        {"geometry": Point(0, 0), "t": datetime(2018, 1, 1, 12, 0, 0)},
        {"geometry": Point(6, 0), "t": datetime(2018, 1, 1, 12, 0, 6)},
        {"geometry": Point(6, 6), "t": datetime(2018, 1, 1, 12, 0, 11)},
        {"geometry": Point(9, 9), "t": datetime(2018, 1, 1, 12, 0, 14)},
    ]
).set_index("t")
gdf = GeoDataFrame(df, crs=31256)
toy_traj = mpd.Trajectory(gdf, 1)
toy_traj
Out[2]:
Trajectory 1 (2018-01-01 12:00:00 to 2018-01-01 12:00:14) | Size: 4 | Length: 16.2m
Bounds: (0.0, 0.0, 9.0, 9.0)
LINESTRING (0 0, 6 0, 6 6, 9 9)
In [3]:
toy_traj.add_speed(overwrite=True)
toy_traj.df
Out[3]:
geometry traj_id speed
t
2018-01-01 12:00:00 POINT (0 0) 1 1.000000
2018-01-01 12:00:06 POINT (6 0) 1 1.000000
2018-01-01 12:00:11 POINT (6 6) 1 1.200000
2018-01-01 12:00:14 POINT (9 9) 1 1.414214

We can also visualize the speed values:

In [4]:
toy_traj.plot(column="speed", linewidth=5, capstyle="round", legend=True)
Out[4]:
<Axes: >
No description has been provided for this image

Similar to speed, we can also add other columns:

In [5]:
toy_traj.add_direction(overwrite=True)
toy_traj.df
Out[5]:
geometry traj_id speed direction
t
2018-01-01 12:00:00 POINT (0 0) 1 1.000000 90.0
2018-01-01 12:00:06 POINT (6 0) 1 1.000000 90.0
2018-01-01 12:00:11 POINT (6 6) 1 1.200000 0.0
2018-01-01 12:00:14 POINT (9 9) 1 1.414214 45.0
In [6]:
toy_traj.add_timedelta(overwrite=True)
toy_traj.df
Out[6]:
geometry traj_id speed direction timedelta
t
2018-01-01 12:00:00 POINT (0 0) 1 1.000000 90.0 NaT
2018-01-01 12:00:06 POINT (6 0) 1 1.000000 90.0 0 days 00:00:06
2018-01-01 12:00:11 POINT (6 6) 1 1.200000 0.0 0 days 00:00:05
2018-01-01 12:00:14 POINT (9 9) 1 1.414214 45.0 0 days 00:00:03

We can also use custom units for distance, speed, and acceleration. Allowed units include metric units from mm to km, imperial units from inch to mile, nautical miles, and non-standard units which are used as CRS distance units e.g. US Survey units.

In [7]:
toy_traj.add_distance(overwrite=True, name="distance (km)", units="km")
toy_traj.add_distance(overwrite=True, name="distance (yards)", units="yd")
toy_traj.add_speed(overwrite=True, name="speed (ft/min)", units=("ft", "min"))
toy_traj.add_speed(overwrite=True, name="speed (knots)", units=("nm", "h"))
toy_traj.add_acceleration(
    overwrite=True, name="acceleration (mph/s)", units=("mi", "h", "s")
)
toy_traj.df
Out[7]:
geometry traj_id speed direction timedelta distance (km) distance (yards) speed (ft/min) speed (knots) acceleration (mph/s)
t
2018-01-01 12:00:00 POINT (0 0) 1 1.000000 90.0 NaT 0.000000 0.000000 196.850394 1.943844 0.000000
2018-01-01 12:00:06 POINT (6 0) 1 1.000000 90.0 0 days 00:00:06 0.006000 6.561680 196.850394 1.943844 0.000000
2018-01-01 12:00:11 POINT (6 6) 1 1.200000 0.0 0 days 00:00:05 0.006000 6.561680 236.220472 2.332613 0.089477
2018-01-01 12:00:14 POINT (9 9) 1 1.414214 45.0 0 days 00:00:03 0.004243 4.639808 278.388497 2.749011 0.159727

Real-world trajectories¶

In [8]:
gdf = read_file("../data/geolife_small.gpkg")
tc = mpd.TrajectoryCollection(gdf, "trajectory_id", t="t")
In [9]:
my_traj = tc.trajectories[1]
In [10]:
my_traj.df
Out[10]:
id sequence trajectory_id tracker geometry
t
2009-06-29 07:02:25 1556 1090 2 0 POINT (116.59096 40.07196)
2009-06-29 07:02:30 1557 1091 2 0 POINT (116.5909 40.07201)
2009-06-29 07:02:35 1558 1092 2 0 POINT (116.59088 40.07203)
2009-06-29 07:02:40 1559 1093 2 0 POINT (116.59092 40.072)
2009-06-29 07:02:45 1560 1094 2 0 POINT (116.59096 40.07198)
... ... ... ... ... ...
2009-06-29 11:09:47 2448 1982 2 0 POINT (116.32349 40.00037)
2009-06-29 11:09:57 2449 1983 2 0 POINT (116.32513 40.00057)
2009-06-29 11:10:02 2450 1984 2 0 POINT (116.32688 40.00087)
2009-06-29 11:10:07 2451 1985 2 0 POINT (116.32722 40.00101)
2009-06-29 11:13:12 2452 1986 2 0 POINT (116.32746 40.00052)

897 rows × 5 columns

Even if the Trajectory/TrajectoryCollection GeoDataFrame does not contain a speed column, we can still plot movement speed:

In [11]:
my_traj.plot(
    column="speed", linewidth=5, capstyle="round", figsize=(9, 3), legend=True, vmax=20
)
Out[11]:
<Axes: >
No description has been provided for this image
In [12]:
my_traj.hvplot(
    c="speed",
    clim=(0, 20),
    line_width=7.0,
    tiles="CartoLight",
    cmap="Viridis",
    colorbar=True,
)
Out[12]:
In [13]:
tc.plot(column="speed", linewidth=5, capstyle="round", legend=True, vmax=20)
Out[13]:
<Axes: >
No description has been provided for this image
In [ ]: