Racing, Data, & Maps
There’s a popular quote in the business world that says “you can’t change what you don’t measure,” and nowhere is that more true than in the world of Formula One. As a business that generated more than $2.5 billion in 2022, F1 relies heavily on data analytics, affecting everything from car design, to driving techniques, and even broadcasting. No longer are race outcomes dependent solely on a driver's split-second decisions.
Beginning in the 1970s, small telemetry systems were introduced to gather information about car operations. In the ‘80s, electronic systems became common, able to store data for a single lap. Drivers could activate telemetry when data needed collection. Later, burst telemetry transmitted radio signals during races, alerting pit crews of a car's condition. Streaming data replaced bursts, to enable real-time information flow. Today, a single F1 car has around 300 sensors, producing around 100,000 data points and accumulating 1.5 terabytes of data in a single race, with teams of analysts monitoring it all.
While having all that data is great, it can also be a problem. Human brains aren’t computers, and making sense of raw data isn’t easy. GIS however, can visualize that data on a map, to spot trends in driver and car performance based on their location on the track. After all, GIS is just data science with maps. Since the data exists, there’s two questions that need answering:
How do I get the data?
How do I convert it into a GIS source?
The Data
The FastF1 python API makes the official F1 data stream available for users to access car telemetry, lap timing, positional data, weather data, session results, and more. With good documentation, even those with minimal coding experience could start reading telemetry data with only a few lines of code!
# Imports import fastf1 import matplotlib as mpl from datetime import timedelta # Load a session session = fastf1.get_session(2021, 4, 'R') session.load() print('{} - {}'.format( session.session_info['Meeting']['Name'], session.name)) time_stamp = session.date print('{}, {} {}, {}'.format( time_stamp.day_name(), time_stamp.month_name(), time_stamp.day, time_stamp.year)) # Get the Fastest Lap fast_lap = session.laps.pick_fastest(only_by_time=True) fast_driver = session.get_driver(fast_lap['Driver']) print('Fastest Lap: {} - Driver: {} ({}), Lap {}'.format( timedelta(seconds=fast_lap['LapTime'].total_seconds()), fast_driver['FullName'], fast_driver['TeamName'], fast_lap['LapNumber'])) # Get telemetry data print(fast_lap.get_telemetry())
Those 30 lines of code are all that’s needed to select a race, identify the fastest lap, the driver responsible, and print out all of the telemetry. While the FastF1 API doesn’t provide all of the telemetry available (teams choose to keep that information close-hold so they can have a competitive advantage,) it provides a lot of data and puts it into an easy to read table:
Spanish Grand Prix - Race Sunday, May 9, 2021 Fastest Lap: 0:01:18.149000 - Driver: Max Verstappen (Red Bull Racing), Lap 62.0 Date SessionTime DriverAhead DistanceToDriverAhead Time RPM Speed nGear ... DRS Source Distance RelativeDistance Status X Y Z 2 2021-05-09 14:30:02.779 0 days 02:00:02.771000 1743.161111 0 days 00:00:00 11413 283 7 ... 0 interpolation 0.056589 0.000012 OnTrack 880 -381 1707 3 2021-05-09 14:30:02.870 0 days 02:00:02.862000 1743.161111 0 days 00:00:00.091000 11434 284 7 ... 0 car 7.261667 0.001551 OnTrack 841 -442 1707 4 2021-05-09 14:30:02.923 0 days 02:00:02.915000 1743.161111 0 days 00:00:00.144000 11459 285 7 ... 0 pos 11.472710 0.002451 OnTrack 819 -478 1707 5 2021-05-09 14:30:03.110 0 days 02:00:03.102000 44 1743.161111 0 days 00:00:00.331000 11484 287 7 ... 0 car 26.395000 0.005639 OnTrack 739 -602 1706 6 2021-05-09 14:30:03.143 0 days 02:00:03.135000 44 1738.761111 0 days 00:00:00.364000 11535 287 7 ... 0 pos 29.032415 0.006202 OnTrack 725 -625 1707 .. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 678 2021-05-09 14:31:20.470 0 days 02:01:20.462000 44 1553.103333 0 days 00:01:17.691000 11293 281 7 ... 0 car 4642.898333 0.991910 OnTrack 1062 -97 1706 679 2021-05-09 14:31:20.563 0 days 02:01:20.555000 44 1553.070000 0 days 00:01:17.784000 11327 282 7 ... 0 pos 4650.193166 0.993469 OnTrack 1035 -141 1706 680 2021-05-09 14:31:20.710 0 days 02:01:20.702000 44 1553.036667 0 days 00:01:17.931000 11362 283 7 ... 0 car 4661.765000 0.995941 OnTrack 975 -233 1706 681 2021-05-09 14:31:20.783 0 days 02:01:20.775000 44 1553.036667 0 days 00:01:18.004000 11436 284 7 ... 0 pos 4667.530093 0.997172 OnTrack 944 -283 1707 682 2021-05-09 14:31:20.928 0 days 02:01:20.920000 44 1553.036667 0 days 00:01:18.149000 11473 284 7 ... 0 interpolation 4679.017788 0.999627 OnTrack 882 -377 1707
While the data is interesting, a list of numbers isn’t very easy to interpret. Luckily, FastF1 uses the Python matplotlib library to let us plot the data on a graph. For example, speed data for the fastest laps of Max Verstappen and Lewis Hamilton can be plotted and compared. As a graph, this data is more useful, showing that Verstappen pushes his car harder than Hamilton, attaining higher speeds and braking harder.
The Maps
It’s easy to see some information in the chart, but doesn’t help explain the why. Yes, should be obvious that those are curves, since a car moving more than 300km/h would need to slow for each corner, but visualizing it on a map makes the data easier to understand, especially for more casual observers.
This is easy to do, since the telemetry data also provides position coordinates, in an X,Y,Z format. Since FastF1 uses the Python matplotlib library to plot the data on a graph, it uses local coordinates instead of global ones.
Whilee there are ways of converting that into a normal latitude, longitude, and elevation, those assume that the X, Y, and Z values are based on the center of the earth. That means there’s still some work to do before adding it to ArcGIS or other programs, but it’s a start.