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.22.4 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-107-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
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
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
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
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 [ ]: