Note

Interactive online version: Binder badge

Visualization of trajectories#

If we work with trajectory data, we often want to visualize them from a so called birds eye view. The following example demonstrates how to achieve this with TASI using the DLR Urban Traffic Dataset.

Load trajectories#

At first, let’s load trajectories from the DLR dataset.

[1]:
from tasi.dlr import DLRTrajectoryDataset, DLRUTDatasetManager, DLRUTVersion

dataset = DLRUTDatasetManager(DLRUTVersion.latest)
dataset.load()
ut = DLRTrajectoryDataset.from_csv(dataset.trajectory()[0])
ut
Downloading DLR-Urban-Traffic-dataset_v1-3-0: 100%|██████████| 420M/420M [05:50<00:00, 1.20MB/s]
Extracting: 100%|██████████| 592/592 [00:19<00:00, 30.10file/s]
[1]:
acceleration position classifications dimension interpolated velocity yaw
easting magnitude northing easting northing bicycle car motorbike pedestrian truck van height length width easting magnitude northing
timestamp id
2023-09-24 00:00:00.016482+00:00 1695513598769889 0.047 0.093 0.080 604825.208 5.793e+06 0.0 0.645 0.205 0.0 0.054 0.096 1.562 4.294 1.811 False -12.789 13.496 -4.311 -161.405
2023-09-24 00:00:00.066482+00:00 1695513598769889 0.052 0.097 0.081 604824.540 5.793e+06 0.0 0.645 0.205 0.0 0.054 0.096 1.562 4.294 1.811 False -12.788 13.494 -4.308 -161.411
2023-09-24 00:00:00.116482+00:00 1695513598769889 0.058 0.101 0.083 604823.871 5.793e+06 0.0 0.645 0.205 0.0 0.054 0.096 1.562 4.294 1.811 False -12.787 13.493 -4.305 -161.418
2023-09-24 00:00:00.166482+00:00 1695513598769889 0.063 0.105 0.084 604823.202 5.793e+06 0.0 0.645 0.205 0.0 0.054 0.096 1.562 4.294 1.811 False -12.786 13.490 -4.302 -161.426
2023-09-24 00:00:00.216482+00:00 1695513598769889 0.069 0.109 0.085 604822.533 5.793e+06 0.0 0.645 0.205 0.0 0.054 0.096 1.562 4.294 1.811 False -12.785 13.488 -4.298 -161.435
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2023-09-24 00:14:59.766482+00:00 1695514432518548 -0.006 0.013 -0.012 604743.005 5.793e+06 0.0 0.135 0.865 0.0 0.000 0.000 1.656 1.058 0.675 False -0.021 0.022 -0.006 8.619
2023-09-24 00:14:59.816482+00:00 1695514432518548 -0.005 0.012 -0.011 604743.003 5.793e+06 0.0 0.135 0.865 0.0 0.000 0.000 1.656 1.058 0.675 False -0.022 0.023 -0.008 8.619
2023-09-24 00:14:59.866482+00:00 1695514432518548 -0.004 0.011 -0.010 604743.001 5.793e+06 0.0 0.135 0.865 0.0 0.000 0.000 1.656 1.058 0.675 False -0.022 0.025 -0.011 8.619
2023-09-24 00:14:59.916482+00:00 1695514432518548 -0.004 0.009 -0.009 604742.999 5.793e+06 0.0 0.135 0.865 0.0 0.000 0.000 1.656 1.058 0.675 False -0.023 0.027 -0.013 8.619
2023-09-24 00:14:59.966482+00:00 1695514432518548 -0.003 0.008 -0.007 604742.996 5.793e+06 0.0 0.135 0.865 0.0 0.000 0.000 1.656 1.058 0.675 False -0.024 0.028 -0.015 8.619

33614 rows × 19 columns

Plot trajectories#

We now utilize the TrajectoryPlotter to visualize the trajectories of the traffic participants that we’ve loaded.

[2]:
import matplotlib.pyplot as plt

from tasi.plotting import TrajectoryPlotter

f, ax = plt.subplots()

plotter = TrajectoryPlotter()
plotter.plot(ut, ax=ax)
../../_images/user_guide_data_visualization_trajectory_3_0.png

Change trajectory color#

Note that the trajectories are colorized with the default color which we can change so any arbitrary color, such as lightgray.

[3]:
f, ax = plt.subplots()
plotter.plot(ut, ax=ax, color="lightgray")
../../_images/user_guide_data_visualization_trajectory_5_0.png

Change color of a specific trajectory#

You can also define the color of a specific trajectory.

[4]:
f, ax = plt.subplots()
plotter.plot(
    ut, ax=ax, color="black", trajectory_kwargs={ut.ids[-20]: {"color": "red"}}
)
../../_images/user_guide_data_visualization_trajectory_7_0.png

Change trajectory opacity#

or even change the opacity of each trajectory to quickly get an overview of the traffic density. Let’s change the opacity to 20% via the alpha argument.

[5]:
f, ax = plt.subplots()
plotter.plot(ut, ax=ax, alpha=0.2)
../../_images/user_guide_data_visualization_trajectory_9_0.png

The plot already indicates the various traffic volumes on the different routes at the intersection.

Plot DLR UT trajectories on orthophoto#

We can also combine the TrajectoryPlotter with the BoundingboxPlotter to visualize trajectories on an orthophoto.

