Python library for trajectory and movement data analysis built on pandas and GeoPandas.
—
Functions for importing and exporting trajectory data in various formats, with special support for OGC Moving Features JSON, plus utility functions for system information and unit handling.
Functions for working with OGC Moving Features JSON format, a standard for representing movement data.
def read_mf_json(json_file_path, traj_id_property=None, traj_id=0):
"""
Read OGC Moving Features JSON files into Trajectory/TrajectoryCollection objects.
Parameters:
- json_file_path: Path to Moving Features JSON file
- traj_id_property: Property name to use as trajectory ID (optional)
- traj_id: Default trajectory ID if traj_id_property not specified
Returns:
Trajectory or TrajectoryCollection object depending on input data
Raises:
ValueError: If JSON format is invalid or unsupported
"""
def read_mf_dict(data, traj_id=0, traj_id_property=None):
"""
Read Moving Features JSON from dictionary format.
Parameters:
- data: Dictionary containing Moving Features JSON data
- traj_id: Default trajectory ID
- traj_id_property: Property name to use as trajectory ID (optional)
Returns:
Trajectory or TrajectoryCollection object
Raises:
ValueError: If dictionary format is invalid
"""def gdf_to_mf_json(gdf, traj_id_column, datetime_column, temporal_columns=None, temporal_columns_static_fields=None, interpolation=None, crs=None, trs=None, datetime_encoder=None, datetime_to_str=False):
"""
Convert GeoDataFrame to Moving Features JSON format.
Parameters:
- gdf: GeoDataFrame with trajectory data
- traj_id_column: Column name containing trajectory IDs
- datetime_column: Column name containing datetime values
- temporal_columns: List of column names with temporal data (optional)
- temporal_columns_static_fields: Dict mapping temporal columns to static field definitions (optional)
- interpolation: Interpolation method for temporal properties ("Linear", "Discrete", etc.)
- crs: Coordinate reference system specification (optional)
- trs: Temporal reference system specification (optional)
- datetime_encoder: Function to encode datetime objects (optional)
- datetime_to_str: Whether to convert datetime to string format (default: False)
Returns:
Dictionary in Moving Features JSON format
Raises:
ValueError: If required columns are missing or data format is invalid
"""Utility functions for system diagnostics and version reporting.
def show_versions():
"""
Print system information and installed module versions.
Displays:
- Python version and implementation
- Platform information
- MovingPandas version
- Versions of key dependencies (pandas, GeoPandas, Shapely, etc.)
- Optional dependencies and their availability
Returns:
None (prints to stdout)
"""Constants and utilities for working with different unit systems.
from collections import namedtuple
UNITS = namedtuple("UNITS", "distance time time2 crs", defaults=(None, None, None, None))MovingPandas supports a wide range of distance units through its integration with GeoPandas and pyproj:
Standard time units supported:
import movingpandas as mpd
# Read from file
trajectory = mpd.read_mf_json('trajectory_data.json')
# Read with specific trajectory ID property
collection = mpd.read_mf_json(
'multi_trajectory.json',
traj_id_property='vehicle_id'
)
# Read from dictionary
mf_data = {
"type": "Feature",
"geometry": {
"type": "MovingPoint",
"coordinates": [[[0, 0], [1, 1], [2, 2]]],
"datetimes": ["2023-01-01T12:00:00Z", "2023-01-01T12:05:00Z", "2023-01-01T12:10:00Z"]
},
"properties": {"vehicle_id": "A"}
}
traj = mpd.read_mf_dict(mf_data, traj_id_property='vehicle_id')import geopandas as gpd
import pandas as pd
from shapely.geometry import Point
from datetime import datetime, timedelta
# Create sample trajectory data
data = []
base_time = datetime(2023, 1, 1, 12, 0, 0)
for i in range(5):
data.append({
'geometry': Point(i * 0.1, i * 0.1),
'timestamp': base_time + timedelta(minutes=i * 5),
'vehicle_id': 'A',
'speed': 10 + i * 2,
'temperature': 20 + i * 0.5
})
gdf = gpd.GeoDataFrame(data, crs='EPSG:4326')
# Convert to Moving Features JSON
mf_json = mpd.gdf_to_mf_json(
gdf=gdf,
traj_id_column='vehicle_id',
datetime_column='timestamp',
temporal_columns=['speed', 'temperature'],
interpolation='Linear',
datetime_to_str=True
)
# Save to file
import json
with open('output.json', 'w') as f:
json.dump(mf_json, f, indent=2)# More complex example with temporal properties
temporal_static_fields = {
'speed': {
'uom': 'm/s',
'description': 'Vehicle speed in meters per second'
},
'temperature': {
'uom': 'celsius',
'description': 'Ambient temperature'
}
}
mf_json = mpd.gdf_to_mf_json(
gdf=trajectory_gdf,
traj_id_column='trajectory_id',
datetime_column='time',
temporal_columns=['speed', 'temperature', 'elevation'],
temporal_columns_static_fields=temporal_static_fields,
interpolation='Linear',
crs='EPSG:4326',
trs='http://www.opengis.net/def/uom/ISO-8601/0/Gregorian'
)# Display system and dependency information
mpd.show_versions()
# Output includes:
# Python: 3.9.7 | packaged by conda-forge
# Platform: Linux-5.4.0-90-generic-x86_64
# MovingPandas: 0.22.4
# pandas: 1.5.2
# geopandas: 0.12.2
# shapely: 2.0.0
# ... (additional dependencies)from movingpandas import UNITS
# Create trajectory and specify units for length calculation
traj = mpd.Trajectory(gdf, traj_id='test')
# Get length in different units
length_meters = traj.get_length() # Default units
length_km = traj.get_length(units=UNITS(distance='km'))
length_miles = traj.get_length(units=UNITS(distance='mi'))
print(f"Length: {length_meters:.2f} m, {length_km:.2f} km, {length_miles:.2f} mi")
# Add speed with specific units
traj_with_speed = traj.add_speed(units=UNITS(distance='km', time='h')) # km/h
traj_with_speed_ms = traj.add_speed(units=UNITS(distance='m', time='s')) # m/sdef convert_trajectory_formats(input_path, output_format='mf_json'):
"""Example function to convert between trajectory formats."""
# Detect input format and read accordingly
if input_path.endswith('.json'):
# Assume Moving Features JSON
traj = mpd.read_mf_json(input_path)
elif input_path.endswith(('.gpx', '.geojson', '.shp')):
# Read as GeoDataFrame first
gdf = gpd.read_file(input_path)
# Convert to trajectory (assumes appropriate columns exist)
traj = mpd.Trajectory(gdf, traj_id='imported')
else:
raise ValueError(f"Unsupported input format: {input_path}")
# Convert to requested output format
if output_format == 'mf_json':
# Convert to Moving Features JSON
result = traj.to_mf_json()
return result
elif output_format == 'geojson':
# Convert to point GeoJSON
return traj.to_point_gdf().to_json()
elif output_format == 'linestring':
# Convert to LineString GeoJSON
return traj.to_line_gdf().to_json()
else:
raise ValueError(f"Unsupported output format: {output_format}")The OGC Moving Features JSON format supported by MovingPandas follows this structure:
{
"type": "Feature",
"geometry": {
"type": "MovingPoint",
"coordinates": [
[longitude1, latitude1],
[longitude2, latitude2],
[longitude3, latitude3]
],
"datetimes": [
"2023-01-01T12:00:00Z",
"2023-01-01T12:05:00Z",
"2023-01-01T12:10:00Z"
]
},
"properties": {
"trajectory_id": "A",
"temporalProperties": [
{
"name": "speed",
"values": [10.5, 12.3, 8.7],
"interpolation": "Linear"
}
]
}
}Temporal properties allow associating time-varying attributes with geometries:
Common exceptions when working with IO operations:
try:
traj = mpd.read_mf_json('invalid_file.json')
except FileNotFoundError:
print("File not found")
except ValueError as e:
print(f"Invalid Moving Features JSON format: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
try:
mf_json = mpd.gdf_to_mf_json(gdf, 'missing_column', 'timestamp')
except KeyError as e:
print(f"Required column missing: {e}")
except ValueError as e:
print(f"Data format error: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-movingpandas