Note
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)
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")
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"}}
)
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)
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")
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")
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")
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]:
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.