pycontrails.Fleet#

class pycontrails.Fleet(data=None, *, longitude=None, latitude=None, altitude=None, altitude_ft=None, level=None, time=None, attrs=None, copy=True, fuel=None, fl_attrs=None, **attrs_kwargs)#

Bases: Flight

Data structure for holding a sequence of Flight instances.

Flight waypoints are merged into a single Flight-like object.

__init__(data=None, *, longitude=None, latitude=None, altitude=None, altitude_ft=None, level=None, time=None, attrs=None, copy=True, fuel=None, fl_attrs=None, **attrs_kwargs)#

Methods

T_isa()

Calculate the ICAO standard atmosphere temperature at each point.

__init__([data, longitude, latitude, ...])

broadcast_attrs(keys[, overwrite, raise_error])

Attach values from keys in attrs onto data.

broadcast_numeric_attrs([ignore_keys, overwrite])

Attach numeric values in attrs onto data.

clean_and_resample([freq, fill_method, ...])

Resample and (possibly) filter a flight trajectory.

coords_intersect_met(met)

Return boolean mask of data inside the bounding box defined by met.

copy(**kwargs)

Return a copy of this VectorDatasetType class.

create_empty([keys, attrs])

Create instance with variables defined by keys and size 0.

downselect_met(met, *[, longitude_buffer, ...])

Downselect met to encompass a spatiotemporal region of the data.

ensure_vars(vars[, raise_error])

Ensure variables exist in column of data or attrs.

filter(mask[, copy])

Filter data according to a boolean array mask.

filter_altitude([kernel_size, cruise_threshold])

Filter noisy altitude on a single flight.

filter_by_first()

Keep first row of group of waypoints with identical coordinates.

from_dict(obj[, copy])

Create instance from dict representation containing data and attrs.

from_seq(seq[, broadcast_numeric, copy, attrs])

Instantiate a Fleet instance from an iterable of Flight.

generate_splits(n_splits[, copy])

Split instance into n_split sub-vectors.

get(key[, default_value])

Get values from data with default_value if key not in data.

get_data_or_attr(key[, default])

Get value from data or attrs.

intersect_met(mda, *[, longitude, latitude, ...])

Intersect waypoints with MetDataArray.

length_met(key[, threshold])

Calculate total horizontal distance where column key exceeds threshold.

plot(**kwargs)

Plot flight trajectory longitude-latitude values.

proportion_met(key[, threshold])

Calculate proportion of flight with certain meteorological constraint.

resample_and_fill(*args, **kwargs)

Resample and fill flight trajectory with geodesics and linear interpolation.

segment_angle()

Calculate sine and cosine for the angle between each segment and the longitudinal axis.

segment_azimuth()

Calculate (forward) azimuth at each waypoint.

segment_duration([dtype])

Compute time elapsed between waypoints in seconds.

segment_groundspeed(*args, **kwargs)

Return groundspeed across segments.

segment_length()

Compute spherical distance between flight waypoints.

segment_mach_number(true_airspeed, ...)

Calculate the mach number of each segment.

segment_phase([threshold_rocd, ...])

Identify the phase of flight (climb, cruise, descent) for each segment.

segment_rocd()

Calculate the rate of climb and descent (ROCD).

segment_true_airspeed([u_wind, v_wind, ...])

Calculate the true airspeed [\(m / s\)] from the ground speed and horizontal winds.

select(keys[, copy])

Return new class instance only containing specified keys.

setdefault(key[, default])

Shortcut to VectorDataDict.setdefault().

sort(by)

Sort data by key(s).

sum(vectors[, infer_attrs, fill_value])

Sum a list of VectorDataset instances.

to_dataframe([copy])

Create pd.DataFrame in which each key-value pair in data is a column.

to_dict()

Create dictionary with data and attrs.

to_flight_list([copy])

De-concatenate merged waypoints into a list of Flight instances.

to_geojson_linestring()

Return trajectory as geojson FeatureCollection containing single LineString.

to_geojson_multilinestring(key[, ...])

Return trajectory as GeoJSON FeatureCollection of MultiLineStrings.

to_geojson_points()

Return dataset as GeoJSON FeatureCollection of Points.

to_lon_lat_grid(agg, *[, spatial_bbox, ...])

Convert vectors to a longitude-latitude grid.