[6]:
from tasi.plotting.wms import BoundingboxPlotter, LowerSaxonyOrthophotoTile

f, ax = plt.subplots()

# plot the orthophoto first
bbox_plotter = BoundingboxPlotter(ut.roi, LowerSaxonyOrthophotoTile())
bbox_plotter.plot(ax)

# and the trajectories on top
tj_plotter = TrajectoryPlotter()
tj_plotter.plot(ut, ax=ax)

# hide the axis
_ = ax.axis("off")
../../_images/user_guide_data_visualization_trajectory_12_0.png

Note that it may become hard to see the trajectories on the background. To increase the contrast, we can adapt the opacity of the ortophoto via the alpha argument. Let’s set is to 0.5 (50%) to highlight the trajectories.

[7]:
f, ax = plt.subplots()

bbox_plotter.plot(ax, alpha=0.5)
tj_plotter.plot(ut, ax=ax, alpha=0.25)

_ = ax.axis("off")
../../_images/user_guide_data_visualization_trajectory_14_0.png

Plot DLR HT trajectories on orthophoto#

We can also use the TrajectoryPlotter with the BoundingboxPlotter to visualize trajectories of the DLR HT dataset on an orthophoto. Let’s load and plot the trajectories from the DLR HT dataset. This time, let’s use the DLRTrajectoryPlotter to color the trajectories in default DLR-colors.

[8]:
from tasi.dlr.dataset import DLRHTDatasetManager, DLRHTVersion
from tasi.dlr.plotting import DLRTrajectoryPlotter

# load dataset
dataset = DLRHTDatasetManager(DLRHTVersion.v1_1_0)
dataset.load()
ht = DLRTrajectoryDataset.from_csv(dataset.trajectory()[0])

f, ax = plt.subplots()

# plot the orthophoto first
bbox_plotter = BoundingboxPlotter(ht.roi, LowerSaxonyOrthophotoTile())
bbox_plotter.plot(ax)

# and the trajectories on top
tj_plotter = DLRTrajectoryPlotter()
tj_plotter.plot(ht, ax=ax)

# hide the axis
_ = ax.axis("off")
../../_images/user_guide_data_visualization_trajectory_16_0.png

Visualizing geospatial trajectories#

The TASI model for representing trajectory data using geospatial objects opens the world to utilize tools that support geopandas. For instance, if you want an interactive view on trajectory data, we can utilize folium via geopandas. For this purpose, we need two conversion steps.

At first, we need to convert the dataset to a native TASI representation.

[9]:
ds = ut.to_tasi()
ds.head()
[9]:
position velocity acceleration heading yaw_rate ... boundingbox
easting northing easting magnitude northing easting magnitude northing ... front front_right right rear_right rear
... easting northing easting northing easting northing easting northing easting northing
timestamp id
2023-09-24 00:00:00.016482+00:00 1695513598769889 604825.208 5.793e+06 -12.789 13.496 -4.311 0.047 0.093 0.080 -2.817 NaN ... 604827.352 5.793e+06 604827.308 5.793e+06 604825.163 5.793e+06 604823.019 5.793e+06 604823.064 5.793e+06
2023-09-24 00:00:00.066482+00:00 1695513598769889 604824.540 5.793e+06 -12.788 13.494 -4.308 0.052 0.097 0.081 -2.817 -0.002 ... 604826.684 5.793e+06 604826.640 5.793e+06 604824.495 5.793e+06 604822.351 5.793e+06 604822.396 5.793e+06
2023-09-24 00:00:00.116482+00:00 1695513598769889 604823.871 5.793e+06 -12.787 13.493 -4.305 0.058 0.101 0.083 -2.817 -0.002 ... 604826.015 5.793e+06 604825.971 5.793e+06 604823.826 5.793e+06 604821.682 5.793e+06 604821.727 5.793e+06
2023-09-24 00:00:00.166482+00:00 1695513598769889 604823.202 5.793e+06 -12.786 13.490 -4.302 0.063 0.105 0.084 -2.817 -0.003 ... 604825.346 5.793e+06 604825.302 5.793e+06 604823.157 5.793e+06 604821.013 5.793e+06 604821.058 5.793e+06
2023-09-24 00:00:00.216482+00:00 1695513598769889 604822.533 5.793e+06 -12.785 13.488 -4.298 0.069 0.109 0.085 -2.818 -0.003 ... 604824.677 5.793e+06 604824.633 5.793e+06 604822.488 5.793e+06 604820.344 5.793e+06 604820.389 5.793e+06

5 rows × 35 columns

Note that the boundingbox attribute was added in this step. Since ds is a tasi.TrajectoryDataset it also uses pandas. Hence, we will now convert to use geopandas while the position attribute should be encoded as a GeoObject.

[10]:
gds = ds.as_geo("position")

We need to set the position attribute as the active geometry.

[11]:
gds.set_geometry("position", inplace=True)

Now, we are ready to visualize the trajectories in a dynamic window, while we use the “CartoDB positron” background layer for reference.

[12]:
gds.explore(crs="EPSG:32632", tiles="CartoDB positron")
[12]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Note that for each traffic participant (or trajectory), additional information is available when hovering over its representation in the map. You can customize the representaton of the trajectories and add or remove attributes to you liking.