Skip to main content
Weather plays a crucial role in F1 performance. This tutorial shows you how to analyze the impact of temperature, humidity, and rainfall on lap times.

Loading weather data

Weather data is automatically included in lap data and available separately.
import tif1
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Load session
session = tif1.get_session(2024, "Singapore Grand Prix", "Race")
laps = session.laps
weather = session.weather

Weather data structure

Weather is recorded approximately once per minute.
# View weather data
print(weather[["Time", "AirTemp", "TrackTemp", "Humidity", "Rainfall"]].head())

# Check for rain
if weather["Rainfall"].any():
    print("Rain detected during session")
else:
    print("Dry session")

Temperature vs Lap Time

Analyze how track temperature affects lap times.
# Clean laps (remove outliers)
clean_laps = laps[
    (laps["LapTime"] < laps["LapTime"].min() * 1.07) &
    (laps["PitInTime"].isna()) &
    (laps["LapNumber"] > 1)
]

# Plot track temp vs lap time
plt.figure(figsize=(12, 6))
plt.scatter(clean_laps["TrackTemp"], clean_laps["LapTime"], alpha=0.3)
plt.xlabel("Track Temperature (°C)")
plt.ylabel("Lap Time (s)")
plt.title("Track Temperature Impact on Lap Times")

# Add trend line
z = np.polyfit(clean_laps["TrackTemp"], clean_laps["LapTime"], 1)
p = np.poly1d(z)
plt.plot(clean_laps["TrackTemp"], p(clean_laps["TrackTemp"]),
         "r--", linewidth=2, label=f"Trend: {z[0]:.3f}s/°C")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Temperature Evolution

Track how temperature changes during the session.
# Plot temperature evolution
fig, ax1 = plt.subplots(figsize=(14, 6))

# Air temp
ax1.plot(weather["Time"] / 60, weather["AirTemp"],
         color="blue", label="Air Temp", linewidth=2)
ax1.set_xlabel("Time (minutes)")
ax1.set_ylabel("Air Temperature (°C)", color="blue")
ax1.tick_params(axis="y", labelcolor="blue")

# Track temp
ax2 = ax1.twinx()
ax2.plot(weather["Time"] / 60, weather["TrackTemp"],
         color="red", label="Track Temp", linewidth=2)
ax2.set_ylabel("Track Temperature (°C)", color="red")
ax2.tick_params(axis="y", labelcolor="red")

plt.title("Temperature Evolution During Session")
fig.tight_layout()
plt.show()

Humidity Impact

Analyze how humidity affects performance.
# Group by humidity ranges
clean_laps["HumidityRange"] = pd.cut(
    clean_laps["Humidity"],
    bins=[0, 40, 60, 80, 100],
    labels=["Low", "Medium", "High", "Very High"]
)

# Compare lap times by humidity
plt.figure(figsize=(10, 6))
sns.boxplot(x="HumidityRange", y="LapTime", data=clean_laps)
plt.xlabel("Humidity Range (%)")
plt.ylabel("Lap Time (s)")
plt.title("Humidity Impact on Lap Times")
plt.show()

# Statistical summary
humidity_stats = clean_laps.groupby("HumidityRange")["LapTime"].agg([
    "mean", "median", "std", "count"
])
print(humidity_stats)

Rain Analysis

Analyze performance in wet conditions.
# Check if it rained
if weather["Rainfall"].any():
    # Find when rain started
    rain_start = weather[weather["Rainfall"] == True]["Time"].min()
    print(f"Rain started at: {rain_start / 60:.1f} minutes")

    # Mark laps as wet or dry
    laps["Wet"] = laps["SessionTime"] >= rain_start

    # Compare dry vs wet lap times
    dry_laps = laps[laps["Wet"] == False]
    wet_laps = laps[laps["Wet"] == True]

    print(f"Dry avg: {dry_laps['LapTime'].mean():.3f}s")
    print(f"Wet avg: {wet_laps['LapTime'].mean():.3f}s")
    print(f"Difference: {wet_laps['LapTime'].mean() - dry_laps['LapTime'].mean():.3f}s")

    # Visualize
    plt.figure(figsize=(12, 6))
    plt.scatter(dry_laps["LapNumber"], dry_laps["LapTime"],
                label="Dry", alpha=0.5, color="orange")
    plt.scatter(wet_laps["LapNumber"], wet_laps["LapTime"],
                label="Wet", alpha=0.5, color="blue")
    plt.axvline(x=rain_start / 60, color="red", linestyle="--",
                label="Rain Start")
    plt.xlabel("Lap Number")
    plt.ylabel("Lap Time (s)")
    plt.title("Lap Times: Dry vs Wet Conditions")
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

Tire Compound Performance by Temperature

See how different compounds perform at different temperatures.
# Filter for clean laps
clean_laps = laps[
    (laps["LapTime"] < laps["LapTime"].min() * 1.07) &
    (laps["PitInTime"].isna())
]

# Group by compound and temperature range
clean_laps["TempRange"] = pd.cut(
    clean_laps["TrackTemp"],
    bins=[0, 35, 40, 45, 100],
    labels=["Cool", "Optimal", "Hot", "Very Hot"]
)