to_pseudo_mercator([copy])

Convert data from attrs["crs"] to Pseudo Mercator (EPSG:3857).

to_traffic()

Convert Flight instance to traffic.core.Flight instance.

transform_crs(crs[, copy])

Transform trajectory data from one coordinate reference system (CRS) to another.

update([other])

Update values in data dict without warning if overwriting.

Attributes

fl_attrs

final_waypoints

air_pressure

Get air_pressure values for points.

altitude

Get altitude.

altitude_ft

Get altitude in feet.

attrs

Generic dataset attributes

constants

Return a dictionary of constant attributes and data values.

coords

Get geospatial coordinates for compatibility with MetDataArray.

data

Vector data with labels as keys and numpy.ndarray as values

dataframe

Shorthand property to access to_dataframe() with copy=False.

duration

Determine flight duration.

fuel

Fuel used in flight trajectory

hash

Generate a unique hash for this class instance.

length

Return flight length based on WGS84 geodesic.

level

Get pressure level values for points.

max_distance_gap

Return maximum distance gap between waypoints along flight trajectory.

max_time_gap

Return maximum time gap between waypoints along flight trajectory.

n_flights

Return number of distinct flights.

required_keys

Required keys for creating GeoVectorDataset

shape

Shape of each array in data.

size

Length of each array in data.

time_end

Last waypoint time.

time_start

First waypoint time.

vertical_keys

At least one of these vertical-coordinate keys must also be included

clean_and_resample(freq='1min', fill_method='geodesic', geodesic_threshold=100000.0, nominal_rocd=0.0, kernel_size=17, cruise_threshold=120, force_filter=False, drop=True, keep_original_index=False, climb_descend_at_end=False)#

Resample and (possibly) filter a flight trajectory.

Waypoints are resampled according to the frequency freq. If the original flight data has a short sampling period, filter_altitude will also be called to clean the data. Large gaps in trajectories may be interpolated as step climbs through _altitude_interpolation.

Parameters:
  • freq (str, optional) – Resampling frequency, by default “1min”

  • fill_method ({"geodesic", "linear"}, optional) – Choose between "geodesic" and "linear", by default "geodesic". In geodesic mode, large gaps between waypoints are filled with geodesic interpolation and small gaps are filled with linear interpolation. In linear mode, all gaps are filled with linear interpolation.

  • geodesic_threshold (float, optional) – Threshold for geodesic interpolation, [\(m\)]. If the distance between consecutive waypoints is under this threshold, values are interpolated linearly.

  • nominal_rocd (float, optional) – Nominal rate of climb / descent for aircraft type. Defaults to constants.nominal_rocd.

  • kernel_size (int, optional) – Passed directly to scipy.signal.medfilt(), by default 11. Passed also to scipy.signal.medfilt()

  • cruise_theshold (float, optional) – Minimal length of time, in seconds, for a flight to be in cruise to apply median filter

  • force_filter (bool, optional) – If set to true, meth:filter_altitude will always be called. otherwise, it will only be called if the flight has a median sample period under 10 seconds

  • drop (bool, optional) – Drop any columns that are not resampled and filled. Defaults to True, dropping all keys outside of “time”, “latitude”, “longitude” and “altitude”. If set to False, the extra keys will be kept but filled with nan or None values, depending on the data type.

  • keep_original_index (bool, optional) – Keep the original index of the Flight in addition to the new resampled index. Defaults to False. .. versionadded:: 0.45.2

  • climb_or_descend_at_end (bool) – If true, the climb or descent will be placed at the end of each segment rather than the start. Default is false (climb or descent immediately).

Returns:

Flight – Filled Flight

copy(**kwargs)#

Return a copy of this VectorDatasetType class.

Parameters:

**kwargs (Any) – Additional keyword arguments passed into the constructor of the returned class.

Returns:

VectorDatasetType – Copy of class

filter(mask, copy=True, **kwargs)#

Filter data according to a boolean array mask.

Entries corresponding to mask == True are kept.

Parameters:
  • mask (npt.NDArray[np.bool_]) – Boolean array with compatible shape.

  • copy (bool, optional) – Copy data on filter. Defaults to True. See numpy best practices for insight into whether copy is appropriate.

  • **kwargs (Any) – Additional keyword arguments passed into the constructor of the returned class.

Returns:

VectorDatasetType – Containing filtered data

Raises:

TypeError – If mask is not a boolean array.

final_waypoints#
fl_attrs#
classmethod from_seq(seq, broadcast_numeric=True, copy=True, attrs=None)#

Instantiate a Fleet instance from an iterable of Flight.

Changed in version 0.49.3: Empty flights are now filtered out before concatenation.

Parameters:
  • seq (Iterable[Flight]) – An iterable of Flight instances.

  • broadcast_numeric (bool, optional) – If True, broadcast numeric attributes to data variables.

  • copy (bool, optional) – If True, make copy of each flight instance in seq.

  • attrs (dict[str, Any] | None, optional) – Global attribute to attach to instance.

Returns:

Fleet – A Fleet instance made from concatenating the Flight instances in seq. The fuel type is taken from the first Flight in seq.

property max_distance_gap#

Return maximum distance gap between waypoints along flight trajectory.

Distance is calculated based on WGS84 geodesic.

Returns:

float – Maximum distance between waypoints, [\(m\)]

Raises:

NotImplementedError – Raises when attr:attrs[“crs”] is not EPSG:4326

Examples

>>> import numpy as np
>>> fl = Flight(
...     longitude=np.linspace(20, 30, 200),
...     latitude=np.linspace(40, 30, 200),
...     altitude=11000 * np.ones(200),
...     time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=200),
... )
>>> fl.max_distance_gap
7391.27...
property n_flights#

Return number of distinct flights.

Returns:

int – Number of flights

resample_and_fill(*args, **kwargs)#

Resample and fill flight trajectory with geodesics and linear interpolation.

Waypoints are resampled according to the frequency freq. Values for data columns longitude, latitude, and altitude are interpolated.

Parameters:
  • freq (str, optional) – Resampling frequency, by default “1min”

  • fill_method ({"geodesic", "linear"}, optional) – Choose between "geodesic" and "linear", by default "geodesic". In geodesic mode, large gaps between waypoints are filled with geodesic interpolation and small gaps are filled with linear interpolation. In linear mode, all gaps are filled with linear interpolation.

  • geodesic_threshold (float, optional) – Threshold for geodesic interpolation, [\(m\)]. If the distance between consecutive waypoints is under this threshold, values are interpolated linearly.

  • nominal_rocd (float | None, optional) – Nominal rate of climb / descent for aircraft type. Defaults to constants.nominal_rocd.

  • drop (bool, optional) – Drop any columns that are not resampled and filled. Defaults to True, dropping all keys outside of “time”, “latitude”, “longitude” and “altitude”. If set to False, the extra keys will be kept but filled with nan or None values, depending on the data type.

  • keep_original_index (bool, optional) – Keep the original index of the Flight in addition to the new resampled index. Defaults to False. .. versionadded:: 0.45.2

  • climb_or_descend_at_end (bool) – If true, the climb or descent will be placed at the end of each segment rather than the start. Default is false (climb or descent immediately).

Returns:

Flight – Filled Flight

Raises:

ValueError – Unknown fill_method

Examples

>>> from datetime import datetime
>>> import pandas as pd
>>> df = pd.DataFrame()
>>> df['longitude'] = [0, 0, 50]
>>> df['latitude'] = 0
>>> df['altitude'] = 0
>>> df['time'] = [datetime(2020, 1, 1, h) for h in range(3)]
>>> fl = Flight(df)
>>> fl.dataframe
   longitude  latitude  altitude                time
           0        0.0       0.0       0.0 2020-01-01 00:00:00
           1        0.0       0.0       0.0 2020-01-01 01:00:00
           2       50.0       0.0       0.0 2020-01-01 02:00:00
>>> fl.resample_and_fill('10min').dataframe  # resample with 10 minute frequency
    longitude  latitude  altitude                time
0    0.000000       0.0       0.0 2020-01-01 00:00:00
1    0.000000       0.0       0.0 2020-01-01 00:10:00
2    0.000000       0.0       0.0 2020-01-01 00:20:00
3    0.000000       0.0       0.0 2020-01-01 00:30:00
4    0.000000       0.0       0.0 2020-01-01 00:40:00
5    0.000000       0.0       0.0 2020-01-01 00:50:00
6    0.000000       0.0       0.0 2020-01-01 01:00:00
7    8.333333       0.0       0.0 2020-01-01 01:10:00
8   16.666667       0.0       0.0 2020-01-01 01:20:00
9   25.000000       0.0       0.0 2020-01-01 01:30:00
10  33.333333       0.0       0.0 2020-01-01 01:40:00
11  41.666667       0.0       0.0 2020-01-01 01:50:00
12  50.000000       0.0       0.0 2020-01-01 02:00:00
segment_angle()#

