From f9ed914f18a5ee5c5c416d7ebda21f1aee08f4a6 Mon Sep 17 00:00:00 2001 From: Philipp Schaefer <23384863+theoehrly@users.noreply.github.com> Date: Sat, 10 Jan 2026 22:51:01 +0100 Subject: [PATCH] ENH: fill in speed trap values missing in src data --- docs/api_reference/timing_data.rst | 8 ++++---- fastf1/core.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/api_reference/timing_data.rst b/docs/api_reference/timing_data.rst index e16be3c1b..f8b2c2968 100644 --- a/docs/api_reference/timing_data.rst +++ b/docs/api_reference/timing_data.rst @@ -73,16 +73,16 @@ for each): - Session time when the Sector 3 time was set * - **SpeedI1** - ``float`` - - Speedtrap sector 1 [km/h] + - Speedtrap sector 1 [km/h] (missing under red flag) * - **SpeedI2** - ``float`` - - Speedtrap sector 2 [km/h] + - Speedtrap sector 2 [km/h] (missing under red flag) * - **SpeedFL** - ``float`` - - Speedtrap at finish line [km/h] + - Speedtrap at finish line [km/h] (missing under red flag and missing on laps where a driver enters the pits) * - **SpeedST** - ``float`` - - Speedtrap on longest straight (Not sure) [km/h] + - Speedtrap on longest straight or at a select high speed point, dependent on the circuit [km/h] (missing under red flag) * - **IsPersonalBest** - ``bool`` - Flag that indicates whether this lap is the official personal best lap of a driver. If any lap of a driver is quicker than their respective personal best lap, this means that the quicker lap is invalid and not counted. For example, this can happen if the track limits were exceeded. diff --git a/fastf1/core.py b/fastf1/core.py index ac9cb6e39..5bb55ac22 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -1619,6 +1619,32 @@ def _load_laps_data(self, livedata=None): self._add_track_status_to_laps(laps) + # fix missing speed trap values, caused by the API data skipping + # over consecutive equivalent values (#775) + for drv in drivers: + drv_mask = laps["DriverNumber"] == drv + # drv_laps = laps[drv_mask] + + # forward fill sector 1, sector 2 and the "ST" speed trap for all + # original laps that didn't take place under a red flag + appl_mask = ( + ~laps.loc[drv_mask, "FastF1Generated"] + & ~laps.loc[drv_mask, "TrackStatus"].str.contains("5") + ) + fill_12st = laps.loc[ + drv_mask, ("SpeedI1", "SpeedI2", "SpeedST") + ].ffill().loc[appl_mask] + laps.loc[ + appl_mask & drv_mask, + ("SpeedI1", "SpeedI2", "SpeedST") + ] = fill_12st + + # forward fill finish line speed trap like sector 1 speed trap, + # additionally excluding laps where the driver entered the pits + appl_mask &= pd.isnull(laps.loc[drv_mask, "PitInTime"]) + fill_fl = laps.loc[drv_mask, "SpeedFL"].ffill().loc[appl_mask] + laps.loc[appl_mask & drv_mask, "SpeedFL"] = fill_fl + self._laps = Laps(laps, session=self, _force_default_cols=True) self._check_lap_accuracy()