In [8]:
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import datashader as ds
from hvplot import pandas
from holoviews import opts #, dim 
from holoviews.element import tiles
from datetime import datetime, timedelta
In [9]:
mpd.show_versions()
MovingPandas 0.17.2

SYSTEM INFO
-----------
python     : 3.11.4 | packaged by Anaconda, Inc. | (main, Jul  5 2023, 13:47:18) [MSC v.1916 64 bit (AMD64)]
executable : C:\Users\leoni\Programme\Miniconda\python.exe
machine    : Windows-10-10.0.22621-SP0

GEOS, GDAL, PROJ INFO
---------------------
GEOS       : None
GEOS lib   : None
GDAL       : 3.6.4
GDAL data dir: C:\Users\leoni\Programme\Miniconda\Lib\site-packages\fiona\gdal_data
PROJ       : 9.3.0
PROJ data dir: C:\Users\leoni\Programme\Miniconda\Lib\site-packages\pyproj\proj_dir\share\proj

PYTHON DEPENDENCIES
-------------------
geopandas  : 0.14.1
pandas     : 2.1.3
fiona      : 1.9.5
numpy      : 1.26.2
shapely    : 2.0.2
rtree      : 1.1.0
pyproj     : 3.6.1
matplotlib : 3.8.1
mapclassify: 2.6.1
geopy      : 2.4.0
holoviews  : 1.18.1
hvplot     : 0.9.0
geoviews   : None
stonesoup  : None
In [10]:
opts.defaults(opts.Overlay(active_tools=['wheel_zoom'], frame_width=700, frame_height=300))

BG_TILES = tiles.CartoLight()
EVERID = 235
In [14]:
df = pd.read_csv('data/boat-positions.csv', parse_dates=True)
df['ais_pos_timestamp'] = pd.to_datetime(df['ais_pos_timestamp'], format='%d/%m/%Y %H:%M')
df
Out[14]:
ID ais_pos_timestamp longitude latitude
0 1 2021-03-20 00:22:00 32.32925 31.43860
1 1 2021-03-20 01:25:00 32.39860 31.40955
2 1 2021-03-20 02:07:00 32.37395 31.32413
3 1 2021-03-20 02:33:00 32.35152 31.24716
4 1 2021-03-20 02:53:00 32.33933 31.20590
... ... ... ... ...
22282 256 2021-03-24 11:12:00 32.32908 31.19488
22283 256 2021-03-24 11:33:00 32.32909 31.19486
22284 256 2021-03-24 11:54:00 32.32910 31.19484
22285 256 2021-03-24 12:14:00 32.32908 31.19485
22286 256 2021-03-24 12:35:00 32.32909 31.19483

22287 rows × 4 columns

In [16]:
tmp = df.copy()
tmp.loc[:, 'x'], tmp.loc[:, 'y'] = ds.utils.lnglat_to_meters(tmp.longitude, tmp.latitude)
BG_TILES * tmp.hvplot.scatter(title='Density map', x='x', y='y', datashade=True)
Out[16]:
In [20]:
tc = mpd.TrajectoryCollection(df, 'ID', t='ais_pos_timestamp', x='longitude', y='latitude', crs=4326)
tc
Out[20]:
TrajectoryCollection with 250 trajectories
In [25]:
tc.to_traj_gdf().hvplot(title='All trajectories', geo=True, tiles='OSM')
Out[25]:
In [26]:
tc.get_trajectory(1)#.hvplot(geo=True)
Out[26]:
Trajectory 1 (2021-03-20 00:22:00 to 2021-03-20 13:08:00) | Size: 36 | Length: 195232.1m
Bounds: (32.30417, 29.82953, 32.5869, 31.4386)
LINESTRING (32.32925 31.4386, 32.3986 31.40955, 32.37395 31.32413, 32.35152 31.24716, 32.33933 31.20
In [27]:
tc.get_trajectory(1).hvplot(geo=True)
Out[27]:
In [28]:
tc.add_speed(units=('km','h'))
In [30]:
df.ID.max()
Out[30]:
256
In [31]:
traj_id = 15
tc.get_trajectory(traj_id).hvplot(title=f'Trajectory {traj_id}', c='speed', cmap='Viridis', 
                                  clim=(0,10), tiles='CartoLight') 
Out[31]:
In [33]:
traj_id = EVERID  
( tc.to_traj_gdf().hvplot(title=f'Trajectory {traj_id} on top of all other trajectories', 
                          geo=True, tiles='OSM', color='orange', alpha=0.5) *
tc.get_trajectory(traj_id).hvplot(c='speed', cmap='Viridis', clim=(0,7), tiles=None) )
Out[33]:
In [34]:
( BG_TILES * 
  tmp.hvplot.scatter(title=f'Trajectory {traj_id} on top of density map',
                    x='x', y='y', datashade=True, cmap=['lightpink','hotpink','darkblue']) *
  tc.get_trajectory(traj_id).hvplot(c='speed', cmap='Viridis', clim=(0,7), tiles=None) )
Out[34]:
In [35]:
stop_pts = mpd.TrajectoryStopDetector(tc, n_threads=3).get_stop_points(min_duration=timedelta(hours=3), max_diameter=1000)
stop_pts['duration_h'] = stop_pts['duration_s'] / 3600
stop_pts
Out[35]:
geometry start_time end_time traj_id duration_s duration_h
stop_id
2_2021-03-21 08:29:00 POINT (32.35567 31.21248) 2021-03-21 08:29:00 2021-03-21 23:11:00 2 52920.0 14.700000
4_2021-03-23 22:23:00 POINT (32.32796 31.39507) 2021-03-23 22:23:00 2021-03-24 12:46:00 4 51780.0 14.383333
5_2021-03-20 09:47:00 POINT (32.35727 31.21790) 2021-03-20 09:47:00 2021-03-21 03:55:00 5 65280.0 18.133333
8_2021-03-23 06:15:00 POINT (32.58077 30.00576) 2021-03-23 06:15:00 2021-03-24 12:50:00 8 110100.0 30.583333
9_2021-03-20 02:07:00 POINT (32.43236 30.30340) 2021-03-20 02:07:00 2021-03-20 05:56:00 9 13740.0 3.816667
... ... ... ... ... ... ...
249_2021-03-20 06:30:00 POINT (32.34406 30.36822) 2021-03-20 06:30:00 2021-03-20 14:09:00 249 27540.0 7.650000
250_2021-03-23 17:17:00 POINT (32.53383 29.83297) 2021-03-23 17:17:00 2021-03-24 12:21:00 250 68640.0 19.066667
251_2021-03-23 22:21:00 POINT (32.35181 31.45093) 2021-03-23 22:21:00 2021-03-24 12:48:00 251 52020.0 14.450000
255_2021-03-23 08:52:00 POINT (32.57538 29.85072) 2021-03-23 08:52:00 2021-03-24 11:14:00 255 94920.0 26.366667
256_2021-03-20 00:25:00 POINT (32.32908 31.19485) 2021-03-20 00:25:00 2021-03-24 12:35:00 256 389400.0 108.166667

258 rows × 6 columns

In [36]:
stop_pts.hvplot(title='Stops', geo=True, tiles='OSM', color='red', size='duration_h')
Out[36]:
In [37]:
( pd.DataFrame(stop_pts).hvplot.scatter(
    title='Stop start & duration (in hours)', x='start_time', y='duration_h') *
  pd.DataFrame(stop_pts[stop_pts['traj_id']==EVERID]).hvplot.scatter(
      x='start_time', y='duration_h', color='red', size=200) )
Out[37]:
In [38]:
stop_pts[stop_pts.start_time > datetime(2021,3,23,5,0,0)]\
    .sort_values('duration_s', ascending=False)\
    .head(7)\
    .style.background_gradient(cmap='Reds')
Out[38]:
  geometry start_time end_time traj_id duration_s duration_h
stop_id            
235_2021-03-23 05:47:00 POINT (32.58019 30.01763) 2021-03-23 05:47:00 2021-03-24 12:52:00 235 111900.000000 31.083333
8_2021-03-23 06:15:00 POINT (32.58077 30.00576) 2021-03-23 06:15:00 2021-03-24 12:50:00 8 110100.000000 30.583333
168_2021-03-23 06:26:00 POINT (32.58109 30.003) 2021-03-23 06:26:00 2021-03-24 12:49:00 168 109380.000000 30.383333
124_2021-03-23 06:53:00 POINT (32.588544999999996 29.77551) 2021-03-23 06:53:00 2021-03-24 12:30:00 124 106620.000000 29.616667
81_2021-03-23 07:48:00 POINT (32.57137 29.83667) 2021-03-23 07:48:00 2021-03-24 12:33:00 81 103500.000000 28.750000
193_2021-03-23 08:04:00 POINT (32.53971 29.92151) 2021-03-23 08:04:00 2021-03-24 12:46:00 193 103320.000000 28.700000
54_2021-03-23 08:48:00 POINT (32.58387 29.98875) 2021-03-23 08:48:00 2021-03-24 12:51:00 54 100980.000000 28.050000
In [ ]: