From d74335cb8ef2014cd18bce873f2fe54f01f03044 Mon Sep 17 00:00:00 2001
From: Lennard Geese <lennard.geese@sva.de>
Date: Wed, 9 Apr 2025 17:27:08 +0200
Subject: [PATCH] Implement painting graph background for weather change window

---
 DataPlotter.py | 75 +++++++++++++++++++++++++++++++++++++++++---------
 Todos.md       |  2 +-
 main.py        | 18 ++++++++----
 3 files changed, 75 insertions(+), 20 deletions(-)

diff --git a/DataPlotter.py b/DataPlotter.py
index 9b95e74..d0bbb6d 100644
--- a/DataPlotter.py
+++ b/DataPlotter.py
@@ -1,41 +1,90 @@
+import random
+
 import matplotlib.pyplot as plt
+import pandas as pd
+from matplotlib import cm
+import matplotlib as mpl
 import numpy as np
-from DataHandler import DataHandler
+from matplotlib.colors import ListedColormap
 
+from DataHandler import DataHandler
 
+# TODO: Adjust input parameters for multiple weather change windows
 class DataPlotter(DataHandler):
-    def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: list[int], earliestTireChange: int, latestTireChange: int, raceName: str):
+    def plotOvertakesWithTireChangeWindow(self, overtakesPerLap: list[int], firstTireChange: int, lastTireChange: int, raceName: str):
+
+        # TODO: Account for cases where no tire changes (meaning values of 0 or -1)
+        # TODO: Let visualization start at 0, but graph at 1
+        # Adjust values
+        #overtakesPerLap.insert(0, 0) # Insert 0th lap, which cannot have overtakes
+        firstTireChange -= 1
+        lastTireChange += 1
+
 
-        overtakesPerLap.insert(0, 0) # Insert 0th lap, which cannot have overtakes
         laps: int = len(overtakesPerLap)
+        plt.xlim(0, laps + 1) # set x-range of plot
+
 
-        figure, axis = plt.subplots(figsize=(8.0, 4.9))
+        # Define data range
+        x_values = np.arange(1, laps + 1)
+        plt.plot(x_values, overtakesPerLap)
 
-        axis.plot(overtakesPerLap)
 
 
+        axis = plt.gca()
+
+        # Label stuff
         axis.set_xlabel('Lap')
         axis.set_ylabel('Position changes in lap')
         axis.set_title(raceName)
 
-        major_ticks_laps = np.arange(0, laps, 5)
+        # Set ticks on axis
+        major_ticks_laps = np.arange(0, laps + 1, 5)
         major_ticks_overtakes = np.arange(0, max(overtakesPerLap) + 1, 5)
-        minor_ticks_laps = np.arange(0, laps, 1)
+        minor_ticks_laps = np.arange(0, laps + 1, 1)
         minor_ticks_overtakes = np.arange(0, max(overtakesPerLap) + 1, 1)
-
         axis.set_xticks(major_ticks_laps)
         axis.set_xticks(minor_ticks_laps, minor=True)
         axis.set_yticks(major_ticks_overtakes)
         axis.set_yticks(minor_ticks_overtakes, minor=True)
 
-        # And a corresponding grid
+        # Add grid
         axis.grid(which='both')
-
-        # Or if you want different settings for the grids:
         axis.grid(which='minor', alpha=0.2)
         axis.grid(which='major', alpha=0.5)
 
-
+        # Add legend
         axis.legend(bbox_to_anchor=(1.0, 1.02))
+
+        # Paint background between the first and last tire change
+        axis.axvspan(firstTireChange, lastTireChange, color='blue', alpha=0.3)
+
+
+
         plt.tight_layout()
-        plt.show()
\ No newline at end of file
+        plt.show()
+
+
+    def plotBackgroundPaintTest(self):
+
+        laps: int = 50
+        overtakesPerLap: list[int] = [random.randint(0,10) for _ in range(laps)]
+        firstTireChange: int = random.randint(10, 20)
+        lastTireChange: int = random.randint(30, 40)
+
+        isWeatherChanging: list[bool] = [False] * laps
+        for lap in range(laps):
+            if firstTireChange <= lap <= lastTireChange:
+                isWeatherChanging[lap] = True
+
+        colormap = mpl.colors.ListedColormap(['white', 'blue'])
+        dataFrame = pd.DataFrame(overtakesPerLap)
+        dataFrame[1] = isWeatherChanging
+        axis = dataFrame[0].plot()
+        axis.pcolorfast(axis.get_xlim(), axis.get_ylim(),
+                        dataFrame[1].values[np.newaxis],
+                        cmap=colormap, alpha=0.3)
+
+        plt.show()
+
+
diff --git a/Todos.md b/Todos.md
index 14da210..d34f5ff 100644
--- a/Todos.md
+++ b/Todos.md
@@ -2,7 +2,7 @@
 - [x] Automatically title graph by race name (no more hardcoding the graph name)
 - [x] Adjust for pitstop discrepancies
 - [x] Fetch rain races via API, not Reddit
-- [ ] Paint back of graph for weather change window
+- [x] Paint back of graph for weather change window
 - [ ] Adjust for position changes caused by crashes (keep out of calculation similarly to PCs due to pitstops ?)
 - [ ] Include safety car periods & driver crashes
 - [ ] Automatically determine if race is DWR or SWR
diff --git a/main.py b/main.py
index d462a51..b10339d 100644
--- a/main.py
+++ b/main.py
@@ -18,12 +18,10 @@ class Main:
 
     def main(self):
 
-        dataHandler: Main.DataHandlingPackage = Main.DataHandlingPackage()
-        year: int = 2015
-        rainRaces: list[Session] = dataHandler.importer.getRainRacesSince(year)
-        print(f"Rain races since {max(year, 2018)}")
-        for rainRace in rainRaces:
-            print(rainRace)
+        #dataHandler = Main.DataHandlingPackage()
+        #dataHandler.plotter.plotBackgroundPaintTest()
+
+        # self.printRainRaces()
 
         racesToAnalyse = [
             SessionIdentifier(2022, "Imola", "R"),      # Imola 2022 (DWR)
@@ -34,6 +32,14 @@ class Main:
         self.overtakeAnalysis(racesToAnalyse)
 
 
+    def printRainRaces(self):
+        dataHandler: Main.DataHandlingPackage = Main.DataHandlingPackage()
+        year: int = 2015
+        rainRaces: list[Session] = dataHandler.importer.getRainRacesSince(year)
+        print(f"Rain races since {max(year, 2018)}")
+        for rainRace in rainRaces:
+            print(rainRace)
+
     def overtakeAnalysis(self, raceSessionIdentifiers: list[SessionIdentifier]):
         dataHandler: Main.DataHandlingPackage = self.DataHandlingPackage()
 
-- 
GitLab