Core concepts

Getting started

Core concepts

What goes in, what comes out, how lapbox refuses, and the conventions every module shares.

A few ideas run through every module. Knowing them makes each function’s output easier to read — and tells you when not to read it.

FastF1 in, pandas out

lapbox takes FastF1’s objects exactly as FastF1 hands them over:

  • Telemetry — one lap’s car and position data, from lap.get_telemetry(), with FastF1’s column names: Distance, Speed, Throttle, Brake, RPM, nGear, DRS, X, Y, Time, Source. That’s the input to lapbox.telemetry.
  • Laps — session.laps, with Driver, LapNumber, LapTime, sector times, PitInTime / PitOutTime, Compound, Stint, TyreLife, Team. That’s the input to lapbox.data, lapbox.practice, lapbox.pace and lapbox.tyres.

Extra columns are ignored, and the input is never modified: every function returns new objects — DataFrames, dicts, NumPy arrays or small dataclasses whose fields are listed in the API reference. Nothing in lapbox downloads anything; FastF1 does that when you call session.load().

Most lap functions also read the same laps after normalize_laps (with LapTimeSeconds beside LapTime), and lapbox.practice and TyreDegradationModel read snake_case laps (driver, lap_number, lap_time_seconds, …).

Refusals

When the data can’t support an answer, lapbox doesn’t return a number that looks fine and isn’t. It refuses, in one of a few ways:

What comes backWhereWhat it means
matched is FalseComparison.matchedThe two laps couldn’t be put on the same points of track. The gap, speed delta, corner speeds, minisectors and segments describe the mismatch; don’t use them.
Noneclean_air_split, driver_consistency, ideal_lap, biggest_lossToo few laps to measure, or a result that would mislead (an ideal lap slower than the real one).
Rows left outtrue_pace_ranking, clean_air_ranking, stint_degradation, TyreDegradationModelA driver, stint or compound with too few laps is not ranked or fitted.
An empty tableMany functionsNothing to report, or a column the function needs is missing; the empty table keeps its columns. Functions that can’t work at all without a column (resample without Distance) raise a ValueError instead.

Fernando Alonso’s Monza 2025, for example, had too few laps in traffic to compare:

Python
from lapbox.pace import clean_air_split

print(clean_air_split(race.laps, "ALO"))
Output
None

Check for these before you display a result. Limits lists what lapbox can’t tell you at all yet.

Representative laps: the 107 % rule

A lap behind the safety car, in traffic or after a mistake says nothing about pace. Wherever lapbox measures pace it keeps only representative laps: laps within 107 % of a best lap.

fuel_correct is the exception: it returns every timed, non-pit lap, lap 1 included, and leaves the choosing to you.

Fuel correction

A car burns about 1.6 kg of fuel a lap and each kilogram costs about 0.03 s, so it gets roughly 0.048 s a lap quicker as the race goes on (FUEL_EFFECT_S_PER_LAP). To compare laps run on different fuel loads, lapbox corrects each one to end-of-race fuel:

Formula
corrected = raw - (total_laps - lap) * 0.048

fuel_correct, true_pace_ranking, the clean-air split, stint_degradation and TyreDegradationModel all use this one constant; long_run_pace adds it back to a run’s slope to get the tyre’s own trend.

Units and signs

QuantityUnit
Distancemetres, from the start of the lap (lap A’s, in a comparison)
Speedkm/h
Times, gaps, pacesseconds, as floats
Degradationseconds per lap (positive: slower with age)
Accelerationg (9.81 m/s²)
DriversFastF1’s three-letter abbreviations: VER, NOR, …

Signs, so a number’s direction is never a guess:

  • delta_time is time_b - time_a: positive means driver A is ahead.
  • A segment’s time_delta is positive where driver A gained time.
  • channel_delta is a - b: positive speed means A was faster there.
  • rank_change in true_pace_ranking is positive when a driver moves up once the fuel is taken out.
  • A clean-air delta is positive when traffic cost time.

Logging

lapbox logs through logging.getLogger(__name__) and never configures logging itself: with nothing set up, nothing is printed. To see what it does, configure the standard library as usual (continuing the Quickstart):

Python
import logging

logging.basicConfig(level=logging.INFO, format="%(name)s: %(message)s")
logging.getLogger("fastf1").setLevel(logging.WARNING)
result = compare(ver, nor, driver_a="VER", driver_b="NOR")
Output (stderr)
lapbox.telemetry.comparison: Laps re-aligned before comparison
lapbox.telemetry.comparison: Laps re-aligned before comparison
lapbox.telemetry.comparison: Drivers compared

The laps are aligned twice on purpose: once for the comparison, once on the minisectors’ own finer grid. Records carry their numbers as extra fields (shift_metres, residual_kmh, …) for a structured formatter.

Versions

Until 1.0, a minor release (0.2, 0.3, …) may change the API, and a fix can move a number (0.1.0.dev14 changed some true-pace medians by dropping lap 1). Every change is in the changelog. Pin a version (lapbox==0.1.0) where results must not move.

These docs describe lapbox 0.1.0. Something wrong or missing? Open an issue.