Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion movingpandas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
TopDownTimeRatioGeneralizer,
)
from .trajectory_collection import TrajectoryCollection # noqa F401
from .io import read_mf_json # noqa F401
from .io import read_mf_json, read_mf_dict, gdf_to_mf_json # noqa F401
from .trajectory_aggregator import TrajectoryCollectionAggregator # noqa F401
from .trajectory_splitter import ( # noqa F401
TrajectorySplitter,
Expand Down
6 changes: 4 additions & 2 deletions movingpandas/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from geopandas import GeoDataFrame
from pandas import DataFrame

from movingpandas import Trajectory, TrajectoryCollection


def gdf_to_mf_json(
gdf: GeoDataFrame,
Expand Down Expand Up @@ -245,6 +243,8 @@ def _get_temporal_properties(data):


def _create_traj_from_movingfeature_json(data, traj_id_property, traj_id):
from movingpandas import Trajectory

df = _create_geometry(data)
if traj_id_property:
traj_id = _get_id_property_value(data, traj_id_property)
Expand All @@ -257,6 +257,8 @@ def _create_traj_from_movingfeature_json(data, traj_id_property, traj_id):


def _create_trajcollection_from_movingfeaturecollection_json(data, traj_id_property):
from movingpandas import TrajectoryCollection

assert (
traj_id_property is not None
), "traj_id_property must be supplied when reading a collection of trajectories"
Expand Down
7 changes: 7 additions & 0 deletions movingpandas/tests/test_trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,13 @@ def test_to_traj_gdf(self):

assert_frame_equal(traj_gdf_wkt, expected_line_gdf_wkt)

def test_to_mf_json(self):
json = self.default_traj_metric.to_mf_json()
assert (
str(json)
== """{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {'traj_id': 1, 'value': 1}, 'temporalGeometry': {'type': 'MovingPoint', 'coordinates': [(0.0, 0.0), (6.0, 0.0), (10.0, 0.0)], 'datetimes': [Timestamp('1970-01-01 00:00:00'), Timestamp('1970-01-01 00:00:10'), Timestamp('1970-01-01 00:00:20')]}}]}""" # noqa F401
)

def test_error_due_to_wrong_gdf_index(self):
with pytest.raises(TypeError):
df = pd.DataFrame(
Expand Down
7 changes: 7 additions & 0 deletions movingpandas/tests/test_trajectory_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,10 @@ def test_to_traj_gdf_aggregate(self):
expected_line_gdf = GeoDataFrame(df2, crs=CRS_METRIC)

assert_frame_equal(traj_gdf, expected_line_gdf)

def test_to_mf_json(self):
json = self.collection.to_mf_json()
assert (
str(json)
== """{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {'id': 1, 'obj': 'A', 'val': 9, 'val2': 'a'}, 'temporalGeometry': {'type': 'MovingPoint', 'coordinates': [(0.0, 0.0), (6.0, 0.0), (6.0, 6.0), (9.0, 9.0)], 'datetimes': [Timestamp('2018-01-01 12:00:00'), Timestamp('2018-01-01 12:06:00'), Timestamp('2018-01-01 14:10:00'), Timestamp('2018-01-01 14:15:00')]}}, {'type': 'Feature', 'properties': {'id': 2, 'obj': 'A', 'val': 10, 'val2': 'e'}, 'temporalGeometry': {'type': 'MovingPoint', 'coordinates': [(10.0, 10.0), (16.0, 10.0), (16.0, 16.0), (190.0, 10.0)], 'datetimes': [Timestamp('2018-01-01 12:00:00'), Timestamp('2018-01-01 12:06:00'), Timestamp('2018-01-02 13:10:00'), Timestamp('2018-01-02 13:15:00')]}}]}""" # noqa F401
)
19 changes: 19 additions & 0 deletions movingpandas/trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
)
from .spatiotemporal_utils import get_speed2
from .trajectory_plotter import _TrajectoryPlotter
from .io import gdf_to_mf_json

warnings.filterwarnings( # see https://github.com/movingpandas/movingpandas/issues/289
"ignore", message="CRS not set for some of the concatenation inputs."
Expand Down Expand Up @@ -642,6 +643,24 @@ def to_traj_gdf(self, wkt=False, agg=False):
traj_gdf = GeoDataFrame(df, crs=self.crs)
return traj_gdf

def to_mf_json(self):
"""
Converts a Trajectory to a dictionary compatible with the Moving
Features JSON (MF-JSON) specification.

Examples
--------

>>> traj.to_mf_json()

Returns:
dict: The MF-JSON representation of the GeoDataFrame as a dictionary.
"""
tmp = self.to_point_gdf()
t = tmp.index.name
mf_json = gdf_to_mf_json(tmp.reset_index(), self.get_traj_id_col(), t)
return mf_json

def get_start_location(self):
"""
Return the trajectory's start location.
Expand Down
19 changes: 19 additions & 0 deletions movingpandas/trajectory_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
)
from .trajectory_plotter import _TrajectoryPlotter
from .unit_utils import UNITS
from .io import gdf_to_mf_json


@staticmethod
Expand Down Expand Up @@ -179,6 +180,24 @@ def to_traj_gdf(self, wkt=False, agg=False):
gdf.reset_index(drop=True, inplace=True)
return gdf

def to_mf_json(self):
"""
Converts a TrajectoryCollection to a dictionary compatible with the Moving
Features JSON (MF-JSON) specification.

Examples
--------

>>> tc.to_mf_json()

Returns:
dict: The MF-JSON representation of the GeoDataFrame as a dictionary.
"""
tmp = self.to_point_gdf()
t = tmp.index.name
mf_json = gdf_to_mf_json(tmp.reset_index(), self.get_traj_id_col(), t)
return mf_json

def _df_to_trajectories(self, df, traj_id_col, obj_id_col, t, x, y, crs):
trajectories = []
for traj_id, values in df.groupby(traj_id_col):
Expand Down
39 changes: 33 additions & 6 deletions tutorials/2-reading-data-from-files.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
"id": "eeeadeb1-0f5c-4037-98e0-4f61fda45573",
"metadata": {},
"source": [
"## Reading MovingFeatures JSONs"
"## Reading MovingFeatures JSONs (MF-JSON)"
]
},
{
Expand Down Expand Up @@ -269,9 +269,7 @@
"id": "peaceful-nomination",
"metadata": {},
"source": [
"## Writing\n",
"\n",
"### as points"
"## Writing as points"
]
},
{
Expand Down Expand Up @@ -302,7 +300,7 @@
"id": "animated-worcester",
"metadata": {},
"source": [
"### as lines"
"## Writing as lines"
]
},
{
Expand Down Expand Up @@ -333,7 +331,7 @@
"id": "french-director",
"metadata": {},
"source": [
"### as trajectories"
"## Writing as trajectories"
]
},
{
Expand All @@ -358,6 +356,35 @@
"read_file('temp.gpkg', layer='trajectories').plot()"
]
},
{
"cell_type": "markdown",
"id": "990919e0",
"metadata": {},
"source": [
"## Writing as MF-JSON"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14852dcd",
"metadata": {},
"outputs": [],
"source": [
"mf_json = traj_collection.to_mf_json()\n",
"mf_json"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fd1d069f",
"metadata": {},
"outputs": [],
"source": [
"mpd.read_mf_dict(mf_json, traj_id_property ='trajectory_id').plot()"
]
},
{
"attachments": {},
"cell_type": "markdown",
Expand Down