Computing movement speed¶
MovingPandas offers functions to compute and/or visualize the speed of movement along the trajectory between consecutive points.
In [ ]:
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.18.1 SYSTEM INFO ----------- python : 3.10.14 | packaged by conda-forge | (main, Mar 20 2024, 12:40:08) [MSC v.1938 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 : 3.8.5 GDAL data dir: None PROJ : 9.4.0 PROJ data dir: C:\Users\Agarkovam\AppData\Local\miniforge3\envs\mpd-ex\Library\share\proj PYTHON DEPENDENCIES ------------------- geopandas : 0.14.4 pandas : 2.2.2 fiona : 1.9.6 numpy : 1.26.4 shapely : 2.0.4 rtree : 1.2.0 pyproj : 3.6.1 matplotlib : 3.8.4 mapclassify: 2.6.1 geopy : 2.4.1 holoviews : 1.17.1 hvplot : 0.8.3 geoviews : 1.9.6 stonesoup : 1.2
Basic example¶
In [ ]:
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[ ]:
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 [ ]:
toy_traj.add_speed(overwrite=True)
toy_traj.df
Out[ ]:
geometry | traj_id | speed | |
---|---|---|---|
t | |||
2018-01-01 12:00:00 | POINT (0.000 0.000) | 1 | 1.000000 |
2018-01-01 12:00:06 | POINT (6.000 0.000) | 1 | 1.000000 |
2018-01-01 12:00:11 | POINT (6.000 6.000) | 1 | 1.200000 |
2018-01-01 12:00:14 | POINT (9.000 9.000) | 1 | 1.414214 |
We can also visualize the speed values:
In [ ]:
toy_traj.plot(column="speed", linewidth=5, capstyle='round', legend=True)
Out[ ]:
<Axes: >
Similar to speed, we can also add other columns:
In [ ]:
toy_traj.add_direction(overwrite=True)
toy_traj.df
Out[ ]:
geometry | traj_id | speed | direction | |
---|---|---|---|---|
t | ||||
2018-01-01 12:00:00 | POINT (0.000 0.000) | 1 | 1.000000 | 90.0 |
2018-01-01 12:00:06 | POINT (6.000 0.000) | 1 | 1.000000 | 90.0 |
2018-01-01 12:00:11 | POINT (6.000 6.000) | 1 | 1.200000 | 0.0 |
2018-01-01 12:00:14 | POINT (9.000 9.000) | 1 | 1.414214 | 45.0 |
In [ ]:
toy_traj.add_timedelta(overwrite=True)
toy_traj.df
Out[ ]:
geometry | traj_id | speed | direction | timedelta | |
---|---|---|---|---|---|
t | |||||
2018-01-01 12:00:00 | POINT (0.000 0.000) | 1 | 1.000000 | 90.0 | NaT |
2018-01-01 12:00:06 | POINT (6.000 0.000) | 1 | 1.000000 | 90.0 | 0 days 00:00:06 |
2018-01-01 12:00:11 | POINT (6.000 6.000) | 1 | 1.200000 | 0.0 | 0 days 00:00:05 |
2018-01-01 12:00:14 | POINT (9.000 9.000) | 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 [ ]:
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[ ]:
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.000 0.000) | 1 | 1.000000 | 90.0 | NaT | 0.000000 | 0.000000 | 196.850394 | 1.943844 | 0.000000 |
2018-01-01 12:00:06 | POINT (6.000 0.000) | 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.000 6.000) | 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.000 9.000) | 1 | 1.414214 | 45.0 | 0 days 00:00:03 | 0.004243 | 4.639808 | 278.388497 | 2.749011 | 0.159727 |
Real-world trajectories¶
In [ ]:
gdf = read_file('../data/geolife_small.gpkg')
tc = mpd.TrajectoryCollection(gdf, 'trajectory_id', t='t')
In [ ]:
my_traj = tc.trajectories[1]
In [ ]:
my_traj.df
Out[ ]:
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.59091 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.59091 40.07200) |
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 [ ]:
my_traj.plot(column='speed', linewidth=5, capstyle='round', figsize=(9,3), legend=True, vmax=20)
Out[ ]:
<Axes: >
In [ ]:
my_traj.hvplot(c='speed', clim=(0,20), line_width=7.0, tiles='CartoLight', cmap='Viridis', colorbar=True)
Out[ ]:
In [ ]:
tc.plot(column='speed', linewidth=5, capstyle='round', legend=True, vmax=20)
Out[ ]:
<Axes: >
In [ ]: