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.20.0 SYSTEM INFO ----------- python : 3.10.15 | packaged by conda-forge | (main, Oct 16 2024, 01:15:49) [MSC v.1941 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 : None GDAL data dir: None PROJ : 9.5.0 PROJ data dir: C:\Users\Agarkovam\AppData\Local\miniforge3\envs\mpd-ex\Library\share\proj PYTHON DEPENDENCIES ------------------- geopandas : 1.0.1 pandas : 2.2.3 fiona : None numpy : 1.23.1 shapely : 2.0.6 pyproj : 3.7.0 matplotlib : 3.9.2 mapclassify: 2.8.1 geopy : 2.4.1 holoviews : 1.20.0 hvplot : 0.11.1 geoviews : 1.13.0 stonesoup : 1.4
MF-JSON MovingPoint¶
In [2]:
traj = mpd.read_mf_json("../data/mf-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/mf-trajectory.json", traj_id=3)
traj.df.head()
Out[8]:
preasure | wind | class | geometry | traj_id | |
---|---|---|---|---|---|
t | |||||
2019-08-05 00:00:00 | 1004.0 | 0.0 | 2.0 | POINT (147.7 15.6) | 3 |
2019-08-05 06:00:00 | 1000.0 | 0.0 | 2.0 | POINT (146.5 16.1) | 3 |
2019-08-05 12:00:00 | 1000.0 | 0.0 | 2.0 | POINT (145.2 16.8) | 3 |
2019-08-05 18:00:00 | 1000.0 | 0.0 | 2.0 | POINT (144 17.5) | 3 |
2019-08-06 00:00:00 | 1000.0 | 0.0 | 2.0 | POINT (143.4 18) | 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': [(147.7, 15.6), (146.5, 16.1), (145.2, 16.8), (144.0, 17.5), (143.4, 18.0), (142.8, 18.5), (142.4, 18.9), (142.1, 19.7), (141.9, 20.5), (141.4, 21.1), (141.0, 21.5), (140.8, 21.7), (140.5, 21.9), (140.6, 22.1), (140.7, 22.1), (141.0, 22.0), (141.1, 22.0), (141.3, 22.0), (141.4, 22.2), (141.4, 22.3), (141.3, 22.7), (141.0, 22.9), (140.7, 22.8), (140.5, 22.7), (140.3, 23.1), (139.8, 23.6), (139.2, 24.0), (138.5, 24.2), (138.0, 24.7), (137.7, 25.0), (137.1, 25.9), (136.4, 26.8), (135.2, 27.4), (134.7, 27.6), (134.3, 28.1), (133.5, 28.3), (133.4, 28.4), (133.2, 28.8), (133.1, 29.1), (133.1, 29.6), (133.0, 30.1), (132.9, 30.6), (132.7, 30.8), (132.6, 31.7), (132.6, 32.2), (132.4, 32.7), (132.3, 33.4), (132.3, 33.6), (132.6, 34.3), (133.0, 35.3), (133.1, 36.2), (133.5, 38.0), (134.3, 39.9), (135.6, 40.9), (138.0, 43.0), (138.5, 43.7), (140.1, 44.4), (140.5, 44.7), (141.0, 45.1)], 'datetimes': ['2019-08-05 00:00:00', '2019-08-05 06:00:00', '2019-08-05 12:00:00', '2019-08-05 18:00:00', '2019-08-06 00:00:00', '2019-08-06 06:00:00', '2019-08-06 12:00:00', '2019-08-06 18:00:00', '2019-08-07 00:00:00', '2019-08-07 06:00:00', '2019-08-07 12:00:00', '2019-08-07 18:00:00', '2019-08-08 00:00:00', '2019-08-08 06:00:00', '2019-08-08 12:00:00', '2019-08-08 18:00:00', '2019-08-09 00:00:00', '2019-08-09 06:00:00', '2019-08-09 12:00:00', '2019-08-09 18:00:00', '2019-08-10 00:00:00', '2019-08-10 06:00:00', '2019-08-10 12:00:00', '2019-08-10 18:00:00', '2019-08-11 00:00:00', '2019-08-11 06:00:00', '2019-08-11 12:00:00', '2019-08-11 18:00:00', '2019-08-12 00:00:00', '2019-08-12 06:00:00', '2019-08-12 12:00:00', '2019-08-12 18:00:00', '2019-08-13 00:00:00', '2019-08-13 06:00:00', '2019-08-13 12:00:00', '2019-08-13 18:00:00', '2019-08-13 21:00:00', '2019-08-14 00:00:00', '2019-08-14 03:00:00', '2019-08-14 06:00:00', '2019-08-14 09:00:00', '2019-08-14 12:00:00', '2019-08-14 15:00:00', '2019-08-14 18:00:00', '2019-08-14 21:00:00', '2019-08-15 00:00:00', '2019-08-15 02:00:00', '2019-08-15 03:00:00', '2019-08-15 06:00:00', '2019-08-15 09:00:00', '2019-08-15 12:00:00', '2019-08-15 18:00:00', '2019-08-16 00:00:00', '2019-08-16 06:00:00', '2019-08-16 12:00:00', '2019-08-16 18:00:00', '2019-08-17 00:00:00', '2019-08-17 06:00:00', '2019-08-17 12:00:00']}, 'temporalProperties': [{'datetimes': ['2019-08-05 00:00:00', '2019-08-05 06:00:00', '2019-08-05 12:00:00', '2019-08-05 18:00:00', '2019-08-06 00:00:00', '2019-08-06 06:00:00', '2019-08-06 12:00:00', '2019-08-06 18:00:00', '2019-08-07 00:00:00', '2019-08-07 06:00:00', '2019-08-07 12:00:00', '2019-08-07 18:00:00', '2019-08-08 00:00:00', '2019-08-08 06:00:00', '2019-08-08 12:00:00', '2019-08-08 18:00:00', '2019-08-09 00:00:00', '2019-08-09 06:00:00', '2019-08-09 12:00:00', '2019-08-09 18:00:00', '2019-08-10 00:00:00', '2019-08-10 06:00:00', '2019-08-10 12:00:00', '2019-08-10 18:00:00', '2019-08-11 00:00:00', '2019-08-11 06:00:00', '2019-08-11 12:00:00', '2019-08-11 18:00:00', '2019-08-12 00:00:00', '2019-08-12 06:00:00', '2019-08-12 12:00:00', '2019-08-12 18:00:00', '2019-08-13 00:00:00', '2019-08-13 06:00:00', '2019-08-13 12:00:00', '2019-08-13 18:00:00', '2019-08-13 21:00:00', '2019-08-14 00:00:00', '2019-08-14 03:00:00', '2019-08-14 06:00:00', '2019-08-14 09:00:00', '2019-08-14 12:00:00', '2019-08-14 15:00:00', '2019-08-14 18:00:00', '2019-08-14 21:00:00', '2019-08-15 00:00:00', '2019-08-15 02:00:00', '2019-08-15 03:00:00', '2019-08-15 06:00:00', '2019-08-15 09:00:00', '2019-08-15 12:00:00', '2019-08-15 18:00:00', '2019-08-16 00:00:00', '2019-08-16 06:00:00', '2019-08-16 12:00:00', '2019-08-16 18:00:00', '2019-08-17 00:00:00', '2019-08-17 06:00:00', '2019-08-17 12:00:00'], 'preasure': {'values': [1004.0, 1000.0, 1000.0, 1000.0, 1000.0, 998.0, 996.0, 992.0, 990.0, 990.0, 980.0, 975.0, 970.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 970.0, 970.0, 970.0, 970.0, 970.0, 970.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 965.0, 970.0, 975.0, 975.0, 975.0, 975.0, 978.0, 978.0, 980.0, 980.0, 980.0, 980.0, 984.0, 986.0, 990.0, 994.0, 994.0]}, 'wind': {'values': [0.0, 0.0, 0.0, 0.0, 0.0, 35.0, 40.0, 45.0, 50.0, 50.0, 60.0, 65.0, 70.0, 75.0, 75.0, 75.0, 75.0, 75.0, 75.0, 70.0, 70.0, 65.0, 65.0, 65.0, 65.0, 65.0, 60.0, 60.0, 60.0, 50.0, 50.0, 50.0, 50.0, 50.0, 50.0, 55.0, 55.0, 55.0, 55.0, 55.0, 55.0, 55.0, 55.0, 55.0, 55.0, 50.0, 50.0, 50.0, 45.0, 45.0, 45.0, 45.0, 45.0, 45.0, 0.0, 0.0, 0.0, 0.0, 0.0]}, 'class': {'values': [2.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 6.0, 6.0, 6.0, 6.0, 6.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 | |||||
2019-08-05 00:00:00 | 1004.0 | 0.0 | 2.0 | POINT (147.7 15.6) | 3 |
2019-08-05 06:00:00 | 1000.0 | 0.0 | 2.0 | POINT (146.5 16.1) | 3 |
2019-08-05 12:00:00 | 1000.0 | 0.0 | 2.0 | POINT (145.2 16.8) | 3 |
2019-08-05 18:00:00 | 1000.0 | 0.0 | 2.0 | POINT (144 17.5) | 3 |
2019-08-06 00:00:00 | 1000.0 | 0.0 | 2.0 | POINT (143.4 18) | 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