Lesson 06
Mobility Analytics
goals of the tutorial
- transform movement data into information
- trajectory
- map matching (look the solutions)
based on the data of Strava
requirements
- python knowledge
- geopandas
- GPX format
status
“Where’s Wally?”
GNSS
Global Navigation Satellite System (GNSS) refers to a constellation of satellites providing signals from space that transmit positioning and timing data to GNSS receivers. The receivers then use this data to determine location. By definition, GNSS provides global coverage.
basic
with corrections
GPX Format
GPX, or GPS Exchange Format, is an XML schema designed as a common GPS data format for software applications. It can be used to describe waypoints, tracks, and routes.
units
position
latitude and longitude are expressed in decimal degrees, and elevation in meters, both using the WGS 84 datum (epsg 4326).
time
dates and times are not local time, but instead are Coordinated Universal Time (UTC) using ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)
data
(image by Berklas distributed under cc-by-sa 3.0)
- wptType is an individual waypoint among a collection of points with no sequential relationship. It consists of the WGS 84 (GPS) coordinates of a point and possibly other descriptive information.
- rteType is a route, an ordered list of routepoint (waypoints representing a series of significant turn or stage points) leading to a destination.
- trkType is a track, made of at least one segment containing waypoints, that is, an ordered list of points describing a path. A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data.
details about the format on fhe officiale website
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="Oregon 400t" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<metadata>
<link href="http://www.garmin.com">
<text>Garmin International</text>
</link>
<time>2009-10-17T22:58:43Z</time>
</metadata>
<trk>
<name>Example GPX Document</name>
<trkseg>
<trkpt lat="47.644548" lon="-122.326897">
<ele>4.46</ele>
<time>2009-10-17T18:37:26Z</time>
</trkpt>
<trkpt lat="47.644548" lon="-122.326897">
<ele>4.94</ele>
<time>2009-10-17T18:37:31Z</time>
</trkpt>
<trkpt lat="47.644548" lon="-122.326897">
<ele>6.87</ele>
<time>2009-10-17T18:37:34Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
information from wikipedia
Commmon problems
Missing Data
- Temporal gaps
- Spatial gaps
Incorrect data:
- location or time is incorrect in the data frame
Outliers:
- Too fast movements
- Incorrect order of temporal information
Setup
try:
import gpxpy
except ModuleNotFoundError as e:
!pip install gpxpy==1.4.2
import gpxpy
if gpxpy.__version__ != "1.4.2":
!pip install -U gpxpy==1.4.2
try:
import pygeos
except ModuleNotFoundError as e:
!pip install pygeos==0.13
import pygeos
if pygeos.__version__ != "0.13":
!pip install -U pygeos==0.13
try:
import mapclassify
except ModuleNotFoundError as e:
!pip install mapclassify==2.4.3
import mapclassify
if mapclassify.__version__ != "2.4.3":
!pip install -U mapclassify==2.4.3
try:
import movingpandas as mpd
except ModuleNotFoundError as e:
!pip install movingpandas==0.7.rc1
import movingpandas as mpd
if mpd.__version__ != "0.7.rc1":
!pip install -U movingpandas==0.7.rc1
import os
os.environ["USE_PYGEOS"] = "0"
import gpxpy
import urllib.request
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
from datetime import datetime,timedelta
import matplotlib.pyplot as plt
from shapely.geometry import Point
import warnings
warnings.filterwarnings('ignore') # ignore warnings
Let’s start to play with GPX files
Download the data
If you are registered and the author permits the download you can download the gps track but and investigate with GPX Studio without timestamps
]
or … you can use Strava To Gpx
]
investigate the file
gpx_url = "https://gist.githubusercontent.com/napo/4d0c14585da0ef96f263faa0e8d97ff5/raw/efba18f806459b462a1e485023cdd01c4d20e01a/strava_full.gpx"
gpx_file = "strava_full.gpx"
urllib.request.urlretrieve(gpx_url,gpx_file)
gpx_file = open(gpx_file, 'r')
gpx = gpxpy.parse(gpx_file)
gpx.creator
'https://www.mapstogpx.com/strava'
len(gpx.tracks)
1
len(gpx.tracks[0].segments)
1
segment = gpx.tracks[0].segments[0]
segment
GPXTrackSegment(points=[...])
type(segment.points)
list
segment.points[0].latitude
45.900222
segment.points[0].longitude
10.847826
segment.points[0].elevation
96.5
creation of a pandas DataFrame
data = []
for point_idx, point in enumerate(segment.points):
data.append([point.longitude, point.latitude,
point.elevation, point.time])
columns = ['longitude', 'latitude', 'altitude', 'time']
gpx_tracks = pd.DataFrame(data, columns=columns)
# Strava to GPX assign the date of the download of the file as timestamp and SimpleTZ("Z") as TimeZone.
# we can remove it
gpx_tracks['time'] = gpx_tracks['time'].apply(lambda x: x.replace(tzinfo=None))
# index creation needed by MovingPandas
df = gpx_tracks.set_index('time')
travel time
start_point = data[0]
end_point = data[-1]
# travel time
# steps to calcolate the difference of time from the timestamp in the first point to the last.
travel_time = end_point[3]-start_point[3]
travel_time_seconds = timedelta(seconds=travel_time.total_seconds())
travel_time_hours = str(timedelta(seconds=travel_time_seconds.seconds))
print_travel_time = travel_time_hours.split(':')
print("travel time %sh %s' %s''" % (print_travel_time[0], print_travel_time[1], print_travel_time[2]))
travel time 2h 34' 41''
reverse geocoding
from geopy.geocoders import Nominatim
latlon = str(start_point[1]) + "," + str(start_point[0])
geolocator = Nominatim(user_agent="geospatial course unitn")
starting_place = geolocator.reverse(latlon)
starting_place
Location(Residenza Gardaverde, Via Luigi Pigarelli, Pasina, Varone, Riva del Garda, Comunità Alto Garda e Ledro, Provincia di Trento, Trentino-Alto Adige/Südtirol, 38066, Italia, (45.900411399999996, 10.847324175675148, 0.0))
latlon = str(end_point[1]) + "," + str(end_point[0])
geolocator = Nominatim(user_agent="geospatial course unitn")
arrival_place = geolocator.reverse(latlon)
arrival_place
Location(Pronto Soccorso Ospedale di Arco, Viale dei Capitelli, Chiarano, Arco, Comunità Alto Garda e Ledro, Provincia di Trento, Trentino-Alto Adige/Südtirol, 38062, Italia, (45.919077, 10.875114, 0.0))
Analyzing trajectories
# GeoDataFrame for MovingPandas
geo_df = gpd.GeoDataFrame(df,
crs=4326,
geometry= gpd.points_from_xy(df.longitude, df.latitude, df.altitude))
geo_df.plot()
plt.show()
trajectory = mpd.Trajectory(geo_df, 0)
trajectory
Trajectory 0 (2021-10-12 12:01:38 to 2021-10-12 14:36:19) | Size: 5532 | Length: 40316.6m
Bounds: (10.731099, 45.861882, 10.875513, 45.919142)
LINESTRING Z (10.847826 45.900222 96.5, 10.84785 45.900264 96.5, 10.847843 45.900125 96.5, 10.847836
# object trajectory from MovingPandas
trajectory = mpd.Trajectory(geo_df, 1)
trajectory.plot()
plt.show()
trajectory.add_speed(overwrite=True)
trajectory.df
longitude | latitude | altitude | geometry | speed | |
---|---|---|---|---|---|
time | |||||
2021-10-12 12:01:38 | 10.847826 | 45.900222 | 96.5 | POINT Z (10.84783 45.90022 96.50000) | 5.026084 |
2021-10-12 12:01:39 | 10.847850 | 45.900264 | 96.5 | POINT Z (10.84785 45.90026 96.50000) | 5.026084 |
2021-10-12 12:01:40 | 10.847843 | 45.900125 | 96.5 | POINT Z (10.84784 45.90013 96.50000) | 15.459309 |
2021-10-12 12:01:41 | 10.847836 | 45.899890 | 96.5 | POINT Z (10.84784 45.89989 96.50000) | 26.125749 |
2021-10-12 12:01:42 | 10.847835 | 45.899786 | 96.5 | POINT Z (10.84783 45.89979 96.50000) | 11.559794 |
... | ... | ... | ... | ... | ... |
2021-10-12 14:34:13 | 10.875184 | 45.919097 | 91.6 | POINT Z (10.87518 45.91910 91.60000) | 0.765202 |
2021-10-12 14:34:20 | 10.875213 | 45.919122 | 91.6 | POINT Z (10.87521 45.91912 91.60000) | 0.510754 |
2021-10-12 14:34:30 | 10.875186 | 45.919142 | 91.6 | POINT Z (10.87519 45.91914 91.60000) | 0.305432 |
2021-10-12 14:35:45 | 10.875151 | 45.919126 | 91.6 | POINT Z (10.87515 45.91913 91.60000) | 0.043276 |
2021-10-12 14:36:19 | 10.875091 | 45.919049 | 91.6 | POINT Z (10.87509 45.91905 91.60000) | 0.286540 |
5532 rows × 5 columns
#trajectory.hvplot(geo=True, tiles='OSM', line_width=5) #, frame_width=300, frame_height=300)
# conversion m/s to km/h
def ms_to_km(ms):
v = (ms) * (60*60)/1000
return v
# km/h column
trajectory.df['kmh'] = trajectory.df['speed'].apply(ms_to_km)
trajectory.plot(column="kmh", linewidth=5, capstyle='round', legend=True)
plt.show()
Extracting a moving object’s position was at a certain time
trajectory
Trajectory 1 (2021-10-12 12:01:38 to 2021-10-12 14:36:19) | Size: 5532 | Length: 40316.6m
Bounds: (10.731099, 45.861882, 10.875513, 45.919142)
LINESTRING Z (10.847826 45.900222 96.5, 10.84785 45.900264 96.5, 10.847843 45.900125 96.5, 10.847836
trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="nearest")
print(trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="nearest"))
POINT Z (10.840998 45.888594 81.1)
print(trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="nearest"))
print(trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="interpolated"))
print(trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="ffill")) # from the previous row
print(trajectory.get_position_at(datetime(2021,10,12,12,6,0), method="bfill")) # from the following row
POINT Z (10.840998 45.888594 81.1)
POINT Z (10.840998 45.888594 81.1)
POINT Z (10.840998 45.888594 81.1)
POINT Z (10.840998 45.888594 81.1)
Extracting trajectory segments based on time
segment_clip = trajectory.get_segment_between(datetime(2021,10,12,13,36,1),datetime(2021,10,12,13,38,51))
print(segment_clip)
Trajectory 1_2021-10-12 13:36:01 (2021-10-12 13:36:01 to 2021-10-12 13:38:49) | Size: 158 | Length: 1457.3m
Bounds: (10.832986, 45.870462, 10.839058, 45.879066)
LINESTRING Z (10.832986 45.870462 160.3, 10.833045 45.870534 159.9, 10.83311 45.870598 159.5, 10.833
segment_clip.plot()
plt.show()
Extracting trajectory segments based on geometry (i.e. clipping)
from shapely.geometry import Point, Polygon
latitude=45.88880
longitude=10.84269
p = Point(longitude, latitude)
point = gpd.GeoDataFrame(pd.DataFrame(),
crs=4326,
geometry= [p])
distance = 10 # meters
# create a bounding box
xmin, ymax, xmax, ymin = point.to_crs(epsg=32632).buffer(distance).geometry.to_crs(epsg=4326).iloc[0].bounds
polygon = Polygon([(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin)])
polygon
intersections = trajectory.clip(polygon)
intersections
TrajectoryCollection with 3 trajectories
intersections.trajectories[0].plot(linewidth=5, capstyle='round')
plt.show()
intersections.trajectories[1].plot(linewidth=5, capstyle='round')
plt.show()
intersections.trajectories[2].plot(linewidth=5, capstyle='round')
plt.show()
Splitting trajectories
Gaps are quite common in trajectories. For example, GPS tracks may contain gaps if moving objects enter tunnels where GPS reception is lost. In other use cases, moving objects may leave the observation area for longer time before returning and continuing their recorded track.
Depending on the use case, we therefore might want to split trajectories at observation gaps that exceed a certain minimum duration:
duration 15 minutes
split = mpd.ObservationGapSplitter(trajectory).split(gap=timedelta(minutes=15))
for traj in split:
print(traj)
Trajectory 1_0 (2021-10-12 12:01:38 to 2021-10-12 13:47:11) | Size: 5070 | Length: 34131.1m
Bounds: (10.731099, 45.861882, 10.84785, 45.901398)
LINESTRING Z (10.847826 45.900222 96.5, 10.84785 45.900264 96.5, 10.847843 45.900125 96.5, 10.847836
Trajectory 1_2 (2021-10-12 14:24:10 to 2021-10-12 14:36:19) | Size: 461 | Length: 6182.5m
Bounds: (10.837456, 45.887391, 10.875513, 45.919142)
LINESTRING Z (10.842638 45.888938 79.4, 10.842624 45.888947 79.5, 10.842587 45.888957 79.5, 10.84259
fig, axes = plt.subplots(nrows=1, ncols=len(split), figsize=(19,4))
for i, traj in enumerate(split):
traj.plot(ax=axes[i], linewidth=5.0, capstyle='round', column='speed', vmax=20)
1km
split = mpd.StopSplitter(trajectory).split(min_duration=timedelta(minutes=15), max_diameter=30, min_length=1000)
for traj in split:
print(traj)
Trajectory 1_2021-10-12 12:01:38 (2021-10-12 12:01:38 to 2021-10-12 13:47:11) | Size: 5070 | Length: 34131.1m
Bounds: (10.731099, 45.861882, 10.84785, 45.901398)
LINESTRING Z (10.847826 45.900222 96.5, 10.84785 45.900264 96.5, 10.847843 45.900125 96.5, 10.847836
Trajectory 1_2021-10-12 14:24:50 (2021-10-12 14:24:50 to 2021-10-12 14:36:19) | Size: 449 | Length: 6131.0m
Bounds: (10.837456, 45.887391, 10.875513, 45.919142)
LINESTRING Z (10.842435 45.889193 81.1, 10.842394 45.889205 81.2, 10.842355 45.889195 81.3, 10.84228
fig, axes = plt.subplots(nrows=1, ncols=len(split), figsize=(19,4))
for i, traj in enumerate(split):
traj.plot(ax=axes[i], linewidth=5.0, capstyle='round', column='speed', vmax=20)
Stop detection
detector = mpd.TrajectoryStopDetector(trajectory)
%time
CPU times: user 5 µs, sys: 0 ns, total: 5 µs
Wall time: 9.54 µs
#traj_plot = trajectory.hvplot(title='Trajectory {}'.format(trajectory.id), line_width=7.0, tiles='CartoLight', color='slategray', frame_width=350, frame_height=350)
#traj_plot
stop duration
%%time
stop_durations = detector.get_stop_time_ranges(min_duration=timedelta(seconds=60), max_diameter=100)
CPU times: user 14.7 s, sys: 33.7 ms, total: 14.7 s
Wall time: 14.7 s
for x in stop_durations:
print(x)
Traj 1: 2021-10-12 12:40:59 - 2021-10-12 12:41:59 (duration: 0 days 00:01:00)
Traj 1: 2021-10-12 12:45:28 - 2021-10-12 12:46:40 (duration: 0 days 00:01:12)
Traj 1: 2021-10-12 12:46:44 - 2021-10-12 12:47:51 (duration: 0 days 00:01:07)
Traj 1: 2021-10-12 12:47:56 - 2021-10-12 12:49:26 (duration: 0 days 00:01:30)
Traj 1: 2021-10-12 12:50:03 - 2021-10-12 12:51:04 (duration: 0 days 00:01:01)
Traj 1: 2021-10-12 12:51:09 - 2021-10-12 12:52:47 (duration: 0 days 00:01:38)
Traj 1: 2021-10-12 13:41:59 - 2021-10-12 14:25:49 (duration: 0 days 00:43:50)
Traj 1: 2021-10-12 14:34:30 - 2021-10-12 14:36:19 (duration: 0 days 00:01:49)
stop points
%%time
stop_points = detector.get_stop_points(min_duration=timedelta(seconds=60), max_diameter=100)
CPU times: user 14.6 s, sys: 24.5 ms, total: 14.6 s
Wall time: 14.6 s
stop_points
geometry | start_time | end_time | traj_id | duration_s | |
---|---|---|---|---|---|
stop_id | |||||
1_2021-10-12 12:40:59 | POINT Z (10.78989 45.86505 462.90000) | 2021-10-12 12:40:59 | 2021-10-12 12:41:59 | 1 | 60.0 |
1_2021-10-12 12:45:28 | POINT Z (10.78315 45.86742 518.50000) | 2021-10-12 12:45:28 | 2021-10-12 12:46:40 | 1 | 72.0 |
1_2021-10-12 12:46:44 | POINT Z (10.78217 45.86820 533.70000) | 2021-10-12 12:46:44 | 2021-10-12 12:47:51 | 1 | 67.0 |
1_2021-10-12 12:47:56 | POINT Z (10.78158 45.86913 550.40000) | 2021-10-12 12:47:56 | 2021-10-12 12:49:26 | 1 | 90.0 |
1_2021-10-12 12:50:03 | POINT Z (10.77957 45.86942 579.00000) | 2021-10-12 12:50:03 | 2021-10-12 12:51:04 | 1 | 61.0 |
1_2021-10-12 12:51:09 | POINT Z (10.77831 45.86930 592.90000) | 2021-10-12 12:51:09 | 2021-10-12 12:52:47 | 1 | 98.0 |
1_2021-10-12 13:41:59 | POINT Z (10.84269 45.88890 79.40000) | 2021-10-12 13:41:59 | 2021-10-12 14:25:49 | 1 | 2630.0 |
1_2021-10-12 14:34:30 | POINT Z (10.87519 45.91914 91.60000) | 2021-10-12 14:34:30 | 2021-10-12 14:36:19 | 1 | 109.0 |
#stop_point_plot = traj_plot * stop_points.hvplot(geo=True, size='duration_s', color='deeppink')
#stop_point_plot
stop segments
%%time
stops = detector.get_stop_segments(min_duration=timedelta(seconds=60), max_diameter=100)
CPU times: user 14.6 s, sys: 16.5 ms, total: 14.6 s
Wall time: 14.6 s
stops
TrajectoryCollection with 8 trajectories
#stop_segment_plot = stop_point_plot * stops.hvplot( size=200, line_width=7.0, tiles=None, color='orange')
#stop_segment_plot
split a stop
%%time
split = mpd.StopSplitter(trajectory).split(min_duration=timedelta(seconds=60), max_diameter=100)
CPU times: user 17.7 s, sys: 18.5 ms, total: 17.7 s
Wall time: 17.8 s
split
TrajectoryCollection with 8 trajectories
for segment in split:
print(segment)
Trajectory 1_2021-10-12 12:01:38 (2021-10-12 12:01:38 to 2021-10-12 12:40:59) | Size: 1859 | Length: 10497.8m
Bounds: (10.789892, 45.861981, 10.84785, 45.901398)
LINESTRING Z (10.847826 45.900222 96.5, 10.84785 45.900264 96.5, 10.847843 45.900125 96.5, 10.847836
Trajectory 1_2021-10-12 12:41:59 (2021-10-12 12:41:59 to 2021-10-12 12:45:28) | Size: 150 | Length: 647.8m
Bounds: (10.78315, 45.865551, 10.788879, 45.867858)
LINESTRING Z (10.788848 45.865551 478.6, 10.788839 45.865583 478.8, 10.788834 45.865623 479.1, 10.78
Trajectory 1_2021-10-12 12:46:40 (2021-10-12 12:46:40 to 2021-10-12 12:46:44) | Size: 3 | Length: 8.3m
Bounds: (10.782169, 45.868145, 10.782239, 45.868201)
LINESTRING Z (10.782239 45.868145 533, 10.782199 45.868181 533.4, 10.782169 45.868201 533.7)
Trajectory 1_2021-10-12 12:47:51 (2021-10-12 12:47:51 to 2021-10-12 12:47:56) | Size: 3 | Length: 8.5m
Bounds: (10.781579, 45.869051, 10.781585, 45.869127)
LINESTRING Z (10.781579 45.869051 549, 10.781585 45.869089 549.7, 10.781585 45.869127 550.4)
Trajectory 1_2021-10-12 12:49:26 (2021-10-12 12:49:26 to 2021-10-12 12:50:03) | Size: 20 | Length: 81.9m
Bounds: (10.779572, 45.869424, 10.780497, 45.869678)
LINESTRING Z (10.780497 45.869637 571.2, 10.780459 45.869661 571.6, 10.780419 45.869664 572, 10.7803
Trajectory 1_2021-10-12 12:51:04 (2021-10-12 12:51:04 to 2021-10-12 12:51:09) | Size: 3 | Length: 8.4m
Bounds: (10.778313, 45.869304, 10.778396, 45.869351)
LINESTRING Z (10.778396 45.869351 592.1, 10.778364 45.869326 592.4, 10.778313 45.869304 592.9)
Trajectory 1_2021-10-12 12:52:47 (2021-10-12 12:52:47 to 2021-10-12 13:41:59) | Size: 2808 | Length: 21940.7m
Bounds: (10.731099, 45.861882, 10.842706, 45.888921)
LINESTRING Z (10.77706 45.869333 613.9, 10.77702 45.869337 614.4, 10.77698 45.869345 614.8, 10.77694
Trajectory 1_2021-10-12 14:25:49 (2021-10-12 14:25:49 to 2021-10-12 14:34:30) | Size: 423 | Length: 6002.9m
Bounds: (10.837456, 45.887391, 10.875513, 45.919142)
LINESTRING Z (10.842126 45.888566 79.1, 10.842008 45.888542 79.5, 10.841949 45.888514 79.7, 10.84182
Generalizing trajectories
Douglas-Peucker algorithm
trajectory.plot(column='speed', linewidth=5, capstyle='round', figsize=(9,3), legend=True, vmax=20)
plt.show()
generalized_trajectory = mpd.DouglasPeuckerGeneralizer(trajectory).generalize(tolerance=0.001)
generalized_trajectory.plot(column='speed', linewidth=5, capstyle='round', figsize=(9,3), legend=True, vmax=20)
plt.show()
print('Original length: %s'%(trajectory.get_length()))
print('Generalized length: %s'%(generalized_trajectory.get_length()))
Original length: 40316.62984544139
Generalized length: 37390.63448916281
alternative down-sample the trajectory to ensure a certain time delta between records
time_generalized = mpd.MinTimeDeltaGeneralizer(trajectory).generalize(tolerance=timedelta(minutes=10))
time_generalized.plot(column='speed', linewidth=5, capstyle='round', figsize=(9,3), legend=True, vmax=20)
plt.show()
time_generalized.to_point_gdf().head(10)
longitude | latitude | altitude | geometry | speed | kmh | |
---|---|---|---|---|---|---|
time | ||||||
2021-10-12 12:01:38 | 10.847826 | 45.900222 | 96.5 | POINT Z (10.84783 45.90022 96.50000) | 5.026084 | 18.093904 |
2021-10-12 12:11:38 | 10.837393 | 45.874687 | 118.6 | POINT Z (10.83739 45.87469 118.60000) | 4.446633 | 16.007878 |
2021-10-12 12:21:38 | 10.830129 | 45.862466 | 244.0 | POINT Z (10.83013 45.86247 244.00000) | 3.863094 | 13.907137 |
2021-10-12 12:31:38 | 10.813936 | 45.864505 | 371.3 | POINT Z (10.81394 45.86451 371.30000) | 3.815148 | 13.734534 |
2021-10-12 12:41:38 | 10.788925 | 45.865013 | 477.9 | POINT Z (10.78893 45.86501 477.90000) | 3.525257 | 12.690925 |
2021-10-12 12:51:39 | 10.778118 | 45.869216 | 598.4 | POINT Z (10.77812 45.86922 598.40000) | 1.619121 | 5.828837 |
2021-10-12 13:01:39 | 10.746818 | 45.869637 | 657.8 | POINT Z (10.74682 45.86964 657.80000) | 8.849716 | 31.858976 |
2021-10-12 13:11:39 | 10.741853 | 45.885748 | 656.5 | POINT Z (10.74185 45.88575 656.50000) | 6.003111 | 21.611198 |
2021-10-12 13:21:39 | 10.774246 | 45.870862 | 637.8 | POINT Z (10.77425 45.87086 637.80000) | 10.406578 | 37.463682 |
2021-10-12 13:31:39 | 10.827858 | 45.863224 | 301.4 | POINT Z (10.82786 45.86322 301.40000) | 10.652206 | 38.347942 |
trajectory.to_point_gdf().head(10)
longitude | latitude | altitude | geometry | speed | kmh | |
---|---|---|---|---|---|---|
time | ||||||
2021-10-12 12:01:38 | 10.847826 | 45.900222 | 96.5 | POINT Z (10.84783 45.90022 96.50000) | 5.026084 | 18.093904 |
2021-10-12 12:01:39 | 10.847850 | 45.900264 | 96.5 | POINT Z (10.84785 45.90026 96.50000) | 5.026084 | 18.093904 |
2021-10-12 12:01:40 | 10.847843 | 45.900125 | 96.5 | POINT Z (10.84784 45.90013 96.50000) | 15.459309 | 55.653513 |
2021-10-12 12:01:41 | 10.847836 | 45.899890 | 96.5 | POINT Z (10.84784 45.89989 96.50000) | 26.125749 | 94.052696 |
2021-10-12 12:01:42 | 10.847835 | 45.899786 | 96.5 | POINT Z (10.84783 45.89979 96.50000) | 11.559794 | 41.615259 |
2021-10-12 12:01:44 | 10.847798 | 45.899773 | 96.5 | POINT Z (10.84780 45.89977 96.50000) | 1.607194 | 5.785899 |
2021-10-12 12:01:54 | 10.847751 | 45.899764 | 96.5 | POINT Z (10.84775 45.89976 96.50000) | 0.378204 | 1.361533 |
2021-10-12 12:01:56 | 10.847786 | 45.899790 | 96.5 | POINT Z (10.84779 45.89979 96.50000) | 1.982969 | 7.138687 |
2021-10-12 12:01:57 | 10.847749 | 45.899800 | 96.5 | POINT Z (10.84775 45.89980 96.50000) | 3.078936 | 11.084170 |
2021-10-12 12:02:01 | 10.847702 | 45.899803 | 96.5 | POINT Z (10.84770 45.89980 96.50000) | 0.915638 | 3.296297 |
Exercise
the trips_truck.gpkg dataset contains the routes of a garbage vehicle in April 2018.
Based on this data:
- identify the longest route carried out
- identify the places of the daily departure and arrival points
- show the km traveled day by day
- identify the breaks carried out in the shortest route of the third week and in the longest one of the last
- identify the longest route of the third week of the month on the OpenStreetMap road graph