Computing movement speed¶
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: >
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: >
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: >
In [ ]: