How to use arithmetic operators on trajectories?
Visualization with the | (or) operator
The |
(prononce “or”) operator is very useful in interactive environments
(IPython, Jupyter, etc.) in order to put data structures next to each other.
The result of this operation is not designed to be stored in any variable.
For example, we can preview two trajectories on the same line:
from traffic.data.samples import belevingsvlucht
belevingsvlucht | belevingsvlucht.next("aligned_on_ils('EHAM')")
Flight
- callsign: TRA051
- aircraft:
484506
· 🇳🇱 PH-HZO (B738) - start: 2018-05-30 15:21:38+00:00
- stop: 2018-05-30 20:22:56+00:00
- duration: 0 days 05:01:18
- sampling rate: 1 second(s)
Flight
- callsign: TRA051
- aircraft:
484506
· 🇳🇱 PH-HZO (B738) - start: 2018-05-30 20:14:29+00:00
- stop: 2018-05-30 20:17:58+00:00
- duration: 0 days 00:03:29
- sampling rate: 1 second(s)
Concatenation with the + (plus) operator
The +
operator is a simple concatenation operator. In other words, all the
pandas DataFrames of the given structures are concatenated and wrapped in a
Traffic object.
- Flight.__add__(other)
Concatenation operator.
- Traffic.__add__(other)
Concatenation operator.
With the same trajectories as above, we can construct a Traffic object:
from traffic.data.samples import belevingsvlucht, pixair_toulouse
belevingsvlucht + pixair_toulouse
Traffic
with 2 identifierscount | ||
---|---|---|
icao24 | callsign | |
484506 | TRA051 | 16005 |
39b861 | PXR31F | 1819 |
The sum
built-in function can be used to concatenate many flights into a
Traffic collection.
Differences on trajectories with the - (minus) operator
The -
operator serves a way to remove segments in a trajectory. The
resulting structure will consist in 0, 1 or many trajectory segments wrapped in
a FlightIterator object.
- Flight.__sub__(other)
Difference operator.
- Parameters:
other (
Flight
|FlightIterator
|Interval
|IntervalCollection
) – refers to anything having one or several start and end (a.k.a. stop) dates.- Return type:
- Returns:
After intervals are pruned from a trajectory, unconnected segments may remain. You should iterate on the result of the
-
operator.
For example, on the following sample trajectory, the aircraft performs many landing attempts at Lelystad airport (EHLE) in the Netherlands, which are easily labelled as go-arounds. The difference operator will result in the trajectory section before and after all the landing attempts.
belevingsvlucht - belevingsvlucht.go_around("EHLE")
FlightIterator
Flight
- callsign: TRA051
- aircraft:
484506
· 🇳🇱 PH-HZO (B738) - start: 2018-05-30 15:21:38+00:00
- stop: 2018-05-30 16:00:56+00:00
- duration: 0 days 00:39:18
- sampling rate: 1 second(s)
Flight
- callsign: TRA051
- aircraft:
484506
· 🇳🇱 PH-HZO (B738) - start: 2018-05-30 19:47:46+00:00
- stop: 2018-05-30 20:22:56+00:00
- duration: 0 days 00:35:10
- sampling rate: 1 second(s)
Differences on collections with the - (minus) operator
The -
operators also serves as a way to remove flights from a Traffic
collection. The operator behaves slightly differently if both collections are
equipped with a flight_id
attribute or not.
- Traffic.__sub__(other)
Remove trajectories from a Traffic object.
- Parameters:
other (
str
|list
[str
] |set
[str
] |Flight
|Traffic
) –When the
other
attribute is a string, or a list/set of strings, all flights matching theflight_id
,callsign
oricao24
attribute are removed from the collection;When the
other
attribute is a Flight, the collection will be pruned of the trajectory with the sameflight_id
; or the segment of trajectory for thaticao24
address between thestart
andstop
timestamps;When the
other
attribute is a Traffic object, the difference is computed based on theflight_id
if both structures have one; otherwise, we iterate through flights and consider removing part of the trajectory.
- Return type:
- Returns:
a new collection of trajectories as a Traffic object
For example, in the following sample dataset, we build a sub dataset of all
trajectories going through a navaid point called “ODINA” at the border between
Switzerland and Italy. The -
operator produces a new dataset of
trajectories not going through ODINA.
from traffic.data.samples import switzerland
through_odina = switzerland.has('aligned_on_navpoint("ODINA")').eval()
difference = switzerland - through_odina
through_odina | difference
Traffic
with 113 identifierscount | ||
---|---|---|
icao24 | callsign | |
440005 | EZY12VJ | 169 |
39e46f | CCM531D | 155 |
40123f | BAW544K | 147 |
3946e2 | AFR85EZ | 145 |
400e4a | EXS88C | 145 |
3950c0 | AFR36RB | 143 |
44c24d | OOPRM | 142 |
4bb852 | PGT89P | 142 |
396672 | FPO09P | 141 |
4ca2c0 | RYR248Z | 141 |
Traffic
with 1130 identifierscount | ||
---|---|---|
icao24 | callsign | |
500142 | T7STK | 282 |
4baa61 | THY7WR | 186 |
344417 | IBE3279 | 185 |
40755f | EZY24DP | 184 |
4068cb | EXS33W | 180 |
3c5ee9 | EWG5938 | 178 |
3420ca | IBE31CW | 176 |
4009f9 | BAW585E | 175 |
4006d6 | CLJ6325 | 174 |
42428d | AFL2603 | 174 |
Indexation with the [] (bracket) operator
- Flight.__getitem__(key)
Indexation of flights.
- Parameters:
key (
str
|Interval
|IntervalCollection
) – the key parameter passed in the brackets- Return type:
- Returns:
if key is a string, the bracket operator is equivalent to the dot notation(e.g.
flight["duration"]
is equivalent toflight.duration
)if key is an Interval, the bracket operator is equivalent to the
between()
methodif key is an IntervalCollection, the operator iterates on all the intervals provided
The indexation of a Traffic collection is intended to be used in the most versatile way. Any object that could identify a particular trajectory can be used as a key.
- Traffic.__getitem__(key)
Indexation of collections.
- Parameters:
key (
Union
[int
,slice
,str
,List
[str
],Set
[str
],Series
,DataFrame
,Traffic
]) –if the key is an integer, will return a Flight object (in order of iteration);
if the key is a slice, will return a Traffic object (in order of iteration);
if the key is a string, will return a Flight object, based on the
flight_id
,icao24
orcallsign
;if the key is a list of string, will return a Traffic object, based on the same criteria as above;
if the key is a pd.Series, will return a Flight object. The key must contain an
icao24
feature. It may contain acallsign
, astart
(orfirstSeen
) timestamp, astop
(orlastSeen
) timestamp. If it contains aflight_id
column, this will be assigned to the Flight.if the key is a pd.DataFrame, will return a Traffic object. The key must contain an
icao24
feature. It may contain acallsign
, astart
(orfirstSeen
) timestamp, astop
(orlastSeen
) timestamp. If it contains aflight_id
column, this will be assigned to the Flight.if the key is a Traffic object, will return a new Traffic collection, based on the
flight_id
elements present in key. If noflight_id
is available, it will return the subset of trajectories inself
that overlap with any trajectory in key (with the same icao24 indicator)
- Return type:
- Returns:
According to the type of the key, the result could be a Flight or a Traffic object.
The following lets us get one or many trajectories:
# The first trajectory in the dataset
switzerland[0]
# The ten first trajectories in the dataset
switzerland[:10]
# The trajectory assigned with callsign ``EZY12VJ``
switzerland['EZY12VJ']
The DataFrame indexation can be useful for example with the following use case. We want to get full trajectories of aircraft entering the Swiss airspace at a particular hour. We first compute the statistics for each trajectory, then build a trajectory subcollection.
from traffic.data import eurofirs
stats = (
switzerland.clip(eurofirs["LSAS"])
.summary(["icao24", "callsign", "start", "stop"])
.eval(max_workers=2)
)
stats
icao24 | callsign | start | stop | |
---|---|---|---|---|
0 | 34150f | VLG86TM | 2018-08-01 06:04:30+00:00 | 2018-08-01 06:19:30+00:00 |
1 | 341682 | IBS3674 | 2018-08-01 19:24:10+00:00 | 2018-08-01 19:34:30+00:00 |
2 | 345101 | VLG56RH | 2018-08-01 18:37:30+00:00 | 2018-08-01 18:47:10+00:00 |
3 | 342441 | IBE3122 | 2018-08-01 15:57:40+00:00 | 2018-08-01 16:15:20+00:00 |
4 | 04c117 | KQA117 | 2018-08-01 20:43:30+00:00 | 2018-08-01 20:56:30+00:00 |
... | ... | ... | ... | ... |
1218 | a954ca | CKS9557 | 2018-08-01 21:45:20+00:00 | 2018-08-01 21:56:20+00:00 |
1219 | adf775 | N9997X | 2018-08-01 06:00:30+00:00 | 2018-08-01 06:14:00+00:00 |
1220 | ab1deb | N815WH | 2018-08-01 10:08:00+00:00 | 2018-08-01 10:16:10+00:00 |
1221 | e80444 | LAN705 | 2018-08-01 18:31:10+00:00 | 2018-08-01 18:41:50+00:00 |
1222 | c078b1 | TSC300 | 2018-08-01 08:32:50+00:00 | 2018-08-01 08:41:30+00:00 |
1223 rows × 4 columns
# All trajectories quitting the airspace between 15:30 and 15:40
subset = stats.query('stop.dt.floor("10 min") == "2018-08-01 15:30Z"')
subset_1530 = switzerland[subset] # subset is a pd.DataFrame
subset_1530
Traffic
with 13 identifierscount | ||
---|---|---|
icao24 | callsign | |
4006c8 | BAW66GA | 95 |
478771 | NAX3YO | 94 |
406ae0 | TCX702 | 88 |
440005 | EZY12VJ | 88 |
3c6628 | DLH52X | 82 |
8005ec | AIC143 | 81 |
4ca4ed | RYR87WH | 75 |
501d1d | CTN476 | 66 |
484aa1 | TRA93U | 58 |
44064a | EZY97QR | 57 |
The start
and stop
timestamps are based on the clipping of the
trajectories within the LSAS FIR boundaries. If we want to select the subset of
the original trajectories matching those (shorter) selected in subset_1530
,
we can use the bracket operator again:
# We might prefer the full trajectories that have been matched in subset_1530
switzerland[subset_1530] # subset is a Traffic object
Traffic
with 13 identifierscount | ||
---|---|---|
icao24 | callsign | |
440005 | EZY12VJ | 169 |
501d1d | CTN476 | 159 |
8005ec | AIC143 | 144 |
4006c8 | BAW66GA | 124 |
3c6628 | DLH52X | 114 |
4ca4ed | RYR87WH | 108 |
406ae0 | TCX702 | 107 |
478771 | NAX3YO | 107 |
484aa1 | TRA93U | 98 |
4ca175 | RYR31CR | 98 |
Overlapping of trajectories with the & (and) operator
When applied on Flight structures, the & operator expresses the concurrency of two trajectories, i.e. the piece of trajectory that is flown while another aircraft is flying.
- Flight.__and__(other)
Overlapping of trajectories.
from traffic.data.samples import dreamliner_airfrance
# expansion of the collection into two flights
video, dreamliner = dreamliner_airfrance
# the operator is not commutative
video & dreamliner | dreamliner & video
Flight
- callsign: FWKDL
- aircraft:
3900fb
· 🇫🇷 F-WKDL (TBM7) - start: 2017-12-01 14:40:34+00:00
- stop: 2017-12-01 15:59:58+00:00
- duration: 0 days 01:19:24
- sampling rate: 1 second(s)
Flight
- callsign: AFR787V
- aircraft:
39c424
· 🇫🇷 F-HRBE (B789) - start: 2017-12-01 14:40:34+00:00
- stop: 2017-12-01 15:59:58+00:00
- duration: 0 days 01:19:24
- sampling rate: 1 second(s)
Intersection of collections with the & (and) operator
When applied on collections, the & operator returns the subset of trajectories that are present in both collections.
- Traffic.__and__(other)
Intersection of collections.
# All trajectories entering or quitting the airspace between 15:30 and 15:40 through ODINA
result = through_odina & switzerland[subset_1530]
result
Traffic
with 2 identifierscount | ||
---|---|---|
icao24 | callsign | |
440005 | EZY12VJ | 169 |
4ca4ed | RYR87WH | 108 |
from traffic.data import navaids
ODINA = navaids['ODINA']
m = result.map_leaflet(
center=ODINA.latlon,
highlight=dict(red="aligned_on_navpoint('ODINA')")
)
m.add(ODINA)
m