Calculate sine and cosine for the angle between each segment and the longitudinal axis.

This is different from the usual navigational angle between two points known as bearing.

Bearing in 3D spherical coordinates is referred to as azimuth.

        (lon_2, lat_2)  X
                       /|
                      / |
                     /  |
                    /   |
                   /    |
                  /     |
                 /      |
(lon_1, lat_1)  X -------> longitude (x-axis)
Returns:

npt.NDArray[np.float64], npt.NDArray[np.float64] – Returns sin(a), cos(a), where a is the angle between the segment and the longitudinal axis. The final values are of both arrays are np.nan.

See also

geo.segment_angle(), units.heading_to_longitudinal_angle(), segment_azimuth(), geo.forward_azimuth()

Examples

>>> from pycontrails import Flight
>>> fl = Flight(
... longitude=np.array([1, 2, 3, 5, 8]),
... latitude=np.arange(5),
... altitude=np.full(shape=(5,), fill_value=11000),
... time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=5),
... )
>>> sin, cos = fl.segment_angle()
>>> sin
array([0.70716063, 0.70737598, 0.44819424, 0.31820671,        nan])
>>> cos
array([0.70705293, 0.70683748, 0.8939362 , 0.94802136,        nan])
segment_azimuth()#

Calculate (forward) azimuth at each waypoint.

Method calls pyproj.Geod.inv, which is slow. See geo.forward_azimuth for an outline of a faster implementation.

Changed in version 0.33.7: The dtype of the output now matches the dtype of self["longitude"].

Returns:

npt.NDArray[np.float64] – Array of azimuths.

See also

segment_angle(), geo.forward_azimuth()

segment_groundspeed(*args, **kwargs)#

Return groundspeed across segments.

Calculate by dividing the horizontal segment length by the difference in waypoint times.

Parameters:
Returns:

npt.NDArray[np.float64] – Groundspeed of the segment, [\(m s^{-1}\)]

segment_length()#

Compute spherical distance between flight waypoints.

Helper function used in length() and length_met(). np.nan appended so the length of the output is the same as number of waypoints.

Returns:

npt.NDArray[np.float64] – Array of distances in [\(m\)] between waypoints

Raises:

NotImplementedError – Raises when attr:attrs[“crs”] is not EPSG:4326

Examples

>>> from pycontrails import Flight
>>> fl = Flight(
... longitude=np.array([1, 2, 3, 5, 8]),
... latitude=np.arange(5),
... altitude=np.full(shape=(5,), fill_value=11000),
... time=pd.date_range('2021-01-01T12', '2021-01-01T14', periods=5),
... )
>>> fl.segment_length()
array([157255.03346286, 157231.08336815, 248456.48781503, 351047.44358851,
                   nan])

See also

segment_length()

segment_true_airspeed(u_wind=0.0, v_wind=0.0, smooth=True, window_length=7, polyorder=1)#

Calculate the true airspeed [\(m / s\)] from the ground speed and horizontal winds.

Because Flight.segment_true_airspeed uses a smoothing pattern, waypoints in data are not independent. Moreover, we expect the final waypoint of each flight to have a nan value associated to any segment property. Consequently, we need to define a custom method here to deal with these issues when applying this method on a fleet of flights.

See docstring for Flight.segment_true_airspeed().

Raises:

RuntimeError – Unexpected key __u_wind or __v_wind found in data.

sort(by)#

Sort data by key(s).

This method always creates a copy of the data by calling pandas.DataFrame.sort_values().

Parameters:

by (str | list[str]) – Key or list of keys to sort by.

Returns:

VectorDatasetType – Instance with sorted data.

to_flight_list(copy=True)#

De-concatenate merged waypoints into a list of Flight instances.

Any global attrs are lost.

Parameters:

copy (bool, optional) – If True, make copy of each flight instance in seq.

Returns:

list[Flight] – List of Flights in the same order as was passed into the Fleet instance.