# Compare compounds
compound_temp = clean_laps.groupby(["Compound", "TempRange"])["LapTime"].mean().reset_index()

# Visualize
plt.figure(figsize=(12, 6))
for compound in ["SOFT", "MEDIUM", "HARD"]:
    data = compound_temp[compound_temp["Compound"] == compound]
    plt.plot(data["TempRange"], data["LapTime"],
             marker="o", label=compound, linewidth=2)

plt.xlabel("Track Temperature Range")
plt.ylabel("Average Lap Time (s)")
plt.title("Tire Compound Performance by Temperature")
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

Wind Impact

Analyze how wind affects lap times.
# Check wind data
print(f"Wind speed range: {weather['WindSpeed'].min():.1f} - {weather['WindSpeed'].max():.1f} m/s")
print(f"Wind direction range: {weather['WindDirection'].min()}° - {weather['WindDirection'].max()}°")

# Categorize wind strength
clean_laps["WindStrength"] = pd.cut(
    clean_laps["WindSpeed"],
    bins=[0, 2, 5, 10, 100],
    labels=["Calm", "Light", "Moderate", "Strong"]
)

# Compare lap times by wind
plt.figure(figsize=(10, 6))
sns.violinplot(x="WindStrength", y="LapTime", data=clean_laps)
plt.xlabel("Wind Strength")
plt.ylabel("Lap Time (s)")
plt.title("Wind Impact on Lap Times")
plt.show()

Pressure Analysis

Atmospheric pressure can affect engine performance.
# Plot pressure over time
plt.figure(figsize=(12, 6))
plt.plot(weather["Time"] / 60, weather["Pressure"], linewidth=2)
plt.xlabel("Time (minutes)")
plt.ylabel("Atmospheric Pressure (mbar)")
plt.title("Atmospheric Pressure During Session")
plt.grid(True, alpha=0.3)
plt.show()

# Correlate with lap times
from scipy import stats

correlation, p_value = stats.pearsonr(
    clean_laps["Pressure"],
    clean_laps["LapTime"]
)
print(f"Pressure-LapTime correlation: {correlation:.3f} (p={p_value:.3f})")

Multi-Factor Analysis

Combine multiple weather factors.
# Create feature matrix
features = clean_laps[["AirTemp", "TrackTemp", "Humidity", "Pressure", "WindSpeed"]]
target = clean_laps["LapTime"]

# Calculate correlations
correlations = features.corrwith(target).sort_values(ascending=False)
print("Weather factor correlations with lap time:")
print(correlations)

# Visualize correlations
plt.figure(figsize=(10, 6))
correlations.plot(kind="barh")
plt.xlabel("Correlation with Lap Time")
plt.title("Weather Factors Impact on Performance")
plt.axvline(x=0, color="black", linestyle="--")
plt.tight_layout()
plt.show()

Weather-Adjusted Performance

Normalize lap times for weather conditions.
from sklearn.linear_model import LinearRegression

# Train model to predict lap time from weather
X = clean_laps[["TrackTemp", "Humidity", "WindSpeed"]]
y = clean_laps["LapTime"]

model = LinearRegression()
model.fit(X, y)

# Predict expected lap time
clean_laps["ExpectedLapTime"] = model.predict(X)

# Calculate weather-adjusted performance
clean_laps["WeatherAdjusted"] = clean_laps["LapTime"] - clean_laps["ExpectedLapTime"]

# Find best performers (accounting for weather)
adjusted_performance = clean_laps.groupby("Driver")["WeatherAdjusted"].mean().sort_values()
print("Weather-Adjusted Performance (negative is better):")
print(adjusted_performance.head(10))

Complete Weather Analysis Function

def analyze_weather_impact(year, gp, session_type):
    """Complete weather impact analysis."""
    # Load data
    session = tif1.get_session(year, gp, session_type)
    laps = session.laps
    weather = session.weather

    # Clean laps
    clean_laps = laps[
        (laps["LapTime"] < laps["LapTime"].min() * 1.07) &
        (laps["PitInTime"].isna()) &
        (laps["LapNumber"] > 1)
    ]

    # Temperature analysis
    temp_corr, _ = stats.pearsonr(clean_laps["TrackTemp"], clean_laps["LapTime"])

    # Rain check
    rain_detected = weather["Rainfall"].any()

    # Wind analysis
    avg_wind = weather["WindSpeed"].mean()

    # Results
    results = {
        "event": gp,
        "session": session_type,
        "temp_correlation": temp_corr,
        "rain_detected": rain_detected,
        "avg_wind_speed": avg_wind,
        "temp_range": (weather["TrackTemp"].min(), weather["TrackTemp"].max()),
        "humidity_range": (weather["Humidity"].min(), weather["Humidity"].max())
    }

    return results

# Use it
results = analyze_weather_impact(2024, "Singapore Grand Prix", "Race")
print(results)

Summary

Weather analysis with tif1 allows you to:
  • Correlate temperature with lap times
  • Identify rain impact on performance
  • Analyze humidity and wind effects
  • Compare tire compound performance by temperature
  • Normalize performance for weather conditions
Understanding weather impact is crucial for strategy decisions and performance analysis.

Race Analysis

Race analysis

Core API

Weather data API

Examples

More examples
Last modified on March 6, 2026