OGC MovingFeatures functionality¶
Ressources:
MovingPandas offers OGC MovingFeatures functionality to read and convert MF-JSON files.
In [1]:
import pandas as pd
import geopandas as gpd
import movingpandas as mpd
import shapely as shp
import hvplot.pandas
import json
from geopandas import GeoDataFrame, read_file
from movingpandas import read_mf_dict, gdf_to_mf_json
from shapely.geometry import Point, LineString, Polygon
from datetime import datetime, timedelta
from holoviews import opts, dim
import warnings
warnings.filterwarnings("ignore")
opts.defaults(opts.Overlay(active_tools=["wheel_zoom"]))
mpd.show_versions()
MovingPandas 0.23.0 SYSTEM INFO ----------- python : 3.10.19 | packaged by conda-forge | (main, Jan 26 2026, 23:45:08) [GCC 14.3.0] executable : /home/anita/miniforge3/envs/mpd-ex/bin/python machine : Linux-6.8.0-134-generic-x86_64-with-glibc2.39 PROJ INFO ----------- PROJ : 9.6.2 PROJ data dir: /home/anita/miniforge3/envs/mpd-ex/share/proj PYTHON DEPENDENCIES ------------------- numpy : 1.23.1 geopandas : 1.0.1 geopy : 2.4.1 geoviews : 1.15.1 holoviews : 1.22.1 hvplot : 0.12.2 mapclassify: 2.8.1 matplotlib : 3.10.8 pandas : 2.3.3 pyproj : 3.7.1 shapely : 2.1.2 stonesoup : 1.8
MF-JSON MovingPoint¶
In [2]:
traj = mpd.read_mf_json("../data/201901.en-movingpoint.json")
traj.df.head()
Out[2]:
| preasure | wind | class | geometry | traj_id | |
|---|---|---|---|---|---|
| t | |||||
| 2018-12-31 06:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.9 7.6) | 0 |
| 2018-12-31 12:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.3 7.3) | 0 |
| 2018-12-31 18:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.1 7) | 0 |
| 2019-01-01 00:00:00 | 1004.0 | 0.0 | 2.0 | POINT (110.7 6.6) | 0 |
| 2019-01-01 06:00:00 | 1000.0 | 35.0 | 3.0 | POINT (110.2 6.3) | 0 |
In [3]:
traj.explore(color="red")
Out[3]:
Make this Notebook Trusted to load map: File -> Trust Notebook
MF-JSON MovingFeatureCollection¶
In [4]:
collection = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"id": 5},
"temporalGeometry": {
"type": "MovingPoint",
"datetimes": ["2008-02-02T15:02:18Z", "2008-02-02T18:32:28Z"],
"coordinates": [[116.52299, 40.07757], [116.52302, 39.92129]],
},
}
],
}
In [5]:
trajs_collection = read_mf_dict(collection, traj_id_property="id")
trajs_collection
Out[5]:
TrajectoryCollection with 1 trajectories
Trajectory 5 (No. rows: 2 | Length: 17.4 km)
| Start: 2008-02-02 15:02:18 | End: 2008-02-02 18:32:28 | Duration: 3:30:10 |
| Bounds: (116.52299, 39.92129, 116.52302, 40.07757) | CRS: epsg:4326 | |
| Columns: id (int64) | ||
Data preview
| geometry | id | |
|---|---|---|
| t | ||
| 2008-02-02 15:02:18 | POINT (116.52299 40.07757) | 5 |
| 2008-02-02 18:32:28 | POINT (116.52302 39.92129) | 5 |
Convert TrajectoryCollection to a dict compatible with MF-JSON¶
In [6]:
df = pd.DataFrame(
{
"t": pd.date_range("2020-01-01", periods=5, freq="min"),
"trajectory_id": [1, 1, 2, 2, 2],
"geometry": [Point(0, 0), Point(0, 1), Point(1, 2), Point(1, 3), Point(2, 4)],
}
)
gdf = gpd.GeoDataFrame(df, crs=4326)
tc = mpd.TrajectoryCollection(gdf, traj_id_col="trajectory_id", t="t")
tc
Out[6]:
TrajectoryCollection with 2 trajectories
Trajectory 1 (No. rows: 2 | Length: 110.6 km)
| Start: 2020-01-01 00:00:00 | End: 2020-01-01 00:01:00 | Duration: 0:01:00 |
| Bounds: (0.0, 0.0, 0.0, 1.0) | CRS: EPSG:4326 | |
| Columns: trajectory_id (int64) | ||
Data preview
| trajectory_id | geometry | |
|---|---|---|
| t | ||
| 2020-01-01 00:00:00 | 1 | POINT (0 0) |
| 2020-01-01 00:01:00 | 1 | POINT (0 1) |
Trajectory 2 (No. rows: 3 | Length: 267.3 km)
| Start: 2020-01-01 00:02:00 | End: 2020-01-01 00:04:00 | Duration: 0:02:00 |
| Bounds: (1.0, 2.0, 2.0, 4.0) | CRS: EPSG:4326 | |
| Columns: trajectory_id (int64) | ||
Data preview
| trajectory_id | geometry | |
|---|---|---|
| t | ||
| 2020-01-01 00:02:00 | 2 | POINT (1 2) |
| 2020-01-01 00:03:00 | 2 | POINT (1 3) |
| 2020-01-01 00:04:00 | 2 | POINT (2 4) |
In [7]:
mf_json = tc.to_mf_json()
mf_json
Out[7]:
{'type': 'FeatureCollection',
'features': [{'type': 'Feature',
'properties': {'trajectory_id': 1},
'temporalGeometry': {'type': 'MovingPoint',
'coordinates': [(0.0, 0.0), (0.0, 1.0)],
'datetimes': ['2020-01-01 00:00:00', '2020-01-01 00:01:00']}},
{'type': 'Feature',
'properties': {'trajectory_id': 2},
'temporalGeometry': {'type': 'MovingPoint',
'coordinates': [(1.0, 2.0), (1.0, 3.0), (2.0, 4.0)],
'datetimes': ['2020-01-01 00:02:00',
'2020-01-01 00:03:00',
'2020-01-01 00:04:00']}}]}
MF-JSON Trajectory¶
In [8]:
traj = mpd.read_mf_json("../data/201901.en-trajectory.json", traj_id=3)
traj.df.head()
Out[8]:
| preasure | wind | class | geometry | traj_id | |
|---|---|---|---|---|---|
| t | |||||
| 2018-12-31 06:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.9 7.6) | 3 |
| 2018-12-31 12:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.3 7.3) | 3 |
| 2018-12-31 18:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.1 7) | 3 |
| 2019-01-01 00:00:00 | 1004.0 | 0.0 | 2.0 | POINT (110.7 6.6) | 3 |
| 2019-01-01 06:00:00 | 1000.0 | 35.0 | 3.0 | POINT (110.2 6.3) | 3 |
In [9]:
traj.explore(color="green")
Out[9]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Writing MF-JSON¶
Convert Trajectory to a dict compatible with MF-JSON¶
In [10]:
mf_json = traj.to_mf_json(temporal_columns=["preasure", "wind", "class"])
mf_json
Out[10]:
{'type': 'FeatureCollection',
'features': [{'type': 'Feature',
'properties': {'traj_id': 3},
'temporalGeometry': {'type': 'MovingPoint',
'coordinates': [(111.9, 7.6),
(111.3, 7.3),
(111.1, 7.0),
(110.7, 6.6),
(110.2, 6.3),
(109.9, 6.0),
(109.5, 5.8),
(108.6, 5.9),
(108.0, 6.2),
(107.0, 6.3),
(105.8, 6.0),
(105.0, 5.8),
(104.1, 6.1),
(103.4, 6.8),
(102.5, 7.5),
(101.5, 7.9),
(100.8, 8.1),
(100.1, 8.2),
(99.4, 8.4)],
'datetimes': ['2018-12-31 06:00:00',
'2018-12-31 12:00:00',
'2018-12-31 18:00:00',
'2019-01-01 00:00:00',
'2019-01-01 06:00:00',
'2019-01-01 12:00:00',
'2019-01-01 18:00:00',
'2019-01-02 00:00:00',
'2019-01-02 06:00:00',
'2019-01-02 12:00:00',
'2019-01-02 18:00:00',
'2019-01-03 00:00:00',
'2019-01-03 06:00:00',
'2019-01-03 12:00:00',
'2019-01-03 18:00:00',
'2019-01-04 00:00:00',
'2019-01-04 06:00:00',
'2019-01-04 12:00:00',
'2019-01-04 18:00:00']},
'temporalProperties': [{'datetimes': ['2018-12-31 06:00:00',
'2018-12-31 12:00:00',
'2018-12-31 18:00:00',
'2019-01-01 00:00:00',
'2019-01-01 06:00:00',
'2019-01-01 12:00:00',
'2019-01-01 18:00:00',
'2019-01-02 00:00:00',
'2019-01-02 06:00:00',
'2019-01-02 12:00:00',
'2019-01-02 18:00:00',
'2019-01-03 00:00:00',
'2019-01-03 06:00:00',
'2019-01-03 12:00:00',
'2019-01-03 18:00:00',
'2019-01-04 00:00:00',
'2019-01-04 06:00:00',
'2019-01-04 12:00:00',
'2019-01-04 18:00:00'],
'preasure': {'values': [1004.0,
1004.0,
1004.0,
1004.0,
1000.0,
1000.0,
1000.0,
1000.0,
1000.0,
1000.0,
1000.0,
1000.0,
1000.0,
998.0,
996.0,
996.0,
996.0,
1000.0,
1000.0]},
'wind': {'values': [0.0,
0.0,
0.0,
0.0,
35.0,
35.0,
35.0,
35.0,
35.0,
35.0,
35.0,
35.0,
35.0,
40.0,
45.0,
45.0,
45.0,
40.0,
40.0]},
'class': {'values': [2.0,
2.0,
2.0,
2.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0,
3.0]}}]}]}
Save MF-JSON dict to file¶
In [11]:
with open("../data/mf1.json", "w") as json_file:
json.dump(mf_json, json_file, indent=4)
Read MF-JSON file¶
In [12]:
traj = (
mpd.read_mf_json("../data/mf1.json", traj_id_property="traj_id").trajectories[0].df
)
traj.head()
Out[12]:
| preasure | wind | class | geometry | traj_id | |
|---|---|---|---|---|---|
| t | |||||
| 2018-12-31 06:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.9 7.6) | 3 |
| 2018-12-31 12:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.3 7.3) | 3 |
| 2018-12-31 18:00:00 | 1004.0 | 0.0 | 2.0 | POINT (111.1 7) | 3 |
| 2019-01-01 00:00:00 | 1004.0 | 0.0 | 2.0 | POINT (110.7 6.6) | 3 |
| 2019-01-01 06:00:00 | 1000.0 | 35.0 | 3.0 | POINT (110.2 6.3) | 3 |
In [13]:
traj.explore()
Out[13]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Convert GeoDataFrame to a dict compatible with MF-JSON¶
In [14]:
df = read_file("../data/geolife_small.csv")
gdf = GeoDataFrame(df, geometry=gpd.points_from_xy(df["X"], df["Y"]))
gdf.head()
Out[14]:
| X | Y | fid | id | sequence | trajectory_id | tracker | t | geometry | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 116.391305 | 39.898573 | 1 | 1 | 1 | 1 | 19 | 2008-12-11 04:42:14+00 | POINT (116.3913 39.89857) |
| 1 | 116.391317 | 39.898617 | 2 | 2 | 2 | 1 | 19 | 2008-12-11 04:42:16+00 | POINT (116.39132 39.89862) |
| 2 | 116.390928 | 39.898613 | 3 | 3 | 3 | 1 | 19 | 2008-12-11 04:43:26+00 | POINT (116.39093 39.89861) |
| 3 | 116.390833 | 39.898635 | 4 | 4 | 4 | 1 | 19 | 2008-12-11 04:43:32+00 | POINT (116.39083 39.89864) |
| 4 | 116.38941 | 39.898723 | 5 | 5 | 5 | 1 | 19 | 2008-12-11 04:43:47+00 | POINT (116.38941 39.89872) |
In [15]:
mf_json = gdf_to_mf_json(gdf, traj_id_column="trajectory_id", datetime_column="t")
Save MF-JSON dict to file¶
In [16]:
with open("../data/mf-geolife_small.json", "w") as json_file:
json.dump(mf_json, json_file, indent=4)
Read JSON file to dict¶
In [17]:
with open("../data/mf-geolife_small.json", "r") as file:
data = json.load(file)
In [18]:
s = list(data.items())[:2]
s = str(s)
s[:1000]
Out[18]:
"[('type', 'FeatureCollection'), ('features', [{'type': 'Feature', 'properties': {'trajectory_id': '1', 'X': '116.391305', 'Y': '39.898573', 'fid': '1', 'id': '1', 'sequence': '1', 'tracker': '19'}, 'temporalGeometry': {'type': 'MovingPoint', 'coordinates': [[116.391305, 39.898573], [116.391317, 39.898617], [116.390928, 39.898613], [116.390833, 39.898635], [116.38941, 39.898723], [116.390522, 39.897928], [116.390608, 39.897837], [116.390708, 39.8979], [116.390725, 39.89801], [116.390747, 39.898107], [116.390805, 39.898187], [116.39086, 39.898287], [116.390913, 39.898398], [116.390827, 39.898373], [116.390695, 39.898377], [116.390598, 39.898382], [116.390505, 39.898408], [116.39041, 39.898417], [116.390303, 39.898428], [116.390193, 39.898437], [116.390127, 39.898375], [116.39003, 39.89834], [116.389932, 39.898292], [116.389837, 39.898238], [116.389738, 39.898182], [116.389652, 39.898123], [116.389572, 39.898078], [116.389427, 39.898013], [116.389335, 39.89797], [116.389237, 39.897933], ["
Read MF-JSON from a dict¶
In [19]:
tc = read_mf_dict(data, traj_id_property="trajectory_id")
tc
Out[19]:
TrajectoryCollection with 5 trajectories
Trajectory 1 (No. rows: 466 | Length: 6.2 km)
| Start: 2008-12-11 04:42:14 | End: 2008-12-11 05:15:46 | Duration: 0:33:32 |
| Bounds: (116.385602, 39.862378, 116.393553, 39.898723) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2008-12-11 04:42:14 | POINT (116.3913 39.89857) | 1 |
| 2008-12-11 04:42:16 | POINT (116.39132 39.89862) | 1 |
| 2008-12-11 04:43:26 | POINT (116.39093 39.89861) | 1 |
| 2008-12-11 04:43:32 | POINT (116.39083 39.89864) | 1 |
| 2008-12-11 04:43:47 | POINT (116.38941 39.89872) | 1 |
Trajectory 2 (No. rows: 897 | Length: 38.8 km)
| Start: 2009-06-29 07:02:25 | End: 2009-06-29 11:13:12 | Duration: 4:10:47 |
| Bounds: (116.319212, 39.971703, 116.592616, 40.082514) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-06-29 07:02:25 | POINT (116.59096 40.07196) | 2 |
| 2009-06-29 07:02:30 | POINT (116.5909 40.07201) | 2 |
| 2009-06-29 07:02:35 | POINT (116.59088 40.07203) | 2 |
| 2009-06-29 07:02:40 | POINT (116.59092 40.072) | 2 |
| 2009-06-29 07:02:45 | POINT (116.59096 40.07198) | 2 |
Trajectory 3 (No. rows: 1810 | Length: 12.7 km)
| Start: 2009-02-04 04:32:53 | End: 2009-02-04 11:20:12 | Duration: 6:47:19 |
| Bounds: (116.332706, 39.897023, 116.387307, 39.927949) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-02-04 04:32:53 | POINT (116.38569 39.89977) | 3 |
| 2009-02-04 04:32:54 | POINT (116.38565 39.89965) | 3 |
| 2009-02-04 04:32:55 | POINT (116.38555 39.8997) | 3 |
| 2009-02-04 04:32:56 | POINT (116.38553 39.89963) | 3 |
| 2009-02-04 04:32:57 | POINT (116.38548 39.89959) | 3 |
Trajectory 4 (No. rows: 1864 | Length: 14.4 km)
| Start: 2009-03-10 10:36:45 | End: 2009-03-10 12:01:07 | Duration: 1:24:22 |
| Bounds: (116.327347, 39.896671, 116.389611, 39.927947) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-03-10 10:36:45 | POINT (116.38805 39.90342) | 4 |
| 2009-03-10 10:36:46 | POINT (116.38804 39.9035) | 4 |
| 2009-03-10 10:36:47 | POINT (116.38804 39.90347) | 4 |
| 2009-03-10 10:36:48 | POINT (116.38806 39.90354) | 4 |
| 2009-03-10 10:36:49 | POINT (116.38808 39.90359) | 4 |
Trajectory 5 (No. rows: 871 | Length: 39.3 km)
| Start: 2009-02-25 09:47:03 | End: 2009-02-25 14:31:24 | Duration: 4:44:21 |
| Bounds: (116.294527, 39.89825, 116.38552, 40.052399) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-02-25 09:47:03 | POINT (116.38526 39.90027) | 5 |
| 2009-02-25 09:47:05 | POINT (116.38525 39.90022) | 5 |
| 2009-02-25 09:47:06 | POINT (116.38537 39.90025) | 5 |
| 2009-02-25 09:47:07 | POINT (116.38537 39.90026) | 5 |
| 2009-02-25 09:47:08 | POINT (116.38534 39.90026) | 5 |
Read MF-JSON file¶
In [20]:
tc = mpd.read_mf_json("../data/mf-geolife_small.json", traj_id_property="trajectory_id")
tc
Out[20]:
TrajectoryCollection with 5 trajectories
Trajectory 1 (No. rows: 466 | Length: 6.2 km)
| Start: 2008-12-11 04:42:14 | End: 2008-12-11 05:15:46 | Duration: 0:33:32 |
| Bounds: (116.385602, 39.862378, 116.393553, 39.898723) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2008-12-11 04:42:14 | POINT (116.3913 39.89857) | 1 |
| 2008-12-11 04:42:16 | POINT (116.39132 39.89862) | 1 |
| 2008-12-11 04:43:26 | POINT (116.39093 39.89861) | 1 |
| 2008-12-11 04:43:32 | POINT (116.39083 39.89864) | 1 |
| 2008-12-11 04:43:47 | POINT (116.38941 39.89872) | 1 |
Trajectory 2 (No. rows: 897 | Length: 38.8 km)
| Start: 2009-06-29 07:02:25 | End: 2009-06-29 11:13:12 | Duration: 4:10:47 |
| Bounds: (116.319212, 39.971703, 116.592616, 40.082514) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-06-29 07:02:25 | POINT (116.59096 40.07196) | 2 |
| 2009-06-29 07:02:30 | POINT (116.5909 40.07201) | 2 |
| 2009-06-29 07:02:35 | POINT (116.59088 40.07203) | 2 |
| 2009-06-29 07:02:40 | POINT (116.59092 40.072) | 2 |
| 2009-06-29 07:02:45 | POINT (116.59096 40.07198) | 2 |
Trajectory 3 (No. rows: 1810 | Length: 12.7 km)
| Start: 2009-02-04 04:32:53 | End: 2009-02-04 11:20:12 | Duration: 6:47:19 |
| Bounds: (116.332706, 39.897023, 116.387307, 39.927949) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-02-04 04:32:53 | POINT (116.38569 39.89977) | 3 |
| 2009-02-04 04:32:54 | POINT (116.38565 39.89965) | 3 |
| 2009-02-04 04:32:55 | POINT (116.38555 39.8997) | 3 |
| 2009-02-04 04:32:56 | POINT (116.38553 39.89963) | 3 |
| 2009-02-04 04:32:57 | POINT (116.38548 39.89959) | 3 |
Trajectory 4 (No. rows: 1864 | Length: 14.4 km)
| Start: 2009-03-10 10:36:45 | End: 2009-03-10 12:01:07 | Duration: 1:24:22 |
| Bounds: (116.327347, 39.896671, 116.389611, 39.927947) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-03-10 10:36:45 | POINT (116.38805 39.90342) | 4 |
| 2009-03-10 10:36:46 | POINT (116.38804 39.9035) | 4 |
| 2009-03-10 10:36:47 | POINT (116.38804 39.90347) | 4 |
| 2009-03-10 10:36:48 | POINT (116.38806 39.90354) | 4 |
| 2009-03-10 10:36:49 | POINT (116.38808 39.90359) | 4 |
Trajectory 5 (No. rows: 871 | Length: 39.3 km)
| Start: 2009-02-25 09:47:03 | End: 2009-02-25 14:31:24 | Duration: 4:44:21 |
| Bounds: (116.294527, 39.89825, 116.38552, 40.052399) | CRS: epsg:4326 | |
| Columns: trajectory_id (object) | ||
Data preview
| geometry | trajectory_id | |
|---|---|---|
| t | ||
| 2009-02-25 09:47:03 | POINT (116.38526 39.90027) | 5 |
| 2009-02-25 09:47:05 | POINT (116.38525 39.90022) | 5 |
| 2009-02-25 09:47:06 | POINT (116.38537 39.90025) | 5 |
| 2009-02-25 09:47:07 | POINT (116.38537 39.90026) | 5 |
| 2009-02-25 09:47:08 | POINT (116.38534 39.90026) | 5 |
In [21]:
tc.explore(column="trajectory_id", cmap="viridis", style_kwds={"weight": 4})
Out[21]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [ ]: