xoolive / traffic

A toolbox for processing and analysing air traffic data
https://traffic-viz.github.io/
MIT License
361 stars 80 forks source link

Allow interpolation options for resampling trajectories #440

Closed niclaswue closed 3 months ago

niclaswue commented 3 months ago

The resample function for trajectories is great, however currently only linear interpolation and ffill are supported. This is sufficient if the trajectories have a high resolution because normally, I would want to downsample them. However, for some use cases it would be cool to enhance the trajectories using the resample function to get a more realistic trajectory. The SCAT data, for example, has a resolution of 5s which may not be enough to measure the duration of smaller maneuvers precisely.

Therefore, I suggest introducing another argument to the resample function where the user can provide options for the interpolation. See this example:

flight_coarse = flight.resample("1min", how="interpolate")
flight_linear = flight.resample("1s", how="interpolate")
flight_cubic = flight.resample("1s", how="interpolate", interpolation_options={"method": "cubic"})
flight_polynomial_5 = flight.resample("1s", how="interpolate", interpolation_options={"method": "polynomial", "order": 5})

This would keep the interface backwards compatible and it would also be simple to implement.

diff --git a/src/traffic/core/flight.py b/src/traffic/core/flight.py
index 7513b08..f72316a 100644
--- a/src/traffic/core/flight.py
+++ b/src/traffic/core/flight.py
@@ -1658,6 +1658,7 @@ class Flight(
         self,
         rule: str | int = "1s",
         how: None | str | dict[str, Iterable[str]] = "interpolate",
+        interpolation_options: dict = {},
         projection: None | str | pyproj.Proj | "crs.Projection" = None,
     ) -> Flight:
         """Resample the trajectory at a given frequency or for a target number
@@ -1729,7 +1730,8 @@ class Flight(
             for meth, columns in how.items():
                 if meth is not None:
                     idx = data.columns.get_indexer(columns)
-                    value = getattr(data.iloc[:, idx], meth)()
+                    kwargs = interpolation_options if meth == "interpolate" else {} 
+                    value = getattr(data.iloc[:, idx], meth)(**kwargs)
                     data[data.columns[idx]] = value

         elif isinstance(rule, int):

Let me know what you think. Thanks!

xoolive commented 3 months ago

Makes sense, happy to merge a PR 👍