Skip to content
Snippets Groups Projects
Commit ae299a1a authored by Lennard Geese's avatar Lennard Geese
Browse files

Add todos; implement fetching race names; centralize fetching driver by position

parent e77919cd
No related branches found
No related tags found
1 merge request!2Master
...@@ -19,8 +19,6 @@ class DataAnalyser(DataHandler): ...@@ -19,8 +19,6 @@ class DataAnalyser(DataHandler):
return overtakesInRaces return overtakesInRaces
def analyseRaceForOvertakes(self, race: Session): def analyseRaceForOvertakes(self, race: Session):
# Collect grid positions # Collect grid positions
allLapPositions: List[dict[str, int]] = [] allLapPositions: List[dict[str, int]] = []
...@@ -46,10 +44,11 @@ class DataAnalyser(DataHandler): ...@@ -46,10 +44,11 @@ class DataAnalyser(DataHandler):
if self.activateDebugOvertakeAnalysis: if self.activateDebugOvertakeAnalysis:
print(f"\nLap: 0") print(f"\nLap: 0")
for position in range(len(gridPositions)): for i in range(len(gridPositions)):
position: int = i + 1
gridPositions.values() gridPositions.values()
driverAtPosition = list(gridPositions.keys())[list(gridPositions.values()).index(position + 1)] # get dictionary keys (driverIds) by values (current race position) driverAtPosition = self.getDriverByPositionFromMap(gridPositions, position)
print(f"P{position + 1}: {driverAtPosition}") print(f"P{position}: {driverAtPosition}")
return gridPositions return gridPositions
...@@ -75,10 +74,11 @@ class DataAnalyser(DataHandler): ...@@ -75,10 +74,11 @@ class DataAnalyser(DataHandler):
for raceLapIndex in range(race.total_laps): for raceLapIndex in range(race.total_laps):
print(f"\nLap: {raceLapIndex + 1}") print(f"\nLap: {raceLapIndex + 1}")
runningLapPositions = runningLapsPositions[raceLapIndex] runningLapPositions = runningLapsPositions[raceLapIndex]
for position in range(len(runningLapPositions)): for i in range(len(runningLapPositions)):
runningLapPositions.values() runningLapPositions.values()
driverAtPosition = list(runningLapPositions.keys())[list(runningLapPositions.values()).index(position + 1)] position: int = i + 1
print(f"P{position + 1}: {driverAtPosition}") driverAtPosition = self.getDriverByPositionFromMap(runningLapPositions, position)
print(f"P{position}: {driverAtPosition}")
return runningLapsPositions return runningLapsPositions
...@@ -110,20 +110,30 @@ class DataAnalyser(DataHandler): ...@@ -110,20 +110,30 @@ class DataAnalyser(DataHandler):
#print(orderToSort[i]) #print(orderToSort[i])
overtakes: int = 0 overtakes: int = 0
index: int = 0 i: int = 0
while index < len(orderToSort) - 1: while i < len(orderToSort) - 1:
if orderToSort[index] > orderToSort[index + 1]: if self.countOutPitstops:
temp: int = orderToSort[index] driverPittedThisLap: bool = False
orderToSort[index] = orderToSort[index + 1] currentDriversEndPosition = orderToSort[i]
orderToSort[index + 1] = temp driver = self.getDriverByPositionFromMap(endOrder, currentDriversEndPosition)
if orderToSort[i] > orderToSort[i + 1]:
temp: int = orderToSort[i]
orderToSort[i] = orderToSort[i + 1]
orderToSort[i + 1] = temp
overtakes += 1 overtakes += 1
index = -1 i = -1
index += 1 i += 1
return overtakes return overtakes
def getDriverByPositionFromMap(self, positions: dict[str, int], position: int):
driver = list(positions.keys())[list(positions.values()).index(position)]
return driver
# ===== Weather ===== # ===== Weather =====
def analyseRacesForWeather(self, races: List[Session]): def analyseRacesForWeather(self, races: List[Session]):
...@@ -183,6 +193,8 @@ class DataAnalyser(DataHandler): ...@@ -183,6 +193,8 @@ class DataAnalyser(DataHandler):
if noStartingCompoundsLeft: return currentLap if noStartingCompoundsLeft: return currentLap
currentLap += 1 currentLap += 1
return -1 # no lap without compound found; all laps use same compound type
def getCompoundsForRace(self, race: Session): def getCompoundsForRace(self, race: Session):
compoundsPerLap: List[List[str]] = [[]] compoundsPerLap: List[List[str]] = [[]]
...@@ -225,6 +237,7 @@ class DataAnalyser(DataHandler): ...@@ -225,6 +237,7 @@ class DataAnalyser(DataHandler):
if compound not in filter: if compound not in filter:
return currentLap return currentLap
currentLap += 1 currentLap += 1
return -1 # no lap with opposite compound found; all laps use same compound type
def setFilter(self, startingCompound: str): def setFilter(self, startingCompound: str):
if startingCompound == 'SLICK': return self.slickCompounds if startingCompound == 'SLICK': return self.slickCompounds
......
...@@ -7,4 +7,5 @@ class DataHandler(ABC): ...@@ -7,4 +7,5 @@ class DataHandler(ABC):
self.invalidDriverId = "NO_DRIVER" self.invalidDriverId = "NO_DRIVER"
self.enableTestingMode = False # only partially import data to speed up testing, because HTTP 429 limits import speed self.enableTestingMode = False # only partially import data to speed up testing, because HTTP 429 limits import speed
self.activateDebugOvertakeAnalysis = False self.activateDebugOvertakeAnalysis = False
self.slickCompounds = ('SOFT', 'MEDIUM', 'HARD') self.slickCompounds = ('SOFT', 'MEDIUM', 'HARD')
\ No newline at end of file self.countOutPitstops = True
\ No newline at end of file
...@@ -12,7 +12,7 @@ from DataHandler import DataHandler ...@@ -12,7 +12,7 @@ from DataHandler import DataHandler
class DataPlotter(DataHandler): class DataPlotter(DataHandler):
def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: List[int], earliestTireChange: int, latestTireChange: int): def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: List[int], earliestTireChange: int, latestTireChange: int, raceName: str):
overtakesPerLap.insert(0, 0) # Insert 0th lap, which cannot have overtakes overtakesPerLap.insert(0, 0) # Insert 0th lap, which cannot have overtakes
laps: int = len(overtakesPerLap) laps: int = len(overtakesPerLap)
...@@ -24,6 +24,7 @@ class DataPlotter(DataHandler): ...@@ -24,6 +24,7 @@ class DataPlotter(DataHandler):
axis.set_xlabel('Lap') axis.set_xlabel('Lap')
axis.set_ylabel('Position changes in lap') axis.set_ylabel('Position changes in lap')
axis.set_title(raceName)
major_ticks_laps = np.arange(0, laps, 5) major_ticks_laps = np.arange(0, laps, 5)
major_ticks_overtakes = np.arange(0, max(overtakesPerLap) + 1, 5) major_ticks_overtakes = np.arange(0, max(overtakesPerLap) + 1, 5)
......
Todos.md 0 → 100644
# Todo (sorted by priority)
- Fetch rain races via API, not Reddit
- Adjust for pitstop discreptancies
- Include safety car periods & driver crashes
- Automatically determine if race is DWR or SWR
- Adjust for situations like Canada 2024 -> 2 drivers taking wets at the start does not constitute a weather change
- Implement actual 1/2 of drivers changing compounds rule
- Save data in CSV file
- Adjust for finding multiple weather changes in a race, not just one
- Read out number of drivers participating in session, rather than hardcoding number of drivers (since it might change from 20 to more (or less) in future)
- Also read out direct weather data from API
# Done
- Automatically title graph by race name (no more hardcoding the graph name)
\ No newline at end of file
...@@ -19,10 +19,10 @@ class Main: ...@@ -19,10 +19,10 @@ class Main:
def main(self): def main(self):
# contains pairs of season & race number to identify specific races # contains pairs of season & race number to identify specific races
race_indexes = [ race_indexes = [
[2022, 4] # Imola 2022 (DWR) [2022, 4], # Imola 2022 (DWR)
# [2024, 7] # Imola 2024 (SWR) [2024, 7], # Imola 2024 (SWR)
# [2024, 9] # Canada 2024 (DWR) [2024, 9], # Canada 2024 (DWR)
# [2023, 8] # Canada 2023 (SWR)
# TODO: add more races # TODO: add more races
] ]
...@@ -31,10 +31,14 @@ class Main: ...@@ -31,10 +31,14 @@ class Main:
plotter = DataPlotter() plotter = DataPlotter()
for race_index in race_indexes: for race_index in race_indexes:
# Import # Import
raceSession = importer.importRaceSession(race_index) raceSession = importer.importRaceSession(race_index)
raceName: str = f"{raceSession.event['EventName']} {raceSession.event.year}"
print("Import done") print("Import done")
# Analyse # Analyse
overtakesInRaces: List[int] = analyser.analyseRaceForOvertakes(raceSession) overtakesInRaces: List[int] = analyser.analyseRaceForOvertakes(raceSession)
print("Overtake analysis done") print("Overtake analysis done")
...@@ -44,11 +48,13 @@ class Main: ...@@ -44,11 +48,13 @@ class Main:
latestTireChange: int = analyser.getLatestTireChange(raceSession) latestTireChange: int = analyser.getLatestTireChange(raceSession)
print("Last tire change done") print("Last tire change done")
plotter.plotOvertakesWithTireChangeWindow(overtakesInRaces, earliestTireChange, latestTireChange)
print("Plot done")
# Plot
plotter.plotOvertakesWithTireChangeWindow(overtakesInRaces, earliestTireChange, latestTireChange, raceName)
print("Plot done")
# Print data
print(f"\n\n===== Data for race {race_index[0]}/{race_index[1]} =====") print(f"\n\n===== Data for race {race_index[0]}/{race_index[1]} =====")
print("Lap\tOvertakes") print("Lap\tOvertakes")
currentLap = 0 currentLap = 0
...@@ -60,70 +66,6 @@ class Main: ...@@ -60,70 +66,6 @@ class Main:
print(f"Weather change window is therefore: laps {earliestTireChange-1} - {latestTireChange+1}") print(f"Weather change window is therefore: laps {earliestTireChange-1} - {latestTireChange+1}")
def fastF1Example(self):
# Load FastF1's dark color scheme
fastf1.plotting.setup_mpl(mpl_timedelta_support=False, misc_mpl_mods=False,
color_scheme='fastf1')
session = fastf1.get_session(2024, 7, 'R')
session.load(laps=True, weather=True)
figure, axis = plt.subplots(figsize=(8.0, 4.9))
for driver in session.drivers:
driverLaps = session.laps.pick_drivers(driver)
driverAbbreviation = driverLaps['Driver'].iloc[0]
style = fastf1.plotting.get_driver_style(identifier=driverAbbreviation,
style=['color', 'linestyle'],
session=session)
axis.plot(driverLaps['LapNumber'], driverLaps['Position'],
label=driverAbbreviation, **style)
axis.set_ylim([20.5, 0.5])
axis.set_yticks([1, 5, 10, 15, 20])
axis.set_xlabel('Lap')
axis.set_ylabel('Position')
axis.legend(bbox_to_anchor=(1.0, 1.02))
plt.tight_layout()
plt.show()
def oldJavaTransfer(self):
# contains pairs of season & race number to identify specific races
race_indexes = [
[2024, 7], # Imola 2024
[2022, 4] # Imola 2022
# TODO: add more races
]
importer = DataImporter()
checker = DataChecker()
analyser = DataAnalyser()
# plotter = DataPlotter() # Commented as it's not used
races = importer.import_laps_for_races(race_indexes)
checker.check_imported_races(races)
overtakes_in_races = analyser.count_overtakes_in_races(races)
print(f"Data for race {race_indexes[0][1]}/{race_indexes[0][0]}")
for current_lap in range(len(overtakes_in_races[0])):
print(f"Overtakes in lap {current_lap + 1}: {overtakes_in_races[0][current_lap]}")
return overtakes_in_races
if __name__ == '__main__': if __name__ == '__main__':
app = Main() app = Main()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment