From 34cd10c92c985bb4ca8ff449ff6572a9a91d3a59 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Wed, 15 May 2024 11:52:47 +0200 Subject: [PATCH 01/31] FIX: support starting SignalR client when an event loop is already running (fixes #521) --- fastf1/livetiming/client.py | 49 ++++++++++++++++++++- fastf1/signalr_aio/transports/_transport.py | 9 ++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/fastf1/livetiming/client.py b/fastf1/livetiming/client.py index 7a8261a60..4a845f682 100644 --- a/fastf1/livetiming/client.py +++ b/fastf1/livetiming/client.py @@ -101,6 +101,7 @@ def __init__(self, filename: str, filemode: str = 'w', debug: bool = False, format="%(asctime)s - %(levelname)s: %(message)s" ) self.logger = logging.getLogger('SignalR') + self.logger.setLevel(logging.INFO) else: self.logger = logger @@ -175,8 +176,12 @@ async def _supervise(self): and time.time() - self._t_last_message > self.timeout): self.logger.warning(f"Timeout - received no data for more " f"than {self.timeout} seconds!") + self._connection.close() + while self._connection.started: + await asyncio.sleep(0.1) return + await asyncio.sleep(1) async def _async_start(self): @@ -189,8 +194,50 @@ async def _async_start(self): def start(self): """Connect to the data stream and start writing the data to a file.""" + try: + # try to get an already running loop (e.g. in newer IPython) + loop = asyncio.get_running_loop() + except RuntimeError: + # there is no running loop yet + self._start_without_existing_loop() + return + + try: + __IPYTHON__ # noqa + is_ipython = True + except NameError: + is_ipython = False + + if loop and is_ipython: + raise RuntimeError( + "Running in an asynchronous IPython session. " + "Please use `await SignalRClient().async_start()`" + ) + + else: + raise RuntimeError( + "Cannot start because an asynchronous event loop already " + "exists. You can try to use the " + "`SignalRClient().async_start()` coroutine." + ) + + async def async_start(self): + """ + Connect to the data stream and start writing the data to a file + when running inside an existing event loop. + + In most cases, you want to use :func:`start` instead. + """ + loop = asyncio.get_running_loop() + try: + task = loop.create_task(self._async_start()) + while not task.done(): + await asyncio.sleep(1) + except asyncio.CancelledError: + self.logger.warning("Async execution cancelled - exiting...") + + def _start_without_existing_loop(self): try: asyncio.run(self._async_start()) except KeyboardInterrupt: self.logger.warning("Keyboard interrupt - exiting...") - return diff --git a/fastf1/signalr_aio/transports/_transport.py b/fastf1/signalr_aio/transports/_transport.py index ec0edd4a7..902a0ac2b 100644 --- a/fastf1/signalr_aio/transports/_transport.py +++ b/fastf1/signalr_aio/transports/_transport.py @@ -93,6 +93,15 @@ async def _master_handler(self, ws): for task in pending: task.cancel() + try: + consumer_exception = consumer_task.exception() + except asyncio.CancelledError: + pass + else: + if not isinstance(consumer_exception, + websockets.exceptions.ConnectionClosedOK): + raise consumer_exception + async def _consumer_handler(self, ws): while True: message = await ws.recv() From a61e4f00f9a800e07fbb04083e4a136b6314c166 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Wed, 15 May 2024 16:11:42 +0200 Subject: [PATCH 02/31] FIX: incorrect circuit info for Mugello 2020 (fixes #563) --- fastf1/core.py | 6 ++++++ fastf1/mvapi/data.py | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fastf1/core.py b/fastf1/core.py index e16bae1c7..4a3b40dd7 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -2468,6 +2468,12 @@ def get_circuit_info(self) -> Optional[CircuitInfo]: See :class:`~fastf1.mvapi.CircuitInfo` for detailed information. """ circuit_key = self.session_info['Meeting']['Circuit']['Key'] + + if ((circuit_key == 149) + and (self.session_info['Meeting']['Circuit']['ShortName'] + == 'Mugello')): + circuit_key = 146 + circuit_info = get_circuit_info(year=self.event.year, circuit_key=circuit_key) circuit_info.add_marker_distance( diff --git a/fastf1/mvapi/data.py b/fastf1/mvapi/data.py index 58bd81900..8088c8038 100644 --- a/fastf1/mvapi/data.py +++ b/fastf1/mvapi/data.py @@ -135,7 +135,8 @@ def get_circuit_info(*, year: int, circuit_key: int) -> Optional[CircuitInfo]: ret = list() for cat in ('corners', 'marshalLights', 'marshalSectors'): rows = list() - for entry in data[cat]: + array = data.get(cat) or list() + for entry in array: rows.append(( float(entry.get('trackPosition', {}).get('x', 0.0)), float(entry.get('trackPosition', {}).get('y', 0.0)), From 3cd2bf434d9da49d7309cc855847add0cbe9a5c5 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Wed, 15 May 2024 16:57:18 +0200 Subject: [PATCH 03/31] FIX: crash laps missing track status (fixes #575) --- fastf1/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastf1/core.py b/fastf1/core.py index 4a3b40dd7..0337b9edc 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -1749,6 +1749,8 @@ def _fix_missing_laps_retired_on_track(self): 'IsAccurate': [False] }) + self._add_track_status_to_laps(new_last) + # add generated laps at the end and fix sorting at the end self._laps = (pd.concat([self._laps, new_last]) .__finalize__(self._laps)) From 2814e506694f5dfec1e634ec266f1f9fdb2218b0 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Wed, 15 May 2024 19:09:29 +0200 Subject: [PATCH 04/31] CLN/FIX: unify lt parser categories, speed up, more cleanup (fixes #542) --- fastf1/__init__.py | 50 ------------ fastf1/_api.py | 6 +- fastf1/core.py | 52 ++++++++----- fastf1/livetiming/data.py | 130 ++++++++++++-------------------- fastf1/tests/test_livetiming.py | 10 ++- 5 files changed, 89 insertions(+), 159 deletions(-) diff --git a/fastf1/__init__.py b/fastf1/__init__.py index b1eafbae4..a8ff04a0b 100644 --- a/fastf1/__init__.py +++ b/fastf1/__init__.py @@ -103,8 +103,6 @@ __version_short__ = __version__ -from typing import Dict - from fastf1.events import get_session # noqa: F401 from fastf1.events import ( # noqa: F401 get_event, @@ -118,51 +116,3 @@ Cache, RateLimitExceededError ) - - -_DRIVER_TEAM_MAPPING: Dict[str, Dict[str, str]] = { - # only necessary when loading live timing data that does not include - # the driver and team listing and no data is available on ergast yet - '23': {'Abbreviation': 'ALB', 'FirstName': 'Alexander', - 'LastName': 'Albon', 'TeamName': 'Williams'}, - '14': {'Abbreviation': 'ALO', 'FirstName': 'Fernando', - 'LastName': 'Alonso', 'TeamName': 'Alpine F1 Team'}, - '77': {'Abbreviation': 'BOT', 'FirstName': 'Valtteri', - 'LastName': 'Bottas', 'TeamName': 'Alfa Romeo'}, - '10': {'Abbreviation': 'GAS', 'FirstName': 'Pierre', - 'LastName': 'Gasly', 'TeamName': 'AlphaTauri'}, - '44': {'Abbreviation': 'HAM', 'FirstName': 'Lewis', - 'LastName': 'Hamilton', 'TeamName': 'Mercedes'}, - '27': {'Abbreviation': 'HUL', 'FirstName': 'Nico', - 'LastName': 'Hülkenberg', 'TeamName': 'Aston Martin'}, - '6': {'Abbreviation': 'LAT', 'FirstName': 'Nicholas', - 'LastName': 'Latifi', 'TeamName': 'Williams'}, - '16': {'Abbreviation': 'LEC', 'FirstName': 'Charles', - 'LastName': 'Leclerc', 'TeamName': 'Ferrari'}, - '20': {'Abbreviation': 'MAG', 'FirstName': 'Kevin', - 'LastName': 'Magnussen', 'TeamName': 'Haas F1 Team'}, - '4': {'Abbreviation': 'NOR', 'FirstName': 'Lando', - 'LastName': 'Norris', 'TeamName': 'McLaren'}, - '31': {'Abbreviation': 'OCO', 'FirstName': 'Esteban', - 'LastName': 'Ocon', 'TeamName': 'Alpine F1 Team'}, - '11': {'Abbreviation': 'PER', 'FirstName': 'Sergio', - 'LastName': 'Pérez', 'TeamName': 'Red Bull'}, - '3': {'Abbreviation': 'RIC', 'FirstName': 'Daniel', - 'LastName': 'Ricciardo', 'TeamName': 'McLaren'}, - '63': {'Abbreviation': 'RUS', 'FirstName': 'George', - 'LastName': 'Russell', 'TeamName': 'Mercedes'}, - '55': {'Abbreviation': 'SAI', 'FirstName': 'Carlos', - 'LastName': 'Sainz', 'TeamName': 'Ferrari'}, - '47': {'Abbreviation': 'MSC', 'FirstName': 'Mick', - 'LastName': 'Schumacher', 'TeamName': 'Haas F1 Team'}, - '18': {'Abbreviation': 'STR', 'FirstName': 'Lance', - 'LastName': 'Stroll', 'TeamName': 'Aston Martin'}, - '22': {'Abbreviation': 'TSU', 'FirstName': 'Yuki', - 'LastName': 'Tsunoda', 'TeamName': 'AlphaTauri'}, - '1': {'Abbreviation': 'VER', 'FirstName': 'Max', - 'LastName': 'Verstappen', 'TeamName': 'Red Bull'}, - '5': {'Abbreviation': 'VET', 'FirstName': 'Sebastian', - 'LastName': 'Vettel', 'TeamName': 'Aston Martin'}, - '24': {'Abbreviation': 'ZHO', 'FirstName': 'Guanyu', - 'LastName': 'Zhou', 'TeamName': 'Alfa Romeo'} -} diff --git a/fastf1/_api.py b/fastf1/_api.py index 9d07fa72e..da4acd6c6 100644 --- a/fastf1/_api.py +++ b/fastf1/_api.py @@ -1237,7 +1237,7 @@ def track_status_data(path, response=None, livedata=None): if livedata is not None and livedata.has('TrackStatus'): # does not need any further processing _logger.info("Loading track status data") - return livedata.get('TrackStatus') + response = livedata.get('TrackStatus') elif response is None: _logger.info("Fetching track status data...") response = fetch_page(path, 'track_status') @@ -1293,7 +1293,7 @@ def session_status_data(path, response=None, livedata=None): if livedata is not None and livedata.has('SessionStatus'): # does not need any further processing _logger.info("Loading session status data") - return livedata.get('SessionStatus') + response = livedata.get('SessionStatus') elif response is None: _logger.info("Fetching session status data...") response = fetch_page(path, 'session_status') @@ -1364,7 +1364,7 @@ def race_control_messages(path, response=None, livedata=None): if livedata is not None and livedata.has('RaceControlMessages'): # does not need any further processing _logger.info("Loading race control messages") - return livedata.get('RaceControlMessages') + response = livedata.get('RaceControlMessages') elif response is None: _logger.info("Fetching race control messages...") response = fetch_page(path, 'race_control_messages') diff --git a/fastf1/core.py b/fastf1/core.py index 0337b9edc..c49f7a091 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -1472,16 +1472,10 @@ def _load_laps_data(self, livedata=None): # no driver list, generate from lap data drivers = set(data['Driver'].unique()) \ .intersection(set(useful['Driver'].unique())) - _nums_df = pd.DataFrame({'DriverNumber': list(drivers)}, index=list(drivers)) - _info_df = pd.DataFrame(fastf1._DRIVER_TEAM_MAPPING).T - - self._results = SessionResults(_nums_df.join(_info_df), - force_default_cols=True) - - _logger.warning("Generating minimal driver " - "list from timing data.") + self._results = SessionResults(_nums_df, force_default_cols=True) + _logger.warning("Generating minimal driver list from timing data.") df = None for _, driver in enumerate(drivers): @@ -2184,21 +2178,24 @@ def _load_drivers_results(self, *, livedata=None): # set results from either source or join if both data is available # use driver info from F1 as primary source, only fall back to Ergast # if unavailable - # use results from Ergast, unavailable from F1 API + # use results from Ergast, if data is unavailable from F1 API + + no_driver_info_f1 = (driver_info_f1 is None) or driver_info_f1.empty + no_driver_info_ergast \ + = (driver_info_ergast is None) or driver_info_ergast.empty # no data - if (driver_info_f1 is None) and (driver_info_ergast is None): # LP1 - _logger.warning("Failed to load driver list and " - "session results!") + if no_driver_info_f1 and no_driver_info_ergast: + _logger.warning("Failed to load driver list and session results!") self._results = SessionResults(force_default_cols=True) # only Ergast data - elif driver_info_f1 is None: # LP2 + elif no_driver_info_f1: # LP2 self._results = SessionResults(driver_info_ergast, force_default_cols=True) # only F1 data - elif driver_info_ergast is None: # LP3 + elif no_driver_info_ergast: self._results = SessionResults(driver_info_f1, force_default_cols=True) @@ -2244,21 +2241,38 @@ def _drivers_from_f1_api(self, *, livedata=None): driver_info = {} else: driver_info = collections.defaultdict(list) + for key1, key2 in { - 'RacingNumber': 'DriverNumber', 'BroadcastName': 'BroadcastName', - 'Tla': 'Abbreviation', 'TeamName': 'TeamName', - 'TeamColour': 'TeamColor', 'FirstName': 'FirstName', - 'LastName': 'LastName', 'HeadshotUrl': 'HeadshotUrl', + 'Tla': 'Abbreviation', + 'TeamName': 'TeamName', + 'TeamColour': 'TeamColor', + 'FirstName': 'FirstName', + 'LastName': 'LastName', + 'HeadshotUrl': 'HeadshotUrl', 'CountryCode': 'CountryCode' }.items(): for entry in f1di.values(): driver_info[key2].append(entry.get(key1)) + + # special case for driver number which seems to be duplicated and + # is used as dictionary key as well; use explicit racing number + # property when available, else fallback to using dict key + for key, entry in f1di.items(): + driver_info['DriverNumber'].append( + entry.get('RacingNumber') or key + ) + if 'FirstName' in driver_info and 'LastName' in driver_info: for first, last in zip(driver_info['FirstName'], driver_info['LastName']): driver_info['FullName'].append(f"{first} {last}") - return pd.DataFrame(driver_info, index=driver_info['DriverNumber']) + + # driver info is required for joining on index (used as index), + # therefore drop rows where driver number is unavailable as they have + # an invalid index + return pd.DataFrame(driver_info, index=driver_info['DriverNumber']) \ + .dropna(subset=['DriverNumber']) def _drivers_results_from_ergast( self, *, load_drivers=False, load_results=False diff --git a/fastf1/livetiming/data.py b/fastf1/livetiming/data.py index ab2ed3ebf..220b3e48e 100644 --- a/fastf1/livetiming/data.py +++ b/fastf1/livetiming/data.py @@ -2,8 +2,8 @@ Data object for livetiming data """ -import hashlib import json +import warnings from datetime import timedelta from fastf1.logger import get_logger @@ -50,27 +50,23 @@ class LiveTimingData: Args: *files (str): One or multiple file names - remove_duplicates (bool): Remove duplicate lines. Mainly useful when - loading multiple overlapping recordings. (Checking for duplicates - is currently very slow for large files. Therefore, it can be - disabled if this may cause problems.) """ - def __init__(self, *files, remove_duplicates=True): + def __init__(self, *files, **kwargs): # file names self.files = files # parsed data self.data = dict() # number of json errors self.errorcount = 0 - # flag for auto loading on first access + # flag for automatic data loading on first access self._files_read = False # date when session was started self._start_date = None - # whether any files were loaded previously, i.e. appending data - self._previous_files = False - # hash each line, used to skip duplicates from multiple files - self._line_hashes = list() - self._remove_duplicates = remove_duplicates + + if 'remove_duplicates' in kwargs: + warnings.warn("The argument `remove_duplicates` is no longer " + "available. Duplicates caused by overlapping files " + "will now always be removed.") def load(self): """ @@ -82,21 +78,52 @@ def load(self): """ _logger.info("Reading live timing data from recording. " "This may take a bit.") - for fname in self.files: - self._load_single_file(fname) + + is_first = True + _files = [*self.files, None] + current_data, next_data = None, None + + # We always need the current and next file loaded, so we can detect + # where they overlap. The "next" file then becomes the "current" file + # and the next "next" file is read. + for next_file in _files: + # make the previous "next" file the "current" file + current_data = next_data + + if next_file is None: + # reached the end, there is no subsequent data anymore + next_data = None + else: + # read a new file as next file + with open(next_file, 'r') as fobj: + next_data = fobj.readlines() + + if current_data is None: + # there is no "current" file yet (i.e. first iteration), + # skip ahead once right away to read one more file + continue + + next_line = next_data[0] if next_data else None + + self._load_single_file(current_data, + is_first_file=is_first, + next_line=next_line) + is_first = False + + # set flag that all files have been read self._files_read = True - def _load_single_file(self, fname): - # read one file, parse its content and add it to the already loaded + def _load_single_file(self, data, *, is_first_file, next_line): + # parse its content and add it to the already loaded # data (if there is data already) - with open(fname, 'r') as fobj: - data = fobj.readlines() # try to find the correct start date (only if this is the first file) - if not self._previous_files: + if is_first_file: self._try_set_correct_start_date(data) for line in data: + if line == next_line: + break self._parse_line(line) # first file was loaded, others are appended if any more are loaded @@ -105,14 +132,6 @@ def _load_single_file(self, fname): def _parse_line(self, elem): # parse a single line of data - if self._remove_duplicates: - # prevent duplicates when loading data (slow, but it works...) - # allows to load data from overlapping recordings - lhash = hashlib.md5(elem.encode()).hexdigest() - if lhash in self._line_hashes: - return - self._line_hashes.append(lhash) - # load the three parts of each data element elem = self._fix_json(elem) try: @@ -136,17 +155,7 @@ def _parse_line(self, elem): else: td = dt - self._start_date - self._store_message(cat, td, msg) - - def _store_message(self, cat, td, msg): - # stores parsed messages by category - # TrackStatus and SessionStatus categories need special handling - if cat == 'SessionData': - self._parse_session_data(msg) - elif cat == 'RaceControlMessages': - self._parse_race_control_message(msg) - elif cat not in ('TrackStatus', 'SessionStatus'): - self._add_to_category(cat, [td, msg]) + self._add_to_category(cat, [td, msg]) def _fix_json(self, elem): # fix F1's not json compliant data @@ -161,51 +170,6 @@ def _add_to_category(self, cat, entry): else: self.data[cat].append(entry) - def _parse_session_data(self, msg): - # make sure the categories exist as we want to append to them - if 'TrackStatus' not in self.data: - self.data['TrackStatus'] = {'Time': [], 'Status': [], - 'Message': []} - if 'SessionStatus' not in self.data: - self.data['SessionStatus'] = {'Time': [], 'Status': []} - - if ('StatusSeries' in msg) and isinstance(msg['StatusSeries'], dict): - for entry in msg['StatusSeries'].values(): - # convert timestamp to timedelta - try: - status_dt = to_datetime(entry['Utc']) - except (KeyError, ValueError, TypeError): - self.errorcount += 1 - continue - status_timedelta = status_dt - self._start_date - - # add data to category - if 'TrackStatus' in entry.keys(): - status_value = str(entry['TrackStatus']) - # convert to numeric system used by the api - if not status_value.isnumeric(): - status_value = _track_status_mapping[status_value] - self.data['TrackStatus']['Time'].append(status_timedelta) - self.data['TrackStatus']['Status'].append(status_value) - self.data['TrackStatus']['Message'].append("") - - elif 'SessionStatus' in entry.keys(): - self.data['SessionStatus']['Time'].append(status_timedelta) - self.data['SessionStatus']['Status'].append(entry['SessionStatus']) - - def _parse_race_control_message(self, msg): - if 'RaceControlMessages' not in self.data: - self.data['RaceControlMessages'] = { - 'Utc': [], 'Category': [], 'Message': [], 'Status': [], - 'Flag': [], 'Scope': [], 'Sector': [], 'RacingNumber': [] - } - - if ('Messages' in msg) and isinstance(msg['Messages'], dict): - for data in msg['Messages'].values(): - for key in ('Utc', 'Category', 'Message', 'Status', 'Flag', - 'Scope', 'Sector', 'RacingNumber'): - self.data['RaceControlMessages'][key].append(data.get(key)) - def _try_set_correct_start_date(self, data): # skim content to find 'Started' session status without actually # decoding each line to save time diff --git a/fastf1/tests/test_livetiming.py b/fastf1/tests/test_livetiming.py index 611900255..2105d91fb 100644 --- a/fastf1/tests/test_livetiming.py +++ b/fastf1/tests/test_livetiming.py @@ -25,16 +25,18 @@ def test_file_loading(): def test_duplicate_removal(tmpdir): # create a temporary file with two identical lines of data tmpfile = os.path.join(tmpdir, 'tmpfile.txt') + tmpfile2 = os.path.join(tmpdir, 'tmpfile2.txt') + data = "['TimingAppData', {'Lines': {'22': {'Stints': {'0': {" \ "'LapFlags': 0, 'Compound': 'UNKNOWN', 'New': 'false'," \ "'TyresNotChanged': '0', 'TotalLaps': 0, 'StartLaps':" \ "0}}}}}, '2021-03-27T12:00:32.086Z']\n" + with open(tmpfile, 'w') as fobj: fobj.write(data) + + with open(tmpfile2, 'w') as fobj: fobj.write(data) - livedata = LiveTimingData(tmpfile) + livedata = LiveTimingData(tmpfile, tmpfile2) assert len(livedata.get('TimingAppData')) == 1 - - livedata = LiveTimingData(tmpfile, remove_duplicates=False) - assert len(livedata.get('TimingAppData')) == 2 From 2cc9a159e17a75d1f7d35059f7dd530386444b32 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Thu, 16 May 2024 13:43:10 +0200 Subject: [PATCH 05/31] MNT: changelog for v3.3.6 --- docs/changelog/v3.3.x.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/changelog/v3.3.x.rst b/docs/changelog/v3.3.x.rst index 0293fd1fc..87859d694 100644 --- a/docs/changelog/v3.3.x.rst +++ b/docs/changelog/v3.3.x.rst @@ -1,3 +1,25 @@ +What's new in v3.3.6 +-------------------- + +(released 16/05/2024) + + +Bug Fixes +^^^^^^^^^ + +- Laps where a driver crashes and retires on track now contain a correct + track status (fixes #575) + +- Fixed previously incorrect circuit info for Mugello 2020 (fixes #563) + + +Others +^^^^^^ + +- Improved a warning message that informs about missing data when calculating + qualification results + + What's new in v3.3.5 -------------------- From f3b0e46863b824b8fde288869eac78b7f962768a Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Tue, 28 May 2024 12:48:08 +0200 Subject: [PATCH 06/31] FIX: missing first lap in Monaco 2024 race in timing data (fixes #594) --- fastf1/_api.py | 24 +++++++++++++++++------- fastf1/req.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/fastf1/_api.py b/fastf1/_api.py index da4acd6c6..7374614c6 100644 --- a/fastf1/_api.py +++ b/fastf1/_api.py @@ -423,13 +423,6 @@ def _laps_data_driver(driver_raw, empty_vals, drv): in_past = True continue - if (lapcnt == 0) and ((drv_data['Time'][lapcnt] - to_timedelta(time)) > pd.Timedelta(5, 'min')): - # ignore any data which arrives more than 5 minutes before the end of the first lap, except 'PitOut' - if ('InPit' in resp) and (resp['InPit'] is False): - drv_data['PitOutTime'][lapcnt] = to_timedelta(time) - pitstops = 0 # special here, can be multiple times for no reason therefore set zero instead of +=1 - continue - # values which are up to five seconds late are still counted towards the previous lap # (sector times, speed traps and lap times) lap_offset = 0 @@ -706,6 +699,23 @@ def data_in_lap(lap_n): else: drv_data['IsPersonalBest'][pb_idx] = True + # fix the number of pit stops; due to potentially multiple laps to the grid + # where a car goes through the pit lane before finally taking its place + # on the grid, the number of pit stops on the first lap may be already + # greater than zero; therefore, apply correction so that we start with zero + pitstop_offset = drv_data['NumberOfPitStops'][0] + for i in range(len(drv_data['NumberOfPitStops'])): + drv_data['NumberOfPitStops'][i] -= pitstop_offset + + # fix first lap PitInTime; same reason as above for pit stops, there may + # be an incorrect PitInTime on the first lap. There always is a PitOutTime + # for when the car leaves the box for the lap to the grid. There is a + # PitInTime if the car drives multiple laps to the grid, discard these. + # There is also a PitInTime if the car actually pits at the end of the + # first lap, those need to be kept. + if drv_data['PitInTime'][0] < drv_data['PitOutTime'][0]: + drv_data['PitInTime'][0] = pd.NaT + if integrity_errors: _logger.warning( f"Driver {drv: >2}: Encountered {len(integrity_errors)} timing " diff --git a/fastf1/req.py b/fastf1/req.py index faa76e390..d03d81923 100644 --- a/fastf1/req.py +++ b/fastf1/req.py @@ -213,7 +213,7 @@ class Cache(metaclass=_MetaCache): """ _CACHE_DIR = None # version of the api parser code (unrelated to release version number) - _API_CORE_VERSION = 12 + _API_CORE_VERSION = 13 _IGNORE_VERSION = False _FORCE_RENEW = False From 7f412fb1f29b43402a8be5fd6118204f79979dc3 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Tue, 28 May 2024 15:08:04 +0200 Subject: [PATCH 07/31] MNT: changelog for v3.3.7 --- docs/changelog/v3.3.x.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/changelog/v3.3.x.rst b/docs/changelog/v3.3.x.rst index 87859d694..6c7982d5d 100644 --- a/docs/changelog/v3.3.x.rst +++ b/docs/changelog/v3.3.x.rst @@ -1,3 +1,16 @@ +What's new in v3.3.7 +-------------------- + +(released 28/05/2024) + + +Bug Fixes +^^^^^^^^^ + +- Fixed a bug that caused the timing data for the first lap of the Monaco GP + 2024 to be missing entirely (fixes #579) + + What's new in v3.3.6 -------------------- From 193168c7ebad0ae934fd2de53537a3f649f16e98 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:04:10 +0200 Subject: [PATCH 08/31] FIX: session results for Sprint Quali in 2024 not calculated (#597) --- fastf1/core.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/fastf1/core.py b/fastf1/core.py index c49f7a091..44bbace46 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -2293,16 +2293,23 @@ def _get_data(): return self._ergast.get_race_results( self.event.year, self.event.RoundNumber ) + elif session_name == 'Qualifying': return self._ergast.get_qualifying_results( self.event.year, self.event.RoundNumber ) - elif session_name in ('Sprint', 'Sprint Qualifying'): + + # double condition because of reuse of the "Sprint Qualifying" name + # for a race-like session in 2018 and a quali-like session in 2024+ + # Ergast only supports the race-like sprint results. + elif ('Sprint' in session_name + and session_name in self._RACE_LIKE_SESSIONS): return self._ergast.get_sprint_results( self.event.year, self.event.RoundNumber ) + else: - # TODO: Use Ergast when/if it supports sprint shootout sessions + # TODO: Use Ergast when it supports quali-like sprint results # return self._ergast.get_sprint_shootout_results( # self.event.year, self.event.RoundNumber # ) @@ -2311,8 +2318,15 @@ def _get_data(): response = _get_data() if not response or not response.content: - _logger.warning("No result data for this session available on " - "Ergast! (This is expected for recent sessions)") + if (('Sprint' in session_name) + and (session_name in self._QUALI_LIKE_SESSIONS)): + _logger.warning(f"{session_name} is not supported by " + f"Ergast! Limited results are calculated from " + f"timing data.") + else: + _logger.warning("No result data for this session available on " + "Ergast! (This is expected for recent " + "sessions)") return None data = response.content[0] From 84500c99e972eec0b5a7c0c5531ecda8ae1e5350 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:39:53 +0200 Subject: [PATCH 09/31] MNT: changelog for v3.3.8 --- docs/changelog/v3.3.x.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/changelog/v3.3.x.rst b/docs/changelog/v3.3.x.rst index 6c7982d5d..9f1b6a82c 100644 --- a/docs/changelog/v3.3.x.rst +++ b/docs/changelog/v3.3.x.rst @@ -1,3 +1,15 @@ +What's new in v3.3.8 +-------------------- + +(released 10/06/2024) + +Bug Fixes +^^^^^^^^^ + +- Resolved an issue where the majority of data was missing from the 2024 + Sprint Qualifying session results (fixes #597). + + What's new in v3.3.7 -------------------- From 6cb68db66aa61b26b939c685f92c9743cb7e62de Mon Sep 17 00:00:00 2001 From: AND2797 <37261177+AND2797@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:43:01 +0100 Subject: [PATCH 10/31] FIX: Assign NaN position for drivers that crashed in Lap 1 (#595) fixes #569 --- fastf1/core.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fastf1/core.py b/fastf1/core.py index 44bbace46..455dde68d 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -1628,6 +1628,13 @@ def _load_laps_data(self, livedata=None): laps.loc[laps['LapNumber'] == lap_n, 'Position'] \ = laps_eq_n.sort_index()['Position'].to_list() + # assign NaN to drivers who crashed on lap 1 + lap_counts = laps['Driver'].value_counts() + drivers_with_one_lap = lap_counts[lap_counts == 1].index + dnf_and_generated = (laps['FastF1Generated'] & + laps['Driver'].isin(drivers_with_one_lap)) + laps.loc[dnf_and_generated, 'Position'] = np.NaN + self._add_track_status_to_laps(laps) self._laps = Laps(laps, session=self, force_default_cols=True) From 70c038afabcc3cd5285a793e1014a36cfc9d1ffa Mon Sep 17 00:00:00 2001 From: Casper Guo Date: Tue, 11 Jun 2024 13:21:03 -0400 Subject: [PATCH 11/31] DOC: fix misc typos (#600) --- docs/contributing/documenting_fastf1.rst | 2 +- docs/examples/index.rst | 2 +- docs/time_explanation.rst | 2 +- fastf1/req.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/contributing/documenting_fastf1.rst b/docs/contributing/documenting_fastf1.rst index db538a45b..583d119d8 100644 --- a/docs/contributing/documenting_fastf1.rst +++ b/docs/contributing/documenting_fastf1.rst @@ -59,7 +59,7 @@ In general, the style guidelines and formatting conventions described in https://matplotlib.org/stable/devel/documenting_mpl.html should be applied to FastF1 as well. -One noteable exception is that FastF1 uses the `google docstring standard +One notable exception is that FastF1 uses the `google docstring standard `_ instead of the numpydoc format. diff --git a/docs/examples/index.rst b/docs/examples/index.rst index a689a24d3..d11e7b5de 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -14,7 +14,7 @@ This section offers various examples to get started with FastF1. Example Plot ============ -FastF1 is largely built ontop of Pandas DataFrames and Series. But It adds +FastF1 is largely built on top of Pandas DataFrames and Series. But It adds its own convenient methods for working specifically with F1 data. This makes it much easier to get started and work with the data in general. Still, you have all the capabilities of Pandas at hand whenever you need them. diff --git a/docs/time_explanation.rst b/docs/time_explanation.rst index 728c58cde..cebf3c9dd 100644 --- a/docs/time_explanation.rst +++ b/docs/time_explanation.rst @@ -98,7 +98,7 @@ Next, the data is sliced to only include a subset of the full session. zero is now the first sample of this set of data. If this subset of data was sliced again, `Time` would change again so as to start at zero on the first sample. -All three of these values have a use for different reasons. Here are some exmaples. +All three of these values have a use for different reasons. Here are some examples. To check which other cars are on track while one driver is on a fast lap `SessionTime` is useful. diff --git a/fastf1/req.py b/fastf1/req.py index d03d81923..d23a01f31 100644 --- a/fastf1/req.py +++ b/fastf1/req.py @@ -150,7 +150,7 @@ class Cache(metaclass=_MetaCache): Fast-F1 will per default enable caching. While this can be disabled, it should almost always be left enabled to speed up the runtime of your - 0scripts and to prevent exceeding the rate limit of api servers. + scripts and to prevent exceeding the rate limit of api servers. The default cache directory is defined, in order of precedence, in one of the following ways: From 1dc86a063e344f07150cab92f6721e894a5c856e Mon Sep 17 00:00:00 2001 From: Graham White <9819480+grahamjwhite@users.noreply.github.com> Date: Sat, 6 Jul 2024 02:26:38 +1000 Subject: [PATCH 12/31] [ENH] Add COL to driver dictionaries (#609) --- fastf1/events.py | 2 +- fastf1/plotting.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fastf1/events.py b/fastf1/events.py index f3c682a85..a88e3fff4 100644 --- a/fastf1/events.py +++ b/fastf1/events.py @@ -887,7 +887,7 @@ def __init__(self, *args, year: int = 0, if self[col].isna().all(): if _type == 'datetime64[ns]': self[col] = pd.NaT - elif _type == object: + elif _type == object: # noqa: E721, type comparison with == self[col] = None else: self[col] = _type() diff --git a/fastf1/plotting.py b/fastf1/plotting.py index f5e88c515..9ac64d7b1 100644 --- a/fastf1/plotting.py +++ b/fastf1/plotting.py @@ -145,6 +145,7 @@ def warn_change(self): "alexander albon": "#005aff", "logan sargeant": "#012564", "zak osullivan": "#1b3d97", + "franco colapinto": "#639aff" } """Mapping of driver names to driver colors (hex color codes). (current season only)""" @@ -170,7 +171,7 @@ def warn_change(self): 'HAM': 'lewis hamilton', 'RUS': 'george russell', 'VES': 'frederik vesti', 'ALB': 'alexander albon', 'SAR': 'logan sargeant', - 'OSU': 'zak osullivan'} + 'OSU': 'zak osullivan', 'COL': 'franco colapinto'} """Mapping of driver names to theirs respective abbreviations.""" COMPOUND_COLORS: Dict[str, str] = { From 7d7a248b520163f4401e5a999b53f90fa4150155 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 5 Jul 2024 18:07:07 +0200 Subject: [PATCH 13/31] MNT: changelog for v3.3.9 --- docs/changelog/v3.3.x.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/changelog/v3.3.x.rst b/docs/changelog/v3.3.x.rst index 9f1b6a82c..fc0b0f5f2 100644 --- a/docs/changelog/v3.3.x.rst +++ b/docs/changelog/v3.3.x.rst @@ -1,3 +1,14 @@ +What's new in v3.3.9 +-------------------- + +(released 05/07/2024) + +New Features +^^^^^^^^^^^^ + +- Added support for driver Franco Colapinto (COL) (by @grahamjwhite) (#609) + + What's new in v3.3.8 -------------------- From 04ec86aa62f388dff8d67cd6292aceea35548ba1 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 12 Jul 2024 18:35:03 +0200 Subject: [PATCH 14/31] MNT: numpy 2.0 support (#602) --- fastf1/_api.py | 10 +++++----- fastf1/core.py | 8 ++++---- pyproject.toml | 19 +++++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/fastf1/_api.py b/fastf1/_api.py index 7374614c6..e5e3aa5ba 100644 --- a/fastf1/_api.py +++ b/fastf1/_api.py @@ -84,16 +84,16 @@ def make_path(wname, wdate, sname, sdate): # define all empty columns for timing data EMPTY_LAPS = {'Time': pd.NaT, 'Driver': str(), 'LapTime': pd.NaT, - 'NumberOfLaps': np.NaN, 'NumberOfPitStops': np.NaN, + 'NumberOfLaps': np.nan, 'NumberOfPitStops': np.nan, 'PitOutTime': pd.NaT, 'PitInTime': pd.NaT, 'Sector1Time': pd.NaT, 'Sector2Time': pd.NaT, 'Sector3Time': pd.NaT, 'Sector1SessionTime': pd.NaT, 'Sector2SessionTime': pd.NaT, 'Sector3SessionTime': pd.NaT, - 'SpeedI1': np.NaN, 'SpeedI2': np.NaN, 'SpeedFL': np.NaN, - 'SpeedST': np.NaN, 'IsPersonalBest': False} + 'SpeedI1': np.nan, 'SpeedI2': np.nan, 'SpeedFL': np.nan, + 'SpeedST': np.nan, 'IsPersonalBest': False} -EMPTY_STREAM = {'Time': pd.NaT, 'Driver': str(), 'Position': np.NaN, - 'GapToLeader': np.NaN, 'IntervalToPositionAhead': np.NaN} +EMPTY_STREAM = {'Time': pd.NaT, 'Driver': str(), 'Position': np.nan, + 'GapToLeader': np.nan, 'IntervalToPositionAhead': np.nan} def timing_data(path: str, diff --git a/fastf1/core.py b/fastf1/core.py index 455dde68d..e01eab58c 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -1614,7 +1614,7 @@ def _load_laps_data(self, livedata=None): laps['Driver'] = laps['DriverNumber'].map(d_map) # add Position based on lap timing - laps['Position'] = np.NaN # create empty column + laps['Position'] = np.nan # create empty column if self.name in self._RACE_LIKE_SESSIONS: for lap_n in laps['LapNumber'].unique(): # get each drivers lap for the current lap number, sorted by @@ -1633,7 +1633,7 @@ def _load_laps_data(self, livedata=None): drivers_with_one_lap = lap_counts[lap_counts == 1].index dnf_and_generated = (laps['FastF1Generated'] & laps['Driver'].isin(drivers_with_one_lap)) - laps.loc[dnf_and_generated, 'Position'] = np.NaN + laps.loc[dnf_and_generated, 'Position'] = np.nan self._add_track_status_to_laps(laps) @@ -1745,7 +1745,7 @@ def _fix_missing_laps_retired_on_track(self): 'Compound': [drv_laps['Compound'].iloc[-1]], 'TyreLife': [drv_laps['TyreLife'].iloc[-1] + 1], 'FreshTyre': [drv_laps['FreshTyre'].iloc[-1]], - 'Position': [np.NaN], + 'Position': [np.nan], 'FastF1Generated': [True], 'IsAccurate': [False] }) @@ -2229,7 +2229,7 @@ def _load_drivers_results(self, *, livedata=None): # set (Grid)Position to NaN instead of default last or zero to # make the DNS more obvious self._results.loc[missing_drivers, - ('Position', 'GridPosition')] = np.NaN + ('Position', 'GridPosition')] = np.nan if (dupl_mask := self._results.index.duplicated()).any(): dupl_drv = list(self._results.index[dupl_mask]) diff --git a/pyproject.toml b/pyproject.toml index 03c44ce3c..13b9d4c24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ requires-python = ">=3.8" # minimum package versions additionally need to be changed in requirements/minver.txt dependencies = [ "matplotlib>=3.5.1,<4.0.0", - "numpy>=1.21.5,<2.0.0", + "numpy>=1.21.5,<3.0.0", "pandas>=1.4.1,<3.0.0", "python-dateutil", "requests>=2.28.1", @@ -71,12 +71,6 @@ fallback_version = "0.0+UNKNOWN" [tool.ruff] line-length = 79 -select = [ -# "D", TODO: select and fix docstrings - "E", - "F", - "W", -] exclude = [ "scripts", "fastf1/tests", @@ -85,7 +79,16 @@ exclude = [ "fastf1/legacy.py", ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint] +select = [ +# "D", TODO: select and fix docstrings + "E", + "F", + "W", + "NPY201" +] + +[tool.ruff.lint.per-file-ignores] "fastf1/_api.py" = ["E501"] [tool.isort] From 44f86fdf4650803afa7e49b9758fac3fc613096a Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:54:21 +0100 Subject: [PATCH 15/31] ENH: reimplement plotting module --- .gitignore | 2 +- docs/_plots/colormap_overview.py | 77 +++ docs/changelog/index.rst | 2 +- docs/changelog/previous.rst | 1 + docs/changelog/v3.4.x.rst | 37 + docs/conf.py | 14 +- docs/examples/basics.rst | 2 +- docs/examples/index.rst | 2 +- docs/index.rst | 4 +- docs/plotting.rst | 126 +++- docs/plotting_colormaps.rst | 11 + examples/plot_annotate_speed_trace.py | 10 +- examples/plot_driver_laptimes.py | 9 +- examples/plot_driver_styling.py | 108 +++ examples/plot_laptimes_distribution.py | 22 +- examples/plot_position_changes.py | 11 +- examples/plot_qualifying_results.py | 13 +- examples/plot_speed_traces.py | 11 +- examples/plot_strategy.py | 4 +- examples/plot_team_pace_ranking.py | 9 +- examples/plot_who_can_still_win_wdc.py | 2 +- fastf1/core.py | 3 - fastf1/legacy.py | 2 +- fastf1/plotting/__init__.py | 173 +++++ fastf1/plotting/_backend.py | 67 ++ fastf1/plotting/_base.py | 84 +++ fastf1/plotting/_constants/__init__.py | 114 ++++ fastf1/plotting/_constants/base.py | 34 + fastf1/plotting/_constants/season2018.py | 102 +++ fastf1/plotting/_constants/season2019.py | 91 +++ fastf1/plotting/_constants/season2020.py | 91 +++ fastf1/plotting/_constants/season2021.py | 91 +++ fastf1/plotting/_constants/season2022.py | 91 +++ fastf1/plotting/_constants/season2023.py | 91 +++ fastf1/plotting/_constants/season2024.py | 92 +++ fastf1/plotting/_interface.py | 643 ++++++++++++++++++ fastf1/{plotting.py => plotting/_plotting.py} | 377 ++++------ .../test_doc_example_delta_time.png | Bin 100861 -> 59386 bytes .../test_doc_example_fast_lec.png | Bin 88080 -> 40533 bytes .../mpl-baseline/test_readme_example.png | Bin 59724 -> 31927 bytes .../tests/mpl-baseline/test_speed_trace.png | Bin 35676 -> 35490 bytes fastf1/tests/test_example_plots.py | 13 +- fastf1/tests/test_plotting.py | 406 ++++++++++- fastf1/tests/test_plotting_deprecated.py | 115 ++++ fastf1/utils.py | 8 +- 45 files changed, 2845 insertions(+), 320 deletions(-) create mode 100644 docs/_plots/colormap_overview.py create mode 100644 docs/changelog/v3.4.x.rst create mode 100644 docs/plotting_colormaps.rst create mode 100644 examples/plot_driver_styling.py create mode 100644 fastf1/plotting/__init__.py create mode 100644 fastf1/plotting/_backend.py create mode 100644 fastf1/plotting/_base.py create mode 100644 fastf1/plotting/_constants/__init__.py create mode 100644 fastf1/plotting/_constants/base.py create mode 100644 fastf1/plotting/_constants/season2018.py create mode 100644 fastf1/plotting/_constants/season2019.py create mode 100644 fastf1/plotting/_constants/season2020.py create mode 100644 fastf1/plotting/_constants/season2021.py create mode 100644 fastf1/plotting/_constants/season2022.py create mode 100644 fastf1/plotting/_constants/season2023.py create mode 100644 fastf1/plotting/_constants/season2024.py create mode 100644 fastf1/plotting/_interface.py rename fastf1/{plotting.py => plotting/_plotting.py} (54%) create mode 100644 fastf1/tests/test_plotting_deprecated.py diff --git a/.gitignore b/.gitignore index 9cb05c714..98fc55832 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ fastf1/tests/mpl-baseline-new/ # documentation build directories docs/_build/ -docs/examples_gallery/ +docs/gen_modules/ **/sg_execution_times.rst # all variations of cache directories diff --git a/docs/_plots/colormap_overview.py b/docs/_plots/colormap_overview.py new file mode 100644 index 000000000..0250dccca --- /dev/null +++ b/docs/_plots/colormap_overview.py @@ -0,0 +1,77 @@ +import matplotlib.pyplot as plt + +from fastf1.plotting._constants import Constants + + +n = len(Constants) # total number of years + +# dynamically adjust figure size depending on number of required subplots +fig = plt.figure(figsize=(10, 3 * n)) + +# slightly paranoid, sort years explicitly (order is not necessarily +# guaranteed in the internal code) +years_sorted = [str(year) for year in + sorted((int(year) for year in Constants.keys()), reverse=True)] + +# generate one axis/graphic for each year +for i, year in enumerate(years_sorted): + teams = Constants[year].Teams + + ax = fig.add_subplot(n, 1, i + 1) + + x_labels = list() + x_ranges = list() + default_colors = list() + official_colors = list() + + for j, (name, team) in enumerate(teams.items()): + x_labels.append(team.ShortName) + default_colors.append(team.TeamColor.Default) + official_colors.append(team.TeamColor.Official) + + x_ranges.append((j + 0.5, 1)) + + # draw color rectangles as horizontal bar graph + ax.broken_barh(x_ranges, (0.5, 0.9), facecolors=official_colors) + ax.broken_barh(x_ranges, (1.5, 0.9), facecolors=default_colors) + + # configure y axis and label + ax.set_ylim((0.5, 2.5)) + ax.set_yticks([1, 2]) + ax.set_yticklabels(['official', 'default']) + + # configure x axis and label + ax.set_xlim((0.5, len(x_ranges) + 0.5)) + ax.set_xticks(range(1, len(x_labels) + 1)) + ax.set_xticklabels(x_labels) + + # disable frame around axis + ax.spines['top'].set_visible(False) + ax.spines['bottom'].set_visible(False) + ax.spines['right'].set_visible(False) + ax.spines['left'].set_visible(False) + + # disable tick markers everywhere, label x axis at the top + ax.tick_params(top=False, labeltop=True, bottom=False, labelbottom=False, + left=False, labelleft=True, right=False, labelright=False) + + # set tick label text color (grey, so it works on light and dark theme and + # isn't too distracting next to the colors) + ax.tick_params(colors='#787878') + + # set background color within axes + # (transparent, fallback white if transparency not supported) + ax.set_facecolor('#ffffff00') + + # set axes title (grey, so it works on light and dark theme and + # isn't too distracting next to the colors) + ax.set_title(year, color='#787878') + +# set background color for figure/margins around axes +# (transparent, fallback white if transparency not supported) +fig.patch.set_facecolor('#ffffff00') + +# adjust margins between and around axes +plt.subplots_adjust(top=0.95, bottom=0.05, left=0.1, right=0.95, hspace=0.5) + +plt.show() diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index e5eb155ea..bce493ab2 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -3,5 +3,5 @@ Release Notes Looking for :ref:`previous-release-notes`? -.. include:: v3.3.x.rst +.. include:: v3.4.x.rst diff --git a/docs/changelog/previous.rst b/docs/changelog/previous.rst index 6e02c04a2..cfe3d24a9 100644 --- a/docs/changelog/previous.rst +++ b/docs/changelog/previous.rst @@ -8,6 +8,7 @@ Release Notes for Older Versions .. toctree:: :maxdepth: 1 + v3.3.x v3.2.x v3.1.x v3.0.x diff --git a/docs/changelog/v3.4.x.rst b/docs/changelog/v3.4.x.rst new file mode 100644 index 000000000..fcd173145 --- /dev/null +++ b/docs/changelog/v3.4.x.rst @@ -0,0 +1,37 @@ + +What's new in v3.4.0 +-------------------- + +(released dd/mm/yyyy) + + +New Features +^^^^^^^^^^^^ + + + +Bug Fixes +^^^^^^^^^ + + +Deprecations +^^^^^^^^^^^^ + +- The following module level properties of :mod:`fastf1.plotting` have been + deprecated: + :attr:`~fastf1.plotting.COMPOUND_COLORS`, + :attr:`~fastf1.plotting.DRIVER_TRANSLATE`, + :attr:`~fastf1.plotting.TEAM_COLORS`, + :attr:`~fastf1.plotting.TEAM_TRANSLATE`, + :attr:`~fastf1.plotting.COLOR_PALETTE` + + +- The following functions in :mod:`fastf1.plotting` have been deprecated: + :func:`~fastf1.plotting.driver_color`, + :func:`~fastf1.plotting.team_color` + + +Removals +^^^^^^^^ + +- ``fastf1.plotting.lapnumber_axis`` has been removed \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index e31a5dc34..389f4a0f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,10 @@ warnings.filterwarnings(action='ignore', message=r'`utils.delta_time` is considered ' r'deprecated.*') +warnings.filterwarnings(action='ignore', + message=r'(COMPOUND_COLORS|DRIVER_COLORS|' + r'DRIVER_TRANSLATE|TEAM_COLORS|TEAM_TRANSLATE|' + r'COLOR_PALETTE) is deprecated and.*') doc_cache = os.path.abspath('../doc_cache') @@ -84,6 +88,7 @@ (r'py:.*', r'pandas\..*'), (r'py:.*', r'pd\..*'), (r'py:.*', r'numpy\..*'), + (r'py:.*', r'matplotlib\..*'), (r'py:mod', r'logging'), (r'py:class', r'logging.Logger'), ] @@ -151,14 +156,19 @@ def sphinx_gallery_setup(gallery_conf, fname): sphinx_gallery_conf = { 'examples_dirs': '../examples', - 'gallery_dirs': 'examples_gallery', + 'gallery_dirs': 'gen_modules/examples_gallery', 'download_all_examples': False, 'remove_config_comments': True, 'image_scrapers': ('matplotlib', # default plotly_sg_scraper), # for plotly thumbnail 'reset_modules': ('matplotlib', 'seaborn', # defaults sphinx_gallery_setup), # custom setup - 'expected_failing_examples': ('../examples/plot_qualifying_results.py', ), + # directory where function/class granular galleries are stored + 'backreferences_dir': 'gen_modules/backreferences', + + # Modules for which function/class level galleries are created. In + # this case sphinx_gallery and numpy in a tuple of strings. + 'doc_module': ('fastf1', ), } diff --git a/docs/examples/basics.rst b/docs/examples/basics.rst index 9a8260c8e..6c91086de 100644 --- a/docs/examples/basics.rst +++ b/docs/examples/basics.rst @@ -336,5 +336,5 @@ So let's see what the fastest lap time was and who is on pole. Check out this example that shows how you can plot lap times: -:ref:`sphx_glr_examples_gallery_plot_qualifying_results.py` +:ref:`sphx_glr_gen_modules_examples_gallery_plot_qualifying_results.py` diff --git a/docs/examples/index.rst b/docs/examples/index.rst index d11e7b5de..1a2e0cd46 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -39,7 +39,7 @@ For some more advanced stuff, it's just a few more steps. import fastf1 import fastf1.plotting - fastf1.plotting.setup_mpl() + fastf1.plotting.setup_mpl(misc_mpl_mods=False, color_scheme='fastf1') session = fastf1.get_session(2019, 'Monza', 'Q') diff --git a/docs/index.rst b/docs/index.rst index a1b3ce874..10a833a6c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,7 +25,7 @@ tyre data, weather data, the event schedule and session results. To get a quick overview over how to use FastF1, check out -:doc:`examples/index` or the :doc:`examples_gallery/index`. +:doc:`examples/index` or the :doc:`gen_modules/examples_gallery/index`. Note that FastF1 handles big chunks of data (~50-100mb per session). To improve performance, data is per default cached locally. The default placement @@ -141,7 +141,7 @@ Contents :caption: Contents: examples/index - examples_gallery/index + gen_modules/examples_gallery/index fastf1 core events diff --git a/docs/plotting.rst b/docs/plotting.rst index 81c5931aa..2db05783f 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -1,6 +1,130 @@ Plotting - :mod:`fastf1.plotting` ================================= +Helper functions for creating data plots. + +:mod:`fastf1.plotting` provides optional functionality with the intention of +making it easy to create nice plots. + +This module mainly offers: + - team names and colors + - driver names and driver abbreviations + - Matplotlib integration and helper functions + +FastF1 focuses on plotting with Matplotlib or related libraries like Seaborn. +If you wish to use these libraries, it is highly recommended to enable +extend support for these by calling :func:`~fastf1.plotting.setup_mpl`. + + +Team Colormaps +-------------- + +Currently, two team colormaps are supported. Each colormap provides one color +for each team. Colors are constant over the course of a season. All functions +that return colors for teams or drivers accept an optional ``colormap`` +argument. + +The ``'default'`` colormap is FastF1's default colormap. These colors are teams' +primary colors or accent colors as they are used by the teams on their website +or in promotional material. The colors are chosen to maximize readability in +plots by creating a stronger contrast while still being associated with the +team. + +The ``'official'`` colormap contains the colors exactly as they are used by +the FOM in official graphics and in the TV graphics. Those colors are often +slightly muted. While that makes them more pleasing to look at in some graphics, +it also reduces the contrast between colors which is often bad for +readability of plots. + +See here for a complete list of all colors: :ref:`Team-Colormaps-Overview` + + +.. note:: **Driver Colors** + + Previously, individual colors for each driver were provided. This is no + longer the case. The driver color is now equivalent to the team color, + meaning that drivers from the same team have the exact same color. This + change was made because different colors for 20 drivers end up looking + very similar in many cases anyway, meaning it is not a good solution to + use these to distinguish different drivers. Other means of plot styling + should be used instead. + + + +Overview +-------- + + +Configuration and Setup +^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + setup_mpl + + +Get Colors, Names and Abbreviations for Drivers or Teams +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + get_compound_color, + get_driver_abbreviation, + get_driver_abbreviations_by_team, + get_driver_color, + get_driver_name, + get_driver_names_by_team, + get_driver_style, + get_team_color, + get_team_name, + get_team_name_by_driver + + +List all Names and Abbreviations for Drivers/Teams in a Session +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + get_compound_mapping, + get_driver_color_mapping, + list_driver_abbreviations, + list_driver_names, + list_short_team_names, + list_team_names + + +Plot Styling +^^^^^^^^^^^^ + +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + add_sorted_driver_legend + + +Deprecated Functionality +^^^^^^^^^^^^^^^^^^^^^^^^ + +The following module-level attributes are deprecated since version 3.4.0 and +will be removed in a future release. + + + + + +Plotting API Reference +---------------------- + .. automodule:: fastf1.plotting :members: - :show-inheritance: diff --git a/docs/plotting_colormaps.rst b/docs/plotting_colormaps.rst new file mode 100644 index 000000000..c5b74d571 --- /dev/null +++ b/docs/plotting_colormaps.rst @@ -0,0 +1,11 @@ + +:orphan: + +.. _Team-Colormaps-Overview: + +Overview over Team Colormaps +---------------------------- + + +.. plot:: _plots/colormap_overview.py + :include-source: False diff --git a/examples/plot_annotate_speed_trace.py b/examples/plot_annotate_speed_trace.py index 9c5c483ac..631cf4aa1 100644 --- a/examples/plot_annotate_speed_trace.py +++ b/examples/plot_annotate_speed_trace.py @@ -10,9 +10,10 @@ import fastf1.plotting -# enable some matplotlib patches for plotting timedelta values and load -# FastF1's default color scheme -fastf1.plotting.setup_mpl(misc_mpl_mods=False) +# Enable Matplotlib patches for plotting timedelta values and load +# FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme='fastf1') # load a session and its telemetry data session = fastf1.get_session(2021, 'Spanish Grand Prix', 'Q') @@ -35,7 +36,8 @@ # Finally, we create a plot and plot the speed trace as well as the corner # markers. -team_color = fastf1.plotting.team_color(fastest_lap['Team']) +team_color = fastf1.plotting.get_team_color(fastest_lap['Team'], + session=session) fig, ax = plt.subplots() ax.plot(car_data['Distance'], car_data['Speed'], diff --git a/examples/plot_driver_laptimes.py b/examples/plot_driver_laptimes.py index 3b1ec0501..63c5a3f39 100755 --- a/examples/plot_driver_laptimes.py +++ b/examples/plot_driver_laptimes.py @@ -11,8 +11,11 @@ import fastf1.plotting -# The misc_mpl_mods option enables minor grid lines which clutter the plot -fastf1.plotting.setup_mpl(misc_mpl_mods=False) +# Enable Matplotlib patches for plotting timedelta values and load +# FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme='fastf1') + ############################################################################### # Load the race session. @@ -39,7 +42,7 @@ y="LapTime", ax=ax, hue="Compound", - palette=fastf1.plotting.COMPOUND_COLORS, + palette=fastf1.plotting.get_compound_mapping(session=race), s=80, linewidth=0, legend='auto') diff --git a/examples/plot_driver_styling.py b/examples/plot_driver_styling.py new file mode 100644 index 000000000..4b8d3f403 --- /dev/null +++ b/examples/plot_driver_styling.py @@ -0,0 +1,108 @@ +"""Driver specific plot styling +=============================== + +Create some plots and show the usage of ``fastf1.plotting.get_driver_style``. +""" + +from matplotlib import pyplot as plt + +import fastf1 +from fastf1 import plotting + + +# Enable Matplotlib patches for plotting timedelta values and load +# FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme='fastf1') + + +############################################################################### +# Load the race session. + +race = fastf1.get_session(2023, "Azerbaijan", 'R') +race.load() + +############################################################################### +# Basic driver-specific plot styling +# ---------------------------------- +# Plot all the laps for Hamilton, Russel, Perez and Verstappen. +# Filter out slow laps as they distort the graph axis. +# Note: as LapTime is represented by timedelta, calling ``setup_mpl`` earlier +# is required. + +fig, ax = plt.subplots(figsize=(8, 5)) + +for driver in ('HAM', 'PER', 'VER', 'RUS'): + laps = race.laps.pick_driver(driver).pick_quicklaps().reset_index() + style = plotting.get_driver_style(identifier=driver, + style=['color', 'linestyle'], + session=race) + ax.plot(laps['LapTime'], **style, label=driver) + +# add axis labels and a legend +ax.set_xlabel("Lap Number") +ax.set_ylabel("Lap Time") +ax.legend() + +############################################################################### +# Sorting the legend +# ------------------ +# That plot looks pretty good already, but the order of the labels in the +# legend is slightly chaotic. Instead of trying to order the labels manually, +# use :func:`fastf1.plotting.add_sorted_driver_legend`. +# Let's create the exact same plot again, but this time with a sorted legend +# which means, we only change the very last function call. + +fig, ax = plt.subplots(figsize=(8, 5)) + +for driver in ('HAM', 'PER', 'VER', 'RUS'): + laps = race.laps.pick_driver(driver).pick_quicklaps().reset_index() + style = plotting.get_driver_style(identifier=driver, + style=['color', 'linestyle'], + session=race) + ax.plot(laps['LapTime'], **style, label=driver) + +# add axis labels and a legend +ax.set_xlabel("Lap Number") +ax.set_ylabel("Lap Time") +plotting.add_sorted_driver_legend(ax, race) + +############################################################################### +# Creating fully custom styles +# ---------------------------- +# If you want to fully customize the plot style, you can define your own +# styling variants. +# +# Note that the value ``'auto'`` is treated as a magic keyword when used in +# combination with a color. It will be replaced with the team color. +# +# We define two styles, one for the first driver and one for the second driver +# in any team. +# +# The plot that is generated here isn't intended to be very readable, but it +# shows how you can customize any plot styling parameter. + +my_styles = [ + # style for each first driver + {'color': 'auto', 'linestyle': 'solid', 'linewidth': 5, 'alpha': 0.3}, + # style for each second driver + {'color': 'auto', 'linestyle': 'solid', 'linewidth': 1, 'alpha': 0.7} +] + +fig, ax = plt.subplots(figsize=(8, 5)) + +for driver in ('HAM', 'PER', 'VER', 'RUS'): + laps = race.laps.pick_driver(driver).pick_quicklaps().reset_index() + + # here, we now use ``style=my_style`` to use the custom styling + style = plotting.get_driver_style(identifier=driver, + style=my_styles, + session=race) + + ax.plot(laps['LapTime'], **style, label=driver) + +# add axis labels and a legend +ax.set_xlabel("Lap Number") +ax.set_ylabel("Lap Time") +plotting.add_sorted_driver_legend(ax, race) +plt.show() diff --git a/examples/plot_laptimes_distribution.py b/examples/plot_laptimes_distribution.py index 0d331206a..196f0c523 100755 --- a/examples/plot_laptimes_distribution.py +++ b/examples/plot_laptimes_distribution.py @@ -10,8 +10,11 @@ import fastf1.plotting -# enabling misc_mpl_mods will turn on minor grid lines that clutters the plot -fastf1.plotting.setup_mpl(mpl_timedelta_support=False, misc_mpl_mods=False) +# Enable Matplotlib patches for plotting timedelta values and load +# FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme='fastf1') + ############################################################################### # Load the race session @@ -34,15 +37,6 @@ finishing_order = [race.get_driver(i)["Abbreviation"] for i in point_finishers] print(finishing_order) -############################################################################### -# We need to modify the DRIVER_COLORS palette. -# Its keys are the driver's full names but we need the keys to be the drivers' -# three-letter abbreviations. -# We can do this with the DRIVER_TRANSLATE mapping. -driver_colors = {abv: fastf1.plotting.DRIVER_COLORS[driver] for abv, - driver in fastf1.plotting.DRIVER_TRANSLATE.items()} -print(driver_colors) - ############################################################################### # First create the violin plots to show the distributions. # Then use the swarm plot to show the actual laptimes. @@ -50,7 +44,7 @@ # create the figure fig, ax = plt.subplots(figsize=(10, 5)) -# Seaborn doesn't have proper timedelta support +# Seaborn doesn't have proper timedelta support, # so we have to convert timedelta to float (in seconds) driver_laps["LapTime(s)"] = driver_laps["LapTime"].dt.total_seconds() @@ -61,7 +55,7 @@ inner=None, density_norm="area", order=finishing_order, - palette=driver_colors + palette=fastf1.plotting.get_driver_color_mapping(session=race) ) sns.swarmplot(data=driver_laps, @@ -69,7 +63,7 @@ y="LapTime(s)", order=finishing_order, hue="Compound", - palette=fastf1.plotting.COMPOUND_COLORS, + palette=fastf1.plotting.get_compound_mapping(session=race), hue_order=["SOFT", "MEDIUM", "HARD"], linewidth=0, size=4, diff --git a/examples/plot_position_changes.py b/examples/plot_position_changes.py index fff1726a4..a8d31a140 100644 --- a/examples/plot_position_changes.py +++ b/examples/plot_position_changes.py @@ -10,7 +10,10 @@ import fastf1.plotting -fastf1.plotting.setup_mpl(misc_mpl_mods=False) +# Load FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=False, misc_mpl_mods=False, + color_scheme='fastf1') + ############################################################################## # Load the session and create the plot @@ -28,10 +31,12 @@ drv_laps = session.laps.pick_driver(drv) abb = drv_laps['Driver'].iloc[0] - color = fastf1.plotting.driver_color(abb) + style = fastf1.plotting.get_driver_style(identifier=abb, + style=['color', 'linestyle'], + session=session) ax.plot(drv_laps['LapNumber'], drv_laps['Position'], - label=abb, color=color) + label=abb, **style) # sphinx_gallery_defer_figures ############################################################################## diff --git a/examples/plot_qualifying_results.py b/examples/plot_qualifying_results.py index f466a8c7c..8e056ddfd 100644 --- a/examples/plot_qualifying_results.py +++ b/examples/plot_qualifying_results.py @@ -14,9 +14,10 @@ from fastf1.core import Laps -# we only want support for timedelta plotting in this example -fastf1.plotting.setup_mpl(mpl_timedelta_support=True, color_scheme=None, - misc_mpl_mods=False) +# Enable Matplotlib patches for plotting timedelta values +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme=None) + session = fastf1.get_session(2021, 'Spanish Grand Prix', 'Q') session.load() @@ -30,7 +31,7 @@ ############################################################################## -# After that we'll get each drivers fastest lap, create a new laps object +# After that we'll get each driver's fastest lap, create a new laps object # from these laps, sort them by lap time and have pandas reindex them to # number them nicely by starting position. @@ -45,7 +46,7 @@ ############################################################################## # The plot is nicer to look at and more easily understandable if we just plot -# the time differences. Therefore we subtract the fastest lap time from all +# the time differences. Therefore, we subtract the fastest lap time from all # other lap times. pole_lap = fastest_laps.pick_fastest() @@ -64,7 +65,7 @@ # Finally, we'll create a list of team colors per lap to color our plot. team_colors = list() for index, lap in fastest_laps.iterlaps(): - color = fastf1.plotting.team_color(lap['Team']) + color = fastf1.plotting.get_team_color(lap['Team'], session=session) team_colors.append(color) diff --git a/examples/plot_speed_traces.py b/examples/plot_speed_traces.py index ab179be0a..f09e8ecd0 100644 --- a/examples/plot_speed_traces.py +++ b/examples/plot_speed_traces.py @@ -10,9 +10,10 @@ import fastf1.plotting -# enable some matplotlib patches for plotting timedelta values and load -# FastF1's default color scheme -fastf1.plotting.setup_mpl(misc_mpl_mods=False) +# Enable Matplotlib patches for plotting timedelta values and load +# FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=True, misc_mpl_mods=False, + color_scheme='fastf1') # load a session and its telemetry data session = fastf1.get_session(2021, 'Spanish Grand Prix', 'Q') @@ -35,8 +36,8 @@ # Finally, we create a plot and plot both speed traces. # We color the individual lines with the driver's team colors. -rbr_color = fastf1.plotting.team_color('RBR') -mer_color = fastf1.plotting.team_color('MER') +rbr_color = fastf1.plotting.get_team_color(ver_lap['Team'], session=session) +mer_color = fastf1.plotting.get_team_color(ham_lap['Team'], session=session) fig, ax = plt.subplots() ax.plot(ver_tel['Distance'], ver_tel['Speed'], color=rbr_color, label='VER') diff --git a/examples/plot_strategy.py b/examples/plot_strategy.py index ef33421a1..96ecabeeb 100644 --- a/examples/plot_strategy.py +++ b/examples/plot_strategy.py @@ -55,11 +55,13 @@ for idx, row in driver_stints.iterrows(): # each row contains the compound name and stint length # we can use these information to draw horizontal bars + compound_color = fastf1.plotting.get_compound_color(row["Compound"], + session=session) plt.barh( y=driver, width=row["StintLength"], left=previous_stint_end, - color=fastf1.plotting.COMPOUND_COLORS[row["Compound"]], + color=compound_color, edgecolor="black", fill=True ) diff --git a/examples/plot_team_pace_ranking.py b/examples/plot_team_pace_ranking.py index 1087abee2..fc4221dcf 100755 --- a/examples/plot_team_pace_ranking.py +++ b/examples/plot_team_pace_ranking.py @@ -10,8 +10,10 @@ import fastf1.plotting -# activate the fastf1 color scheme (and no other modifications) -fastf1.plotting.setup_mpl(mpl_timedelta_support=False, misc_mpl_mods=False) +# Load FastF1's dark color scheme +fastf1.plotting.setup_mpl(mpl_timedelta_support=False, misc_mpl_mods=False, + color_scheme='fastf1') + ############################################################################### # Load the race session. @@ -40,7 +42,8 @@ print(team_order) # make a color palette associating team names to hex codes -team_palette = {team: fastf1.plotting.team_color(team) for team in team_order} +team_palette = {team: fastf1.plotting.get_team_color(team, session=race) + for team in team_order} ############################################################################### fig, ax = plt.subplots(figsize=(15, 10)) diff --git a/examples/plot_who_can_still_win_wdc.py b/examples/plot_who_can_still_win_wdc.py index 5f56e9518..77b976961 100644 --- a/examples/plot_who_can_still_win_wdc.py +++ b/examples/plot_who_can_still_win_wdc.py @@ -24,7 +24,7 @@ ############################################################################## # Get the current driver standings from Ergast. -# Reference https://theoehrly.github.io/Fast-F1-Pre-Release-Documentation/ergast.html#fastf1.ergast.Ergast.get_driver_standings +# Reference https://docs.fastf1.dev/ergast.html#fastf1.ergast.Ergast.get_driver_standings def get_drivers_standings(): ergast = Ergast() standings = ergast.get_driver_standings(season=SEASON, round=ROUND) diff --git a/fastf1/core.py b/fastf1/core.py index e01eab58c..e25ad54fc 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -3067,9 +3067,6 @@ def pick_team(self, name: str) -> "Laps": mercedes = session_laps.pick_team('Mercedes') alfa_romeo = session_laps.pick_team('Alfa Romeo') - Have a look to :attr:`fastf1.plotting.TEAM_COLORS` for a quick - reference on team names. - Args: name (str): Team name diff --git a/fastf1/legacy.py b/fastf1/legacy.py index ba59315d3..e2a1d3bc0 100644 --- a/fastf1/legacy.py +++ b/fastf1/legacy.py @@ -22,7 +22,7 @@ import numpy as np import matplotlib.pyplot as plt - fastf1.plotting.setup_mpl() + fastf1.plotting.setup_mpl(misc_mpl_mods=False, color_scheme='fastf1') session = fastf1.get_session(2020, 'Italy', 'R') session.load() diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py new file mode 100644 index 000000000..6b4d3c67e --- /dev/null +++ b/fastf1/plotting/__init__.py @@ -0,0 +1,173 @@ +import warnings +from typing import ( + Dict, + List +) + +from fastf1.plotting._constants import \ + LEGACY_DRIVER_COLORS as _LEGACY_DRIVER_COLORS +from fastf1.plotting._constants import \ + LEGACY_DRIVER_TRANSLATE as _LEGACY_DRIVER_TRANSLATE +from fastf1.plotting._constants import \ + LEGACY_TEAM_TRANSLATE as _LEGACY_TEAM_TRANSLATE +from fastf1.plotting._constants import Constants as _Constants +from fastf1.plotting._interface import ( # noqa: F401 + _get_driver_team_mapping, + add_sorted_driver_legend, + get_compound_color, + get_compound_mapping, + get_driver_abbreviation, + get_driver_abbreviations_by_team, + get_driver_color, + get_driver_color_mapping, + get_driver_name, + get_driver_names_by_team, + get_driver_style, + get_team_color, + get_team_name, + get_team_name_by_driver, + list_compounds, + list_driver_abbreviations, + list_driver_names, + list_short_team_names, + list_team_names +) +from fastf1.plotting._plotting import ( # noqa: F401 + _COLOR_PALETTE, + driver_color, + lapnumber_axis, + setup_mpl, + team_color +) + + +__all__ = [ + # imported, current + 'add_sorted_driver_legend', + 'get_compound_color', + 'get_compound_mapping', + 'get_driver_abbreviation', + 'get_driver_abbreviations_by_team', + 'get_driver_color', + 'get_driver_color_mapping', + 'get_driver_name', + 'get_driver_names_by_team', + 'get_driver_style', + 'get_team_color', + 'get_team_name', + 'get_team_name_by_driver', + 'list_compounds', + 'list_driver_abbreviations', + 'list_driver_names', + 'list_team_names', + 'list_short_team_names', + 'setup_mpl', + + # imported, legacy + 'driver_color', + 'lapnumber_axis', + 'team_color', + + # legacy + 'COMPOUND_COLORS', + 'DRIVER_COLORS', + 'DRIVER_TRANSLATE', + 'TEAM_COLORS', + 'TEAM_TRANSLATE', + 'COLOR_PALETTE' +] + + +def __getattr__(name): + if name in ('COMPOUND_COLORS', 'DRIVER_TRANSLATE', 'DRIVER_COLORS', + 'TEAM_COLORS', 'TEAM_TRANSLATE', 'COLOR_PALETTE'): + warnings.warn(f"{name} is deprecated and will be removed in a future " + f"version.", FutureWarning) + + return globals()[f"_DEPR_{name}"] + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +_DEPR_COMPOUND_COLORS: Dict[str, str] = { + key: val for key, val + in _Constants['2024'].CompoundColors.items() +} +COMPOUND_COLORS: Dict[str, str] +""" +Mapping of tyre compound names to compound colors (hex color codes). +(current season only) + +.. deprecated:: 3.4.0 + The ``COMPOUND_COLORS`` dictionary is deprecated and will be removed in a + future version. Use :func:`~fastf1.plotting.get_compound_color` or + :func:`~fastf1.plotting.get_compound_mapping` instead. +""" + + +_DEPR_DRIVER_COLORS: Dict[str, str] = _LEGACY_DRIVER_COLORS.copy() +DRIVER_COLORS: Dict[str, str] +""" +Mapping of driver names to driver colors (hex color codes). + +.. warning:: + This dictionary will no longer be updated to include new drivers. Use + the new API instead. + +.. deprecated:: 3.4.0 + The ``DRIVER_COLORS`` dictionary is deprecated and will ber removed in a + future version. Use :func:`~fastf1.plotting.get_driver_color` or + :func:`~fastf1.plotting.get_driver_color_mapping` instead. +""" + + +_DEPR_DRIVER_TRANSLATE: Dict[str, str] = _LEGACY_DRIVER_TRANSLATE.copy() +DRIVER_TRANSLATE: Dict[str, str] +""" +Mapping of driver names to theirs respective abbreviations. + +.. warning:: + This dictionary will no longer be updated to include new drivers. Use + the new API instead. + + +.. deprecated:: 3.4.0 + The ``DRIVER_TRANSLATE`` dictionary is deprecated and will be removed in a + future version. Use :func:`~fastf1.plotting.get_driver_name` instead. +""" + +_DEPR_TEAM_COLORS: Dict[str, str] = { + # str(key.value): val for key, val + # in _Constants['2024'].Colormaps[_Colormaps.Default].items() + name: team.TeamColor.Default for name, team + in _Constants['2024'].Teams.items() +} +TEAM_COLORS: Dict[str, str] +""" +Mapping of team names to team colors (hex color codes). +(current season only) + +.. deprecated:: 3.4.0 + The ``TEAM_COLORS`` dictionary is deprecated and will be removed in a + future version. Use :func:`~fastf1.plotting.get_team_color` instead. +""" + +_DEPR_TEAM_TRANSLATE: Dict[str, str] = _LEGACY_TEAM_TRANSLATE.copy() +TEAM_TRANSLATE: Dict[str, str] +""" +Mapping of team names to theirs respective abbreviations. + +.. deprecated:: 3.4.0 + The ``TEAM_TRANSLATE`` dictionary is deprecated and will be removed in a + future version. Use :func:`~fastf1.plotting.get_team_name` instead. +""" + +_DEPR_COLOR_PALETTE: List[str] = _COLOR_PALETTE.copy() +COLOR_PALETTE: List[str] +""" +The default color palette for matplotlib plot lines in fastf1's color scheme. + +.. deprecated:: 3.4.0 + The ``COLOR_PALETTE`` list is deprecated and will be removed in a + future version with no replacement. +""" diff --git a/fastf1/plotting/_backend.py b/fastf1/plotting/_backend.py new file mode 100644 index 000000000..6d9aba34a --- /dev/null +++ b/fastf1/plotting/_backend.py @@ -0,0 +1,67 @@ +import warnings +from typing import ( + Dict, + List +) + +import fastf1._api +from fastf1.plotting._base import ( + _Driver, + _normalize_string, + _Team +) +from fastf1.plotting._constants import Constants + + +def _load_drivers_from_f1_livetiming( + *, api_path: str, year: str +) -> List[_Team]: + # load the driver information for the determined session + driver_info = fastf1._api.driver_info(api_path) + + # parse the data into the required format + teams: Dict[str, _Team] = dict() + + # Sorting by driver number here will directly guarantee that drivers + # are sorted by driver number within each team. This has two advantages: + # - the driver index in a team is consistent as long as the drivers don't + # change/reserver drivers are used/... + # - the reigning champion (number 1) always has index 0, i.e. gets the + # primary style + for num in sorted(driver_info.keys()): + driver_entry = driver_info[num] + team_name = driver_entry.get('TeamName') + + if team_name in teams: + team = teams[team_name] + else: + team = _Team() + team.value = team_name + + abbreviation = driver_entry.get('Tla') + + name = ' '.join((driver_entry.get('FirstName'), + driver_entry.get('LastName'))) + driver = _Driver() + driver.value = name + driver.normalized_value = _normalize_string(name).lower() + driver.abbreviation = abbreviation + driver.team = team + + team.drivers.append(driver) + + if team not in teams: + normalized_full_team_name = _normalize_string(team_name).lower() + for ref_team_name in Constants[year].Teams.keys(): + if ref_team_name in normalized_full_team_name: + team.normalized_value = ref_team_name + break + else: + warnings.warn(f"Encountered unknown team '{team_name}' while " + f"loading driver-team mapping.", + UserWarning) + continue + + teams[team_name] = team + + return list(teams.values()) diff --git a/fastf1/plotting/_base.py b/fastf1/plotting/_base.py new file mode 100644 index 000000000..a651f1999 --- /dev/null +++ b/fastf1/plotting/_base.py @@ -0,0 +1,84 @@ +import unicodedata +from typing import ( + Dict, + List, + Sequence, + TypeVar +) + +from rapidfuzz import fuzz + +from fastf1.logger import get_logger + + +_logger = get_logger(__package__) + + +class _Driver: + value: str = '' + normalized_value: str = '' + abbreviation: str = '' + team: "_Team" + + +class _Team: + value: str = '' + normalized_value: str = '' + + def __init__(self): + super().__init__() + self.drivers: List["_Driver"] = list() + + +class _DriverTeamMapping: + def __init__( + self, + year: str, + teams: List[_Team], + ): + self.year = year + self.teams = teams + + self.drivers_by_normalized: Dict[str, _Driver] = dict() + self.drivers_by_abbreviation: Dict[str, _Driver] = dict() + self.teams_by_normalized: Dict[str, _Team] = dict() + + for team in teams: + for driver in team.drivers: + self.drivers_by_normalized[driver.normalized_value] = driver + self.drivers_by_abbreviation[driver.abbreviation] = driver + self.teams_by_normalized[team.normalized_value] = team + + +S = TypeVar('S', bound=str) + + +def _fuzzy_matcher(identifier: str, reference: Sequence[S]) -> S: + # do fuzzy string matching + key_ratios = list() + for existing_key in reference: + ratio = fuzz.ratio(identifier, existing_key) + key_ratios.append((ratio, existing_key)) + key_ratios.sort(reverse=True) + if ((key_ratios[0][0] < 35) + or (key_ratios[0][0] / key_ratios[1][0] < 1.2)): + # ensure that the best match has a minimum accuracy (35 out of + # 100) and that it has a minimum confidence (at least 20% + # better than second best) + raise KeyError + if key_ratios[0][0] != 100: + _logger.warning( + ("Correcting invalid user input " + f"'{identifier}' to '{key_ratios[0][1]}'." + ) + ) + best_matched_key = key_ratios[0][1] + return best_matched_key + + +def _normalize_string(name: str) -> str: + # removes accents from a string and returns the closest possible + # ascii representation (https://stackoverflow.com/a/518232) + stripped = ''.join(c for c in unicodedata.normalize('NFD', name) + if unicodedata.category(c) != 'Mn') + return stripped diff --git a/fastf1/plotting/_constants/__init__.py b/fastf1/plotting/_constants/__init__.py new file mode 100644 index 000000000..65effa114 --- /dev/null +++ b/fastf1/plotting/_constants/__init__.py @@ -0,0 +1,114 @@ +from typing import Dict + +from fastf1.plotting._constants import ( # noqa: F401, unused import used through globals() + season2018, + season2019, + season2020, + season2021, + season2022, + season2023, + season2024 +) +from fastf1.plotting._constants.base import BaseSeason + + +Constants: Dict[str, BaseSeason] = dict() + +for year in range(2018, 2025): + season = globals()[f"season{year}"] + Constants[str(year)] = BaseSeason(CompoundColors=season.CompoundColors, + Teams=season.Teams) + + +# Deprecated, will be removed for 2025 +LEGACY_TEAM_COLORS = { + 'mercedes': '#00d2be', 'ferrari': '#dc0000', + 'red bull': '#fcd700', 'mclaren': '#ff8700', + 'alpine': '#fe86bc', 'aston martin': '#006f62', + 'sauber': '#00e701', 'visa rb': '#1634cb', + 'haas': '#ffffff', 'williams': '#00a0dd' +} + + +LEGACY_TEAM_TRANSLATE: Dict[str, str] = { + 'MER': 'mercedes', + 'FER': 'ferrari', + 'RBR': 'red bull', + 'MCL': 'mclaren', + 'APN': 'alpine', + 'AMR': 'aston martin', + 'SAU': 'sauber', + 'RB': 'rb', + 'HAA': 'haas', + 'WIL': 'williams' +} + + +LEGACY_DRIVER_COLORS: Dict[str, str] = { + "valtteri bottas": "#00e701", + "zhou guanyu": "#008d01", + "theo pourchaire": "#004601", + + "nyck de vries": "#1e3d61", + "yuki tsunoda": "#356cac", + "daniel ricciardo": "#2b4562", + "liam lawson": "#2b4562", + "isack hadjar": "#1e6176", + "ayumu iwasa": "#1e6176", + + "pierre gasly": "#fe86bc", + "esteban ocon": "#ff117c", + "jack doohan": "#894667", + + "fernando alonso": "#006f62", + "lance stroll": "#00413b", + "felipe drugovich": "#2f9b90", + + "charles leclerc": "#dc0000", + "carlos sainz": "#ff8181", + "robert shwartzman": "#9c0000", + "oliver bearman": "#c40000", + + "kevin magnussen": "#ffffff", + "nico hulkenberg": "#cacaca", + + "oscar piastri": "#ff8700", + "lando norris": "#eeb370", + "pato oward": "#ee6d3a", + + "lewis hamilton": "#00d2be", + "george russell": "#24ffff", + "frederik vesti": "#00a6ff", + + "max verstappen": "#fcd700", + "sergio perez": "#ffec7b", + "jake dennis": "#907400", + + "alexander albon": "#005aff", + "logan sargeant": "#012564", + "zak osullivan": "#1b3d97", +} + + +LEGACY_DRIVER_TRANSLATE: Dict[str, str] = { + 'LEC': 'charles leclerc', 'SAI': 'carlos sainz', + 'SHW': 'robert shwartzman', + 'VER': 'max verstappen', 'PER': 'sergio perez', + 'DEN': 'jake dennis', + 'PIA': 'oscar piastri', 'NOR': 'lando norris', + 'OWA': 'pato oward', + 'GAS': 'pierre gasly', 'OCO': 'esteban ocon', + 'DOO': 'jack doohan', + 'BOT': 'valtteri bottas', 'ZHO': 'zhou guanyu', + 'POU': 'theo pourchaire', + 'DEV': 'nyck de vries', 'TSU': 'yuki tsunoda', + 'RIC': 'daniel ricciardo', 'LAW': 'liam lawson', + 'HAD': 'isack hadjar', 'IWA': 'ayumu iwasa', + 'MAG': 'kevin magnussen', 'HUL': 'nico hulkenberg', + 'BEA': 'oliver bearman', + 'ALO': 'fernando alonso', 'STR': 'lance stroll', + 'DRU': 'felipe drugovich', + 'HAM': 'lewis hamilton', 'RUS': 'george russell', + 'VES': 'frederik vesti', + 'ALB': 'alexander albon', 'SAR': 'logan sargeant', + 'OSU': 'zak osullivan'} diff --git a/fastf1/plotting/_constants/base.py b/fastf1/plotting/_constants/base.py new file mode 100644 index 000000000..18edbaee5 --- /dev/null +++ b/fastf1/plotting/_constants/base.py @@ -0,0 +1,34 @@ +from dataclasses import dataclass +from typing import Dict + + +class Compounds: + HyperSoft = "HYPERSOFT" + UltraSoft = "ULTRASOFT" + SuperSoft = "SUPERSOFT" + Soft = "SOFT" + Medium = "MEDIUM" + Hard = "HARD" + SuperHard = "SUPERHARD" + Intermediate = "INTERMEDIATE" + Wet = "WET" + Unknown = "UNKNOWN" + TestUnknown = "TEST-UNKNOWN" + + +@dataclass(frozen=True) +class TeamColors: + Official: str + Default: str + + +@dataclass(frozen=True) +class Team: + ShortName: str + TeamColor: TeamColors + + +@dataclass(frozen=True) +class BaseSeason: + CompoundColors: Dict[str, str] + Teams: Dict[str, Team] diff --git a/fastf1/plotting/_constants/season2018.py b/fastf1/plotting/_constants/season2018.py new file mode 100644 index 000000000..42e88cae8 --- /dev/null +++ b/fastf1/plotting/_constants/season2018.py @@ -0,0 +1,102 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#dc0000', + Default='#dc0000' + ) + ), + 'force india': Team( + ShortName='Force India', + TeamColor=TeamColors( + Official='#f596c8', + Default='#ff87bc' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#828282', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#ff8000', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#00d2be', + Default='#00f5d0' + ) + ), + 'racing point': Team( + ShortName='Racing Point', + TeamColor=TeamColors( + Official='#f596c8', + Default='#ff87bc' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#1e41ff', + Default='#1e41ff' + ) + ), + 'renault': Team( + ShortName='Renault', + TeamColor=TeamColors( + Official='#fff500', + Default='#fff500' + ) + ), + 'sauber': Team( + ShortName='Sauber', + TeamColor=TeamColors( + Official='#9b0000', + Default='#900000' + ) + ), + 'toro rosso': Team( + ShortName='Toro Rosso', + TeamColor=TeamColors( + Official='#469bff', + Default='#2b4562' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#ffffff', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.HyperSoft: "#feb1c1", + Compounds.UltraSoft: "#b24ba7", + Compounds.SuperSoft: "#fc2b2a", + Compounds.Soft: "#ffd318", + Compounds.Medium: "#f0f0f0", + Compounds.Hard: "#00a2f5", + Compounds.SuperHard: "#fd7d3c", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2019.py b/fastf1/plotting/_constants/season2019.py new file mode 100644 index 000000000..8929e61d1 --- /dev/null +++ b/fastf1/plotting/_constants/season2019.py @@ -0,0 +1,91 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alfa romeo': Team( + ShortName='Alfa Romeo', + TeamColor=TeamColors( + Official='#9b0000', + Default='#900000' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#bd9e57', + Default='#bd9e57' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#dc0000', + Default='#da291c' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#ff8700', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#00d2be', + Default='#00d2be' + ) + ), + 'racing point': Team( + ShortName='Racing Point', + TeamColor=TeamColors( + Official='#f596c8', + Default='#ff87bc' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#1e41ff', + Default='#1e41ff' + ) + ), + 'renault': Team( + ShortName='Renault', + TeamColor=TeamColors( + Official='#fff500', + Default='#fff500' + ) + ), + 'toro rosso': Team( + ShortName='Toro Rosso', + TeamColor=TeamColors( + Official='#469bff', + Default='#2b4562' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#ffffff', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2020.py b/fastf1/plotting/_constants/season2020.py new file mode 100644 index 000000000..5eb1905b9 --- /dev/null +++ b/fastf1/plotting/_constants/season2020.py @@ -0,0 +1,91 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alfa romeo': Team( + ShortName='Alfa Romeo', + TeamColor=TeamColors( + Official='#9B0000', + Default='#900000' + ) + ), + 'alphatauri': Team( + ShortName='AlphaTauri', + TeamColor=TeamColors( + Official='#ffffff', + Default='#2b4562' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#dc0000', + Default='#dc0000' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#787878', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#ff8700', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#00d2be', + Default='#00d2be' + ) + ), + 'racing point': Team( + ShortName='Racing Point', + TeamColor=TeamColors( + Official='#f596c8', + Default='#ff87bc' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#1e41ff', + Default='#1e41ff' + ) + ), + 'renault': Team( + ShortName='Renault', + TeamColor=TeamColors( + Official='#fff500', + Default='#fff500' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#0082fa', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2021.py b/fastf1/plotting/_constants/season2021.py new file mode 100644 index 000000000..fb195b6b9 --- /dev/null +++ b/fastf1/plotting/_constants/season2021.py @@ -0,0 +1,91 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alfa romeo': Team( + ShortName='Alfa Romeo', + TeamColor=TeamColors( + Official='#900000', + Default='#900000' + ) + ), + 'alphatauri': Team( + ShortName='AlphaTauri', + TeamColor=TeamColors( + Official='#2b4562', + Default='#2b4562' + ) + ), + 'alpine': Team( + ShortName='Alpine', + TeamColor=TeamColors( + Official='#0090ff', + Default='#0755ab' + ) + ), + 'aston martin': Team( + ShortName='Aston Martin', + TeamColor=TeamColors( + Official='#006f62', + Default='#00665e' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#dc0004', + Default='#dc0004' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#ffffff', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#ff9800', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#00d2be', + Default='#00f5d0' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#0600ef', + Default='#0600ef' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#005aff', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2022.py b/fastf1/plotting/_constants/season2022.py new file mode 100644 index 000000000..b5a258e38 --- /dev/null +++ b/fastf1/plotting/_constants/season2022.py @@ -0,0 +1,91 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alfa romeo': Team( + ShortName='Alfa Romeo', + TeamColor=TeamColors( + Official='#b12039', + Default='#900000' + ) + ), + 'alphatauri': Team( + ShortName='AlphaTauri', + TeamColor=TeamColors( + Official='#4e7c9b', + Default='#2b4562' + ) + ), + 'alpine': Team( + ShortName='Alpine', + TeamColor=TeamColors( + Official='#2293d1', + Default='#fe86bc' + ) + ), + 'aston martin': Team( + ShortName='Aston Martin', + TeamColor=TeamColors( + Official='#2d826d', + Default='#00665e' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#ed1c24', + Default='#da291c' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#b6babd', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#f58020', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#6cd3bf', + Default='#00f5d0' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#1e5bc6', + Default='#0600ef' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#37bedd', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2023.py b/fastf1/plotting/_constants/season2023.py new file mode 100644 index 000000000..92e9628dd --- /dev/null +++ b/fastf1/plotting/_constants/season2023.py @@ -0,0 +1,91 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alfa romeo': Team( + ShortName='Alfa Romeo', + TeamColor=TeamColors( + Official='#C92D4B', + Default='#900000' + ) + ), + 'alphatauri': Team( + ShortName='AlphaTauri', + TeamColor=TeamColors( + Official='#5E8FAA', + Default='#2b4562' + ) + ), + 'alpine': Team( + ShortName='Alpine', + TeamColor=TeamColors( + Official='#2293D1', + Default='#fe86bc' + ) + ), + 'aston martin': Team( + ShortName='Aston Martin', + TeamColor=TeamColors( + Official='#358C75', + Default='#00665e' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#F91536', + Default='#da291c' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#b6babd', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#F58020', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#6CD3BF', + Default='#00f5d0' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#3671C6', + Default='#0600ef' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#37BEDD', + Default='#00a0dd' + ) + ) +} + +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_constants/season2024.py b/fastf1/plotting/_constants/season2024.py new file mode 100644 index 000000000..c87826a45 --- /dev/null +++ b/fastf1/plotting/_constants/season2024.py @@ -0,0 +1,92 @@ +from typing import Dict + +from fastf1.plotting._constants.base import ( + Compounds, + Team, + TeamColors +) + + +Teams: Dict[str, Team] = { + 'alpine': Team( + ShortName='Alpine', + TeamColor=TeamColors( + Official='#0093cc', + Default='#ff87bc' + ) + ), + 'aston martin': Team( + ShortName='Aston Martin', + TeamColor=TeamColors( + Official='#229971', + Default='#00665f' + ) + ), + 'ferrari': Team( + ShortName='Ferrari', + TeamColor=TeamColors( + Official='#e8002d', + Default='#e8002d' + ) + ), + 'haas': Team( + ShortName='Haas', + TeamColor=TeamColors( + Official='#b6babd', + Default='#b6babd' + ) + ), + 'mclaren': Team( + ShortName='McLaren', + TeamColor=TeamColors( + Official='#ff8000', + Default='#ff8000' + ) + ), + 'mercedes': Team( + ShortName='Mercedes', + TeamColor=TeamColors( + Official='#27f4d2', + Default='#27f4d2' + ) + ), + 'rb': Team( + ShortName='RB', + TeamColor=TeamColors( + Official='#6692ff', + Default='#364aa9' + ) + ), + 'red bull': Team( + ShortName='Red Bull', + TeamColor=TeamColors( + Official='#3671c6', + Default='#0600ef' + ) + ), + 'sauber': Team( + ShortName='Sauber', + TeamColor=TeamColors( + Official='#52e252', + Default='#00e700' + ) + ), + 'williams': Team( + ShortName='Williams', + TeamColor=TeamColors( + Official='#64c4ff', + Default='#00a0dd' + ) + ) +} + +# TODO: future proofing? +CompoundColors: Dict[Compounds, str] = { + Compounds.Soft: "#da291c", + Compounds.Medium: "#ffd12e", + Compounds.Hard: "#f0f0ec", + Compounds.Intermediate: "#43b02a", + Compounds.Wet: "#0067ad", + Compounds.Unknown: "#00ffff", + Compounds.TestUnknown: "#434649" +} diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py new file mode 100644 index 000000000..5d30ce491 --- /dev/null +++ b/fastf1/plotting/_interface.py @@ -0,0 +1,643 @@ +from typing import ( + Any, + Dict, + List, + Sequence, + Union +) + +import matplotlib.axes + +from fastf1.core import Session +from fastf1.plotting._backend import _load_drivers_from_f1_livetiming +from fastf1.plotting._base import ( + _Driver, + _DriverTeamMapping, + _fuzzy_matcher, + _normalize_string, + _Team +) +from fastf1.plotting._constants import Constants +from fastf1.plotting._constants import Constants as _Constants + + +_DRIVER_TEAM_MAPPINGS = dict() + + +def _get_driver_team_mapping( + session: Session +) -> "_DriverTeamMapping": + # driver-team mappings are generated once for each session and then reused + # on future calls + api_path = session.api_path + year = str(session.event['EventDate'].year) + + if api_path not in _DRIVER_TEAM_MAPPINGS: + teams = _load_drivers_from_f1_livetiming( + api_path=api_path, year=year + ) + mapping = _DriverTeamMapping(year, teams) + _DRIVER_TEAM_MAPPINGS[api_path] = mapping + + return _DRIVER_TEAM_MAPPINGS[api_path] + + +def _get_driver(identifier: str, session: Session) -> _Driver: + dtm = _get_driver_team_mapping(session) + identifier = _normalize_string(identifier).lower() + + # try driver abbreviation first + if (abb := identifier.upper()) in dtm.drivers_by_abbreviation: + return dtm.drivers_by_abbreviation[abb] + + # check for an exact driver name match + if identifier in dtm.drivers_by_normalized: + return dtm.drivers_by_normalized[identifier] + + # check for exact partial string match + for normalized_driver in dtm.drivers_by_normalized.keys(): + if identifier in normalized_driver: + return dtm.drivers_by_normalized[normalized_driver] + + # do fuzzy string matching + normalized_driver = _fuzzy_matcher(identifier, + list(dtm.drivers_by_normalized.keys())) + return dtm.drivers_by_normalized[normalized_driver] + + +def _get_team(identifier: str, session: Session) -> _Team: + dtm = _get_driver_team_mapping(session) + identifier = _normalize_string(identifier).lower() + + # check for an exact team name match + if identifier in dtm.teams_by_normalized.keys(): + return dtm.teams_by_normalized[identifier] + + # check full match with full team name or for exact partial string + # match with normalized team name + for normalized, full in dtm.teams_by_normalized.items(): + if (identifier == full) or (identifier in normalized): + return dtm.teams_by_normalized[normalized] + + # do fuzzy string match + team_name = _fuzzy_matcher(identifier, + list(dtm.teams_by_normalized.keys())) + return dtm.teams_by_normalized[team_name] + + +def _get_driver_color( + identifier: str, + session: Session, + *, + colormap: str = 'default', + _variants: bool = False +) -> str: + driver = _get_driver(identifier, session) + team_name = driver.team.normalized_value + + return _get_team_color(team_name, session, colormap=colormap) + + +def _get_team_color( + identifier: str, + session: Session, + *, + colormap: str = 'default', +) -> str: + dtm = _get_driver_team_mapping(session) + + if dtm.year not in Constants.keys(): + raise ValueError(f"No team colors for year '{dtm.year}'") + + team_name = _get_team(identifier, session).normalized_value + team_consts = Constants[dtm.year].Teams[team_name] + + if colormap == 'default': + return team_consts.TeamColor.Default + elif colormap == 'official': + return team_consts.TeamColor.Official + else: + raise ValueError(f"Invalid colormap '{colormap}'") + + +def get_team_name( + identifier: str, + session: Session, + *, + short: bool = False +) -> str: + """ + Get a full team name based on a recognizable and identifiable part of + the team name. + + Alternatively, a shortened version of the team name can be returned. The + short version is intended for saving space when annotating plots and may + skip parts of the official team name, for example "Scuderia Ferrari" + becomes just "Ferrari". + + Args: + identifier: a recognizable part of the team name + session: the session for which the data should be obtained + short: if True, a shortened version of the team name will be returned + """ + team = _get_team(identifier, session) + + if short: + dtm = _get_driver_team_mapping(session) + team_consts = Constants[dtm.year].Teams[team.normalized_value] + return team_consts.ShortName + + return team.value + + +def get_team_name_by_driver( + identifier: str, + session: Session, + *, + short: bool = False, +) -> str: + """ + Get a full team name based on a driver's abbreviation or based on a + recognizable and identifiable part of a driver's name. + + Alternatively, a shortened version of the team name can be returned. The + short version is intended for saving as much space as possible when + annotating plots and may skip parts of the official team name. + + Args: + identifier: driver abbreviation or recognizable part of the driver name + session: the session for which the data should be obtained + short: if True, a shortened version of the team name will be returned + """ + driver = _get_driver(identifier, session) + team = driver.team + + if short: + dtm = _get_driver_team_mapping(session) + team_consts = Constants[dtm.year].Teams[team.normalized_value] + return team_consts.ShortName + + return team.value + + +def get_team_color( + identifier: str, + session: Session, + *, + colormap: str = 'default', +) -> str: + """ + Get a team color based on a recognizable and identifiable part of + the team name. + + The team color is returned as a hexadecimal RGB color code. + + Args: + identifier: a recognizable part of the team name + session: the session for which the data should be obtained + colormap: one of ``'default'`` or ``'official'`` + + Returns: + A hexadecimal RGB color code + """ + return _get_team_color(identifier, session, colormap=colormap) + + +def get_driver_name(identifier: str, session: Session) -> str: + """ + Get a full driver name based on the driver's abbreviation or based on + a recognizable and identifiable part of the driver's name. + + Args: + identifier: driver abbreviation or recognizable part of the driver name + session: the session for which the data should be obtained + """ + driver = _get_driver(identifier, session) + return driver.value + + +def get_driver_abbreviation(identifier, session: Session) -> str: + """ + Get a driver's abbreviation based on a recognizable and identifiable + part of the driver's name. + + Note that the driver's abbreviation, if given exactly, is also a valid + identifier. In this case the same value is returned as was given as the + identifier. + + Args: + identifier: recognizable part of the driver's name (or the + driver's abbreviation) + session: the session for which the data should be obtained + """ + driver = _get_driver(identifier, session) + return driver.abbreviation + + +def get_driver_names_by_team(identifier: str, session: Session) -> List[str]: + """ + Get a list of full names of all drivers that drove for a team in a given + session based on a recognizable and identifiable part of the team name. + + Args: + identifier: a recognizable part of the team name + session: the session for which the data should be obtained + """ + team = _get_team(identifier, session) + return [driver.value for driver in team.drivers] + + +def get_driver_abbreviations_by_team( + identifier: str, session: Session +) -> List[str]: + """ + Get a list of abbreviations of all drivers that drove for a team in a given + session based on a recognizable and identifiable part of the team name. + + Args: + identifier: a recognizable part of the team name + session: the session for which the data should be obtained + """ + team = _get_team(identifier, session) + return [driver.abbreviation for driver in team.drivers] + + +def get_driver_color( + identifier: str, + session: Session, + *, + colormap: str = 'default', +) -> str: + """ + Get the color that is associated with a driver based on the driver's + abbreviation or based on a recognizable and identifiable part of the + driver's name. + + .. note:: This will simply return the team color of the team that the + driver participated for in this session. Contrary to older versions + of FastF1, there are no separate colors for each driver. This was + changed, because the small differences in color between drivers of + the same team can be barely distinguished in a plot. You should use + styling options apart from color if you need to differentiate drivers + of the same team. The function + :func:`~fastf1.plotting.get_driver_style` can help you to customize + the plot styling for each driver. + + Args: + identifier: driver abbreviation or recognizable part of the driver name + session: the session for which the data should be obtained + colormap: one of ``'default'`` or ``'official'`` + + Returns: + A hexadecimal RGB color code + + """ + return _get_driver_color(identifier, session, colormap=colormap) + + +def get_driver_style( + identifier: str, + style: Union[str, Sequence[str], Sequence[dict]], + session: Session, + *, + colormap: str = 'default', + additional_color_kws: Union[list, tuple] = () +) -> Dict[str, Any]: + """ + Get a plotting style that is unique for a driver based on the driver's + abbreviation or based on a recognizable and identifiable part of the + driver's name. + + This function simplifies the task of generating unique and easily + distinguishable visual styles for multiple drivers in a plot. + Primarily, the focus is on plotting with Matplotlib, but it is possible + to customize the behaviour for compatibility with other plotting libraries. + + The general idea for creating visual styles is as follows: + + 1. Set the primary color of the style to the color of the team for + which a driver is driving. This may be the line color in a line plot, + the marker color in a scatter plot, and so on. + + 2. Use one or multiple other styling options (line style, markers, ...) + to differentiate drivers in the same team. + + .. note:: It cannot be guaranteed that the styles are consistent throughout + a full season, especially in case of driver changes within a team. + + + **Option 1**: Rely on built-in styling options + + By default, this function supports the following Matplotlib plot arguments: + ``linestyle``, ``marker``, ``color``, ``facecolor``, ``edgecolor`` as well + as almost all other color-related arguments. + + The styling options include one color for each team and up to four + different line styles and marker styles within a team. That means that no + more than four different drivers are supported for a team in a single + session. This should be sufficent in almost all scenarios. + + The following example obtains the driver style for Alonso and Stroll in a + race in the 2023 season. The drivers should be represented using the + ``color`` and ``marker`` arguments, as may be useful in a scatter plot. + Both drivers were driving for the Aston Martin team, therefore, both + automatically get assigned the same color, which is the Aston Martin team + color. But both drivers get assigned a different marker style, so they can + be uniquely identified in the plot. + + Example:: + >>> from fastf1 import get_session + >>> from fastf1.plotting import get_driver_style + >>> session = get_session(2023, 10, 'R') + >>> get_driver_style('ALO', ['color', 'marker'], session) + {'color': '#00665e', 'marker': 'x'} + >>> get_driver_style('STR', ['color', 'marker'], session) + {'color': '#00665e', 'marker': 'o'} + + **Option 2**: Provide a custom list of styling variants + + To allow for almost unlimited styling options, it is possible to specify + custom styling variants. These are not tied to any specific plotting + library. + + In the following example, a list with two custom stlyes is defined that are + then used to generate driver specific styles. Each style is represented by + a dictionary of keywords and values. + + The first driver in a team gets assigned the first style, the second driver + the second style and so on (if there are more than two drivers). It is + necessary to define at least as many styles as there are drivers in a team. + + The following things need to be noted: + + 1. The notion of first or second driver does not refer to any particular + reference and no specific order for drivers within a team is intended or + guranteed. + + 2. Any color-related key can make use of the "magic" ``'auto'`` value as + shown with Alonso in this example. When the color value is set to + ``'auto'`` it will automatically be replaced with the team color for this + driver. All color keywords that are used in Matplotlib should be recognized + automatically. You can define custom arguments as color arguments through + the ``additional_color_kws`` argument. + + 3. Each style dictionary can contain arbitrary keys and value. Therefore, + you are not limited to any particular plotting library. + + Example:: + >>> from fastf1 import get_session + >>> from fastf1.plotting import get_driver_style + >>> session = get_session(2023, 10, 'R') + >>> my_styles = [ \ + {'linestyle': 'solid', 'color': 'auto', 'custom_arg': True}, \ + {'linestyle': 'dotted', 'color': '#FF0060', 'other_arg': 10} \ + ] + >>> get_driver_style('ALO', my_styles, session) + {'linestyle': 'solid', 'color': '#00665e', 'custom_arg': True} + >>> get_driver_style('STR', my_styles, session) + {'linestyle': 'dotted', 'color': '#FF0060', 'other_arg': 10} + + Args: + identifier: driver abbreviation or recognizable part of the driver name + style: list of matplotlib plot arguments that should be used for + styling or a list of custom style dictionaries + session: the session for which the data should be obtained + colormap: one of ``'default'`` or ``'official'`` + additional_color_kws: A list of keys that should additionally be + treated as colors. This is most usefull for making the magic + ``'auto'`` color work with custom styling options. + + Returns: a dictionary of plot style arguments that can be directly passed + to a matplotlib plot function using the ``**`` expansion operator + + + .. minigallery:: fastf1.plotting.get_driver_style + :add-heading: + """ + stylers = { + 'linestyle': ['solid', 'dashed', 'dashdot', 'dotted'], + 'marker': ['x', 'o', '^', 'D'] + } + + # color keyword arguments that are supported by various matplotlib + # functions + color_kwargs = ( + # generic + 'color', 'colors', 'c', + # .plot + 'gapcolor', + 'markeredgecolor', 'mec', + 'markerfacecolor', 'mfc', + 'markerfacecoloralt', 'mfcalt', + # .scatter + 'facecolor', 'facecolors', 'fc', + 'edgecolor', 'edgecolors', 'ec', + # .errorbar + 'ecolor', + # add user defined color keyword arguments + *additional_color_kws + ) + + driver = _get_driver(identifier, session) + team = driver.team + idx = team.drivers.index(driver) + + if not style: + # catches empty list, tuple, str + raise ValueError("The provided style info is empty!") + + if isinstance(style, str): + style = [style] + + plot_style = dict() + + if isinstance(style[0], str): + # generate the plot style based on the provided keyword + # arguments + for opt in style: + if opt in color_kwargs: + value = _get_team_color(team.normalized_value, + session, + colormap=colormap) + elif opt in stylers: + value = stylers[opt][idx] + else: + raise ValueError(f"'{opt}' is not a supported styling " + f"option") + plot_style[opt] = value + + else: + try: + custom_style = style[idx] + except IndexError: + raise ValueError(f"The provided custom style info does not " + f"contain enough variants! (Has: {len(style)}, " + f"Required: {idx})") + + if not isinstance(custom_style, dict): + raise ValueError("The provided style info has an invalid format!") + + # copy the correct user provided style and replace any 'auto' + # colors with the correct color value + plot_style = custom_style.copy() + for kwarg in color_kwargs: + if plot_style.get(kwarg, None) == 'auto': + color = _get_team_color(team.normalized_value, + session, + colormap=colormap) + plot_style[kwarg] = color + + return plot_style + + +def get_compound_color(compound: str, session: Session) -> str: + """ + Get the compound color as hexadecimal RGB color code for a given compound. + + Args: + compound: The name of the compound + session: the session for which the data should be obtained + + Returns: + A hexadecimal RGB color code + """ + year = str(session.event['EventDate'].year) + return _Constants[year].CompoundColors[compound.upper()] + + +def get_compound_mapping(session: Session) -> Dict[str, str]: + """ + Returns a dictionary that maps compound names to their associated + colors. The colors are given as hexadecimal RGB color codes. + + Args: + session: the session for which the data should be obtained + + Returns: + dictionary mapping compound names to RGB hex colors + """ + year = str(session.event['EventDate'].year) + return Constants[year].CompoundColors.copy() + + +def get_driver_color_mapping( + session: Session, *, colormap: str = 'default', +) -> Dict[str, str]: + """ + Returns a dictionary that maps driver abbreviations to their associated + colors. The colors are given as hexadecimal RGB color codes. + + Args: + session: the session for which the data should be obtained + colormap: one of ``'default'`` or ``'official'`` + + Returns: + dictionary mapping driver abbreviations to RGB hex colors + """ + dtm = _get_driver_team_mapping(session) + + if colormap == 'default': + colors = { + abb: (Constants[dtm.year] + .Teams[driver.team.normalized_value] + .TeamColor.Default) + for abb, driver in dtm.drivers_by_abbreviation.items() + } + elif colormap == 'official': + colors = { + abb: (Constants[dtm.year] + .Teams[driver.team.normalized_value] + .TeamColor.Official) + for abb, driver in dtm.drivers_by_abbreviation.items() + } + else: + raise ValueError(f"Invalid colormap '{colormap}'") + + return colors + + +def list_team_names(session: Session) -> List[str]: + """Returns a list of full team names of all teams in the ``session``.""" + dtm = _get_driver_team_mapping(session) + return list(team.value for team in dtm.teams_by_normalized.values()) + + +def list_short_team_names(session: Session) -> List[str]: + """Returns a list of short team names of all teams in the ``session``.""" + dtm = _get_driver_team_mapping(session) + return list(Constants[dtm.year].Teams[team].ShortName + for team in dtm.teams_by_normalized.keys()) + + +def list_driver_abbreviations(session: Session) -> List[str]: + """Returns a list of abbreviations of all drivers in the ``session``.""" + dtm = _get_driver_team_mapping(session) + return list(dtm.drivers_by_abbreviation.keys()) + + +def list_driver_names(session: Session) -> List[str]: + """Returns a list of full names of all drivers in the ``session``.""" + dtm = _get_driver_team_mapping(session) + return list(driver.value for driver in dtm.drivers_by_normalized.values()) + + +def list_compounds(session: Session) -> List[str]: + """Returns a list of all compound names for this season (not session).""" + year = str(session.event['EventDate'].year) + return list(Constants[year].CompoundColors.keys()) + + +def add_sorted_driver_legend(ax: matplotlib.axes.Axes, session: Session): + """ + Adds a legend to the axis where drivers are ordered by team and within a + team in the same order that is used for selecting plot styles. + + This function is a drop in replacement for calling Matplotlib's + ``ax.legend()`` method. It can only be used when driver names or driver + abbreviations are used as labels for the legend. + + There is no particular need to use this function except to make the + legend more visually pleasing. + + Args: + ax: An instance of a Matplotlib ``Axes`` object + session: the session for which the data should be obtained + + Returns: + ``matplotlib.legend.Legend`` + + .. minigallery:: fastf1.plotting.add_sorted_driver_legend + :add-heading: + + """ + dtm = _get_driver_team_mapping(session) + handles, labels = ax.get_legend_handles_labels() + + teams_list = list(dtm.teams_by_normalized.values()) + driver_list = list(dtm.drivers_by_normalized.values()) + + # create an intermediary list where each element is a tuple that + # contains (team_idx, driver_idx, handle, label). Then sort this list + # based on the team_idx and driver_idx. As a result, drivers from the + # same team will be next to each other and in the same order as their + # styles are cycled. + ref = list() + for hdl, lbl in zip(handles, labels): + driver = _get_driver(lbl, session) + team = driver.team + + team_idx = teams_list.index(team) + driver_idx = driver_list.index(driver) + + ref.append((team_idx, driver_idx, hdl, lbl)) + + # sort based only on team_idx and driver_idx (i.e. first two entries) + ref.sort(key=lambda e: e[:2]) + + handles_new = list() + labels_new = list() + for elem in ref: + handles_new.append(elem[2]) + labels_new.append(elem[3]) + + return ax.legend(handles_new, labels_new) diff --git a/fastf1/plotting.py b/fastf1/plotting/_plotting.py similarity index 54% rename from fastf1/plotting.py rename to fastf1/plotting/_plotting.py index 9ac64d7b1..637810ba0 100644 --- a/fastf1/plotting.py +++ b/fastf1/plotting/_plotting.py @@ -1,37 +1,12 @@ -""" -Helper functions for creating data plots. - -:mod:`fastf1.plotting` provides optional functionality with the intention of -making it easy to create nice plots. - -This module offers mainly two things: - - team names and colors - - matplotlib mods and helper functions - -Fast-F1 focuses on plotting data with matplotlib. Of course, you are not -required to use matplotlib and you can use any other tool you like. - -If you wish to use matplotlib, it is highly recommended to enable some -helper functions by calling :func:`setup_mpl`. - -If you don't want to use matplotlib, you can still use the team names -and colors which are provided below. - - -.. note:: Plotting related functionality is likely to change in a future - release. -""" import warnings from typing import ( - Dict, - List + List, + Optional ) import numpy as np import pandas as pd -from fastf1.logger import get_logger - try: import matplotlib @@ -39,166 +14,60 @@ from matplotlib import pyplot as plt except ImportError: warnings.warn("Failed to import optional dependency 'matplotlib'!" - "Plotting functionality will be unavailable!", UserWarning) + "Plotting functionality will be unavailable!", + RuntimeWarning) try: import timple except ImportError: warnings.warn("Failed to import optional dependency 'timple'!" "Plotting of timedelta values will be restricted!", - UserWarning) - -_logger = get_logger(__name__) - -with warnings.catch_warnings(): - warnings.filterwarnings('ignore', - message="Using slow pure-python SequenceMatcher") - # suppress that warning, it's confusing at best here, we don't need fast - # sequence matching and the installation (on windows) some effort - from rapidfuzz import fuzz - - -class __TeamColorsWarnDict(dict): - """Implements userwarning on KeyError in :any:`TEAM_COLORS` after - changing team names.""" - - def get(self, key, default=None): - value = super().get(key, default) - if value is None: - self.warn_change() - return value - - def __getitem__(self, item): - try: - return super().__getitem__(item) - except KeyError as err: - self.warn_change() - raise err - except Exception as err: - raise err - - def warn_change(self): - warnings.warn( - "Team names in `TEAM_COLORS` are now lower-case and only contain " - "the most identifying part of the name. " - "Use function `.team_color` alternatively.", UserWarning - ) + RuntimeWarning) + +from rapidfuzz import fuzz + +from fastf1.logger import get_logger +from fastf1.plotting._constants import ( + LEGACY_DRIVER_COLORS, + LEGACY_DRIVER_TRANSLATE, + LEGACY_TEAM_COLORS, + LEGACY_TEAM_TRANSLATE +) + + +_logger = get_logger(__package__) + + +_COLOR_PALETTE: List[str] = ['#FF79C6', '#50FA7B', '#8BE9FD', '#BD93F9', + '#FFB86C', '#FF5555', '#F1FA8C'] +# The default color palette for matplotlib plot lines in fastf1's color scheme -TEAM_COLORS = __TeamColorsWarnDict({ - 'mercedes': '#00d2be', 'ferrari': '#dc0000', - 'red bull': '#fcd700', 'mclaren': '#ff8700', - 'alpine': '#fe86bc', 'aston martin': '#006f62', - 'sauber': '#00e701', 'visa rb': '#1634cb', - 'haas': '#ffffff', 'williams': '#00a0dd' -}) -"""Mapping of team names to team colors (hex color codes). -(current season only)""" - -TEAM_TRANSLATE: Dict[str, str] = { - 'MER': 'mercedes', 'FER': 'ferrari', - 'RBR': 'red bull', 'MCL': 'mclaren', - 'APN': 'alpine', 'AMR': 'aston martin', - 'SAU': 'sauber', 'VRB': 'visa rb', - 'HAA': 'haas', 'WIL': 'williams'} -"""Mapping of team names to theirs respective abbreviations.""" - -DRIVER_COLORS: Dict[str, str] = { - "valtteri bottas": "#00e701", - "zhou guanyu": "#008d01", - "theo pourchaire": "#004601", - - "nyck de vries": "#1e3d61", - "yuki tsunoda": "#356cac", - "daniel ricciardo": "#2b4562", - "liam lawson": "#2b4562", - "isack hadjar": "#1e6176", - "ayumu iwasa": "#1e6176", - - "pierre gasly": "#fe86bc", - "esteban ocon": "#ff117c", - "jack doohan": "#894667", - - "fernando alonso": "#006f62", - "lance stroll": "#00413b", - "felipe drugovich": "#2f9b90", - - "charles leclerc": "#dc0000", - "carlos sainz": "#ff8181", - "robert shwartzman": "#9c0000", - "oliver bearman": "#c40000", - - "kevin magnussen": "#ffffff", - "nico hulkenberg": "#cacaca", - - "oscar piastri": "#ff8700", - "lando norris": "#eeb370", - "pato oward": "#ee6d3a", - - "lewis hamilton": "#00d2be", - "george russell": "#24ffff", - "frederik vesti": "#00a6ff", - - "max verstappen": "#fcd700", - "sergio perez": "#ffec7b", - "jake dennis": "#907400", - - "alexander albon": "#005aff", - "logan sargeant": "#012564", - "zak osullivan": "#1b3d97", - "franco colapinto": "#639aff" -} -"""Mapping of driver names to driver colors (hex color codes). -(current season only)""" - -DRIVER_TRANSLATE: Dict[str, str] = { - 'LEC': 'charles leclerc', 'SAI': 'carlos sainz', - 'SHW': 'robert shwartzman', - 'VER': 'max verstappen', 'PER': 'sergio perez', - 'DEN': 'jake dennis', - 'PIA': 'oscar piastri', 'NOR': 'lando norris', - 'OWA': 'pato oward', - 'GAS': 'pierre gasly', 'OCO': 'esteban ocon', - 'DOO': 'jack doohan', - 'BOT': 'valtteri bottas', 'ZHO': 'zhou guanyu', - 'POU': 'theo pourchaire', - 'DEV': 'nyck de vries', 'TSU': 'yuki tsunoda', - 'RIC': 'daniel ricciardo', 'LAW': 'liam lawson', - 'HAD': 'isack hadjar', 'IWA': 'ayumu iwasa', - 'MAG': 'kevin magnussen', 'HUL': 'nico hulkenberg', - 'BEA': 'oliver bearman', - 'ALO': 'fernando alonso', 'STR': 'lance stroll', - 'DRU': 'felipe drugovich', - 'HAM': 'lewis hamilton', 'RUS': 'george russell', - 'VES': 'frederik vesti', - 'ALB': 'alexander albon', 'SAR': 'logan sargeant', - 'OSU': 'zak osullivan', 'COL': 'franco colapinto'} -"""Mapping of driver names to theirs respective abbreviations.""" - -COMPOUND_COLORS: Dict[str, str] = { - "SOFT": "#da291c", - "MEDIUM": "#ffd12e", - "HARD": "#f0f0ec", - "INTERMEDIATE": "#43b02a", - "WET": "#0067ad", - "UNKNOWN": "#00ffff", - "TEST-UNKNOWN": "#434649" -} -"""Mapping of tyre compound names to compound colors (hex color codes). -(current season only)""" - -COLOR_PALETTE: List[str] = ['#FF79C6', '#50FA7B', '#8BE9FD', '#BD93F9', - '#FFB86C', '#FF5555', '#F1FA8C'] -"""The default color palette for matplotlib plot lines in fastf1's color -scheme.""" +class __DefaultStringArgType(str): + pass + + +__color_scheme_default_arg = __DefaultStringArgType('fastf1') def setup_mpl( - mpl_timedelta_support: bool = True, color_scheme: str = 'fastf1', + mpl_timedelta_support: bool = True, + color_scheme: Optional[str] = __color_scheme_default_arg, misc_mpl_mods: bool = True): """Setup matplotlib for use with fastf1. This is optional but, at least partly, highly recommended. + .. deprecated:: 3.4.0 + + The optional argument ``misc_mpls_mods`` is deprecated. + + .. deprecated:: 3.4.0 + + The default value for ``color_scheme`` will change from ``'fastf1'`` + to ``None``. You should explicitly set the desired value when calling + this function. + + Parameters: mpl_timedelta_support (bool): Matplotlib itself offers very limited functionality for plotting @@ -217,13 +86,25 @@ def setup_mpl( Valid color scheme names are: ['fastf1', None] misc_mpl_mods (bool): - This enables a collection of patches for the following mpl - features: - - - ``.savefig`` (saving of figures) - - ``.bar``/``.barh`` (plotting of bar graphs) - - ``plt.subplots`` (for creating a nice background grid) + This argument is deprecated since v3.4.0 and should no longer be + used. """ + if color_scheme is __color_scheme_default_arg: + warnings.warn( + "FastF1 will no longer silently modify the default Matplotlib " + "colors in the future.\nTo remove this warning, explicitly set " + "`color_scheme=None` or `color_scheme='fastf1'` when calling " + "`.setup_mpl()`.", FutureWarning + ) + + if misc_mpl_mods: + warnings.warn( + "FastF1 will stop modifying the default Matplotlib settings in " + "the future.\nTo opt-in to the new behaviour and remove this " + "warning, explicitly set `misc_mpl_mods=False` when calling " + "`.setup_mpl()`.", FutureWarning + ) + if mpl_timedelta_support: _enable_timple() if color_scheme == 'fastf1': @@ -233,33 +114,34 @@ def setup_mpl( def driver_color(identifier: str) -> str: - """Get a driver's color from a driver name or abbreviation. + """ + Get a driver's color from a driver name or abbreviation. + + .. deprecated:: 3.4.0 + This function is deprecated and will be removed in a future version. + Use :func:`~fastf1.plotting.get_driver_color` instead. This function will try to find a matching driver for any identifier string - that is passed to it. This involves case insensitive matching and partial + that is passed to it. This involves case-insensitive matching and partial string matching. - If you want exact string matching, you should use the - :any:`DRIVER_COLORS` dictionary directly, using :any:`DRIVER_TRANSLATE` to - convert abbreviations to team names if necessary. - Example:: - >>> driver_color('charles leclerc') + >>> driver_color('charles leclerc') # doctest: +SKIP '#dc0000' - >>> driver_color('max verstappen') + >>> driver_color('max verstappen') # doctest: +SKIP '#fcd700' - >>> driver_color('ver') + >>> driver_color('ver') # doctest: +SKIP '#fcd700' - >>> driver_color('lec') + >>> driver_color('lec') # doctest: +SKIP '#dc0000' shortened driver names and typos can be dealt with too (within reason) - >>> driver_color('Max Verst') + >>> driver_color('Max Verst') # doctest: +SKIP '#fcd700' - >>> driver_color('Charles') + >>> driver_color('Charles') # doctest: +SKIP '#dc0000' Args: @@ -269,25 +151,31 @@ def driver_color(identifier: str) -> str: Returns: str: hex color code """ + warnings.warn("The function `driver_color` is deprecated and will be " + "removed in a future version. Use " + "`fastf1.plotting.get_driver_color` instead.", + FutureWarning) - if identifier.upper() in DRIVER_TRANSLATE: + if identifier.upper() in LEGACY_DRIVER_TRANSLATE: # try short team abbreviations first - return DRIVER_COLORS[DRIVER_TRANSLATE[identifier.upper()]] + return LEGACY_DRIVER_COLORS[ + LEGACY_DRIVER_TRANSLATE[identifier.upper()] + ] else: identifier = identifier.lower() # check for an exact team name match - if identifier in DRIVER_COLORS: - return DRIVER_COLORS[identifier] + if identifier in LEGACY_DRIVER_COLORS: + return LEGACY_DRIVER_COLORS[identifier] # check for exact partial string match - for team_name, color in DRIVER_COLORS.items(): + for team_name, color in LEGACY_DRIVER_COLORS.items(): if identifier in team_name: return color # do fuzzy string matching key_ratios = list() - for existing_key in DRIVER_COLORS: + for existing_key in LEGACY_DRIVER_COLORS: ratio = fuzz.ratio(identifier, existing_key) key_ratios.append((ratio, existing_key)) key_ratios.sort(reverse=True) @@ -304,41 +192,42 @@ def driver_color(identifier: str) -> str: # than second best) raise KeyError best_matched_key = key_ratios[0][1] - return DRIVER_COLORS[best_matched_key] + return LEGACY_DRIVER_COLORS[best_matched_key] def team_color(identifier: str) -> str: - """Get a team's color from a team name or abbreviation. + """ + Get a team's color from a team name or abbreviation. + + .. deprecated:: 3.4.0 + This function is deprecated and will be removed in a future version. + Use :func:`~fastf1.plotting.get_team_color` instead. This function will try to find a matching team for any identifier string - that is passed to it. This involves case insensitive matching and partial + that is passed to it. This involves case-insensitive matching and partial string matching. - If you want exact string matching, you should use the - :any:`TEAM_COLORS` dictionary directly, using :any:`TEAM_TRANSLATE` to - convert abbreviations to team names if necessary. - Example:: - >>> team_color('Red Bull') + >>> team_color('Red Bull') # doctest: +SKIP '#fcd700' - >>> team_color('redbull') + >>> team_color('redbull') # doctest: +SKIP '#fcd700' - >>> team_color('Red') + >>> team_color('Red') # doctest: +SKIP '#fcd700' - >>> team_color('RBR') + >>> team_color('RBR') # doctest: +SKIP '#fcd700' - shortened team names, included sponsors and typos can be dealt with - too (within reason) + # shortened team names, included sponsors and typos can be dealt with + # too (within reason) - >>> team_color('Mercedes') + >>> team_color('Mercedes') # doctest: +SKIP '#00d2be' - >>> team_color('Merc') + >>> team_color('Merc') # doctest: +SKIP '#00d2be' - >>> team_color('Merecds') + >>> team_color('Merecds') # doctest: +SKIP '#00d2be' - >>> team_color('Mercedes-AMG Petronas F1 Team') + >>> team_color('Mercedes-AMG Petronas F1 Team') # doctest: +SKIP '#00d2be' Args: @@ -348,9 +237,14 @@ def team_color(identifier: str) -> str: Returns: str: hex color code """ - if identifier.upper() in TEAM_TRANSLATE: + warnings.warn("The function `team_color` is deprecated and will be " + "removed in a future version. Use " + "`fastf1.plotting.get_team_color` instead.", + FutureWarning) + + if identifier.upper() in LEGACY_TEAM_TRANSLATE: # try short team abbreviations first - return TEAM_COLORS[TEAM_TRANSLATE[identifier.upper()]] + return LEGACY_TEAM_COLORS[LEGACY_TEAM_TRANSLATE[identifier.upper()]] else: identifier = identifier.lower() # remove common non-unique words @@ -358,17 +252,17 @@ def team_color(identifier: str) -> str: identifier = identifier.replace(word, "") # check for an exact team name match - if identifier in TEAM_COLORS: - return TEAM_COLORS[identifier] + if identifier in LEGACY_TEAM_COLORS: + return LEGACY_TEAM_COLORS[identifier] # check for exact partial string match - for team_name, color in TEAM_COLORS.items(): + for team_name, color in LEGACY_TEAM_COLORS.items(): if identifier in team_name: return color # do fuzzy string matching key_ratios = list() - for existing_key in TEAM_COLORS.keys(): + for existing_key in LEGACY_TEAM_COLORS.keys(): ratio = fuzz.ratio(identifier, existing_key) key_ratios.append((ratio, existing_key)) key_ratios.sort(reverse=True) @@ -385,24 +279,7 @@ def team_color(identifier: str) -> str: # than second best) raise KeyError best_matched_key = key_ratios[0][1] - return TEAM_COLORS[best_matched_key] - - -def lapnumber_axis(ax, axis='xaxis'): - """Set axis to integer ticks only." - - Args: - ax: matplotlib axis - axis: can be 'xaxis' or 'yaxis' - - Returns: - the modified axis instance - - """ - getattr(ax, axis).get_major_locator().set_params(integer=True, - min_n_ticks=0) - - return ax + return LEGACY_TEAM_COLORS[best_matched_key] def _enable_timple(): @@ -501,9 +378,33 @@ def _enable_fastf1_color_scheme(): plt.rcParams['axes.titlesize'] = '19' plt.rcParams['axes.titlepad'] = '12' plt.rcParams['axes.titleweight'] = 'light' - plt.rcParams['axes.prop_cycle'] = cycler('color', COLOR_PALETTE) + plt.rcParams['axes.prop_cycle'] = cycler('color', _COLOR_PALETTE) plt.rcParams['legend.fancybox'] = False plt.rcParams['legend.facecolor'] = (0.1, 0.1, 0.1, 0.7) plt.rcParams['legend.edgecolor'] = (0.1, 0.1, 0.1, 0.9) plt.rcParams['savefig.transparent'] = False plt.rcParams['axes.axisbelow'] = True + + +def lapnumber_axis(ax, axis='xaxis'): + """ + Set axis to integer ticks only. + + .. deprecated:: 3.4.0 + The function ``lapnumber_axis`` is deprecated and will ber removed in a + future version without replacement. + + Args: + ax: matplotlib axis + axis: can be 'xaxis' or 'yaxis' + + Returns: + the modified axis instance + """ + warnings.warn("The function `lapnumber_axis` is deprecated and will be " + "removed without replacement in a future version.", + FutureWarning) + getattr(ax, axis).get_major_locator().set_params(integer=True, + min_n_ticks=0) + + return ax diff --git a/fastf1/tests/mpl-baseline/test_doc_example_delta_time.png b/fastf1/tests/mpl-baseline/test_doc_example_delta_time.png index 91ac060be0c726f9e6c17c5cc0c6af46b31c0634..847f505be73365ccaa4a20a955849af269f37afc 100644 GIT binary patch literal 59386 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ɂeD%c}++5wYE0FsQpN742OSJ|IFBwtbguMR5B2A>fr`- zmy#oit*NOz?!&joxB^XmY8PDZUoKw&$EYK%)K$c;DE{9-*PWrharIbDT$C*Lo4R@_2J)O%pQ65B;g z(Cc1$>7GJs$M0$GVr2a@48w5@Arxz%I3}I2vH(F%;G-k2OkLfKnG;DBIW&0$!4{TK z-&bgaV^$%SEoJ2%GEN6wrBL(jMB)iju&PYTERrP6I~3wQEnieJ9~-;na`LBsb~R6@jDb9ra!m z1!2AwButUR$V_LaqKvu{LiLv2tGQy zY4~3m6JMSP$gK0Y)nE9dcUqhO?j5;v#>M#zfpmHejc)fJTLY?;Tw5TP-cbzb))DL_%B~LYONtpf`E+9Pl zW9r?bmCcwJPD3=1yWJUfzz-y+L*}o{PlgCiq6UGkPg+eO!&7DgJh&G#9*k923*Ljm zkFF%`!=Z}o7X04d)>7;Th3JiQqKB#NF5mnZ30jRN0NJ;ve$^!>tbx`iy>aP|pBUx~ z(%*NgbEN*JOSLZYfs(+Z>`^0>Y3ldjpPz`6;;761{DB9FL-)atKBIB5P_}<-r-KfV zYTp?#2TqpKfUS4t-Y(7%)rj6~ccDmT(;MCJY`0$Y9x)LBA z4ynYfhrZ^N{o%bR!ABZG>!F(y3_B-7j3!HtUs~>RU~?^)SwWJ`4f{hJbWaa`*&QI; z2Y33iUlu6wI_sd5Sk^wnREv!Z@hyDhBz3knHP8Q4E7D0~t<~6d{*x@h&sYfdFg}wU z&moHJNL0jkm{X#W_^qlly95QUdrIhi$Q=hKK@=*k|X^=*Zv8P8s~IVaBbI ze1fQm(%{X}c=mzmLk6aP{96h*!rPszDE5?rjrjxojPId}OA8XtH_JIrBO3x6RvCss z4W{$KJ?<72l|C5MoS*(dQ)2eKYJ z89gmQ`u?03c8JfKdiR5xa%wnF>S4(evOR}|AM8V z*Ew*srR#pinjh7K5P|R=4FQDMyTMmmxmNS(KSI>ALG#S}PJC84lQrLBLy=ry=eqCF zR7q}%5m4?3<>jSnek1e_v<37b2!VcU4raKhGLtpUDvZyVt#q+`06)V~x9dP-)nDfs zs6P=PU3pL!R?tkhF4On1`|GDYD`)DR)1O7Gp(hn~>U?84L7Ig`-pYp&&=oQSwuob1 z3Ra&y$&uUOl~~63m~3h3V{`%k;?_v@rK;2_5kfXuQ_p9~_f<4BVx(El77K2&+f$R1 zF;Y{0SQS}%G9t6a)SD4dMXeWpENJ=&NOx*ZOk>4Sqi^?f^;1ohUh^hPoi&a15rP54 zf{NkT(Yuam@g!9+W& zY9C~5WpJDQYpdt~by+`Rsanbqxz(}Qure4uyJNYnnQsEn z0At(p>A+C~1IGAYx&(P9EQTbdxR+gqGt=Gp84;>+2Shl{JrmEH|Bd@@xZ8Fx5z^?C zkVg6?#9xiDYi};!K5AfQiGdBvWNyHa#^-2%7V`EYlJrBjM`E`gk1`2BbOI&9r~oxs z@&uFKW3*@c-g_@d&k6{P-E5wx(7I;zP9Gc

F+q`XP%GM{gYM(^j(feciRJQv7Y_ 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⋘}x!cldC%|E1~N9gf9xhu{v` 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б2f-*y3{3y=AC*SGq9;ZE5= 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 Q5`O7u?$UUucIe_i0MOvN;{X5v diff --git a/fastf1/tests/mpl-baseline/test_doc_example_fast_lec.png b/fastf1/tests/mpl-baseline/test_doc_example_fast_lec.png index 2be5f980181b82a592c17f8a018ee31a5193cdc5..7f6013a97fef1181247ad0bef547d411c45c648a 100644 GIT binary patch literal 40533 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 $x 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

dU( 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 PfxojlhT7R$w*LPGw$$VF diff --git a/fastf1/tests/mpl-baseline/test_readme_example.png b/fastf1/tests/mpl-baseline/test_readme_example.png index b8ac55693e00a909a269b39c70ba30b98c2789bf..406d144e334ba506a25c747a44705e9a85148c0b 100644 GIT binary patch literal 31927 zcmdqJby$?`+ci2vN{gU0CHf6118ds!HBMK|j0jkC|rik084iq#yn`m7n5%4c~?fyt6uZ|?ccsAn$| z>>_z+Uvb9VDr1#g3hT3Iztq0F?UB@)v??<^={)uAn`eiGE4?W>JN!Cv zA;`x7MGe1}1qkKguSirn>KyWdF)iwvf`S5G7+zXPNQhFvEfg)hOmcxV0QnsHI$8r> zJ&QSqdJZoW(EtDD!%e2zBei%LuA$WY;h)!OCV5D7YaUz(>PTbTx^c27T z=8KC1&K)w}k|d(x+!r2vKK}OY+umw-L3nYj-#UMCHot!AD{uaq`443UC#OrPJ}V^a zGrvsRlO&`!2b{&3!#EXKjUS6C0Qh0 zjK3#{==-k!l34I=q!3$LZe=U>KlJ;clfTd}>%C#a&cRVR5=18MGX1jrxd3~{%Y=Yy z@3h4o#|Xw-UZmejzh1M{Kqm1!943Z^>4ns>IKQX$|*)hF}rU$y2Va| zo9`3t*rlbD2+2-W*rv*Oi?=pj1aG-yLC;bx+>p z$frkZa8M;Qx3F-G|KaX1pJ7eBR;F5|Ou5JMeN9cx=^yFDDEr#=Q&e($7w8OJs0C}+ zPN>UnpN-RZB7yfGK3~@hXOl}AKk(mQr!(@~=5!zOpVt0#>DKv3hz)t9TkqC*u8J?#tX9kwwV}4wy3{MT#zH%?On9>f43+Js zzP-Nc;UO+I=t6^%@me$P&bq~CP!+QpGpBA29Of^M<7Xu$t)f4~iEYhhDA{WcVZRUy+Tyx+`jlz#OorFOnyvghhlCEm!Jt4~8h zL!GS;a`h`Od2h^(?k?8jR@wvw*Ib>v`4{VU1z`FNF<>peCtT~vGcd@X4v_wL60>q};&U%q_F>q)u& z@Zq`gK{qB?HSb|Y&JESx`(DqkX*`2}jy>Z_`t=v6-U>(4!uGCoMXGRSi3W>QUn0!j z_Nrxf7WMZ;G57f{c)84O5V@<$nGYYgMjlaBz~7|5a_(ugZ|@ONv3?_@(;ul)O%jic z=2l<%M9enfWdjf8hLV!;xA=>~_Co`=@119lVuRJmb26`L<~%a*Vdf|)EAy^+_Lo{K z!s>f1X3x62xo9!@^_5+zzuIJ591aG+xFw8XuD>)i&!Bqcn^1?t%EXtk8gj7~dh?Ey z?;<_=jX{KD?G+-ha5{cqbPQZiy3TZ){Q7YF!#+*qm0L6gAu*(IKvO_0>4U9tawgF* z5*n_gizmOqlkIpyXBa=LeF1g(^5p@q*<6)W*<@I}jyr3Agz!cJ@rkqUNxWn~)|BLsVj!m^Ex4k@b z)oB0+0ORz6^%OPFIRri{vb8d&Dr)VA>+*J?z&a-Ov}dcQ%I2ZyX=$6P7wg)PWuItY z_k~QbMjlWam*h-2-(PCFx3!$-yXrLgO6LR%%Xe6r&Nc`8i~fggfMW5&mM0V=STo$_ z`=$4m8l{(;Xb63px0O{@%{~PY>U&PU($3WrY4uGIw!E^xv+jAgzv)Z?wfWlUg%)}v zx+_qf6>1b8$s>RNe=XwA(n8P3$Rs0==J`q9l)|&GpvG@;o02PrGrxhyO+ZL!ZV-=W zd~t8R$4Eg@akq*dIDsYsz{z{K-a3I`^>e6GkDOII2dmw+vNbu`;;zGGkg`iiyq=z( zK4E~ZE?KrhF^kzTv-xeExmRZM#-^_bxhLtvy;WgYz8&L!JAb(Eo0@JP>@G^cc+p=l zMgi`)VsT5OjbZc`g8+nIJ|d>lEVna&+Qn&CF&cb7Sxm6qeE8<8^9XW;#9Rs-@NN5u zc7O`g)Y9U#JsIb`vu1g)cz6(@mMpov+99V^=d;ZmaYIe*JpjGSTyG>y)8rRSVon`0 zn;Ml)W()O)ekgcvvulrm;tNKRyA=*+fC&ir?=2HU)o(B5Bb3O8vH9Hh8P3yJWM&s( z(Vlbzd1t+!3_Rkt<#+^KXS#XbtEZ|V%fiU#A_)nJN`mm0lil#M_D_$9x2F>Ak5Nz% zrWw|HdB$d(#+?MFCBd}qGOetsc>)CpARJ%QX@}#oNbz$Ij z?!9uS>CQ7K*@G?9`}gmMym-NR=~5JzYQoZ7aYs~aZ0u|)nbXi5)GsA9HMi<#aJ4a_ zvSa~&{`?_l6b=Cv()sQNP0vPxh_z;>8cWZ3QLtcVt(W+jq(95&Y~~%mmL6t~M|6Iw}-sqUA*KElgoyp-q3uvr_AxDqA)& zJN-8uuToOfU{E|@C6Z85z6bQ*+s37;#9s*fk**l09myc;BYriQ+)>6Yoc#nGjz`t! z1PYL?BZ^b`Zn3#)-Rh#kwQGg;!?NYJ?X9b1~Qg-(+^Ytt>>X-|X=w_i7;2!PwGIXu`!iVv)g zsQ7rL`}f(o)sh_Mg?zRgyfzo+y#|Uc)EgQarhD?)627br*m@4Mv`O*k60V8-*Qekp{~XE+?-Vr~ zqJEZ7BDeO>r~VHYK-PjByyNH$4PT-ic1m_lsi_730X^V!5+`}@yu1E_(PeQc8J6&r z_W-OZ1#Fou53uzgKYoO<$;tNk;@Xo#8%NW;Hy5^3+@VD4d;Q6Psoj-!86Q-NZio&C zyC%7=^&uwsQ%)cZ!J`^Rluo{(s*Mfbu-`7fqod=y_wRo~kqc*$ik-a(?8arL`&pIi zY?0r-7ne#rCjO!+vM4)x-QiTyJJabUwph{OqPgC}M?fE(fG)gz`4W?M`BBB@koPu} z+|YH#YYL=I45&v%dkktfmQ{5X&W?zOU2M^zJH(~>XWdFC`lyrt9uP`mLCAGR`+6At zWmq1dmQVM3KD z@p9N&GKuBCcPDLyo12@4n))(8A}rMNofp~JQ8vA(I73nqE6lJz)^>OEYN=Hnf1DDk z6IULwi{j$sL~E2<-R>!amGiUC*SlwYYs&+u6OPm$1v1Ed_IEC`q|4`0Tew|d$B+E> zcTP_CFE1}cCHP@`4@Tr!L`27WJW$N2=;%Q^D6V5U=p229D_7=x*YRoLdFrB6)YUCI z(=L}-b_E0IR+RPR=tfJr&Q!1hIXS_=@W(A@)e#2ZNMe8%oXRa9I={5;EM*U?4nX7c za=hbs3oO6Us%wghbX#8R>~=}$0!_|yS}j95FzWWY=M8>qOF zi~}SFniL9TDiqjK+ym;43xGbsL19?zU}xMbtfl_5onNPK9RgBIX)4&@sGFHa`Z}{@2t<_yj4_G$T_Zu zofZ*!)!C_m8XFsX*jsSs_6KdG=GzQZ{FsmDPVoo=V!s6Z3#WILj)tc3XNK}%S#xtU zH4TkclMXk#=CPw?xMIbI>FvEcDaO1_-pv;MDg-T))NQ zP%RMdwsrBppj>R)N~u?7^MxZqx&anM1r!T1*ZDbIu2H>gs^1O|EK4BxNr=|A?H87G zU(ny9L%6;OIy8i8+l3YLQ*HIwGo{EucQ%zoB6T^6RDVh%UqUjv2LAG`st4>AGQNJ+ z{KnMO!y3TWw_YMRD0qZ}N(c_pIWZC@wVhpKXXjKs`hPb8AG_=ksFEFx;t`?}suJ-3 z?>{Zm%ABJ>)E_s3h&A8)_Q((@r9q%{Xv*e*|K6!9SCH3dk6!1WJ!X6a(pm^UmgR5+ zAdJ064LL2gC>%wEuwzLCeC@T6ON~b^wLBYvY?Y(;99`Ob1hQ?9F74arG(9*m>ECw@ z5iql+Y$w5~Jpzx;Z)T52Ng3R!;cbLmto+}L6+=HF3JM9)IXZ3EpDu^7$F++#ct>|| zKA#8!tJDz~q*memYgXM^mp2y%`>I^6>st3gcLQj~UNZZ797z1u^7vqi|7>pgLu?s8 zGRc9BBE%9A!o#b1uqc!TYhz&jFbY4!e0wbvy7Lo=af|LQ@dq?5bt)7H{aP;(pcp>8 z^W{y=&5;QSH#60e#ogxa=Cz*X=I#P8pZT5J221Pp1rt2ematK9b6n<&!CG3VSye+M z(AfC+v+!_)(jqLYGR3_$oCSo;E9<<<;Kz>%5OW74c^kmB;oE#&g{BumsNg4kiP6Xi zMK;o#`nWFpA8bEm6tODsTDJngj2oAQgPApjP@e@*i(PJA0kg*ffgt9a< zNI}THcV8R=+y??LyT7Id+;XD-H)v!^Hra0g9HiO@;OYSNP`Y{Zt>*9d%+!$sHbdm9 z3G(YROC55rv56v&UND^zppvh{gv9Dr3dYinz3 zSDt~C&KCakK&8;Va=S@bx)LdyF!)gKs*=U30q7;ocR8??&K58l&N5I7p1`@w6GN2V zJYYl5y+iPdJ(Uo%w&nukp^zwQ3r^fKYj051Am+kn5zGcjXxA#q20%XLu>f`H*2g=! zLU@LEDwD-P$k4P?_VMoNv;h3xDy#tn0mMjzRTr z+uaJs@#n5XpdP|2opD9*xV}C}HmD~cXOm4jb2S+11vfV@!E>e22dM=8H;{?>nHyc; ze|W&BTl5&PMx)woUV8Jz^XK=6>wN97NfGI9-wu@3gNKF~eLmoh30wcpQNrbFXP*Fm z{e3we0qNrQUO{%vyOknnslx?ibW2Ic`( z3X!3&!Egh11F#$kTB2Omz40lPJ5we0f8xYISET{{AArp7{;1R8Is_irl-Ce3t49DR z9wC=$jWV0Q2J8IV7O+?tq&*6r)|0WH=tQ8y4+FAmraK$B>klaKz}5d$ffvwG+A&n? z-3JqQ)=@!$pe;_&0+v9DO<$BEtLI~|9v$H_tCKf@T_Yxj9nN?337wOSJ?Q9dSkBL2 z0HAEBfH?!k+YgvSRQ_~;E|#mD%Z0Tv22@tSjTlxcJ z+K_@y&U62&{7Vl^%%_LWul{F z01!I@wA+8qClQY;{d`T~W)$)XyflwTN9TseFAnIInUVR(`3d_`v4Q^{{m4u=MH8l+ z56ru!FMSe#i_*<~drT*y7`BoSv_~j<642|ESXTmvjV~?#q3!TubC(knnjEfl>^5?_ z3CHxL`OB#>2i_Nm}ZV}j+eT-I0yMBq;>qENwq6hc$8Ef zHTiHlR;VL*uSJAjoxl9jkH6_E@)BuK!G$B3msUx2VNW~oA7k+pK|i{V7aGz7;{ikJ zp=b!@0=ZgfeBhA=jIroeGfp6aq6YpTC?O5;cxnYh0FK7<04r3p6fz!1|AEgwMF#fY z|NQ$lcqQc`G9+TKDq3GKwNAzvsR3EZ26haNhy@VOZPv{$b-5p9w)ep0zUty4Jl+~1 zXPOF*b!XNs4&-M59J*C5mUTFTQmd2T&+~w+6@J(m@LI^?)TG&$K1`o*CXAZXTs%c! z8ZuoZpi2Gvr~{I)4g79peSK!|-VnZT+8RFTr2>32S<>~b-C$LYQGE(ndKb*U(GU5o zs`khZ`>awRUNy{rQ?TC$5d z%Xkb!(v?)|fBCXTo__l-0x@xqJy!37D0TLhhE@U;%TG|OEW!H?Zw1dc6e`I@-yIi_ z#}!~#BZeomKoGAPg=l1b@Xn<-dQDLX>OlRw=(+O15Prtou?u=xtKQF-OD*Y`JZOI1 zYBzqtx-E8K@&eg$d>Kz*)DwhIce0FolG>jkwd|QXhyXL6X>hE5mF9vwS7JXrv@R|y zn*tJ=dP<*z=D(GXJYPw-xoNirFez!+*ivUpL!DG^-b4&xJ244mxUbAfF+6(Y;amHh zLUna@F$h0AZrfk-=0-GE-aG*GJMf9}TAw|8rf~gw70awoQha;Eo;}6FVi2HnJ|l=L=#+Y!J?a=Ta6N#{;va$ELg8$JvO8E7!6eqM$oX{` zxGlq_2O+bLPEJKvM*6OZ1dLfC^GosnNa@da_$GDGP1S&8dJENBf|Z7qRn5c0BW3cH z<~h#hAz(k!nWt4T?e#Lq0Zj~T@kCoX>;3(q-P8mfi)^6Lb*)WJO$FxP88x-E46y%2 z;2r0S?>Cc{kHb$wo;~}rTJuEadb?(OzZ}p~k8or)M0kjxT3T9Gz{C@RmeBb-Ifz#R zV`S&M5KP6U2E^GQ0-6Rlz!^g(-|E!&Z;4_NppW}o{)!y?g@AzgVk}MLn~R~u@v}hJGssEUWNmDPDCowi&({2lhOz9=GR2^ z6t^ zWafI7npzzS2UsH>{a>PA#+onEl@Jx6XmFt+w69FVLS54n<4>2Z;)z_*iflF z8Ymy=tRa47snxHs2)P5)NJgCD7&J`JuMvU^akboTFzfcmQ_zVNcQ4pKu zzAy`~!BXSV$zulKnt;~!C?*i!GsPW18W9RklV5=(QLuW?T~tezHJI+1peBWL!vl|v z!pl_a+eMxP_X4)C$H?~;VuVn0TtCjtJlF5nXBJlog6)b?fpVOH zG)S~PXwM3CJA(4(I)DDFEARLo2T4dm@smnCS@Mwuo?%5B2Ua+^y7zuCfuii!#c?MqI>w2P)K8u^B`LS?NjEt<7nuF&;rhIa17mWq_nXU|MP zQ9^%~)|4C^chk{^C&-{y8gfImdas&@I7$7#fn|ab)dwIH-umv{yO&8xb8f2;z36Du z6H0%U)~rR^bx4J*a$dNC_1PZoGiOG_<^j&qVKCqdz$kJ)*v3`cGC>;-EDmk~f$)2F zl~10sdWFCk{#y3|9fWkg+y@+q!LkF-9h|913nAzG_ut;z!q<-go!~5OK2QO)TA{)Y ze9CLSueU+k<0KOO8yhakxm>%cXL22dtOJj0b@S9<>You6jRk3VKWr2_VMs6m(M&)s zUU>xWY%Z#U5*aLe!7TC9wI0Tc8RiU7lO<^9;x7Tm5ONri2bc63cyWD@dWewOpr?{v zLfO~vyFGhlyR|e*&Ty$|U0gz<&-sjoNI*&^FucEuGsYfO1D++%y)r&^>1Be}2)0a% zjua%a0oCO-7>ge1VHOVut3=dg)@gZoc)(T_vKtWZFR^SijgTRdFE;;v&Ztfr9I;8T zBj3Z4u}I=Le|{!RHV7V&vrJs{UlUAu>(@jB1B!|zs9U>QG9-o%Ks&gB2vcM>uY=6b zG(1&&=N<$1Wk`xRu1()MK|=$@gbJ$Ns!N~KtCuh3p)~88%z<_#AgrvX#Ra^|@g*#N z4l@Es&R%jxFh4vca1k7TT%+^Mns}m7dS2Y9>tMf*zpd|Pw0x-8kvPzJ!xiM#9;d?$ zJwwhjXFmPPcL2$A_UzdL>mC6VmwL*#(jLRv{=;Z>SrfQNq(3w4f0ztfcLn-Hmy9u} z9$84dj5kurJpe&vGhCOPUw@GBl+7<5=o2VkeiRaZfhL1~E5a#51*$@zU9~(OA-4i1 z!)g828Un)0>oXg534tXcU&&-*iS0?{-Wl{kh z=I@?e&SDg?+0sI-k^iU4UIipUZVB4lUHL|G&;)Z7XKt=SI$+MWv4m0-(1bD7kAPwE z%7fOZPlptYTDjh*xt)!9Wf0|qWxsOo#bqeRO?lg;{!lXRK*ZRQL-)o9e+1T7GjKY~ zp_)puuN=CTXA3MqeTiieX(;Sz)cK;AM68;C>D1gh^+gTcS)7E{fM?5%xKV6h#ZYxX zaFDJi@O$SG40m%*x8#S?P(mKbC0w$ffw0fUtAPtrUY|F z`c6eaCZqh(^_;V!NW17p*;#O*BSu*PPp=NW1o0Vmh`hk8jQf20I1d5f33BD}=+=S>zmGq%KrS`*SuFX^n3JPlJBj{*9ufzYqX(VWrnJ;zx<4)|KMi8(2`%5hn#k zB=AQfIW``hw(fdKn+nw9stNw--r@CVZUk0M0n`v+LV@2AVV&4G+Ijl8eMm?^rv{dK zFV+9FWPcB*q&GcC=jEEN%uf<8?wBMv-3FG#8VlE7X!=y_>lq10aT_^I{Xx-p3~2x- zZu*vkfHmA=%2>|+qlO;T6>|?-Y914q2*5PG(wUNq3g*H$+FBpk^BL&6DP*>5=H-whxG#C|m#2=~B=pMq1cnI|G>Mf!GMCyC!hj(G#WoA0BOxy^& z2>-x&X>G0I!P5c0W{90YNW&u;| zFAvOI(I-)uJ=j72FUP608woKz1iEnN78P{@4FBzh!m^<)dN4g zo~u{tAkGZkEAe4dX3AEEa`5n~=A)yc8XzE-b+23i#5tH(5r8i^&mj;LKT5520F#i= zfX7^6tN1)Q(E%`Z&Nkg$I@))hC!3vrcFhkYA2CoVPc;IH0*emTBLnwf#~L^kIcBu+ zY30gS-q#>+p;aT$O&GxDH5BmM4wl*yy^P!cP0VeI^;9vyzPtAyUCc)@@l_XA^s-{(!@Dg6F zLpbbfKrHZxl_8Q>zqdjL@`S(`T#EtU&A|ch#afVMIU00xKQqV-s$6(nE`yJ#qOGkR z-T}S6Fut0m7s&khkuNP-7E+P`#af_?}hB1rQa zp3i;o5AA4fLo}mRA20|Ss437~jDyI{OGP%{7#eQ139n@Eg%d<=Z$5bN&Kl|O0aTj9 zkV>$^le_}j8vC8MD4&?GIUUgxy2JsrW$$$nk-|63h?$;#2>Q39HzhU}nGQE=oYHx`FGu2RV~0scWT zxgOpF{VNwT{{X~qz8~I-P$TYCpP~xE!lfjUfb4A1ng`Ygu~&}pc;;`fC8DjI$f4me z2|4`*jO|D(%uaf7htq;JOIM!JWr1IubGNX;77L{jI2HxJUI`LCC1;V00a{g&qOPvq zI_hu%vR?@Mq!1gxK+Mwvm+ZchL&%o{Q!Y9tW}<3-sJ6PPJvp<;Oo*5_i=kpmn4|=7 zN%1eQ)2~ApfSCf^q7ynG&<7-;qRMog{S7H4Dx{waxujpNtFgax??HZ!6@n+IEZt%* zn6-J>pRNETE%c2kGTu(oiZCUS+KQd>NxEm$2z2WF?GF=ftBe!`JQ7D`Lyf|?uV~{V z0)|R;su;*yM$tXLB@X!+FsGlu2T%xIgE*VG*V?(0m#n@bfsLS`ASad#W-zpcI;0zc zE0l!KH0siq zZESLQ@9vy@K_DQ3NJP#b1mq4gv|HoDXQ_F9K@rqVmiCN-k5=09+6Ya<1gMxwu-1=w zO3r}Snqcdv|KSOoe8VV@x!#KqtVFDO35O93Lq}#t#>tr= zB)XK?z*!9%2(cY|#v!*nWQ#XFAZ*ngQc+Q%pSlPEC*X9h*gF8c5H(6ztlSR*XoBR0 z{W&!hIYsIBx|Uv4R_bk}KvUu|NV=Q@*g?oDLfxT}n&Pu^!|K0R(`BI)NZXm(>r0*Mvqwozg`oLME=D3nq@{k^&0&6T*b>M?7)K zFn^>_*bcjcz3qTphMb&}JT;1dbc!^WLlNF~WGAL0v}V{>OzvQd0|itpi)a!{>;O&byj>P4w+Eo|5MLJ_awkHj zPN@}T84miXsy}^1EX1Zf`tDsX6I>v|IYZb0K`vCoym5l)hZan3B<7|bbHnMxDWY~R zcM*KL;$E)jQLuX&0cKLw>vSQGB5jiujkGcYwuq=kZ^Q&F;t!xif(} zC!2=4>oar6J!FjR8`u&d#Qap?2nf>8eK{rh$o#oVwR4?e_2+{4l0(5 zG@u#0^r4roRd3z`)>2bxqWDz13G{uC_2<3On-3QJJ~P7JE(4!nK|`aW+>9p| z@oWyZ8vP)|GmS%7+0kb|+-_sORpDQ6-=?XD(EK9`qy-0srq3|~7-8_%{<0Yf7^3Si zo{GGIA^*P3mKGI?Op?rGX_DQIzkW+5a3ChY1Xk$WWX|`S)yMM2^_iugI~q0QHMlba ztMklqb_l1*d|-RPKXb_e>1?oOpziiVATt?^yl!Ifd(ZA1BAsv#gbJl|jl4yiHeTX? zoHjV#J6a7CpDpkx7vxbQhsX%%!5@JJ;WUKC!ES08btv#y9`lI+g=8@RvDn1%IwSvm z5y)lhJAL8YPT9;%^?M8289_%VoGlS-MxS-Yp`mpR8RvhGSZLb%aHvKCW;{=~qmcPG zgtg?|11F@T7s+|9Ees|?-%oUSmGgh%#Y2l6 zk~~eYOT%b-#q&im(FGn7P0iEN1Lc!EA^W>;%#^+T$6LnyFPwVC6?jTrS^1HS_uPII zX#fw8vC8sw+R%^(7+*~bQ6gFKqA*6bV6+3>S}a3?O)k@&f#ByAf}h3eHGL+WRpu*bd~yu% z#1;_m?VwAqDJgw2)C6N5w1hkM6j)7Od0;qLFe9w!W~^M(7v0R0%du&vvE()G`4j=A z*538xPeiQmOzm?j8~rqMiUSRFzFt{tXqLwKXKwj1K^JHUm}t;>uT;G+n$?03KQ?f z&6`exZi_<(MS?kLH@lQZ`ikd!C|MvsKDxJRE7V7$?orPN*kH-YfMTJfAfTp>;CY3< zaOO-PP?+P;VF9iITLd`Zgn3weDrtG>szIkK4Oo&y3I`WgFxajy6B1_nPXRB1*C6*z zsNd7(wMt@vTHBNjXn7!dIOIwf!%wD_+20z?-MBgIT`v9436DbYEwkt)*pQN!MpOU| zI=GeIR~KCyfT0Y&cZ6Y7j~BIN1T$}JbJ*VkN+c38MF?YEK-y_YjE}i}gjOUNvq<+U zM$kyMb#-H|FS?-M0<`K{!L&to7Qh~fOW@xv|8###e^Z%eDMGHHLk=7HwO!V~$H1a7 z?c&n#VL#>S5Yh;^^AlZQqq}<>>g3J%9^$~9d*$H}H)&b#WvBpN-UvyTzIuN-Fm#+{ z*gz)(F3?MRKvErv!2kuVfP4(8>);&jMM#J-_%slR{aIwDjLc;4efPXc=`(-+B$&(D zpZ)z^#zi%OKsgTfZvctZS8j$Fi9cje42;nOZE3pUGG2n zZhm?p*1(;E!`C{2v}#!2qV6)j3g$AlSY6C5pQ_Qjp>e!sIXHP{ zELuGcWqpM%5orZFi5~vW(RJcoLkh;zbEw$s2ePDF6F2TwbPmiqmoK&w>9D&ZomEBoYH6Sc=8`i(Rs9?Q#v6AeZJnOwBPj5a546!lCGu zr_#Pe3^R!V^mo+0E@G@)h3b+1{G?D~{9fUy&b~cwTyj~qn4m6>$Y=d_$9Ib9xkEZu zL#OY~?7G=tSKXwBlJ$A?oR84bhudxnqgl6Jv;2}7T{5X25}X*^OZ?^9bGaiWC7DS> z3lowF)lZ2B?p^Ps`B?|ADi+J#)sCfZEzx5F1~adne3#Hkl4kjkr1%t(DEuXy-mRVD z?oX(xT}Nf;7K$&IROp1q5BA=gJ~e;MYSFn~v_W#waoKw4SR(m(zt@*rN2aT`(*a)->nbBncd$r+rcRw;?s7AWqOH$0;1Z(Xbd z)!vY3f6C6YEY&~wF#)#3XEyhV7mpoKkk=^lcD^0YB5>|KkdR2sCFF2^Fj|=2!i@ub zss}_ZN!r2?S5Huy8YonO@t7a5b9Ls zcF&(6G8?&uH5YJQ#!{hu(OmrRVTwf2xNhy)xm_U0ZjL)aq?BdpkK_0XdBbyb@pJY1 zEFU=0u-RwEW^16qa|<%!6?7lAt#6ONRq=j$0C|$0k|-~y6*p=UCAh&?#U$dK&A!R^ z0`lvM@TIR@wTr;_Qgm?z za(~D|&Ikk6bUTk3fMe0Zp2+R@!Jx00f+F2MBb~v6#K-w{{lVYt2Iro$=vq%`YMC7P zc-Nmz@J~K}r{v6W8-8O)SP+@--eHDnHxQ>K<^)`rt{O*R{r;)3F&nLg@d&y@#$O*B zS0)`6YelzYRzhkQnVE}xD(5-wrW5IV+b-wFy((t#7?PHfaB+lt%$ystt&inT)D<$) z{Lc(4PP&dKWqs(i8N9QuJOz7I-Spz=j7lC|eXm}=y1u`vZoX3sWy#c}S&;Xyftz5gEi}VNAs9GkrH2Hs@Ded6di7*1lO9OEaK8wTqo&*MywzzJ`Aq$C8_$l%zE( zxdw7mw(aI4RI;DRT?kKRp*wlb9kZ(>6tyYXR}if2ZvQB55|n)Y;pdm%o`q#NY%G*U zzab{Rnybg@e~^RLfcTYW5OT<;VfjWA<)*(;9*q>8MHx?TP7v#r7Wp!%CwsVCK1O zNEHD2#WxVe9h)nhdZ}RJOy?N$?!%a) zP%e-m>&YuyoGvnROUA{}daU2ZX0ASE^D$`n*%-Zlh^fI7L-WZL!T9|38MDOxv2l~O*dR7QeCH_# zd0hL_de2fbU1v!)%dMe0nVfH{-0DfvET|(U*nn?)%5(M~D|YRl7Wes99I`8}ytPAi zmygYNjT+e)4rU;1H~63SqdkMZSAFLsuO&<13wdS-Z$qgemuQ`@<8*J|&M9;&$M*7= zz|OZrQ%cs7Kx%FLc&4X~?WJ1)0H=R^xV^C}Z5^9@N687~9eYO1@H(0qHo=4Hkuvp$ z%_!iMX2Lc$*e%L3uHSct7AgH)jL(C?&Bj3JLNd|_`a3qI^)`*bN33`S0`sh zVjhPx7>x%E7+Ip6MDgo)1(IZwcl|6aFSwr9_b@TH{hbl#Rp*nTt3cqh!7$)coa{ES zfgN4%@ijPqh-Av)ItVfUhn}}ck2A6lof#}YtbIrA0w1JSKYvz2wwXap>AxAnTKy&; zEe=s--gDi(q#oD`$@%g0YX8MycD_7OjVjfn$p zOwdbB-p#vtGF}>3)6X}JuW?aHgv8hcIUMHgkM#M+KP@d`qfGt9>j-PM+BQJ(h5W~^ zEm93bb|fs+ZWj*ZH0I3!0n&svMaJ`>mjp`TyYvt-5kbfHLQ@pkEC^ogWS>Q<872UoceF7DYz$e5PFcnalbL#Dd&R9P9<*qxzmLKB;nnM_f)9d~{{x}Wqe+KWT;3mD*a>t6nNiSj zM|M&k_0sqM>7~QoN5rP7S#Dv1ji}FH4`%g-Czx&$@LdS7^`JXPx674D+#$_6^av$;Lm!#)_;_BgCWw9reN775g;wpx#*-9z@CDcs6f67PU7k>Zb$Xa;?qJIJN z!8M&~tnhJN)XaY(QXBAJr1?$YVjWv4{`1p?6vqOkqng;@r{4Il)Z1>(PA|-)aW_J?#AFxV#B@L^qH!U>;`Q#`YLG* zJ)86RG}D7~YxTBkjXr&Ig|N4R+G{;%wWEB0Dx7uQ z)iM;is*!MvZ3aCW{qS*QGHyN~(jv9A^hvclHjvzP21BDR zU-qR}nZjb;DC4F^WsyZbq_HzFiPrBF>$g2p-OLVXX7IZ#a$&;Ll?wo2o=P5nSI6h zZuUtq$!(#41}L}H9!TnYoEdO@Id^ZX!wNC@R6tON@gLL$67Xu zd;ehHhQyFR#qTeD1oqRuSC(!U0atfvG(7; z>@pa&nfdJZHeQR4dV{)qQvsEGX(4~f?6QLN=uc&n?~Ebg!Tk3|WF3 zUuW|rP)+FllZ=8+Ey1G1H(Vvl7Ne9|pHO>at+omeDh|^jHUa7g+ZmlG?26 zy~)UeaiO+A>7(E67M*5K(acZTPqXaAgfrIdSZ&RV8O41yu(C3zDTQ0(uiN>m)+_5< zHJ`HFYr3?*Sr!430qe`^OB>GS&T{`Ve1ia$21y0ic%c<~KNZiI$B9sbb&I%ndb}va zL&c?pBJc%cpZUng{4$QG`^_mbWjFYw2L#-4kS89y!NcQb*$OX-EV#}#e7Fs&dY^%q ziD>qBX??_aYc-`oMD8D6vOOtNtSW=i>Kw7hQknselFvFjvCHdBBa2CS+p8UJ*V4FD=X}z}gpe>O zt(xMTkFpUeVygmLJh#(>ll{i3W{n$(DyA4iLP4JU+!L_hIE1huPrPd4$a7ws7b(%8 zU`DbHu=}T2Z1KT>>3?~*R&(QI5FjzLKBQy|rsfza?RmcYH6sL`AcKV*Mns6E{~wm8%3BHaC&NKQhwOsByGF zS*q+In(Wk4v%1`}d$GATv7{Mxoy!Kb7s7|WAac^Ko~6vTxTn9oLk({@9~8Q77@gp? z46YH)_aqwl;*>tK$m72D>U`N$zADo_>&`-sn!`GljA^nuQfQud;Jh?hmL?3Y<8#vrtApXc_N*bKFzbB44ZKS>~3B3xyH1O8@RHzm=_-u}5|8 zjJwIxAvv`4Wa-D}TfINh%eK$WejuPTvPsOytLq=Cxp*$!RPi3~cDq#B@8+(J#ix+O z-BeF4vqryfywrNNJ}Qd3F60F zZR;~Klx)Q=l?Xr8p-UU44!mSzNhjbcrSU>;c)i*r>Kx3X_omdOD8`oL$IPN z^NetMkq_t zyM+Dqai0Io=(miI=XJ__NsEVpb?uYBC@c-mucs87TuLl;7wrCEmgz6yc}XbVQ%@ke_djE=+7|GwOz1eaaxddE&J9@l_aq2AVi&t3Ig;?t>f|Wx z4Z1rwTj%%rrxe|*KGk1Vx;Z{RuVgN$f$Bc}Qd7CD;n@SN+=S$oF%X-roA|^~8L;}^ zBLTU#;x5O^?8~wBTMYuX>r;tK3)P^fIt$*gTlM=k9WTNFDa;mvD}bw$;ur~6l$fsq+4;pnaw@| z<)(>>$swW&HmDu}9x|qoZzwtY)4paY$bkRBxFKCA?$!t#u@~HtsPU92_v&Rev8kIJk$_@L3#> zFliyj#@S7&Naa3{vqAqh;XYo+lIG`It-_4qi0Hk{<2=>-iB&!>&wvE&hhEYDQGK1l zV~WAszv4T!s?)D)ZVM&&5(|~Bc5IR{U)={r_3DH>N(0dcyGHj+ zQ)3=jk2a6P-CR@`!9OIO6Bu=V9wRwA3O2D@N~!sG8@VeuD^jRWwk;U2Hv0=h1e2YkC!X+ZlM?QJ5=h;cPvQlkm3SHHUK-E)CTpgYYF)#tfD zbFRJWSara%yz|_#@zB8GP%ZJu;^vIFhRxx|_=|4B0=@n6_V8Hxibo$&&2@};FPa^w zczhAVsHL%Y^6y5=c=di_Hue`Y?{HhMbj>3zI@O!HUoodwURD}nO#C=W)?m&_d7*|C z_5Yl}hfFP;)bJ*JK^GF%g7513-+QJ~hoL;2c}=2(Y)yIP^n@jZT&R0w4ttkJR7b4l zYJwV3I29|!fS~}teT9I63-mIKqIM;04eeA?_B^WSPI@U8^~*TJn7#QvQ+#Sn)-AUc z3qfb7rg-pGPL+)&nYS1vX=C{x@pXOZZob3!&XkvTWqq#Lt@Agm_lYmff)x{AK?y;0 z9oef6-%3F{Q^6o)j(h=0PcEd$@^Hvj8IVPl5I#W^5_|~)5)Jc#fH`FNVS_B}hq?t> zj^Fu49nj>X2S32RZrl8pQ9{oX{6qZf_;JSmpMK+A4ZO}!{sz+%;B36_Xe?W%2mKDg z0teTYruYkMtE ziiyv$3m}rtZ}@@g7J={PDa4jZEmSnREDT8Wm>PP|i)dxsJPB>kv3}Utd7%rwM#ZOX zJSHaQ0Sbar+9RgYf2d5qJup?_HdV>G7|d5b(-O}VcJXA9t-W2C=Ma4{FSgR$T$=5E z*!G+FNxl1FBwxjiC``Yh{;%53JR0i$|NFx*l2Ax?rBb38vNfVbNg+#d30X!YW7lL~ zlB5Q$mXLOBmPy9Wphg&^#Y~N?AsOpv&{%%2&vjkr{{DXF-1k5CeQxJeCynMa@6Y@5 z-d@k=)$TIyNmbNQ-O-Z1o)kW`-ZkUdY~+kNuSUa; zmgyQZZN5%go;O#OjvWqNm+G1k6cvuACtp+m%Z|lMd+zx;w&NxB;f`MLOxI8TL8Zb; zQ-q;Lk<|YzK6_?`YJ;NyHno-Gy?>jdLtNGL|8>MkOAiz2a1LMymfLC9E8?H|JmNdZ zOMD}I7x?awqczj{&B!Nb8sjbZ@l(>Zcq@dO_*lFzdl@ZN+S6}#Ux-4~R+yI$TaQcr zDM;PEy309N(sIKNzDI99qpa=`wtXa~UtntC)|E-!!%|rFKRdb8kIgBVZ$fZZdx3v} z{xs{+vG|a9JhkPb!dj`@h8sP(gsRVvZX48z#QhJc9da%K?#8n2U=c)WSLEdwsrB!% z4IWh6AnF?iDYfD0ZDshJjv?>{C;n~yuDeQY|1@i?7h3REZ=_I=g6{ATiugf`_Y+GM zh`}6|dax#zPv7Il>PbjR&!A1uq#FkZWeUZ-CpZzZ(>VT?PDKKRq#2-C>)Q7su$dl31qo0 zzdS(0d`1m}L%{IfARIR8KvB1jMFFF;JarKSh=xi!5wm9#+P3}rh5X)c>13PDcw4)aujIx|5Z_QXxXuRk2a^Nxu%j_t`Mi7n^har4 zdXISXk@{`SI`W3>fhE61jX@*b6s(URb43zQuki7~;OPgI!qPqqu#+sQf}J25gktkS zFju003&&g)W@$mcJw2;X7W~NQsC{wPkjmf7jM&N|v?rTnMnc78B4Uwlbv-qkL3Pf{q zZMqt?nf2Ni+_P&BEncl-peA|)vbWcFol3j}LRI2(t+*AQ$^37Jy!D!9o6Qb*ZUNWO z^=Zd}5E>A0vUCzHksFeqKsFJ6b$(@ocYVTZ&oZV^B&-v=ui80n~YZQ zW7_>4`vCRm(I8PQ5_Mfc(N}0cJ%T+yYu4#s$b!CgLpu9ZG%a3h3hr zfdAWB5;S<21CE$10A97-29g>{PPe7B1LzKxAfly%1IH_7VQ2$*$D||`6bNwgH2iHF zFI-&N7~zUqf{ls}t|&V275{#{d_c8LA4B5E$@jjN!$*3=XPA@cZ++Fku|$S~k78*? zXGp@W8a71I$Y z1UneQHe=);SH_dZy&YiAWGn+ZF{=WU(iVxU*IR%f!V+Z4Z6KQT2R}!OBj_&<=yBKoDi!!9{$Y@|Og*7PW4HA$bXa=D z){;+aIM_RpunyUDlPxJp@Yu`er=c@b5$i~a5Ue~pnTF8%#;@5 zdp%pFC2vK>R+ja&7F}wT>oi^ zcUA9t2j+)CKj8SvE?*YEApWv9#@E8s)N4UZaYuJW>|$r8^iJ)Lyx(xDjfHLrDp6vf zh5hsA#Ctd`RRbn?m9Fx395cO&9gf1U*c;n4j1ZU6%g?Y+OM+IsmzpGM?N9TMb8y>0 zW4QK;$v$~YFP*V$S(Zc!_Ph?IRHtWQvS1@u4)3o&Q5t=Nw!B~c`O4Wt)gCjR@)EFy zXKW2(lojn{lro0vCJS9?Cti5YDVy|g&a|HE(qO$=Oj)N2skBR%%9HBPeIZt7a8NCNejzs(AddpS#6Jk!GJMH9jJHs~_4W2CTRZaY$6IM! z_bgv_EJfu>`x_sdnj3~gX}3R5rz8*@qn`}=7>w7=UYJC%RvDvZa98(p7! zqX|8fZaBh>&eqi#o~+~a==&D*TI$P|=sS&MHYTNH>33vSO}y^c%9m^SV2zj7+;t=4 zlms`M-gV1I$zVkfpTE9Q<`a$SkE>n#EU(w`PKyn7z$t9siRD6b8)!1;wbL=>0`?VtHWl`;(~v>u3YRY5FygPUpSbti}>wMZFK*eBnP3DS-WzM z74A=YfNQ4q*2(iZ*}5e!txONqA2-<#hgfHBy|T3%KcS!Df|1wT_vM9_ue8P~&$QMZ zD*SK|(-W%<`z`yT%VtXPBARbHk`n8al)u@$j~P&7|LABdwhOrPh7%`F*4g!nPcEWQ z&Q?nd|N7N))x?`n9|SxJxYhV{wvs+sv6ZiE-nV^9P)`a@$fKtCx+B!z_=)&-%~$S* zO2p1nOszZD-4g8fFD-0?a1&#OGR??{T0==aL6`&LnG zcB?gar5gr-PPIr#{6OhB>oWi00-~S%!`DtFv@VOMkD1B$dZWww`o#%9;X9Y9uCa;4 zakg)+7EHbN1?RT;OmuFZlzUh09Js$Tm2>|AbLzro?+f#i$3Ve*e`TZTTPTwiOYYG3 zJD05*t!AuLSp5<6A}_X`(5|rtPnhD(+Q|=``}}@QRKC^vMI#_lyiAYW{>omIMv8xA z<`=?wc<4I$?7jy}(?ZUXI|;1xiUNbum>Bjk_MWkNsw!J<+*>C)<|Qbb-mWaziS}Jt z$MwxKJ|q(B=G)d2C3$yuJm@=jzC3z|u>F-y<1U8%BMeAmRu=IGzbeO43tcFeJHi(k zu2p%D4hpeCPk){g(z7l+?U&%`@vxvm!>S-J?2B+I{EKYM^Nx)6hT3MzqVeHx@Vq$#T8@>ajWa2Nh zo4~>(iL=&~w->eZ%+e~AIa7_^-%+aq{s@K{4=(TPlXSxoW4>%C)={5r#D%0U3zIs^ zO_a7D4lq|sgaU`@Vy+JA>CZ?i<(t&uytOXYMBTjs>G>*00I z6$7~)GC1+xs>yGv-!~m(&#K)~XMIu6DSMUH_$JjVs0}s2*TQFlc8s)niVASgPMY%~ zRH1MkzZ99Hjz>R6u#Z}yR?w&JOf4+s8rLD#!hx07R%e1|Jg3opgK6GYsnu?Lq2s5j zIp(!oyigR%C^>Q-&074X%v!{)ml0aTbPF1xE%?4=SUawnIzn5jT2(!@EgcgNZC-VK zZDhj096D-oKyVXeFq89du78iOEd+H#R-BBx1SCf8)vF= z^r-6yy*0+NbDSBI`&)^LX?D!crfl-DS~Zk_Ud@V1u>CQ?boWM=EgwXyW>0GCu|@0k zI`<}xXU49@DYFErqD*S$@c4ldU|SxSdYuZy>i)~}?4SLqitfV}RaY;k8LfFGxWnDo zEy>NdT!HGzejzhztnSkM=MMeDoC-y+$l#Ypti2iDq`LQA*RSZj#@eRh(id3R(jz3KsZFs9L;R{Ifu%TlNKUZ=)EQdATYnhH2k9LhLg?W^#B@QXYr^rST1L%LW3 z_mQi6)Htm4ot|*7xW?P%D4M%(X>T(#UraC1)wO|YkA>%y4NYuyu=C zHvIgozjI({NSuH&NhwHd@tZf-WOp3XBurVMd!GK-wjYB-o!Ls^z6yqw&qj)myxSIH zf$Q;S{Pd=nA|;HyC*guyBUgvn`BudcOh`8*=ERAwS^CAg1`hlTukKy>eX(IN^OI=T(%v)0+uQ-`hhmLmqc}TnzjC32i5$XpG+CPd?R`{DwJ4OHS=ayPcAo{U!L) z{;OPFhjEE+oN=%MjybGMh%GH^=JCEr%FjpHT4K=}N&k&#=|-K=G~qo~s3&xU`FH`S!L7%#C9TI~O+*sSWzf`%XQd1h*eS z?Z&{7bfU&T-@r!4YbgtFg% z+gAK3GA=j5gFkQ=#pj&h)K*G3!JH<_e%~!7dxj_DR5dKMI<(<(Z7ko(z1G}@t5nQq zbLQQ9j?6d?Usi(L>cQjM4p-jW?dR{iBs}%&C3m@MvZ0hA{lIkVNI1dIX%&}emua39 z@DB5aMMfXC!q+hl2`|-o^uBy2o2KsOi&CcQ-KxFfcQ~c7%lfp#CEvJQuXlzct|o+? zjNO>yX1gvri?!g>GCBl*lb8dR&vkCas-^ZHy~s5+%%Xhe3zC#~R+ z|Nb6j4<6ZN-RUOGd$&Gg_V#b@Nztkv+0Q0vsn5nQi3Uk-4_m1yV0!(!Kwb&VO>ptI ze4F?8EjWe8RjpihvHi70?-illy;qB1P_32Zw8a~foWg8hY}HmWb7SmKj1#?UC`{{G zL!le!3C>H)W9HmUqN+TylaD1(sN&4xD!Fn|nM+Gk9jEQiOE`@gia6;+?qG2Si*-*< z-aMw`bDB?Um)Jyw5Zc0}{QCZ~?gKmY-doi3Hv5#h@n*6}+KXi}BY!q<^D>Q@cRwE2 z@pp^0Dpb)~OL-gfEcY!pArgb@-OP+tz1PHTZEZJv$PFU=6|E?*=k1xJzs;Qatu2dL z`@rg?4rSq>U+Iy1q>O^oHQ&0!22&792j=es-6=9?Ui1;qDIXmYD!T7Q0`bohm>w2D zc(pun;x^*_YXfU0$Ea5sHu!*#$JkK_jvy`^$ppLbXW&Rmmm9&-9HRxl2^t@M>tH2| zkI|=T=+G?mXlt}--DgQYo+M!%+V!S_huEi2u)|h(x(uHFotAl@G;$yXi%!9YuTXNo z+ooU}Er#b_reM8bXZ;2{EP}6dy+h*7y-CJ;(Hjck_H(&{nlx5d3@>_wZ>q)#c{kvmIhBi9$zVk zmzKj@NskXDXN+=KGDQs3zt|oy^3DZm(Spd9N0}y%O4pJz@#s%o#d(jjF5$=`wd~1Se?*cQ~ zr{pM_=sr@*(`ET>BkpVZLvpe&bN4Nb(x-hkx#Z>`kzC((B09yTNLLE?o~kD2q|+ri zXB=A-|A(pCah~~f=(u)!|4mr1rz!#}XHh}1ZD(FIExqzQblrVj4OaQuLQYPlaTi6Y z+poqJC+I%KJLIBxr#9FICv1G(r6gXzOkciK5blzw*cY_QDMW}eIa)%E-R>-UHi^VB zzM7jfwVr*c?>o7-b+040W)&+mY6EdM`N;Eu)>-pS=TNRt9S8w*bvCdrb8OHC?hOJV zU=6JpUx7THOlUrR24|;B$N~-~g95CTyC7W6x_$fNQpbyxja$~{?4~UeNR9-O zYyhc(Arq2;9hP^MZb@76C;9km`zF1R!B6PZUg^;uukT|XmTkJDPm9X=-MsByv2NTF zkJSWw5Xce9oQve{9!gc#m%*Qt#n-k3zqiF(INoxUzff+VsgZpGPnW>c+f+-q5_n(Q zgf?x_{vu0)XNmrpkx-7n3ccPSZCj~1m>+~t>G(Tf)FL1Q6G5XDa zz^V>4<$EkJ5-evS?kTw261N-W(%~o*SRdKIJnPi@|_WTEc;?~%_)1!qdIl+0tk?)y+hl_ z2acr?6r!Z6#eFDX0S9M^ghyQF;1et#OvM?5&uqy*p7#`V%HYx6$`}J8Ze^kg^|t}E zMH3#0Sui&b+G}NH)gEL5u|8*-ow=`yU$|u}@X!GsX7T}osu}9uLg@;7TTPa2m@X*4nxUE8`c>l-ednj28{_Gd(-j7TnMnFk>@p|MISpYg$O01pU_Bnd8A2F(;47S=qQ!qiSlIjrSzD~b`H$cPJgF)UL4s(%K6_M5mR4gNop8_p+E0{?S0da}gp$Pg# z7@(2Nj6y$vYC)mAeGsTb_YaAcjEtN>%P1;Z{!4^!xUkQ3OMo(7C`AE%Zu$3yNZ&8~ z_kY(X(2Gu$THjKiY_JMmRJTUs+y-tEc#D@^E{@lbmU4H!6$>0qP;}d5dlyWm0GMC* zA+I+E*m&QCl%uFXF=KL1957H5oZm; zG}6_UHctb3END`lLv5^d4(*2mFQ7r*#aODS2>#Y&OSpbdRm2}ZJRcc0cvy9}->IML zDCdhy!x(s;2&Jk0IYS^bEw^qWTZ3ojmVqBj$hEVL?lEmw0(Cq>lz_s|g}pswybyvw zC^&ToK=WDv$OJp(k8>Df6PC&_OnXB2f%bKx&{;MPl;}ad(Q{aUmV>634#PGAtps?* zLwlMs9dx2t=r;h@<%j%+T!fAA6I?w2BHaenG=#|xD9S{mb<^q@s9r^r_7WIfOCLN4 zts8x+lJ^orG_RE>*T2Toh$BC=_cNC-Mw9z>%FJsHJr3nWp#B%qX&Th6sGopc((!Kh z1P>;GMJcczfvS%tgvq!=Hjxo%O5tj=#1!{TK{2a}3+77?(6JUaLH-T`KZg5oJu_3L zB|{T3b)sc(L;}|J!IdM;FT>jnt0R2(OW$pE6`(B4*|Xy$p(pF&+GpW zP5AQ=0yY4^7UBtqDl-QF84Hz1_5z#Jh;sD}~{nrE%92Em5lWKtTR0Dly5dxbYMJ>#LW*`eLBckGQyw5+0Lo<-~ zAOQwnfam~ucK``7i$#lN8H+Xk1_1QuLJ0HQ&{ULV9v zc|hSOu17g`2K?w8ntT94cPJZ&OU_wWboR@OJIN_2=l5D2JEjAlT^opT9QWsMW$>sH zfXy%lfo?9je*GCp`sn*cgdh#1E(BVW!32pG0G#-tN&v2dCq$|k{Jq7Fd{(ttYod(i^`8#(+eZVT-h=7R{5kOWsf$|OJX zb+Wcz3wLabv2jn*)>}DAP@=39CRLEFk!Y zw?iXu4)aSN+;)>e!zD3L<6W6A{STBk+C{4QDcE}uf57eAZyORt5T+bto^a2T1(-FF z`VdmK1w0DCU74>m7)XMuw;-q&wiy`AlR8gAuLOu-i`kQ#-3Gl#J&^&{_;d}&27nTp zgA2xm1z2~4N0210Ok}xE-nfvMnAiz%FG!vQbbf@E0KV+ka7&6I!ex1x7qF{l*7m@G z1FM9E-J#ndz4FqfOKW9ipU-Wls-YtG16mgv$P@6>g?`X1fCst=Pl9r~MX)WL4)VR{5%?Ki1B$A~%=k70IvqWF z6)q!iyp-`88Wb$(&SijzCm{%x^RAONZeT9W06gO*WC)^v?nxp^vA~@ z3O)t^!VENYmC_`16W}gDuQ&?*Kn7+h&^+wk;2g*YOagD91|S0&P}6vYANaNaP!i$s zcA6>MKpKNX-eVx}x1{ep2DKCfA`C!MWNw6E5etAmxY6YUSJk7O|4@;DluF=1z&jwr zEzpU)AX5hsEWwDd4;siN+6(k#n#bW$a%TNj5;SlXKPa}PsP@kbSi7e}sE7{Co!XGB zQ&4nGsu+n{K<5OFeacV6(yRn^z{VpfE9(P;WgD;-eIYmH7wdq~^_(7gDv$#kOFLjO zK|csJREYBP0DGzTGGx7FL)zgV_)xgda85`&77F79kn~tF7G7hrylrf^ z77fU=p<;N_v<(+YVqK?fjm%;HSAnfz&9I^`hw5^a%bImS8D2MC3lTYgJRM<7+z&Ro zd7vY7Qvef|3*U~YF+yULpl-qU4$x6x{&3y!$n?q6r++F}so1t4cBbAe2&;p5#V0Tf zLL40D!$ENbb;;nsoc|c$6G-Zh$gc7@cqTr8=m@|Hxsw&JQt5zu-vM>};P3e`FI3Nd zJm$|rV5@+79*kfI8o-ubzZ^^|2&fjoQL3O*f?+EcR00s(7G79Aa}+2?MA|}c*q|to zB9NCMNuRJ`_wP8Kt(O9{ZJ2XpVRU&5zMbI+e;CgJiHP`afFouJpA=xH_O(S$rd!mJ zR=`23A@TqbAU6g!0ZD+1)dnq8Sv16Ywj(qt00*@Ky0#6_G^5~}sU7hL#uj98Zid2p z7`YYvoyR+?E(E}{a2BEXm@(;X$tto>Cc6A*Ki#Ub=zB+^jI|5`nHE);%Ee{m8x06NKx4ThdOAM?(aOD^SZr$gbBQb$7GMz?tYj zvseiEw2Pl}Eq054j^r;+gU@h{TkR6pi9rF}<~!6d0=6w2;iCh5iVh#&GBB_he1IvS z&B*qzYz7K#Q>iOlVjJ*Jei8|Y)&SrV-`jr!*0UUm+mNSL17EJt57G^>fQ<;+3jozO z5ap%^@a`Z#fJ<~(SX*EJ3cg7AFM-?I3+ZUA@o&IZy$v=xEKLT<#6f2w7<&c-VltEw z7f>$(gewQKr6CX7|}_MH^wNlv$Onnn!k2TL)g}6jf!uFPcMmdHg)iXZiAf=j0zG`p7Ls-YKx`Cz~0geZUmT;SI5C{8w`^+ zZ0wxxkHK^G3FeBw(+iOX9)Iikez7jJsuiFc3c4pMZg5uNes2MNW2V0Yr$9 z_jOXmMMV*7+rLu_0*5awA6V_MQR50c2b?aa05}p5n*d`ngA0pzEdY=q$VA}n$if;; zRyXj_Nq7hm3dq0lm*C{pLY~vVbNsTR!0`lY-af$lZv&|wG*=Mh8G?PyR^`mvbv7`_ zO(%nQ6lNrmG8VF5gx-maH%M%V<=x%xz{`Lw?F4DC74mgKp!xG_$u@+`e;{!+tmulY z&pbO-x&u^6g8)bIXTiMM4$ppDihj=#IHelxso}|%UOMyzrdWSary}Qo(0@$fq_F#G zcm)82VF4ruWFjPj7YRE?l9*vu%y|F%kSR(*HPURux^*V{@R5;J9cT_%9zcQ~;w1a; oi(!O%h3qSkLh1kW{$kNYsuSDTyhqmnLc~$#hpbEs54c_YFP7R4^#A|> literal 59724 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 EA50J@LI3~& diff --git a/fastf1/tests/mpl-baseline/test_speed_trace.png b/fastf1/tests/mpl-baseline/test_speed_trace.png index e410c6306cee01007aa31b8d32ef0d7b5f4af293..d160f9b8be6694790eccf496f96f1bfce6e52b26 100644 GIT binary patch literal 35490 zcmeEt^;;ET+wE+&lypd!G%A90gVGJ6fYROFy#)l34(V=?6eXlK4N@ZA-5r~T{SEJX z&iN0{`RRD+rI({K&pgi^>t1V3n3{?#&SQ$l007{~%SpWj02CMiK$bAjz`x-gnOg&Y z6LgiDFVm}BE-RA_kaGu zO9y8Q4q7G#H}EEyj&dJd007VE;TNP>yvPawzT(MCy?*DJzCZ7gOf~+E@2Jj2b*E3A z`;TA{@JhaXLOJt0GQ*b;!%jb;l)i_d%XhLt6O z_aCG3fjsr@P2SGLnH-VOJGb{9&8?dw(A4ei7VgvoF}H(;%_&CtI0-56N1_qGH{{_D z3HsPT*q1L~UW7pC2nYybyEp+xdV2aFWN5I5%Oo8@40yHIm<%8UFMq&>N`P1C!;Jtr z@T%#n|No!=Uu>8YMKer^BvNK%YU)d1Aj*_2UtW?Vxc^QujF|qdw7k5$RkP(OSSCPn zV0X97*!VbkGd6fi3U4GOq1HAwk@_J|$$-M_>}&vbi?w!og{_YR9%ffwQ4zYEo7>J! z{gYRK(x<6&#Fg)V4wNh6TYp_y!?E(i85{jyI%BJ|;r+qOeVrSENCg>=&tM1+Se>DK zDa$SAhfyM{Ai&>o+IFPQtNx`Y1hFZuXQ;>bpWG8Rd>nVy2*KC?5JfIQpYfSNJ(xk= zR~_>nSR$?5?^>A9hiXYnnb%y8;2jr;`+o_zTmRV9T*SV96E4Ffl`xMcABP_$rO~4L zhh_jE+};YfZ=h`TwByJpaQDr+&4$$J@vz*5)6h}2Ud~)`AJg_*SXP_fzC` zc}m_)#TCOSe>wf!hcky2-HV3h{>L%~BT#u@P3_)TW0A0&I?A%#Ep99Ep@q`ML74U> zI?=I|=J`n!iSPOd9zlfEvfK14vN&!xQjW6jXrvi|^ITN@;jWy8_<@fd2S9m$c-O(= z>+hsTkom!{P*ZVO+ZSn$7Q<>riRY1<;{u5Lc?}oWc`e&m+&?avVemoYK8V&%8S+8>%qIr)(c9RI}vU%MzDY=yyc|o%G4AW^FlVV_#Ui< zNnf5>5kY{_Kc}x6t+yVJu2(IueCG9Bn-B6_Lip7i+B0p86Swc1GRLr{1=FivqIXzs zZS_3CD?Qlq97C%iMs?}4{+)@Y!P)K5HY>*vo1%GIs2w_(mb0|R2|he1eqvo@-qCYi)hXT71?zLSdeSABy!C8G3ybQgWSZFJif^Z)5Kx%GQ>1d0R6 zdg~peLz#~O44GVk!_3L!NoCpN5`*%t&47zf*Vi?T)6t3n$LCc`4uf8!ufTXj9tNg> zi-W|}L;^%Go?sogl*tiZ$kAA+ECGh>SadTO=6ZKer)=Th7qvtB3Y@Dfh$^d`K8n>5 z3LpN)uM_?CB)T%m#yxY+@zLa%YJ2+({a_0^y#lR#+)=iT|Kw zCG}#HC2p=dW~<)~04#~qEav-HY%fD@?FK(+ACK~nM`!Ru)L_1Ygh z>^&^s5Rl_}4BipJ!neAf!Oq}+-^yViu#u=FV#`O_;?k$9%UMa7<+BC_;5t4tOQ(Od z_EGg&6i!9iM9~NehMx=T91j-Np#aRp>)79s%H3dL!D`j;7`&~|Itca)ZC+gM_(WdEz z33H@`3nN>g;{Hzj{f^{7fHP>Da5ag578!w12$ zRy_d~V-*>HVu$?a5Es+{3|VK)Y%gLlBVZ8w+h&)=L_;#k`zr^27(H3k%66nIIY4Lz zt6c!Z1jaA{&#OWg_4ixjYyO+6tepYK{x^ujpd5^-E9lhpRM77@U6Jdn0@fkQ8z5!M z+#Ha5c(NSFp=DcP$V*qe;Gxid6F+a?p(^edcYWb@Gkd&kP}$+4ld86T3g2~I(kL3w$(2ase?tE+r1-{X zmEmf|t}Xb@U|?&krylO@b~pmlFESM}<}a9#Lk7I<-rmDn2@jZaY`2=$8@x|Ifg?SQ zi570R$PO-N-4P}h!>mDmKT|0(*fZV+q7pr>Mp*J6_$V)ETJMl|;)$hP*Afy~ZT8_s z6}trhjs^dqV@e?^5bj5eYUM~aeQ^gXUi><=PRw5vzQY8`x< z0X7pV+uaVm;XmacqG;1x$G77F0BpcyK{>sc2EuV|YL9F#>Y#wR){~_qEsnO%f7P<} z$=?K_sj~#*}ka`{!ag3XEH9c!itiX)c@c-Q% zRltyYX0uP;*<5)50p|R!PzJuU@pwufvptWgf$jUf4$^vK4%Q4M4yv$~4Ho{@J1BM4 zGz@uFC(RNe{A1d-UQUornC$C{OLUodj&ekmyMb_p=aQaC?%3V@X=V7>h>iJ%Tc6h9 zC$+JqZ}=ay=&0Iw@miwW)QC0uPmW472AUC+-``o03}Vwkz^#Hd)!vY0&e2Vt4}L$+ zsr6j5n-S*72>l&L1;BmKg^vD3Z5U-a?BXmnuq)S}@b6Z=-kt~;{}(3UVcrn+eKINy z1W+CGrz`e*_OZK;MTwi_6D&OBW`A^#`OE>#hX>ex6+~QzKUbwexbvmqL@zl0_MX{q zD3^p}Gs@SWw_Q|USL22H4gUD>grZVYToOXZ4U>}b^iiesKb?R8@Ya_lU3y7_{GQTb zY)>98K0<>fK=|0YCd4n-P?TQwQ=ZlmDY_glxfP)R_bm+s2#?l4hK#$*3*_t&ZG4e`$@Gb5xY<4y)J_-?d=yIth z{n}AB1%l?lM%-vo$5Vnt?uT!Z)yJ*jm;nu_N&`S#U-|4}l$um~#8+RXO4cvCHelB& ze7}};bbLkROHO$UsfN(i!NUISmy4bh_X@vEvAIs<$YXoUjNyjoNP+PRV2meHjwT&{ z!gS__r|ZY%f6Ia8)cx}_f-5f~+YNTp4i4Di}3n4aCF!^Q(8$v^S?ZcIw-! z6m=Dpr>2&`B^-)pxZM8v=*k!TSzKA!BYuC3hd2!i3es-&=2cKsjLpi5eqK?J!p_d# zaj<%{+@bx;`iZlPi@Lh{r!Bf?QYDveTm8!ciGhK+>qilc-=6EdGxe)DzZyINj2POu30n{#`wOBM~wIOiWCygo@uj zH6KWZfPJ}f@eVgh&z+ple(sCc>BjP|0a7T_=Ri>8YAv4i#f#2VUK_`&^`zAdj|B)I zMNd%n@z>+`@85e~%zKQCjRo6OHj}(e!VPXXB@zU?xrkU?nGm220X)?yG7IK;A6&K=DLi zZo3mXwY4O8VwZF@K6|fx_e^M^fXMApM>4ks?nJpx=%}hVHS%^-yxOD(x9RqzzqqWd zbEPZ%xcSfzuWrHn`9agEO8vY&Lkqjmka!(G16h=@ek2~2HFw@g5;=S^e1s>IdJ=&+bX3C z5ZFvspaNxjjU-qkFC@&&3cS;vJlD(y$FkWv2i2Pk35J{54HlEYLmU)k`BS)T4s{hOr!BcR zs=s^3vv>aO+c!)5L`o<>KR+JUedlJ^rVJ6rBYX^OgzC=r_Q+Oa&Z?cmUU%co%<|7! z$E!Y~2>mFwVqVxD_?~>TQSMM6Q7NJl=UYlOT8y!oEt=y**@vm0RzwRvhoZh${RZ7` zlX{`l!tPtw$sUV-{ExA)#>L&-Qn;a9qu>mN160{+UKQspmUVZq8|MC;U0^lX8vcGv z-bBdWOOV}3O!qVhDp5BZxjkBB(ig{6e{;}SZ8<`JyJsOT`TqTrz&5(yzki3!w-gkh zzJGtBY5e~EIA&2`*J78QjPtBrT~1@8&fVzWzuEiz(!d(9IdXvu1wa%g7%y~II02mC zW2n#A+9YtpPMJ;psefdUOMH#3hAbWDja0m z#{n*YQ6UsWULUtb{djSqHZ>%EY^ z@3Ay73CT(br9E7ke?B-aj_}e~?DnP=DGaW`>3X{e3cRdeLK(;qCY{uE!SO%Kqs?h( zAg^2W7uKxQ$BFJSIr5Ml6b%AkUc8^lXPpf2z!A4#a)QD6+`-w3=0r3F`7xgc<(2Cb zQxftk%K4d@uMc^rtgQTyq3xfsj#t7tR#s_|0>BcB_!Z`!yKqJQ%Hu~UkTUIRl#9iH z)@uZAD0Eot=0(fxI!9hh3yqhTSN*~7UB^j14{`*%dPJ@MRkpGf&FpcfbB`&&B>!j2 z-&D%{V&&Z2_ZW{70E$$VEAUFDJ#`g0M(~9()k4r>`-9bMKVcVTki?d>`BZWq>Us?$7qd<}hC zLD5~0_xKVXAeO;Yz}jGs4j959bWbJ0zOQdHel3ny@jc7-%vq_6hzLMq7%_r89g#y> z#^9qlcq2f+yo0_71qAl^e7EPU&?*O-u7iwx?>%UX1CZxkE<~Bq_L{l*g&bgeCj+~I z>jj8~Yf4XIdtP*LuHa(;!R_j>^-`XwL(xWPfUbwGCn(|!-(7sFu2|d2H&L= z%LQ9od1Gpv@#600y2oM#i(Kq_-&0Tln42nX9N6c5h>1xOQ*ZXeX-BnNBM zN+@#bb6Vz9J|CZI(qgj@zIcEc9?;-^mVvw_t0>QU1Vab9or|0Ch8^OIUYp6TZZ3Cz z{>2ChdfF1AO+EU;l;V@)BM!SHO6N*l_*E-|lkh%>@bL`+OYg<2T|SW(eX+kk^GeV; zeD|sJXdM=-_4n-0AD(+Ndjmp4vmwW`uoa$H0BK4Z5Dt zy+W6)zua`d6Q2K|zto1jpEX8Q#b{j}g3u!GV?Y%YII5n0@}WW0x^6aR)!C4axJ@Fa z6=e+sS`qL?lyMsf2UU=`&+uXJzmUZZM`8)WEF`Mp&3&C&J z>ZvZlV-Lw7zW9Po2Za-qi%)&>IIr!ns#^~9`X<96%imxx2<%w^mR{IEAMrJc(XCR+ zhg7ZjD{g*7yA|EWlgj%XN_`6~c z+u5N2zB^+=AS71P+mhC}pyT6r&GS#?W9X`--tS(=YYLZhwJhCrs1P+9s5}<%!Z76l z=gL~DZ4@9~NU(7?+C}u_@U;PqT;jV4B^j5l;xOHU*4Ijo5ARHltOp{=C0u;=L>mtE zKlOyEvaNQgXyWpOk;svlfg3n_F1%`uB8QLI*>AmJrO#=C z2Zb?B&j)^8U6M0Ii@~m|{6!k~NQr$|QkfuaEUIfzlCE%kfl_U^H}lrH`J;=+Nxrd2 z-7id9nt#kd6B5yEjdnRQ%ptul@F{EQJr~&MJag+3#3B`o5=_^(7qzL-Wl^|cruEbc zn|DHd0W?WEUPR!Ti*f8*z7}|9bRV2E12QfedH^8scOvP;L@qAaBEdP#K(B`JU)YHhs z!2poGBJ zl65a_&Zo!a3cql$xnUi)TD1Y2AM+u8xOFi3HXsHYv5{#4z_@Fgu1YoQQEkPLQ!~MN zdeCC_p|;H-p;z3S?{@e!aGLIaHxK}h)47=P8SkFxz&|-Akm7%}eAmvcz_5QsROUob zTKmc9zlqEVmc2vTm>XnIWJ0D?V^e19#HoW3^9JNjkr6;$FsH!nFu>S*gEBL=m8(fcd;9`l9%x|t!s zmaQ%ZNf{BV_Tsv<_iPRv2lfZ@m#-M*+q1+3P=L!ijh#3hRv@VZH#F|f=sDSk(74#U zz9JIJ#u%OzX-04c?Bl$N>SJLk;=Uo}KVBKU9Hu(|)z{kLQu?^N=}U?p6Mv8jGqk>@ zFB;@2js*7WJ=NWuvEF-TP@$84|1SOrVC{3EY>GRp{%*$DT@e%kR$}ZLWU>gkQ7Njo zgVkp+_r2UKo&!q}PPnfI-=e^yKN8{r22&G{Br4(&UV4}TelJv@F=BhwrfK)6de z5%41_8Jr_clkXJHO-rS%9e!q;133EVkkFZ%s-j<{Dvfq?Y<%=^xu1w`aFklC6n+HM z+a7P}3>+JCZ#@Mmar$R{)2%1I(Ifrxl#~XNa!xC;ynnPCQ+bkJjV-Iu;^4oj4T z8H}Mx5>Rb}!!))b{oVkO+6~S^fHRJb(a=;%gK6Eon8;XI#XbHrKN{VibieiufTQ|) z)E77`;e-YMQ(6OX5qGQp*OSc_`4@9|O4`POIVRewLwS%jM3-*zr0N4Rt6dLwn<>=5STRew`G+^q?p|UpB`K-}0J5bz2r*+JKb;x2KniJf(%}FdC=+xLO2@Tn z#`zHsU`|{Q4jZG-tg*j$;-%#A0j8eP0wwH2uRNJjq;;FQp_XL`bYVy*EuivjFlf|1 zNE}~NHac>1n%y~aIhcMwlVOL=5Q{(1e<{*$2RU3bbB!E8bt z3vOnpcKbst>@AzsgHY4yrwxGHh!f62(uLr)FVdr4CQ;>p7al-F5X=?G*tj=8PWQz`@jYG)R2_ax`o$Zh z97UlgXVKg}Rtp*BQ;G=>p|=zn9R&d@O0x1>;AvNnk;&pP34zCrIK?kdD4NqF+V?3} z?KF4nw3w!nR3k*FIG|)<3iUTv8DPmP?5yje;ut~eE`=;<(9(2On2YP;rZLq8Ko02t z;-kUH4>~$BrWU54jml!N$(WGrsr&Mm1E2bhQKw2MW?EjkQ)@Es*cBzR@U_XNf5A$=pB^wMJBOtl$z|RbCK`T|<;Ai$@U`bu&D&^|2!P$#j zkjM_wit`fa?$eHL^1%lj&m*{q*O@0WyNG1(GC=w6IJ^-8WQmmUHAqLb{UL`hwzvVZ zjc97?rz?9Y6Jfr#$mW>w(p4{m=&(24mxeJqWnj~iT*`HUHa4d9JFzD}t z+7~FzdG0lLSR#5RkwXKizt@*+-w@tC4^J@v%Pty}*K+lh#?6gM5Ho`_D(O8p?2vW~ zt|}5#gtI!)fA(_d4gtaBlH-^T{jRI%?Q%eb)p$=XNlUIV1 z1wC097)|olfsy@2Jyd3IRriLaF=UzCY&0wBy1tUbEAHv|XcAfKe0OsNt;s*XUw;-F zd(C}&C07Ef>PBy3Su>|yi2=t=rc;$E=095Ikc(7K;I_Cc`e7#MI{77n9B&u)4_)0{3ot*^H%>6Kh+4_t1o{g|Inn6tMqsYLkC`sEOgKK@lKNp zl?C@8z0^r#Ux|qe1|`4u%^!PslJQQ@=hN>?R5@Wkrck03HohNQ?j-IO6*}MWTcz-H zZ*$PnP@iAiV-Ewh7pM?W4hZ`d5cWQiCBUx8*`WG1=w!IZJjfpBU%BUF?WO}pjk=Ub zXT1|2DS>AncHY2LIswiOs{J_Crz*5eL5aKW#Vpc;wKy+kblyEV`7H2Z=P7>tAtaPR zUF7${->PUcXEe1q#-FU8q^ur8466x&+G{9_ugX}-VCf4r8^llZE(&;a&)N%Dx2HWS zD3UsGpaupGd7MGufLW$dt4=yb66r~qHdr`;dXAgQ0wgeE9#Y3liUkC^H69iHS^X11 zQ9%*_+)I$X48?iA*{}SEy8+E{cf_9O0=s?pM-h*-v1UONs&9QBZBG;y$|P+96t2O{ z(%L0L^F0G)VeIecK^#3tL0f_Om7)ODx>4LD$(Fc1JhKCrxVI0>C=;K8APvdDV|zi9 zmn^tw(h@}HqvJF3j|kRd)l(AxAw0f}O3OTb$!3ReTEFu8Cb_Q&hWuSZ095&^6nr#~ zjaU(>^CtAvQ)2J{E|;=J#$|^$L#I$^c&yS`%bWA4=B_U16viB}w0X~jj3coi6y#7i z_DSJeWSy<%=a~T)MzBoS3)0s$YwKz~s_cI?RBpv1XpP6=()y|O_xC3NX9=S!PVzN0 z<;I*r=B0kIDYu4Gh%?Ilyk7?tuBR~E`8m(@;#bUSqQMC|dmMz=<=f^sag>Xqjk*tn z3;4+c7Jt*`xTj>5vdQE+ZC@hZ%j=&YG>ClyheeRJJy_DYI|FmzH2HLxp>kTOH9Cxt z*QE<{2uU60c~6rC!Dd^f>>5_YlO%`l1*}F(F*Vg_-IKfAc+~6G20jHVD5&;)5$bnt zVyEY}hlG=+Qkf&)#$k#!30((n;mH`*_30GS&l;ZF?N$fpIXf0g`y^@0JS)J%%d^+J-+WXDU;qh@I{Cn<{Cu97Srxjiz8FxxI=V3EVyVBbJA?qGzWT%)^>6(nMmqIjDR*@0rJYfI|JaxqY6pIBoue?q zAcozSOEJE0j>h_!R#l$jlP8H0jq8>?2qbKM!K4S9wSUl=r51nXP)MBW#xUk`;LC*m ztE;SF)QZ0$X7S^v-EIe&g`Lxzo2+zkb3cbt<6VauFG{eWx*7kovIYDCsd%4fHMc@} zTE;jm*w{PAZAIAWI|-0-V0C4%oYZTHsRK&NL+QV?I zMY2)9bZQ-+kydziEHX7wq))8;alZ#p9NdP;T{%_@SL^U7PPG@bN zXs?st5r^UqNEmOg{T?t-RJsQ1CWKxclhT+Aw(9f@VmKwmE7q90=A<kV#5j*Itv^?&r;Nou+0KLoFtLJ6$8-L|Hn07u~fB8uV($L6$^g zi#AKAFUW#{^X4;S0Xi7>N9y6UU{5)j!yV8x4~vo}jtynlzyLr_r}p`&0I8DUEB9xe z=l+~j(u~ixf9oY2UI&VJx!>nrBw&UJ+ThV~RJ*^`Y&t$yxeed9)w6rv;ean@3aL0yE zy!E@nXG#&LIK5UsDBya7&VX=TcaiyLRzaE~y$pnHH|gPK9UmlSwiRQCF$Nn4=sI-> z?2c!=MA{9^nTX9%-M1^=&%xq^%5RMEgX}?@A~BKGlwt4W8N+4`eJS_2Y5ypW(cmcxU{sr z@vtSlu#j2TXaARDgD$88`NvEgT8Ko>pHQkb%pDB)Cb1SZ!!%C@!UFKwHZ~-m4qc$mg;_T% z^0`B{ag9IQ6Dkq<7HSFN3)cHhOhdc1-|N6%TZFJ*Th)w@v%gY#QL^n*`4bE-0(|qp zR(tEtjgXi1RD6Tb$BpwLNNq96(VK|S$%2TW{&oOtjl59L6Dc%UUNtwsXu3smbo{$< z9h01isYA6_?0PGY_4)IT+pANj2Ti24)!=S!=9f*iVH?UjO2pjD*XCPa;t@+?gPWO2$Bh&V(+F49XOOy32lc0l1&}H8@ z7Zu6wI&40QW6UXeUd?V8Y6&$7w78Jq4Ae?U#3mgud0k5qVqHIgKwFr2F3zuuJ6mO^ zpEiiri1S4uCCLe&{bQlI{1G~~9mK)}P0bVu8q9EQyp=ly6TC-@6Fv;f{?qJ6hke(o z?5?$&JvyItz`MDO*auX33_`tl-^TTxR;|0aQi zJzn9LFvON8T4QJkt;UgfPR1VD-DR6W-%Cc`jM`*ANFj2wSL3<=Yf?=|M|i_7>80Ld zV5-rB1IR8def%Kl+B4jXeVkvitD6rwIIu^kN=izWF1FW4J)3U*;p;J{_0yVGf=Hx6 zTGP_~{p%SOL380~=O3?31F;>-TJ7Rw;d-_88^ObZO0FOTFxF-+6l%wR{PdM`i4N8xhC@~KS4!BwI0+r zGJ5Ll>|EurC?;|~Wm3PD8?N^8<5zZ_+NB41`XQTN=+=XyUK=W@A-K-^jZ~YXJlZ=9 zFe2;k&S$H=5!Rj}8&+EMAK{&icUYZ|Fqkc&3>BP%eAV>vg39k!*<2AI)5k}t#@XJa z8;aRO6t&4vP=XlvvqxdD#n(qtH4(kIL;KEvgB*xb9s^{wp_W$UDG=YKPw0Q==OfMf z6LWt5{&;uVNu&w@bN2lD{#RzY;Bt~hefV0ABOR8$KCgf;BJVvAVpO>3nSSRV1gLO9 zRdRLbdu8{pNqylmhiq~xWqRlqmpWy#VKBKwxu9|~WNzv&DvZwdz# z2HRHJaY=e@!LsELCFIjwes@|8WNUlT{xHHJ?Hk3IG|NQxKSy`aWkQ|``5E`l8W`k! zd=MlFI@&Z?k|JCbzb2(Zct%L7l3O@uw);T?Mo0p7N`H#pv<j%Xef-gm?u3IGLXH=V8zj>Km9{V zfKXa7nhZ)B&>TV5VD6eFP|Ysz{RhxOfQzQ)tjj!yLZbXx_Qu0KwfH5ke(vCq9B*XG zK;F;ze_TMgEGuExdGZ9uN50$z=X@-6%;GaIwZtq@mRdwym|cpT&otssqFIzX4&Adp ztvxf$v8Q1<2tNg!c=dDY_}RdL@`+ZxsBgu*nal#~IK2+^#_V~BQXZ2DXOXt5CQYqG zGe8v03^16U4vcEazP@;kV}sA%$pbTQ9XWO)!~oqw%KJHWcmO~$L4r$J&YLM>_EsvZ zjT|1NU{K#@+n3Fj6lN^~St{ZP$iHv3NU;6DJOR+0_D^5rzLQ;K%f0kZaMFQ@@* z>*PQ?^IRr$r*(G-_p&}`!2(MA1>)*cdrU0eTdSMxnq9=;BqWK?y&mCuJ zL2G?mNV=gyof{@u1dB9q5dk@9f2JVOUn0V@@cbL%BglH7qkp6>OX>QH-R5#~ zw1|E+T8SXiHzA-#VBD+#ByCas(;ZgB$&U5Qobg%T&pZj-v(7W(;T|8|x1}iE_C5(m zAiTLkft~Nu~~p? z?@I0(R5p!s<%D{u7qJarn*xw*gN`@5Qeoa%Z%NE-{wPIeO9PjE@yv$ZWT(!9JQ>V1 zH{T2kY6Vyh$mde%dtj2r)PApd^SrAr2@r4jb?{nK3J`w#n-hWleDH_NZyA?lOX4||g7Tid(vcu>LsrYdgj|c=Dex8Bkd?l`4ofW^sCfD3lUAQt-yMSno5NZhQLS-zjnEy$b?00#Hc7Posdcp}{ilUL&e>1r2Ogn5_Xxg1*0+ zMy4;&V9bbE=ikou%FZTZA>D1{@1Vt|fZ~rMoH0w8L1)oSf$0X*x5xGI)?@N?SYQ zO3Xw_fmrUQsV^g&*Bh(8JV_Klthl9^+-x*ModM6%f0K4Ec1Rr2nx?4^wt6I3QKCnq z`U<86yE*mrQ0_r817tkZQ#ZT2u)dE+`|t{3&gDLW*&^eTrwpgJu;jUL9}Y}HIDwDTJlQ}bvqRx87g(Tb z0^n+BYKK@-PJgs?e_|L@$d|4zr8cHOltP+t9Bx0ad4BXkvE0Tq?c9}Nen^p(&!g*d zO{mz01NBAPxv>YqxqCMGHay%-jy*IdVJwQwwdp@CZ*uB#Citd(j=A1JlQV(8>s0qb z%rA|9&Z2CnNaoHl3o7v?RzR*AddY_$s?(b`M`Gimfs8ehgn4Ee2diJDm#FOoyije8 z&gU-WUb@|_j&&^Bt85EL+&Ra#TCJAGnO%@f`+Uh@dK5q0xxvxg*7k@sH_vO z?Cq@i#E_GF*vUKn=eCjAp(Agx^5BxhFHLyc+LUuP&l zq1GDSO+CqnJqdwa{V$G>}^iebvU;oGcF`p>DCZLtJ2R3NnPXGzyh-PD%f+5m{gH*=%UCQ*h3>~BcFU;-KfpJvLa z_*OBO*6K4h$k+raetpw+au0B#sUeFXsk3N%&IWMs+3RR1Eq}O!5l#c!q`PC?tzoUL;un+8JJNz{SC9 z1kfvo(E0fD(=z7L7`EB^;0NdwS$rgmA4o91CgrAUW9SUHzHIZ#WR{5r5LYcPca<8?@S&z`j(w(5b?2@l3Q1CT@Lf zqE$l+vd@*s)>Acsc1*oWw7ew&bOB!T;Xkw*FT0;T{&CY_$!HGLB&h4a=M@$UMd~_Y zMoTn}*2s!Na2tNf>dD`_WX>~-JF#M$0W}woII|B;6C*=~AwZEb8~LkC=uaWkG9?ID z7>R3W2X@~5mUm1|@V~^(D2Nc^X4-N7<27FRJX)saUA&Xj_P(YTRRFN%lzcNNgI|^;tRz}qKp8$VLOwg*t>5@LJMXA%oSTk&8 zwp9tqfOej>FF2{iL!*XqPvzrgR1=k35FG%gVu@Y+zuP&I`KuJjSd!%$CD&4ya0&Yo zn92%q3623BN(Gy&0@b|26T_V2?1t5&F>=(;a9B15WR=JOnr$kO7(ywU@0O$!0v!^m zgya%vuxlyOsM;o|Bd7;}!qC_vYs$D{h^z2mz+-LQCSuQwj#N8~ zJl#6qH?17SlE9Q8Pn!`>N$r0^P!L2DW5K*I&}RSuSZ}Gq6ih&dw4f8qw-uM;$ixVZ zQxv2#{@tw1i{ii4xr;!c1&GvS2|R+iho1qDU?R~}urP1Ya=EyC8bXTipDK$XO6SDF zszA}ufDU|L;f@yRhv))#EsXS1EYe`9hhYYuaI}_KF{Y6&#Ct-m9R35LnXvnogKOpK zgv|yY=gOE-3F?f>S{QbAcO~9D^eOLm0dt_(R2x06Nn#z$nJ{)kZgZgVX8j^Im!PmW z#{D4+M}iyp!Ri*E=D)Jx^7u0jg$aef=gzwX8oUybG zy!lS3`#;r+0r1X8-T;cE9{>SeVeDg`d>n=T8vQ}WD_2?ED!aIkZZ@j00jO1;Qp9@?t}fyR$e%ZiAm`rdT?OuV#6WQ+Go zqif>H?>+p=$Za7E`c#jhij#u%W(0~cV*irFHB^j0SX(*UH7)T4O$xl=4N%+ zpctJzK@&%a*G&^^^*sSLnn6=yY1VG^~zTDo#N+QGj7A?ytlL}3uHX}gg z?f16=%@J9BX(KhxzVry3SRr(~$hS}VtOh2~)z0Du&z&O7K@C2<;D)ivlHhF`{0pZ- z)GSQhF}F+gb=>-+ZF@9PM_s#=Vs&bHPOA4D31u~?Wp_L=84BdR={v_Bkhl!=0V4Q} z<5cL!<7D|(=htyjKbXFQ)u8L&Jhr!l;9ydkl=~M#lTKEFW1oaQOb0itDHt{#;QD;f zOqPB|1=L`Owby|7DU^vFgb^KC+b4HHD48nx7nVLRIJ>9_qztvj9JpB(kym+8ufe-M zmT6k%0>-kyqG1846YpYPJm9eaqVd3vwIbKKHbR>lnbGF zVblS3L%S)v+=xz75YgQ9UJ%@YVzDtO+>I<={$#W+Yie>Homb;y_v2WQG`Wx4jc1ui zuh4+^SR_i>jmUlM`XY>_oOo3Kv%HVE`D$f8^@&?PrUS$Uw~9IB8c2Nsyiuc96lmo$+tCPGkXlfZRjB>CIe?%tBj!tJy-D)0RetJYBP8^mi z%O-6|v^6%RoC+aM@%}!xLIJuFNWc>GG4q6S@VuKwF3$J;5UKgyy3ZQ_hX5fc9G3}r zp?r|w@f#}P^zog57+r)}*Ke+JZdm!BVa^3Uq1<<-bf45+t4T$u_){o~Fj+py#dT^d zSb^{8i5W~(0MsRM?F z5Ge-@FWn^Q!&_Ek0Sx_>jdbg@pzudrFh7N=E%%x6+BXU5Ir4NHm_Q@?8|(dwZ!fze z+AY*bh>Dv29p5gvzrzJcC%P|IR7=$BV7yeTyoqgUQq5dh#Io^=vBa#QvbR=`fwTlb zEu!4!kXjTV4wZQJxa_nrj|N4)3a4KVR9q4CM?cw^octmM)>GsFR(I|bZHsiSXh=;% z&nQ*A^oG%!J2O+@;cK7OF%4De*RLVZo;^DXQ}sn@^f;t(Pit#?{U93^6cqFh5BEIL z(*2Z}m}pcd=zGbjS^n|!+??*ackh-q(i~(2(pw_FE=ci*yPkPjtJR{%rw}NHfoHM( zr!Xu&N${oYzj!WR!G|x{lQT88R|chY6MmjWEMWY8zt3)wft_u+C8}v>+62mc50(&t z$tNCR5-MCe@Ri`=wAt2@Kl1dzWLmwY$vKB8NO=2#L}(RA1DEO4;c_&e5x&X6fA|FB z41p-AySkoijcP^S9eSShu^e|(I%HQ@6M$M!!}XOMW8nMmnor5FSLQtyyAJ&?ghftz z87_xBT1-0Y^08teO0toaTl?J`8QV{5VWaP%tQ%{IYYp)^XXoakQ1aQr1vk@!{-?LE4yvmE|2&seDG@{v1f>yC>5x*9ZjcZO zK~a?M<{~O3Af-rmC?yRNSLyDMZlpxIVc*y9?r(Nyc6R^TedcjS8SXvje9kA{@e1e~ zi0)1L{Hv0G3jvbc-@mnFCLOWDI;ECZlqHVsk2Vud>!4Tnccb-IN0=3UAXim1v@qoCfUIpOaP$H;&f z?qUv#k_Hq1<2J$lP>Pa|(7a!gy2yFOC|dOfAzFt23_^CDLh^#}Rc4$ICoos5UWQM; zcVFhYX!9+;sngJ^9U`oUT9tZEPOZgkEG)LG&F@HP&!2mn@4j!lEl~Kpv!TwP;+x~@ zBLwqb?Jcb@rMlmY@m*bA^F0oC$Qjtqp8+z}^C1S_LcrM{NPPUgI&Z6E67ag)nD^@9 z3;aT0U?N7Abi4*KGp*!opL+YE9yglP(OqG zzSHjy7ZBx}K{XFll`j;cALIihaLLw~bV`=h44>%{CL+~3Np8J$Py71|zJNTB)mK8B zZM@uGC+>)(ogFXK_yYn0-i?*O;6j&S$->x2V%=rEJaiOVyTHQHJO%X*v!k&WoN@eU zMxW_|F51k{SkmtYIJw)|3mJm+KfVJWq6UuWPfjh{g{=#k!8^}puFFD;3)=rpRlSxP zD!V0nDx(Dd2_8(p9rWYmDYUnwN8^hQ#XAQkjxzJ0jh`~O1*I!LHDclL$obrm(m}iX zcS7(A&&il8G*O01ENJPyj%>ylmPjk_9%LjX-Q8_etcTj`2`bTfI^fSqszmp1 zy;hB4yxlyWxoIxl8=FqDzp1(vH@z7wN9v}e@0V^ylw@N5~-f%!qtJ1oOrprhZqOl#P z!cOtPK?66E;^N|^#;;$#oF^ve?(gSc*@3(1HLp*cwJl?cnP6r|(61GoF-%yE6thhoy zss4ICBN_@|8+vdx66y;Q)LLG-{?CxOrNPGK7oTFyvbpA$6~8`lIkp zu9G5Y7Q^so>lPBINF4JScx*pZ{LJ%gXyMcU#3>v4zjMk)x7?XT6b7mCn-cpdUHh{s z7ga(US{Ue-R8LQz=eaXa)JVVGg*w8uvBI8jG?Kn!=~R(|LFa$_1%5h56y!}&S0h)c zTUNSTG-a||8LaI@qA%*z$0%{yx-rHcU`KlUw&ns$iNnk_oQI}JacH;{uVobw7D65! zA!xa?Ps2D|0Ai2}yRg^M48!`6Nk|e1#=sgf2~KsjuwZ3aibrY;>UQ8rLjr0!Rjfo^@3p7yeSe{8!4iy@arek__3nz*a_s{B zK4MX2J7DEh=uT~^_3-Y!5d9>)xsxB(qo_=Pc1*7^Huq_XvO?v@fh;*k@Qh5`X5?06 zC~6W*427-mhF%GAe}Df{0$aTEy{dK<&kc&l?(6ks(*c~;&>O^dT~)-kBMw}AYrUT* zcu)cLZF_sW>|p7u4K!(|bHD%Lnbzxh+k`B|S&*X=FP3(_XFit(b$PmAss4B4XgW&3 zKZ};80j$gRq$!Pjy~W{9U-+VH0-m@yuJhvbWkvRuyKaW(mm?_JUpFN_ve~PQBBb>X zX85p6@N=kJsBeGrt;NQZawvd4sLgJv8!sXf?MUkV#YER3Y~XeKeTV1%?mJYXK$x(9 z&LwU+Q`2Xt40NiTboF#SMVE7x!6Ts`ga5@V`f!ov+IIG-$q{`UDY53%+a} zDJy33{1?UeqeJ|D)|#(J%zS$-?|a>T4b*}4q%hRu@+Ql!4?>*j)S> zA}&C`Q9F&~0T%QEk*G3%jAGV$bmpbWVAlO<;~#jYr#&pt+M`Ucw?GB{9P440d81}q zG>#*l{q%Gxz|K1K!ivYSzY;QQq!BouZH#zGEd+)M)I8RvI=my?lk{0uQ@t@z_YSVm zNlhbt+CZNCzSz*OKA#twms=24Y6ORR(|%`N>SKUI!?2tweW5|!+w92bZ?r)W$Nf7R z#DksJ|Jq8rJu<7pAMMJ*L$j3cg={`Ys9T8JzIM-l8BID;mu5UTQ5SG*{gt&8Rg2^D zhhk*jFPf*c*RpxsR{5E&iYSd_==yh64*Vh8R9fh5V4<7%^v~5HPK_H|l30g3sJr}N zAWZ#vx{dYyT0H8HsYG5qx;OOs(aGp2J9MwYGS?&lKW~Tnj36Im)1Q7z!zXy<*vZ=&> z&>Z{NbiK486h-L}5G#-x7t8F*z4QPNtrgv1!Z+Vj7zK-Mv6AqHvON!?c&nJ?y(x|4 zK1p>hGa;bbRXo4Z)6!Pt8{JDXC3LTQASa5Fx&Dp^lA%N)-LmZ$r3c^iTh0#rdN`1M z$M*UUO`}+1RcMCDW&MbG6z@wDiH{xr;=?&ye$IIoCrR0&asTH;LUd0ER9~5XK@r== zz8J=)5_4xO%hK=h*|twnSwG4Om*hK#gxHf>72HWFKzOfHObpNlI&Tgf8ihrpZqS`W z0NIK2q0nbl zh@>&6H8Nz~-CchteaL-3^&H zMZ}aJYOe&UjT}UzbM1O-#EDH>4=<7SBg!1@_y486lx`u-gqNk#t=0Yc*%bOXCU&QG zPPnbulqa15BCYt@K|fKE4ysCUCe;Dl>hA(sNah^*996prz+ZlvhO2Ba zER!TA8_jA-OfP7r;q@hm+3}caUrM~)__mxQ_Pq9;i*+_5k~$q1M4+hm{tOb-fs}0F zO)?PIJ}G@7Pt%A=BjQEtw!uT{8M#{E1|s>l8`A{h)3>@d&Np$Vk;pvomKpStal^?_ z4rh@Id!%CTuD=u=qNII#`ccB_E<58Cq#+z3<*k~4H0N)5CAC5sHRF%tVbj$*mp`*Y zGpD1Y7tu2lI8p4JOBie)ke$nanzNNifPP|vi%Fuvl>Zg_EGv5nsy@n3kAoe9^k>4e zb5DTx)}t_nL;6O;a=Uk&jS%fB_~hcZta23uI%;F5xJ6QI$?V+TvKzO(W@WSbA^d{&PM7xLB^bS&{3F zVCk>Te(i|5t3THyY-oDx%wLuEkJ&l9N~vB)4frP!3bD%4h=bjW-o=DF3?SasU?9dT|Er3t8$ObKe`hkmKCu*5@dBxrCO zYv_Ke4VD0DBj9#6KqsZuii4EjhyGaLK9^1r39@>&51|JRmp^pY8q!21UOzD*^Oowz z6>pPEqwpHmRbJi7?agE`MS@I#pSw1YPO6Ic)YS_0Dg7Gm-q8Rnf_WCm_TDuHRFyJR zxaJ%g-zoP8Z(rt)K=ti#)e?lF=YB*Y_VO+mWks*i^s2vWBIA-epM2z!StC(K##%Qs2@t^Ddk@4CG`oj~%aI>yFrtxnwrJBpX^^6h7*G4CJ49sVByz=da7NR3DiXpnwh^huN4yKzI z?KOg>hpZ>R)E_W<$cRgQ8yH*w?no@!dlJ63HT~W3qg^0dnX4we7d|H>Rhylp!kh0+Pnb75*L0s55Y#6^g9@W1Qx~iF_ad@%Y&#ef_PkVkoCd9th z68GjK45F&QnDXi=GBm`GHex;p`}gIzn>;U`x({~PE)L_&BUUEF#olt_h~jgC^VCbn zRGmkIQVt~f1h;j|<3n4|f^Y&pqS$TbrW}iBxpLWs$oYldMEhm#pe!F8`7udW@=~uNR258TusQrrW=S1kDABb+O`IJdcJxJfF>j(;k zGX8JbH4Z6zM)8z_*i2NP1(8r4ml2a$H$nQXF&d0eqZiBlB5#h_YaiZlsp4R+1c{yD zy!4(hxcS%T0{7DBtlntqTbF`^k1jiu-T%dSV;+Ud@t0Hcw$}VaRNyQX(fDj;XKO}9 zwAIBv8}(j_rFcj2X)=4&27eRcxZ__@zJ;e`JQ{uzi`kcpc^vJF6G8#xUbhH~2`ZL5 zDbH(Y*P@?LS>P3+#jIf8W;LgeHb*Wj7vW z;gC||opK=qP5l=8#f1bP?6iY22+$nnC@1!j^m-`VJs7wandrdB7+8mk+svWnNhqbY z7j*`4pd)98{)gIpH@)R^0@Yg(P~Ch+G@j{m)tC)!a?%sBHmuu`6MPWbKvxn^+@a4O zKZNs#NLqUA9&Jby@-dYI$<`QeqK#+^{>b=Jz}t$o`F!}JN5>ljR(2t=XZ!4=i_Q$} zGAv(N=MR9=%f|KXk>re575-x!;?H|S;9l(-Q}>EHa2$CNzQ=083SyeqaLT39?jW(* z=5trf2gMP}w=0g-1uV}Vy{*JQQVV>HTb3e6k1Lo`AX(Z77083v0_98-a79Clya5j135a+CT>VptIs@iBTk(55Rsc~xs;^1E&=y}iLl z%(dBuc7(_}gy)s3X_~mjyBGFQy^g(;E}*jPb5%^##_U|$zU}0|yox9;`)lX#Tpr#> zvpoCqr;;(A&`9tPL75}mq z4#F$>+?j**T~yWwxR^iQA4G6eJ8$p?y@#FRkf$S`ve81L0_Iir_z@&une#@(mF}`i~ zOr+0f$dNx5k%e9l#cw%<5o4Z5;{WbHCryX5zV81jlP68mFm_0>4rGB)zrWWziGIT$ z?Gww~j|mpS`^hyq3+dqYhYrwTL8UG@F%7P&8fJ(b`ttm`#*f?NrBXFp_WllDf%c-H zu+K=%JAksFT#H|mZ$9@hfERP&_;8p)6p!cp`$=H+;v(6xhH3j1(ldc(AewH@A#` zWd{_A=CZRa`ZXf~6icyusSFTs+`ftsKM*45kagG6MK>WY#g=6Hmi%0bo)U+m%$JpJ z;IbERg3M&BnL8>ts6F|z40?&`Hkmgw$cHJ`ZwNMaA@QglC;CtE_E^yHmVe7^%4=ng>tbg-5@&Ejas|20#(T+&xmUM|Xxx?(@b>74&YUB}GCgc89kGuQLF$+%!x@6P#>D#hC z>N!+am2&;bTUJ%pyG)J=EWqO;>IAMGFS^w<@|9ykgm|MMbFdT(pJQvGADfM0l%*&E zJq~%$?_U0QVed>}9^JPvD)M-}OUi@$f(mpXVfKtnknawfzx>c>*`CMI_e{y;vnq4x zW#Jy-#9tl(;(iXqR6OdzZq8SGE)jpts37`fZXhVVgQCo+6jsDg6C+%bv3`98c==x? z{KO#&+#+F`QM?}M6E9VQmJsd3M}%C|*M|iAelQ1RcuS>(9hj;eEr?&ZkZcrV%x zP1{Z^EhgT zXI7Oc?ay9srm;ee-w*HH_ro|JndRCMs?Fr~^X_Ryh|N#&1?@e39Y`Q3hN0(CE{o5VJ@2@ zPMoO88`VNF_aG@x(@;Q&w`*yYKo{`H`?k9Q8>C`=_BYn>l9f9psDn98gyRKj&cLE* z)9h{C#44O6=8!Sa|EW_>lXg&c@czNsYAM~1I5rfazuDM^T!V>=>EbY2#la9fTedv+ z3Q?NLUbN+;{#HeVU`5|7>}K*W?XnFBBFM`?yIv7oA+43)Y}_PQFRqHBV%M*`8$7Nk zBS5f1x_zu&yw~A~YM!BlPE`(SMRVy?XU2?<08KTSZ}uIZE=c|iyHeU_m1xp)s%d6@ zueQ4%d?&>H@=hkCA8!?wB2B&bJWF@3B9kA9o~L;Py>`<*fvHy2gX{wsz%3C!e(sz3b3~_jharr%oq3Uz!HkKAKFX*-=GTq&q7iC);iU*aZl)R{bRH@+V&>&fE`ub(kJTb9#7V`&nG*9iiy9=T z$>?1d5M(l(P3iX2pw}RFMLqbn-tXRNVrAUZzAV!oX`6Ujer^l@vg5B3Dat6{$R4tc zxV3B2Q!3*)E0Eo;lO6pM#(!+a7xCN}hqK3aU*YKoWHA z)%(chkGvmGgxoF#KR8mhz42r|hL$(_Z&5P~L2ljUI^uc2(&@C?sLh;_nQOdY_k-gY zyGacbs-|3)v`K4PHQfBHb&a9rmvb2f0Aq>{2vNid>G?086mz6=YEm|ByXJ_khvd<= zt0FIsb{}MY*5>Wgo$TWvMz*QG*NbP~6%aR={`*Odu$%opE=F*|odQ$|&%S*55EiF-n1|Z>_z9i9$;phP*0m(RS67v0oI=H;txyml z<;>Y#SJMvjY4~&ZXu+_=s5VI%!K_&ckr)~XVE?pt)iQj$?kw~8xh=oxQv1TK;AykDyY}X@weh{RqOmrAsJ{< zmhj^uRQ(sHX8r5mwH;kiNK?t(?qS3ox)f0wN`shI2U2Oy?B^&6IoO_Ec%R`tX6Z9x zCUcuk$qJ#qhy`a!H#Z^Hb1jjej5ilmy6!9reVxnec6Xfq)DhjPL~kz-&O`t%5gBz` ztHM%wtUJYa6Vn^^4%oT4abIvfSGsjyw^~n(#%;bx9kgY6$f2^78jpenM@-F=0LT=p zygMMcpc9}?g7oU(HgOr%K3i2e*&Z~M0gj|;d-U5|Ui+;ttgN&pN};VtdGTV_4+i9h zVKtrO_bY2vyYb|${gDGfiBMy(gkTw3Z(qCwU(u4N;SNo!aN$yeR(5!uX{H5p3!n5B zjwYG6HPO&*-Tjv?*ztvaYGVY429}ECz8N!7*AmHz?Og(!hfh#2CE3`Sj4z|t9~A%K zpCPU_-jawnrYq*5ib{y(gwIF52^>=H5o5>xxA)ua^jWKZ4qV3_>SOV$8hrMgmO7c4 zx|`^OujKnrk-*@PI5yipy>vqd{g&vG@o$&&p)pGvGo7yM#_V(`|37$bp#~f)ZzJKqRAR!^C$kpR~^c*?V zwYGAF6CDbCQ`o5J=3>HfAs6tX`92d zXY|*Zbf($7W}C>1N=s8J9>w$O8XAV==HA41o)kXbKp~aTjPa9B(W$Us%-o$>cUBfs ziajeup!$_QVcI{Y(Ur6J5l%Pn^+`H4`b}<gvNn7sPrJgEAj3I?KYs!p_0*!>Q&_|FKQ|MJz|P+T+l=m8;a~U~5qa z`pk$Cw9d<*)4q;nwbpxPd*ieXN#Ug90eUBU# zI)Dp(C@gmkh;{XCpLuO+Nd%2RCesmq}80#>gySJU^ zWzkof%9&G&cB4VU2&53|0ND@fdt;QovQkRd$XOapWC>I)H68+1`w7p+6?fnfn^Zrk z+?x)Z8JCfhlhYFLp!Xl}m2}13c*t0a=D7GL>MY(5SxpZL`G_WFYfgW5;c-9`vB>@8 z{)Qjhxsam<5KCEqn-{Stx?voFT`H!}F?Z6B?_YO7Teve_lb5R?^9D|J|AOeP(f74T z7Y^JJOlBcS`y)iSa4>J}xXxJ?Q1-d|uebfN`lBu}r7 zU_J-+b5LyQkWZ}1q@&LXts8ks+Tw#+nHa7{u>135Ljx6Q$fYS+|`~ZrNBH<7XWQT zq^m3RF-c+*GC)~ymQSsqvV+eG6-azl1)&Xqn91+5q|t9Ys{)b3xsS9Dgl|%fX|%kI zXwwI&ac{iR1W;1hHqy9=E18@M)itREpXMcPo}ls-mRIc9I0b-2jD}tTY~BwD^8H3? zQoW}ie>(WiQDQgK-^VpkjhUfy481SqPa}dK8&90*`T?{B-vJwfe43N%fm*E%Q^JLz#$Z`;gZZ9*DxP@4eWezt@LKcfGJ@EhB-%S1_+C za(%+ZCUF!8BB7{R)cNE-zuq!jGg5@}ob$RVGu+!XQuD1e9o(|gho0f_2B8TX(SC^0 z%g;yOizK?Cj*VKGi8-To-F9sH_?j5X=<6B8BNopX`@ztZ$5Y!G&TrXpFlKYah#YP2 z^;zP{69E0Si)~O@JCMU*X!<>>JV_L&GHzs)y8s1_dOduZA2cwY4`%%sCyZVK9wMB| zYFH`@F!~;i7g`a4>ol0?dzL7Qw0p4)t7OtZM6VG42nchs7&sDi-~k!6eKRV!?+ol12Bh7|adOG?F>XdQF@R(kzw93=tT$A^2H`Q214%Kf^Tn=g4 zI2`)kYwdoi^bA+w12`znEU&K}g9b$Uy zI}apIjG|~>VK7rFx;Q*|*^of>id4+D+>eIM^Lxy+=PyjUYj z=Iac?rwHgN5=mb9IPupKlZiMXYi?UCig9RvercPZc_2n^{{Oo`XxNhpRXiP7ku_ zrrP@m@?FnWx@zp*{Wt{ukmze~!A(Za^OrPS2_S3HTxI>CfoZ@_S70!%;zyYynFGjt z{{GEH6UX98lFH-XO(-J(V~=R|Mb4&M=u7>&c?G)Ch;b>(#S-F3_~bQw4tl&Ps@sdJ zss0ZTG+D%riS^;b*B_Y6t&GlQpwF8DxyIWs7?r4gsy*rOqr+tbyF9LC?cl6{vz5r5 zXXt@x8|q!QqzWTAKr~CK-1wqzX{Wwx!(ZZC~Fnq zx?@FjJ8;Cer$Q;jYqS?n1%djQv&`7y_>Fgb`wK3m7~+D|VNWtY=bmkRcm*yVJ8jJf zy2jlZFGtL$Rvc3Niy(JjM0sagqZIj|A*uKlmH5_AL;D1fUQqkH`;01oNS?K)wwWSO zO)u6b6OYfHl=v|A43ZJKK=X|+Ir|wLq_#~C#jX}uXf6;Xi#}*Vb4?h;j+f_e81;M- ziK@2Rd)x!O69Q{_8n6J%nPaybKg2mu#C<~X!VbhUVZgUg@8jsFr?&8Wbc=19X2AAk zsqx6?+BTx0L{8>?-YiE|c#^Hfqi7(9j(L{D$PSj++u1bhGg40xyT{OfG_SdPP%*W_ zfuPyMUr5@OJ|-+nQL`jn-4xM%Cz*LeN?@bjZncG5qb~<`-hUOKJiX8u42#NC1+bjQQGntN~_bk7Pa1>0tnt zf*=ly=uk4LgkrCd6g3W3+$N-p_&>isNkxtf@F1yMLROCW$RvYa%z4NV z1}L*nnR*(bE4za-8k9UUl__eRdm{mrNb^5Nop{pS6yZ?P;=(qxKv?`;aFQo_A6~FM zEPW9W(t9*M{dh3{o842o6HXo3yHI~)k-Mjt=YBoABx+TVU2I9-R?T4Yt|rd-uMq+S zc;=J&o0KA<^a1v5$OhuK4;MNgD!fP}eO^s{eci7rr?tb7MxMdu!d`HV1tD@HO7-dF zOTU5`*E3SSNPe*|p=8^;wRx%wdUqn5L?^8kk>B>W5AQ8*CU8C{J3PEMka%HHy7Mx| zq)HSq7J#W;H&gVrke(t7m$<&|t-bIb=lw;yh9Vxy1=66P>1)i4$FtYvUVA6*q)bAM zjG;P4&#&F|zD@4vy_71!6Xmrj**2=%xRUaPUb^am|MZ%OzS+zBceh?^d1Opwy|Utz zW6#n1AmCR+GoN#8hw+zlRp0^D)x+zD?{_QaLO=_RWDLm-Oh(b+z?bqp_#=JGhke-} zv6l2jR98g&YyF;zrrX_+j>WwEL-YRdRh=W+S7z7Wui)b#S4{)i8^#Z*dt~PtYV&}t zI`fp?U8XeZ%f0fGWPWeN8g#A^%xsUS{s0)GHMBak{`d@<*-5{JN|oPBTxGbi?xGKA zOb@KTdQH|))MzgwA-b1y!$FsVoSf!X=c;Py3$p8*6U9Hdj5cA>a9 z0psJyP3sKbbco);5 z1&F+zsyDA_YHKsGu@Qo~Kx4d^+q<#!loVWTeTR$g;tYT{g?fTuVri*h(8OErb9S>7 zI&sJAglM-%bC+I!js%T(@@Kp@Ni_*P0o5j5Q3;h{7HO?<7~$HLPKpbnto zb)YfodAM4(QqYPZSeUh%uC6~kG(p12R>n8G1!bt55b4x-iYW`vQ6iYC-SNP{n-ynv zNA1X<)Y7w4m8z#^X-p$27uJ;#i*vK(*;2e8drbS64OEvSQQ5=KxQ`>2UpFpxt$1?q zgC+-Et2ZuT*XZc`xz6(h}OxT3V!s z&fxZNP(D9z3b=OS!^+-8DLFZR*O>nm2VCiTd~v?QsIb{v-)&+~7bB~P_u@Il3&!MZ zR#G$B3tf5LvSlV!w)+ALxESEUBzXuDE&@%^za&E!E3oR+s|E7jzRw-(2Lby^*+34_yz5>UCfZKWH$lUHZ+vq zPwR=&7;g0Fgrw|Kga(N|JJHXT$v&8qz9-0UALKHUs9w43xS{>lujyRfO*L&V*>JO~ zJ|IfszqUkG{8XJAnXJ7ZXELsghrUUuhdEEK>m7ASA1wd(RTr`AZRVN~5VZhI7L~(B z9V3GA^_3w*?i{>+xm5lB%Ba8JjUUUlncJ@V9$A7uf7F-Se}SGloWXr7FUxaUleh!i z>nT4#TsG^%vw;yJCud2jP_>LH$+I}}Mwu*~;%tsYS7^_1(f-^@!r(I*`a>l89Ij-b?R9<+Xay7xPOOW+49z<- z)tt|OfK=*fB`Ag?$N+;P7a}^q84}Lfx@#Sq*$iiIrrF$n=FKh8AZrl2<;gc~u~P*3 z;yF`TnAuOq@yZq1<3F#Pm<66inz2t20fkGj1A|gm@xqW_DY*}ZjdCINKi6oM=l$Jr za=v0F>N5Xj0`z=6()ANwvz8a~ByGwr+d4u+($6oOy>mt?O@(xLhh9OPi2WrtoOIvo zuzUhOb^uGlsv}4J1f`Wp@Tbgq?TfvdX|+1UZQt%J9;%M`bKFsWicRkR#L~dcZ7cY||Bx1%!p9)j6vnB_rtTA2Mj@QKSGL2E>m@cjFnav$oC z`NoWqUc$lpE@=@i0v2onPqE{h?ZR(MU=0n1B=V)Y#?9r@9b6DCF~6Mt(T=Uz9L8-l zb_pj|EQR=oEah%Zwf3>|TH+{e{(A>n@V@2y#(W8%o(=N99foDvQzB!mP_U!sxJdOz zk-zJW5Ot74n1)OR>%|9YfSPdo1TXc^BvKbCy1Zd{#%5^3s(-Fjuurwy`j*7>%f5^V z;_Rh+w^%8^MMlwpzJFWH)j^jP%XRGND*1lDD!0+k5b}qDTvuBuiLR30k%W260Wg$! zuq~Fqp^#JzKwW(TnAP-;bJs3JVtv8HMQ=#he9C|E$*-yBWyH!@ckYij)s}#CKX6jB zNSc4eXaP2x2)1mCAj>VwzY?A2U-W~(3goEY^~Dp)Ms;L)IzlV2z;6XQz5G5a z%ufsy*UuwH^1AdLF%N@55yVK=a_{p3)^hl%gGS2+f)I`zS`SV*5g(4uEYtS6)ciy} z%anxvK8s5>ijR{3om#OtQ`mQ!pcU`CPvPtu=-0F)1#0(7K|(_}83y~NpO*F6d#cl?L74JsSG1^Vv zrNL;$VKJj~E zdNg>AkujP3A-IP^qz*=9_$`^G;7H_(`()NFcImda`>p%LyfZbV-~`OVGBG3Ntxb9m zT|qFJKa&3~i3oYuPZ9>X0+>N3r}kf5FoqH<*5Olt_PoEmj=;>YCmKL7a`SK}%sq1w6P zU>6)urF5$sF&EWD|Jh8d$t%a}ybr(;{(T4z1z=WO@57IEqmH-$VQ)sYErIyU^%>A` zKJ%IOpB=TlE);ZL2L3u=(Xb}M4$=QpyXppTDdzdiEQg@uem|rB$*L=Sq@>1o`GJWE)46l!pclwjwFX}Sgs-He zB$Rl9O7G!-JZm=jq)2gt!^^-c`Z9Nl`WYmxXt9MB~hlD^8;*u!`DJ zmySI93a?B#$0lxgTBNuhd&xEfC_chxo^oTeg8!4>cj7z93d9xTMQIH3E-8GvS%0`z zBQd{PYX0jraJ6XRhae-j*B#<%|I;GgeM1i0nt&gI&lv`U6(#V4Lm<+B(1`uZ@Yg;SrO$J6YdkTQtB$1*qt1uud2XBlK( z}msD6- z7;7>IPm>U5eJ8~$esy&f+bmLp^ev>(r=mgx2xIea_SdEJHuv}k2L^tc7AAfD+G@W{ zx43_@Hxsg4(UHv(%8I4pHLp44mQX+S{>vhUDH#;j^bI_mHH&O|#&9K_34_LD>xjT+4A1rH*9h>KD<-jfOio=z| z-L+3(5SSKYSs^$4&BWIp@;Z4^-}|l*orXPnZe^9Xm3GTR?f@D|T%a6!uL82M3!ZIH zt52l{_m9`S3@bnC>{eh-+?rTP$( z$$K3y8>WGB?II8hdHY4)8r^1(vu)w%fp%!x&!0b^B=FXXKnQ;o^#QAdn3a_!cT7P{ z;Gn+%bLN)Evfe~kyz3IjS@hOcuS&?i9kFk14+x#6LCU5;D`*)J?{(smm7Q%qRP&v_ zGev5ULoRG(PH$g+)yg6M-hKbST~Q^Dmn-m+*J?YMP9EuIauz2-d?K2 z(G;1wvT`tX6uy*l*LD`Bq};DKJvmH+?y~|R8GQuyw#>lwt|wC4!0d}d19m)8BRRF@ zk<^Y3<=z|$^cGNR$=s^Rh>3q!bePv8s!SPij?qQHA>LjKm6iIEl@iP2U>pPDz$UxKJ)&o;=XFlp#hQj0$Tro*F z=*vh2n?UB`4jqW{$NW%}&LP5K>(!^4100X-yC3vGOFQpm%v?eR>%v%J54px?+qlwE z+d%v6er*LZiKD+~q2M&YfrAO66%0Oza?R$|6195VDREl)v~(m5lG1GxGSRr&_n&sd-f2hGFewO>KbM@)dK@RshPQ%cSJ8PobYo>=T=Ohk)b*2svKhntEJULwZ z)FHO}coD`(_!`33D$@8pZhW~76cPs{Z&TL+kM|#m*97|N*n$PncfnZUc;)#w^ItsM zo8XC94`gNB(vcib^ZI~`Lsf2qB6sfekJOE4lm(S_hQ8nCZ_ehWZ_c$VTB}J*dl2s6 z=;V}=n#w%qu(ZE93W}))&QtiYZhy+t;h@i}4q!`gzW~g0!=E9aI~;H@X`c+BCUWjy zgB0??^ktD58`wLHH)fk_|5*KajSn7>bdFyCT_jh2nQqO2In<$n>2u@zg+mpGxJP0W z+ea<}0s_-n8Sy={`?=d9PM`w({Z9oEwoLJ)G=chZ)U!AQ%Nvh~jGQX!Rj$2HCWgn6 z9`}uWxlNN8;qMw4cqhxuvrd{DI!X)zs<~K3bAKm4AOM`**2}+HGKousbyuf@ z9VE2V&*t&cn~2S0Fp~ESagpzitMV>!UeIUG_dIre>~*|7Bc4t!(aGB(gbUj&uW1|R z*YkuRxTjXlWpgX5Ml9e2%Rx^e)e@`~+1%V*mpI*&_{UrywdEiOM{lab?xS_{0=PL7fUbo1iXaNc%_Tk<9>f>y#)#tQ52Xa!cv$4Ie-SS z-BBMs%W{_Xue7#DA~k>C-kRi1*eAwnyZUJH70e9kYH7X0?rz72@U{XP8l4~k6%`N z`m`Q}>XU?#1u@r0j~>1AsQhPT`H;y|3A`-*N-rhQE(@fLE$A4|Z0@USYk&GHGQ&M! zGCw=Zyv2{)cH3D=9oz?@fypq1n?L^XRY5J=MhyGn;W)wiLSo;9=Uy$tG^|W1<_p~I zB8I?5hBqu`EfNR+mrcE+g#r-?fK7bqU7Prp>6)=+E~m9|8wTEA4#7Kj#6D`quQiK@ zsJkeKuzYUpdld(#1_sO+Lujokv2=!jkZ@i^=eKN!uAKY1`NLG}$H++qMf%&<&i-z?c7oLsIqe@(yvXr=ls{?4Z?<+?{DQP!2#F0CdP5+rf5;}jQDHPPSC@=!}l z9_&7YiY!J17S|g=yUxx|sE6g#V@3dxC=Qp|%;al)nh{H9mg|AqDW?Zm;|3lcs@TUt z5$;PwObq83*p$`|;{x_3W@%v`%!bumr~TRf-7M&0hsQflpUp~7m&QgOip3o>L10Kl zyzGvB9&j{O#NJmCRB0CvCr+!e#|q3h*+GYcW6y0DMDk$b^w{v<4JF<8WtJ0J-_8b`xm%TgUuzl|h#S*Vb0x_5=W2v8n{~#E^)v+0{yPtQ0RGaScZrR8#%0wN zG{oPC4hc^JVZ9N^?+-=99y*{+S>} zzX_-B2Uex%h_2m)CXqbYN681Bk9Li>IybR1LRozODTjoFAv}8cd`BGT@g$)H^+00_ z@v`W+EcU412O$tyyZN?Im^&;9oosQA!)86t4WR7m*8-KJk!n{+n22 zJ15V<#wG(NQ#e+HS~f|QJt;vcxijVIfXkoqh2TAY7)8HjZWg%{58)Gj?-(A*jYx)So>uT!gWNBy1$H~XZ&rWOM>}>D! zf{V-Mf8W4q=V;D_uRhQS{s^YMoVF7H;2Hk=gM61LumpgxUU_Lrb@%kWIk$8Z(?p4T z<+c6o^mb?EA@U$Yvfegw0|tzb@JesVxm1ldnWPWI9U8aKI9Xq-kdl2c#0(2TbUbCj zhGNG%DP=g7c>DRy-pm$dZmBHIH`ZgEG&pYGd@pYaQTVR<>P+O%!E%*zn|RuI}peN zC`w96LAQ5yBK2UPxfqvvV(GsZ7xQ_N2N?h<0RaIhz%h-Aq2brI;-_?UIqs*Yr`atn zdOlQjbTGs-{F#=(z`*|)oHrsd+D_YPCGDSU{QAG-8l#(B6wyn)F2NE1Mys7Zwuy$X z-P!V2+~;e}deq;0dTaT8C#vae&{EO2K6Pa2=K&Z-wOJ@3fbPSk z?DoyRw=dREmUd|0FUs5`8EGaudBPt)yY#zO`+j}`g;Kd_-e)T6DY}=r_~crIo;AG-}E% zGPq6_jj0EAf(gwh9)I@y~PChJRg2__&yB9c6-*;$1NgUUqa(V1#xRGR=(C2G)L z)MW-zPE0BvOPlxxPv0C}1xvtX{op?OEOa;&w{L#*v_FU#^A4pxHNW0gXuiCAr`(zB zck=YUu@G{wZ`G!=AZ$Lqk+9HGMW(;I` z9nvtP`ss`2;nF;Gqg|G9aZsLxJ^`2#H*zW)sBAf9x^>%h<`MNw%wdO)m>%TmS^MK1RRa5%qojJxj~w=KB)wW3|)k z004m#EaEVKcYuv~-{Nx5uTJ8An3X)N!56$-!jq*ZX8?<_Af~#5G?y=ty^IaHZV_~= zM$&}QcAIv4)nygKyh2HwbQ`|ozDpOy)xTLdbNBJ$yZwrx>1U5Gn8Aa2mN#F~3J|0! zG0-iM+U<8;OJ&%L?78pMR;j*=6WQK~IGuHPASI!tlXt%#Gv3_9Thz~*`Q}^lksGlv z=gunraEQKrGnAp~-)*Oboi-SxBO&6m>BI71dMk?ph361_rYCGUZ_Qd<`IOP_d%IMu ztke*lHE7m;r>~1}xe>8HIgo$=%}q^@%@sM&0b;KYEa#1Cjd*klSrWdU#I5hENCEEL zBHFd^1{ys9(qTW(-Om@Tt#wrW)b4gYH%W?|6g(-!2kW>{OfZ689d0(=93HhPtu|0; ziPw4dbSq_Og`JpbS~^Mu3Uhk9x;}34m{-5G8q}LT`=xnijN63cr|sd{hhrEj=NHGY zG~#vv0a&p_>u=(wp7{-mMiUMD_&m$JyTtev_gT0`#@$ATNc_cbe=ria_iQf*q`f7l zc&Txl-i#cP0dHSn1=82=1eSj1Ix|{pP>0 zw#lNu0DyZHRDXL^E?X-DKrR7tUUP2f_fcXNSLE;Qj&RR~#R*}PyU{ZeWp<5)`-1o# z`$6L!`|?tnv0|*l;It{BJdDvl^rPKpQk7IC_q58Jif?)(}Bxz#Al|G5<*|4d^< zz!h(Kkcvad$x2xKqS%j?IM#kB;*qY$u~2D}7;AESRJW~GNy}Yd(yQB(_^jpVo#NPYp^pmO7iw% z<~TK{4NkV8EzllwhCgyh?c+wX@8?r@eXdauMYHy|%Lo>OTI>HcqG})Bbp0UMp*S+> zT`jUz=JCyV@$=%rbso`SXXlx`-=MlMm8+=Z8QrXN7el&8E(%btG)2us=LDu1HJtl@ z`_F-otw7T7$hvoVQb(ZmX9C)1U@%84;{_h+_f0kXeGs539!d*3_7(&OAPB}^59ZJ6 z<+IuA-0g>n#MR}XVa1LI5vNL~k4l}h4l-c=!SK@YJUaiOX)Qh-Xdr|_S`dVv`b$S7 zCtlF^J`gS6W=TEUTKhv42Fru%ZsF=HmR(J-jd(sf_3LwQweQ zJLgiTYS(6~Q*9?|F_9w@K%lo&16dOC4*}8AZ#ai#Rexa3eUjX@*loLQG|EkuHn9Zr z2i}jVPr(bZ#lAF`aUP!}0G8q8o5b3S$hq_{CH|JEeJn;prlwzIIWE7m_q6@GHUf}Y z;$kmG3vhQ@-nlLxUEpOGcB3b^2RWH{NH~jS?7C8{PxNk3xCxv;X?{ZI=_JcX?Wu!% z&-89}DekHUR%YRBdgUlFa_%eP1tA1rhy=-6>K#p;D(}0JXHw#>gK?Mu;tvgF#7%Fh z7j1|#UjLiSWF^ja;|VSSm$9{9x((NE+++gojMArDUpdbn{JiF#*?+m!dS#h;J4=H7 zdXs!rfE#pUY=Tg^`n{=0j37q#EVV$cbYADQ^EkAcL!mv3y|b0{n*~W0O7bN(nYpv% z(oISXBcoK(;?_no^EYL`KVE$~6j}=|mgoRtdgQ!xt`D1P&>=vyUKNHK>v7}<6-q~4 zT;kQ9f|mC;x3IFH0R)6Lb>4tBfQE#V=|!E$tu zj~$4&)xsLq`X#dX(3m5+MjXzj3CQ6zdo4% zNf+6+DbOTYoS0xo0d8&gp0ax_esDfTKU`bz4#~~<)Z-))v*VbZ&w{S6r(33pXO2?m z*dt12hDM{>Xk)k8R#dQxDa|&V5zxeynrmBV7Iuun2%YQ)VkXgJ6!+!20at;uU$#(^ zHz9V#=X`4Y;|~jSv%&FxmqFL(MJM@76dQ`<`(uj3r6m5`P`LzKzj@lal*%cDoj&*6 z;vWWC6JX}L0ZnlLi0i%cQKkS4jym3|6L+}P>^Zzp(f2gUKP=gLOipnNnMGmZjdSO` z?o1{z+hxckESps*^5V8QROrFxJt<3JH#U#gEs5RK+=~~?2+Fz}^B$mj_r2wyag52L zp}Lxg>xIA2`&s;0*Xirq$teaw0|{fRhPGn)%sEasWdnK(6kdM7do@;;+wb0+n1m#! zyd3{^GH2(){kh=Tig*?t+q)mq+S=sDCnpYTiSKe68a#R?guE}gHA}Q0WfS3jeG0R_ zH+vX?layoDwQPSH`HHXzubYod^}Lr7JVh^Rh8NjhcddLhSMF-y<11J+7NUcanZROL zO2O0w0aEl5qbspRE=XVV4;$Ue!hcuG5z8cV`n7J~yt-SLn{`0nZ`h!&pIfIwH)G_o zvqS~bg-d70rT&funggMu2NoN^zm;jix!m50kI++67{{h1gS-v0g>*j(Zg;=lDi~Q< zh|YVRY;<>hh5`FjzZifuJ~NOmOtjJ+-926N5dwUi_|e(yaiXH3kvDI4b-cE@wbfQ@ zGc$TG_B)h8{#Q7~nz(QOx`|SOk658OKn@V*4c>UIEl0<9CucXZbT9t-_6l1C%xDPg zK>!7r#GzB}y!H0dTYPn6V`bRyp3iJJGcuAw@YkMeZhgIb&t7p+(eLqbRKUW@>Iva( zXmogVWXHip`$6=%^7hu&$Y#^mm7ic01lAX^8?K9SSI=K@brX*ZaD$$$kOtP`kdB3* zz5#0m+?XR82zfdroyQm^U^^S)vh#O|V&M|@qxIg?dZFdR#7*--%Z-Y<`nUVyva*S@ z`;y%QueA|7w)KhZ$$kzGgbc0pD|};m^9hnDhu0_JW&ky-idU&^fa#(B5z|Br-BLS9&kv zxEfNsKn#fqE`2y6YS`M|BA<1X{Af$!kDsR@L}w_QO9>1Wa`3u8FRXIHN-;9A2HczF z7*JXlqGiHK+SVMGK%adpQTuU%lTzH942&)`fc--wu}-bE7-Dow!w2>keY{{Hr~Kte`MjcC7dhqFYtfsk5x{oK8eldt94`~`|7{PK`ro6TgwFod^bl$(WpL3b`T2Vm&J~lyn9 zY$(V0{I=puOYpv>07qZUm`+qFc%+}F#s+83>JS}x$63T@|9twWaV`1QA3nL57(;Gi z0?1A6lu{jEwaTw~T;9r09epc)43>Y=R{@6Jp7lhr82{>D0MH1e)^*^e(V^ek#ak>c zme5?d|D(Zd+Ib}b95${Y{b-RD1z-W7nE#O$0{|;EIUIMnbw}xNID>q^U=o^noZPzw z57+n?sQQ|w`s6%tGDTwgC&wb zN1{=i!wh8WPi>#f&G}7vz62-YL9KTYZPqk;zUGyc7Wq**4e$~m_G76>Q>-8Z;tKzb z8{qySG_jbNqHO&tA&_=`;s9?6-ES`FK(q;S2hSz{ti|vCn)6>S1>j(zm)6pXou$UK zeHq|=MAQ4%cy4>Mu3@FJY>>1L@r;BEt(U(MJ>c?&`l|QhS3~-PSMwymO%?|1YMHzT z_jMg*yN)!GRoKZJu}|*D4;lG8KKo$V=wIs#_L1(Jdp`jLI7WmBS0-lJOekgY?eYQE z@vyEK)COT^iWLdW9b)H#IUH6bAw!iYq_GN-<;@2EMZ*$NNxn zlZ{`1MUX26eryVazbUznzo?A{IK4g{tmg+C4kx^O=#t#21$e9XtkV|dnT&WhqduG) zDkLf&SH2HN2Nq{j6JceqXpFGP0N5wP)e|8^-cg-${>Y>lXtcMfRFB;}!7lU=joun& zV+78ubz+z5SiCh#yAEs_ULWW{;q&_$svi(2(L@(|;%;(5vemvvfn)&g#@XKBs`gNSd?-A8#V$+n>(Ak6{njQLxa+{|c=*gybcFS)l^*)^ zbwyPnDQ7TFYl|yEOXD@sTmYwhoc-L&&Ujrb*m!%NMaZ|$YnlLO*su7ebQHSIi`2Sv zMI}Ur-%VNzxPQPsMgK*17!0wk)_MYk^9B}3hzFeC17_-v7auZ&Z?VWAwgpf)hNLYd zEsjCH{^W`SKrqJlsk~c81FA33@I&RkXeRhNXG8sFrbD9f`p}p*21_V;E};m@SjZ~L zVY#@fZ&ZQuU{oOu{gG$7BhaH@&~FUL1;sO9a#_a|_{}=6GblYH3lzyGrA-|MaglK+ z6MbFX=-xGt!$zvjli>1#JUqUl8u^Ci);gSb55tX54{okVNg}R=N9gcd4r$6thoiyH z7C^|XyauDVMGI3AWd<3u1Y%N#%CBi=l|+jDx{)5p_4C!nb^vjdr>84g_e3d}3M;|t z?Z`5VM&#Tlt3$!!eEfd1cZO$?;i|k{ySo+y7!R&d7rm0g7Fntq2)eTV#Xp&?!3XGX$ zaM=sIB_7VMZ2`m}Ow^~}lBF;5fM>;_0>gyi;Mrb5lH$<*E)5c!R)z;E7c}$Ld7egp z`?)*gdN=U9S#OF}c@D(xgssAIA_vU>^xy>IvFbz=Vg%B=TUL2X4Exwv&bHAYITlAs zW)^S(p^xufH6OZ`g@g#fm|l`@t*)x7J_|_F#RUziN=w{EGeLs}fY8F9nCOPY1#M{s zAMb_fyFD`OAk~zWj^35mgx9l_%yo!hK75SAjfeFKb3b$x0^pnvs1}7GOupx4Kqu#B z(SzrLobt`hPc%4$tsMzMzDaURPJ5ik(@!o;M}wUyr;d(;7$_WUnQCoU_sB+_lA=4-h`>}SqpV~b#bgfk~) zi-(?6QZvi8;mGQKe$N3=t}ghmfncxHov|Gouoz)EHRr9tHUj*fbWs@x+tZ*Se_At5 z(nYL-@r*-<Pe{MwQqw;LF%8~ko z>;gp=@~T+ZTKp!ATMAmx>?wN+53Oiton4#^pANCJ8*agdg^tjEKjKk3pYbKDD+r}+ z^ho*WFB@GRe8pY&p9$P` zM+&@@pb$C&%nwiq01pj(fgh5?fay(G@#5cLefnG{R~=!9qvi8R4{18Wzq<+HDN0$q z*W`aw6=3#mPWrztP6SPV^<43>{gLPH1^e~w1w1TCM3g_m^Qmbbi8?z2y+4GO{AC=& zb1&XJy5Yq?Cb*dp{^&QdO~3zc$ohAOsxe23OVw&&a>G7_YUsJ1qK}{WWl31hlGRaX z44SFwv|S40pk`6-0<;nj*zcO-OD`#327p9EjH>|Ueg}yBM;Mi1)%m)jb*Aqe+9ejrP z^Cs3}quT1t$`#^1Ckymf`E@`3ctLh#Pt8s3?o@aEP*v0|-kNH&I}2q(gCg1gWxhLq zZc5j*X?0F*qr*m}WH?~8rUc|3_XEi= zK_2jVcCp>tcRR=AEE=_|rA*W4;Qkr21TGS{eB5Cc*8u?hbK;&8p+DmKX1GA-If)LE zA!-BnA`!S24?#TPeFtBP4{ED}GA z5jCv;wN;Vt&L`Iv<0Nu@VYZVE#m-*%_U;m_AFq_xNU%4CzVo|3Pi1cOG2VSqVs&-{ zqJyMEr9oq{lVb(-LMPFqpQmUZt$-{DB<6Z|!EnN0344)iVfqu8m-5wD4M#p-7S&b7 zMh-vy2Ks-SG~fFsj_JYqy$G&;g9I>47Y%NJ<5}DixkK#7rg~^u4Dy$C5;k4R_qAi2 zc@{=ZaX*!qgibn+CPn`WhwQh}I)1>_b(;RXN+KMlC`4b9T-v=lu-%$2I5@h(Y$N*W zX1*MT zjy5@%QC6i@rK(N6!U*JhIFc(g1XBD#s`lRuV8E>7-_@sM{5j^{1KMkDa>8(l(!Ocs zU%h?Re25z(&-uDabCjKwKP3X0%X8!^KjmlQ0wClv(i&N78ZJY-ffJ^wAqQ5{7_(wg?h>Q62bW779 zeTl^D8RdUPF*TqCeGmE8VKPmQoa5n8hM}ZVIX9P4Hl%2Oh*7`EF)GvH@Se`GmhC!5 z`xV1*<>p<~wWp67jaG-itGO_4eS3TK^Ytla37`Cr%9FUQXjug+C=z>Y2W#0*Ck+53 zu5V|FhALOtst`AK>t6PLU@x;jCaxk20*Y@9S7C%Ra^2HgY>EmgNLRlWUDb;MQMz6@!A^2`U^BDsvhVwIHj{q&6 zR@X_=M_|2qr7UV}Qk_qI1>Ajew0&S=i#LOWyGjI*M>8_yrYO@bHhee zx=g9JAeyQ6EH{Fc7wT{}%IDiNQ-m%zNx~3G-2itx19sHa6XlgFJS4`s(JOMihgpc_W|00BsskCn&BqH&Sf8tye8(A z=S%d>5P9OcD6)_Jw;O$pp0HrEUc<76F2>EZW?2P{Trs6|(fP)~EaNp+h=FwF&;kS} z8e#zRaC^u0k^mDd0bk9&auMF$j&DxIowE~~4fThUtzFsHSUzXuoJb_!a2xma=oH?r z_zWSs6Jy%$jKl#D!-Hk=g%S%Lyj(?CPWTwITp_3g0B7cR{p@AcdtYxR8{)E>i;F%q z+GLIr8CBcm#F?p{oiGwyM~ca5aF>j^aP8lC7|POkzP;BWP@al{9F$$FB`r{54gAo} z+HK8TYZo<4ojM5a*Z{E7e>~17dq;k2RJD(wOy|hb$rzoen6kbcNZFo8}MSwL!NXT9N! zLM~YO7k{1d|F|c1uV#m4$;$bG7MA{4Mgw-5Chp(T@JSQneKo15bGaKEM6{QG@`H7DlEIpux`J0 zQq^9R1Z#cJeJ`a9XAduBfz|H1Odr6Bofz;fv7YfWQ%L2Y`GAL1^P;Yqd6K3cea?N0M2-89>qGgCWaMPvxrq_}jcf zhgnr&^va-Y(_z=S*{-S?)5B$0!!y6Tk<|`je-kIH7_ciy77#=MNU9*GnB#hgwgGR& zIDxmV>3P+c(xv#6H@yRe)=vW!$Jvzl8_sy4DTGym4tpShzZD$~04)wf>c9xLL4GDg zbo80>9@)FNVr|G+LYOyzY&-X*RAbF2Rc3F?!MujCRgk;;vBcGontXJvU9|58`i^J8 zZKZ2-Ed`ek0g7)1FhFpnR-k7kVtI>T{Vi+rz&N|RdA#VW*Ug8jjsx?s{GY>k@+e_H zIbG(RTDoUHQumMG3d4)X?BhB*cpD$%w-^Y0gd*!) zdo(ta*}rRWePLlG8X}CpzwGG&DDd2#f=;26Ks3SaDwANof za4M_bjV*QlIK`uZj%;Aux;++`5nvzT1k!b5qvMUKhq1Q9RFkr9LmH%4P2f*eS?3pK zqVC~j@qH)b&-nQh1lwuizeR!|??KanIJ;gm85$be_mYy1wPgLM4^6H(4THiP>Cm)6 zfz^eH*88)kb;ADxS2U2Ehj0FQc@Qo{wf+KHFNOJN-4Ru{PZ}V@kj3YnDlrG#J;J>Y z?*md3w{N6r;C#=Sl%=KW@DScGmDiw-MepvRSgDj|Eor*1_t=t_0=FN{so;&-*@0XR zX7pv2|GaRF-%^$jtQ+rK(d<=Q?2TqnNv?NK=9<37H{dZe=Cm&O}+aws}Tg%filCPNU}~A8lFd{fk<=g($%VZz2s1 z4Xt|nr@oi%G|N#U`$(~iS!msiXq$pm@-2$G4zWI9QOjz;0~JtSAyr{J7TNGRBpOLYGY;O(bkzT zLJXO5d2$htW7In{R`VCZapXAW4s5hf(mY1dpKb0Z(H!RGNez36UaiKnaB+3dHaIzK zWVjg_7{Ko)K|+ehZeCPfLuO-}Q@@2$OiXOD)<(yZgqk@PQWD7rWvN9BI>J=a4NJze zgTMTlvKAQ2Tp%E&99pT2+rFJrK_!USP3Qp8_CequcZ%~EZA&<}pib8XYf{%w;yozY z_ylJO0K4h<{*$hI)Nn#_q@tH-TrICSBT=aI;hvozMM0MDi}j&M0oA*{cP#;!L`>PW zwIpeRc3o6%v;LsdE?sS8p#%KSpW|TO1K;fg!8cy|zO6LAt@=Jq1qHG@b{nXmjA5_O zB+$JM@drB_vlcOPeS2x&Dth8PwOhnv`{t;}LHPFuUMeSGy%SGELA~)C_-z^8LY2fY z87sU|DgDqVzcw}2(i7jQgUq5PoM~kgeGq)q^q$4y@MVt*ISudwPA=-2i#Odrgm* z-QSLPuVx-YJZTer%I+yZ%wh4WwIYOL5u*;l!I4{scvt#9Fj>zN)2{VSV0-(Og!E67 zUP1sl{}U7`{`vFA!q%4Bk>coFZUc7Ee4^y+=2rX=MJXJ&UB}IIcB}7TJNvGh6ExK& zx?6GF<1eZj28Rlj!8$$=!TSrg&mclp5;5QCY`7N_ExacMMJhUgy&Ty4>f%x`C72Go z=5&+K#R>ib;bHqJse|G@m+I;Q?R_Ec;(V2pvWz!5a3PCIyuc4Dv$boal-1?)P@;>?luZrNE{9p&MF| z>G{a-s$XA4MI}3Pij9@^rL8UJ`QA+MzYC=L-aLJMedQh}X0x6bcU`n2A8_$ zZ-mf_Wj^ykWZzWr(ifkZJ%JE?zaDAH9j)`49&)5*;*^WGqzQ2M^_0}#nH9|jQ2FrP z<{hHdHmkGBIUiK6=QnmXe;197kB`{A&&3>1>(FORqQgG6GK(7a5B$!| zEohXbC<6DLu3n#XpNYll@P2VfEg7cASMw46>OL7QvUhwtrPv1w;u-U<*0(T=(CGOP zWj5iiTJ|C}IHP*%D9G2OQDdh&X7mI!RX7nfN4&kOM&a;f(3I^rwbZM1V zjMq2M#gU|c*~UmoB7b{N80P$yJ|dj@SV!MfIbj>z1LQv(Y~+5T+J5*r70gW*^?l_OovR3+mLSf|;T*+RiFV=sZteMQejX1lWVP^~frNoPc4AcU@ z_hPbWP%OpiMmO*bqaA+`{uY4NABEiN^8GA=pOmgye^Wx~&Bo##rKWktgCoc74c|?&;5K`JTH{f%h9smvXWzQQgQT14UXyniIFD{&L%W4*8#qp0nZ1JohzUi z8)qu<&@#oJm^6)^N;3QFIL9KkCm7b1JE>!frI6241bAupe{_qLDRK{@O*&;0MOh z*AJ~X+lBP=LlKGnxx(Y(fIP}0(V>!?o5*vB;=%!lN1w^{3|KXk3KFg9__zLRTKZSlDLsBL`cmGH^& zpE2gh7hHm4yoj4b15-yCy;;6`zCaMyStHp6!|yy7B&6%cqOM#zf$CzEb2R$x1&y5H zL`}v@q~s?NnHZ2U{*s{V;aEG9WA3_~SRmSlZd4hv_4hg1XZKRBUSr@pW5J7^sY?SZ z^LS9tq0M()9id1e-rD+R{s&lSelT7{SR^By_wl_;P9H=HTgU<%j!)t>$&t#5)Cpjp zT8jvcj~z1r^;qC@dVuvtN=$Rw=FCkE`&P*fVCH6ZZ^5XHZKsGO(kwr0`jbL7e~sfQ z{24f(oCh<3p#%*#jL{SbF_FL06a4^?JHA~VW4Uyf5@z$cA1Es6|GV93gX95tX(?5IT66yO%h1{HP6!(X7qCqb+;8X}IN zP-nZQQ@BU<8vmNV2M!|0#tJp(5k(`>PgN2&(JW7^S$IjH@c3zObzESBdFn4b{e-9J zaRdus2vhMg6GqMznmnYtQatLyNZ>8qE`R4SyJ`+znnS@2B9L!CScwEVXpps|Ox6W* z)=2E5xxP^+7qU_|;1J+|nCO3;m!o?X;GSyHTxRt{ZgLoC0w0IiX9SJz?KBLBQq0S8 zBF*{eSANgZ3;J`OnJp}o)e9vs>E*HV$UL<@p;RXJPl$97h#)jiD!z!u?Mciyidg9T)(gG6$H%Sd zHzqSzH(#hViW-9ulzS#=S3`qn1tD)&^J8Pe9$^x5j;w} zI4A#^P|^YX{v5!A*CU+<#~Q)T=7AWzE~5mJ_<-?rS)U_*TP$}_o{h4E(RVVJqAPx0 zGHY>Sb<#44L1z)Vanq;1wT;H&yO6oUY2wteU|*zzoa-auh9W=L8~f6{I$(&%FYFFp zr}pb2jy8P)t{(9XU8*&a>BtUS#!BXAIq8?i$+sP%KNtk}F0%GSIah`cs-Kb1_XSj7 z!4aESN=VeP*IlD|>VnB;4rpGDo{%t(u9d8AX#ws(8wD1y7}77HJqbX}9K&fRIE@bI zs9Cse24mlkW|r5m=K0#QD*_BzkWbe@^EUeXg**&CO;mF1%BG`~`rA#hx~_MfAZSDn z;b{)6F=xl3Ak`m&8qm@ygXdt$ylS%p(ekQ_T75<@Km0RDu7a@|N9}WlZxSe?e;5#GICM`7WOtcx=`GKbtbOxs!$ z!mLcm#oL&Mw3xoBlAy3-XnB$L`~I&ufLsk5AEqUbh0M;ezf)CW>7VCQf5j_>$K~>o zX^1b=>d)8EDx8;~UDQDcBzH4a(I<XkH+L==>ElF z;KKv(Kjjgybo6jEUIdUmsheqU(~Vx{^0kxL=R~&1)VA$H3>fIXN-_vvI1DmSjzOgl-p`+;fYRhWT8;*?5S4}!n*4+>osl|n zGbnbC)cBPVkdhanka811;4=G862ziBLo$jCq+gXv;A`sF6LF&Oc)(PM>(os=9ux|s z7FZYcOQ${!K^iiYmbgy_YJ{LYB;18Z7Wkic=xLBW(|xV;)P1`wF0db%z4 zvzT=wl^7tmxGH@Ed^zEHh5|PO&f1A_EQ@5P?guY~JnY{wgE}LDH18I*`4;&D%_bq{ zCMvPuzaR7{NgKs`a2&7yBnF;wQCOOBz7Ay z`n5J1!nj|DF0#!rcQm4R*5Z|MoElY4Vec)ud;^cCs_1V=-Z<$p4GUlxVF}HE3sk!{ z<^Bx|us=TyGyEh$>q>}GjEFQkFY$J!Q+CylAP)ssfS2{+Z;|tTS=9aZ0d+^R1|A$f7L_5m>xut_=6&)eG?+y>X0v-xfUq!5pY@Z=aX zy0ea_&SC>D?f>xr1@#ECBKF1j%FG<{^iv5Bn!Ol4M5tn)N-^S1Ga9@6TSXXmlfJXA z>)jK{3-nbayITSuvar^lV5YT!6aA64brNw?GgqOdV`?D9T4EYotQSyRx7{I6Goi227M|EZ<8=Wt9mqgcS1*Cj zP&?BA5aw|#)4)m1JW2qCkE-)SQ|7p`U#ZQwZwmE&WH7?27Y9kiR513=?OM7E&AwMA z3Q2wGBX5qSREx%lxV?zAdR*QE9D6W%n9ZX^WiSr|`XF&pm7u!iV+M>#&7mkc!PoEt z|LnegNe(Y?(D{30_1eDq15^J=4`dSlC|>B5qhiJ)_wj-(NP9H2E|{GIim6g!FoTxv z)uC4&nYYajGO#j+CXg9>>#;vB%fXnN2r+nHKQ3;&<#TMidn_5ZN_sd_dl|)y@>j73 zU^@0OEfO_V%w?JU9mYkbnFZ|vJ;{1I>EP32WUmv8d_V~1FyP7(A4Ime6Al`iQ2Eg3 zi9}npOtt^B3S{{A*qnIEQ3{pNU40u>+m||gW_B;I04gXQH06$z%R>Qbr&|8?@kq1a z#2P%*ZS_9E3P@QcN1El$0BneO^LM-mGmwp9MT7^X(n(E&_Q{KQ1avaQpy1){Z_5u$ z-R2VL+^%7ox$}K}RIk?iBH?}ZHuo3ExN9(c?w*7E4n-2Q(Jl$M7mz<-xXilv0|G7x zIt-!Bs$am7IU*PL4VHdoJ($f__Z}^M9#O>D+kUZ+J&CfvS*LXVJ{>ZCeI?0n{)60j zM@bBtVoi~vrv#BtObv&3D7`&m(Kh)<_^~IJfwpmj{iX@~PG0D32DmVqHNeJhS2K3W zm1`bN4v@o5XA1ebZuFhO!%dM;q~w~Sej6DnqR<-hI_~p2_0>U)6C$2;4n@HIX?HAx zyciS|t+jxB&9k4l9?|&|q(8ZiP^7NypCmwL7yjY_WLa=DZhRb|ouD_tJPNVdc4CCp zy!m|?&%ZpMoK{ssRFi`0=*U3ms5N-VKl_XPdivz5@E_o}E`fnlGz}+DzTX&e8W zBtmoVQF374I|xhm2Ze z#HGOcxgG1kdsIibu-Pv_1*D&Sfq2Fq+3F&{a2ydH2@|yu(YSu^b`q8$_ zzrFMVPwRO)40Iy>2fJkqezLO+{fU^$HX? zyZkLi_PO0Qd?(^N25^U28(_IaY49e+g|Nqfw#DgN0;u@XRy461tw9?=x4o{%wt(ge zT%9vaFe{@Xww|E7-6n*NfXW;z2)%_5sQs#Hz7uH><@!NKQ$y|?Fb2;dhi5_*16c+H zXGqHBv{sK@q}{-!);h%$7aPp}gH20Q-xzKSDLClWp*l%kC9!O*D~$&Cq-a8*_LNC* zi6K4|P%K6?zp*5wwlh<*fn}Ibkb(DimB`T2#Uk}8uR(IV6C}JWg`i~EvIPixEG@s0 zUHNOKpZqRtU|@=-m)b%o>|yvoBl;^`pj1nX)^pSHG4QHxWaZ{21jO|g{J1G4b+WuA zG_OBwwUy`~K|&4>+!*pFnunJ{2n@k^3w9fWTes&|4X-TWnm&@#)_a?EpyUKA->8pR zumIC<0`Oab93I^RSUD3sePpSyoWAfy5vEeTT`^OlR$59L{1%OpXNsh}UWKh%jwdM= z^n{9LeiDCc;lDWG5giTW{+=c6kXt@|6C0&favEG&uCh-@J@1A{^dynJLW9K_FY30+ z3Y5c;^s##Ii^o6noj(#7C9yFeOqHhNbU&U|>L=dW>@IF}_A8+~UqplWsjJ^g%JLSA+CNH%eA=yu=^DPG>=Rk0H2o!hzWn=&C ziRFH`qy!+-r!O<19VGg6;*uh~a3D&Eomi{g%@Yqvy6Tvrg_8b8aKQea8b!anF*{sKLY*we^hszB!>}1Y+ngJ%pF!og*)2ELV59n0NQL zah<2oRc`KL-xJSdw*fs&&DtVN;ti&t4qYflWHONBT_f}a)-i8b+N=6)sjwk*Wwc@j z`hPO_?^970!O$Zzm<>Eo5c{8oDR^W5- zKgQ!DQ&PS%SavjuLf|}#Jf+Kc?kd)aH0{PF8D6%2kN0xQtfGCdqIEdWGRWY@eWSqR z6UHUFdk3O-ED?_A<_Q+g1Rm4wzTZEwo=3B3y~?~<7NedVGaH>4>{k{l!?M3y(Gb$B zCUwbWz7rSIHT&{EJTSZecwkw-*@gEnFwrp4cS1SdKO=)>$Hd2{u4y8qJOeV22Hx(m zo5NdX(HF@PB?`W@sSA|=MtwYP=KWFI70cOuZzY8XK|lPQCwJJ#Pxa?53)zVPy7b(LhJMi5 zcrbEDKr{4bLAlc}XZn4pknQhDIeeia^-HUFc3x~@gLlg;IO6I|>RaS`#KlMj_J7=z@ZR%M}jx_Hu4+ zWu8ehdH*PC&08Mg(8yxg>}v0E!&?Wi17LruuKT}d=epPmhzvbx9)ZV9m;S1s`RQn_ zg%_G=OlrLBvftRiM-`0ZKZm)+?gupS^9$ff)O$q=dglD=JQ;2=c8cr8jka~-H=YX;Pi27gTU+^vkK>Q;KlK#6TZ@%OV(-TJfRKaxDhiGxh$)wQCuTr zC4zsEK(@~~GKxY(S*i7B3*tD}76WbcQ#5AF05}8C81Df44G({g12cQaTzge2SIS4% zcSjv8fOA<1?ZaXqL}F;3Fj0TTn(ZzRSMH8HDYofluZ2G=mkMf%oadB0#D_QTgck^) zy$oV_1PQIwgISGh%f_&N=hnt!H*(<5xu7w8WrY*j3eFIiLiei)Ky9OC_|RHX()rGe z0l9S0pOFU?Db$oEcz>s!?wXrCk*eQcDqHMQIqqoxplT~GbI*vpf7s&O>no2Pn#HUT ztv}8~{RPBUk8nTNRM9+l#Ca{M8m#6##>&Qi1-nt6@fi-xc#-*J7j-SI%u}yF3D$k1 z7((9u*u11acVR7sb&4DH$Gp6arzz85(9yBBx`N$dve5aYHTV@?z^%j8U9PN@n*G4 zsi@<&$PLamw<(yZ<#41`<%>MkHvKZS71;jLZf$Eu`bp{FqF0Rp3aLq)wI>kByO2j# zsNKm#g7@uj$P5dnCg~{iV$@7t*4N!Ii=L-h<~4KD50UO_bI6;bg1wu9<{$HOaNv_l zY?Cp1{!J%$5HS0SQwvl>{p%gtJ^cjwSt~hw*zpgZ(E;Q}sS`j0M%cG;zES)h`W=jI zcLFRf5x)nURE@|RThccyy0?EwFH%?A1Gv2W-^Pt+)hbkc>f^JIY}u5?90`huFV}Kh7YAZl1A83uPVh zRIrVP!lfzU$ks==707!(Iwox zb@_2;)mVW)vbQ=fHD?8uv(NEIDa&k44yEeYuG{|j^OZ%K%mz>(12KQ54d&Ib$#_WOwUQ3+KeNT-`?NJ-nHib#F_4yvt=z++c|LHhN?fY! z{QSMSlIBztC9WV%M?MO%1;rwr3gOFuZ8M6G>Z=mpVVLCWA8x+oYmllLcTd2+F2D?H znJr23SP>#Xs^2=mF`nlt@S|2+scf)=M%HBzW}c(1wS>NJg7bng81 z!7I8wemxkE%{_MHMXJNl%@_(nBM6>y@;&OX)Q&GRj?hB zkqo9Cd2|m*5+P+7yI6u>s2!Qx&9D}l3_YnYgk=up5_qa(L)EKSY3W&`yx1(w{-GxC zd1u4@nL(+SD+NAZdW=lb$l%TQ+1`A zqnn9N0{Odv+kYqI_0EqESGUuun#0_bZpF{JL~@gTROfy^(~7ipS+paMIR>?9r8}e4 zZer4xv7Q$#bvEKFZdga8eS;o=2JuRKcU<`vrn+QGgz644I24zvA-UR z9e54XU4VqQ)E!UV_KPq{FB5-k%V~^<(Ry{tMV;h4$wJTohgJ_mSS0eSJ8N0SIgEzFNj&-q z1ul5%IOyUiE~`Q6ul7-+fdLuV8xmo>WmYqK-3}_0NQev$dU~GLVBKxp=0cSH=;e|j z?B~U2Z!)csgOc}D6_F^CCJmgdn;Y>wKP|`=s@Ef;f5^-jOJFw^psJjIu9R*OnI_s) z;f{^X+~vFWWv(c_n$LP!O+k~zx-*hZF;X9gA_=u!of7}y-o<~U&{<=DMBS?U{O-Aj z8@TA^>Nj|Oz2^G$$&&fv3r93&7UF)y8JY>S(kqq8EQp{m_Fuv`P9KcyIfU!pu6*x# z&6RYG{m(<->+q2ge960;MA)sBFEZ$SAPq)Pa(spnA#fCUqy-x=h;8$R}|2yD&$g^flSW# zfM;&9l^ffEcYiXK^T4n2Zt~!4vTlCmy-3tpz94O? zzD)q8$G5CMQb|Tx;_;oF7Zk@H`gpJNmlwA-C28p%zH3dGk&;701bgpT zz4sf>&Xy&2UEfz`F(vuj**Qe=h1Az}amvx8+}7W>uWFXCe8xemjBhS!-RStv^-LT) zer|K@F!V6c9%Zma6cZuSzhlZ5tS*wV>#8hQeFMEYxORU{jr2cyp5y9z-9oKB$LW4Z zm+5FR2`0ISn+G)W!a~SBHN2v`IYg!+EK_CqDhT=~btnj&fRxj< z6wU0PbT>kV1}@pr$>`2=F<5lGS>3?x&RrJf!~Sq70wq{YnkI6=78?@OX<%9X)Q~^< zyM?Sx(Mo@-OmQ!J{FygY@^L1)wagQ(4}XLGhs+0_5LP~6PE-9Pl3TAEchn-B5xC{$ zH6m9VVyqJ1e|3`o2HJmgZrMcdUDAo1kYy~7>Bgw_iM%J2W}U08k!N_n)E{%lQ@*_l zII#5HZQH^?UoTHP)Ke}RR$S4}=<@IRvpuiN5cHmVMTX0(M)8qXdZRjzHjew&m`)B9 zErW+yWDKt793KfvVsoAib`tRA?-M1=^&xyeh`JR#y*CN%&8`==g@otqViB>Q2#p+J z1EtsWbF0thwsv+hf8P^AUBhs`E0-E_V{qd&?xWRZG_8*q)sE}M>B77yeQH z=x+Z&^^7~UX%CdP#ui<)UAkKIq$AR%sng3d&SAYAZRBh?I-gQQ_DdZza}+j~c91>) z+4iXBA5v^rW}g({il5hUw%_XRCbuK5~3Fhv6Ek*g|Pv-btN%qe9kltLyLW0FaxfTRa1r4@hc+7MkB8B@j z9BVk*3cE2yrB0-Wp8(7gN zjiWWG0*l7ea%jNHq?FHp>{ptcszA%Cn`lM991}Fm(p4-~iFcxHeA%|UCS!Hh6IwW; z*O~8<^R(Elk;l~HQ5Ej;&fl|Jr3>BxCflfMu;9LajLshd*{j7P;FKQe&k}WLr&zJa zaW>>dlniwNrbw8u9~elNm;9(iKmh2ua^CQHfK+JD6&)XU`&S)>Uq)#m8$-iE~LCZ%=#(3W3s$eO`T^8U&C~00? zhZY5<8mrnRsV2dH+n-Y|ZJR=BuUO6|L@xO3s^Z;Wlr`9&aP-1&s2rF+{tzNyg zO@G%CD#y_7P=CSB|NgF;a7qQ*C;47fsbR%k;_XoPHeA~Ly3KYg3Ht4~2Vbu|MEVi+ z9G*wqTi>B|;h8l%!~70^Xy(=l1gN4CLDEAm9Ul7aSkw}gJ>-bkiu;cF)c%`q`UJ`h zTrqD;YSW|i`;a2(21Gp>#bCogi!FWf-I#O1=^iH|%WB2*uwhrI#LjKoVqf`FP%@wB zbUvDA@;Bunk}ZI^4%uDIu}mPTAPsg}`W~2&L6UtTQZw7~P~USd-=sTHwhIzYgtUAw zHT?Bk8CHgs@WDnz-K+R>L&#%1p2!QT#-;But(v${9@AYzflz{xYW$aqDg%&0KVH{O z%>H_=d*v*g5tRnbw=z~PC^bG{fR6odzgu*3{EoeOr70+epShIJ86Gn=j`P~nZx;VC zW&-R+vU`$!$cOy)xd5x#kdHW$X_R#R0*z|_4IdKjq7$Ms?e@(+ic~Y`vv(kw>;-p& zL*KBBiNV_svCt1#x%6W?c_wGuKgAk+0Y$dkVZ0yg8$hV0Z$%Q=68F!}qF$!JPH&S*i%-k41ablSyeoJ=EAN7Ld(Z@?$9LH5~ z((4tL9BifwV4CgLu-r=rg@kx41xHKy?(N<-!J+647R_!9N zrR~q?UWR?VHXr(Iy6=!7EuL8;{2TI10g7>7cqVrxrB2tU%#g;{E_p&Gg9_(k8seU# z%k50f1<>v6tZKot6sW@2WuOL8$~A07*ggMc9P={0mxU*zSXbnv4=juuE3uQsYsRymOf*CUxS)$;8joTa zoq&8UcaOK5C44&-MZ{@v3|Dw5KVT$QX&48)|_Bh`%K=$MU?j9a&`8$1$Izc1+~Gqu7*Mjr*Y^?c0cC;}OJ3ludDR zIX781Ss4ZYE_x~8sedax`m<|=G~#~ldHOD*^vc_pp3#50AbHbbiAVLRh4xmmknxj> zyThJGiY-m($TiPhYL6|@D1gr9d(T1&nn3$^$-TXcuB>)lNQiaCUoWOg(GN{MlsWj_ zm7tM6Jeakuk*5*U5Ey!juKw95+IZN?Uqm2dyBC*bMk1OLfJ(!yj1geew?`e_H7oll z5{61khY{_JzltxhwA;*t*n`3zbDac&diGOM+naIaV&Ci&IN={WBuo~N6^LrV3JiKt zA1~0fAer-+ZIQZ&WadtD&oFPrbFL{tuDk0R4^gUfzhYwN^F!U*c*l$@uwPdZA;6xn zDM(hh+>+xzSCz*RHrUY7ywSvMky`o~Z(QJ_W<}}Gc$F4~=B_L%7xc3xT@$!4${GQ( zL}(_SjU^GnBVFqBtArTfy9ckmymN2n^T<5%n3mP7eH8k>*o!P=ToP0+u6)kTXZ%3xx$me<6Co| zoP2T<1_d2Zd-z`;57bA~O5f!}N)dk&gGT%qqO|xWrKYQZ{~i!A_yXdY#0aPG-(?j+ z><=BZjpdS}QH?7T?QX}kjYcXURz%ysu%`HkP4v3ONMittU|4U#ySrK2=Ex(I`PCP( zw9*^1;$@L5wC$$1A=Z3WJF0tvBzbx7&n0;wh|W91oV}hmLdI2&B4Y&|)I}mkEeRP3 z$~fpc$tpfmYb{d5)XFX0>`BQB!wPPt3TV8CU$P?2dh@#y@@whi~s=Y ze<@^I^bM`F#GFV-EAlqN?;65Sf|fAo_$Sus?SuXrL4$&*Z|~TAQ(hFDhHJF_xW~ zdqNA9n3KnJ)1#@E6ElWO018dy4LWqk- z(SAmf-@@Iny1Ug-Axgcncty#yjlu34wRA|MODY2{b49|9#pI9oFUFvjHOtXKE(h^K z=S}M1`p_TfOr0so0z@-f)A zu@oaUJ7vnbX&Y}?Ap#>A=bY7)iodBFMSm0465IN4zj1*W`C)mLG|8L(jnp$jbpbS8 z3W`$aZSusU>!2soXpb#9G#Fa(v~3=l@0ayDKABe@-S`x#SLHn=a(93;08x)Dt>Pnp zjV)_S8`;esGxvpFi(ITOa2fV z40JtM{UR~p3#Oj4HS}#4 z$>&xr&BzGE1DvAZv^l*(ZH3xE<>knNl*a#sZ|#6e6B9@*(k#U=ZX?u_+=w$vf2A5_kv(?J&uH#E857Y5M z$h~_kN*|ApBBF0g8Ti8!JIWluu)S32VN4v<-oxzfUM@wcII2y8k<2P`!ZeUUz0a{* zmL|lLKCJmAh!L7em0L8E)Iy_ke}5*-sf{ZKK^VQ)ZyS1V{HQ!TJ<>2R$U8_3nf+Bs zAft_P@eUK^Niqsy7^D{Bq&Pu!WPemoBAPU9A7-;hS=X}^5}tYWQe?)N(H7sY1kP#* zDh;6V=HvlpCBoaj&@ENh(+i{(u$siEE{=?j_J`#g)lmQV@dG1-2i-~3viq%pd;{z6 z&TbC})5!&)v#B@tELp@w|Mg*cb5=vn$2+3j6Orb~&=SZQ0U}YqTR~>SNo;vh*jCKo z3yv&RQA(Izrsdq+=4%?`0B9v+MX{@Vt@k-vUpqTp!)O;4xv%I0e+b%&=_SsOsIqz& zWNd7>5)%{Uj;k@0JU`c(k3h+*Si7yvg8e~{iVu!e8n4hcyB_Z4M|gZ?Jf{5o8P(wu zGXaqiGtOyUOiE9<F!%M$*(?*^I$VbDoV+Dr`i#M%51q;%`@ zO~2Dh1Bj!UqH3@;iX*eOmceUp6&KOg(aC)O{$Y#VopdrWF)=yun*_+y-_JOzYij!a zzR(}CYrI6$`TbRicxIdcsJ3L^V%Jq^DpqAfu7N8?G*K98 zX3{g}G_^{+;>ktjU$Ou@(ddFvp$DY|qO{d|ap%&z`j{8%_hob|Oc9HY8H zw*e1LY_v&z1M>*2{HBaWbO?22uY0PXwwyi6Z?ly{WFafcu}6^uh1l1u2q(MtDDI!` zHIVv$d)|?BbEZd`_s8}^FJ?0_>&}qfKbkm`WcAvcjZ!oJ)1Dx5cD&`Z@q=b2SfI1f z!FP)uBqfbB^>VGY2F%}u{CQ}t#v6s4tRq@e%c1Yr}AH@fI z<4Qr>j5&m&9n;~n@D1td>G@=PD9(^C|78bc!iXQ0;a)RVxO#s7&YftYV%+2cC&!cL zMb+c&$S)Dv1XR}dN8|WKUA!i2&V=!rm;aFCYqntU-y?@u2-sY(adULYGTXJuCJnAk zE(JWli0GrWW{@Hi36SCzu(Gtb2b`8t^_@Bpy@M852OdaaUL)7I(Fd*Et61doXYnTj zzycv8)6qS79?otOW{oHkuEvvVw_2ep7?<#nd$}z-0&iuaFFG;aG@_Me9Oc88w9uEn z9m?=whv@MI1mtvVE>EmzCj|ysbq0>O0-1!SkLpR;HI|`XJGM$d+MRB{xC)dKZ`E7=QTsJl-Ahvc#h7c$Kuk$oD|6a={DV znhgOy0v2RtnL@up<)L|TZDVu&`ulz_?isTrdU=PlKFc!9jpH#5h>Tg)aD1tR z#KSCx`W}xo<#QLatJFkC9#1E0b&SrdwW2g~2vYZ@1LDPX` zTNCQKMov-}0h3B!8lVQkFI9IKOy%3D`7}OmimR5<3_UMDeI;3O+vbv%(f1XT4DA5e z$P1lO?H+Wm8MX~@x&qMm__3K4XHUHa#Z8&`2zZC_G9!7`P@Zwbu_&?;fXe2qD@f!ZNvupR}>o9F(tNb9y2JC0OyCY#Hx$ zKAwBwL4^19@BLN(%*kN*lq}BC`1{i5WtpF=2_P#C_~&OTn2ViPMBj;{gc7X(#$yBve|-R{!bO@SrGAGzr!3^PlaW> zk#JgR_#_Bl|8?>WGF;{uT+wB=Cw%a;%XIc6*^aO0Nn3famW3M^CR0glEDRN|L!ALD zJwSi>R_tY!G>qo4%=Qf7D;9z`J9fCe-MmjDO)0*3cvDpb0P=r?nh&W=IsSZk1#*&m z*S4^b-5+}A#zyA-SzE81JAfsgIOOZ?N%JBgVOzEeZY)?IY4D13i%G$ZP}dTXP<40U zu*;oCWS?bH3NVeu2m3jsG!20fprU2S$7i*c0l2*DtfXpVH zRn7O>0wePA-@z3E|2%@X?O5y4HZ1`t7;j(Beh%4tKTSaQ_jf4PjJ}w;R+WSukh~K2 zv_e9fb)199P^PK8uQ8+0qX<&4{jZ&G#YuG3fi~MV^69E2;YAjnEFKKEA2Mi1Z?*~o ze!|L|uZhx9Wtp=wY5Q>zbc%`vK03o>vJ#s2mwWEmB;G(TQuF1Zi7}V|WlpHOP1f#I zOiX0skWGQCDlsFU9wG`^fu&T>_hslW!ecbS`~s#ZC03*T+@u7(M{O_lKr2O6IdjKdDP5Hik?UIzjEy) zW8KLjcPclaJX%PXB9oJ;Dz_jH*nq|T3Sg^TL`PPLf@hnPXkYN}&g^$)4i`cdbp1eZ zcfIOB$i{$Pqg)HSk=2B0`f^ia)g^cLC_dCF-Zhr43la_y%fdwjNYJo%oa>Fx*Pf_4kBI^t3 zon}(MN4On`<2=V5omekNSdEb!5TzBMn423D&ZpkyVeMBkg-CRmxaTLx*C3$(=f*-I zT1=MpUdJ9W(wJ0SstzbI601NH?$eo{hndUTZ;T#q>o;(^-s}(|`KOQi>ymq#7hgbK zK1V06@)&9F37KBzwgm7pmK4e^nzMiS>@5mXLcD*4vYB-PI z>PjR+JeJp>R~>$4Tp{F&9nOs&mWfsH`eA(V^`mkQqQ1RhNzdT|9OlahtFurQ41#bt znuMnPY>chYu7fME*=(z%Pb=X)mw?T(%%^z?9USMF{7zg zLTXybnAK z{GEjzCYmm~&E48+a|`M_mMBk*1;issZ`lg62o#YlYZ)CkBMbIlXTBr(1-GfObcwS+ zTSQkQ>^Gy0i!(MFV)cO*i>bY|?uksfw=_6AeUN1QQk0Bx72Ai4Km0tr{#w?Jb6sR3 zf$L$sk-?+w$bgdA51sv25Xw4S&q}}V_q{dtT4#9gh{Qw2vvVYD}AH0 ztG)=4I{FH_*tes1zGvlpLGPl{;%}Qkp)vbQbm)(OyF0KnDy6KYpWSc-c?Fs1vhSas zrjpP~Yk0?ZA-@Fo-`ex{E8?J!^bZl_LffXR-UV`U+O9lHU`6cM3k$|p&QpT z_%zui>XPWuXlbNU=NyuAe{QLSorUFwvFvkvcY2Vp@5><02Q8&Gb6DaqRzc(v@gtry zOuKb8dhf7qeDfv^CT#_Pp1`c|rAwD8A(7V5)eV@QHpjsF{w^&k z&pb5?HZSY-Vu4)PCBe9rh?!hNI7yGkF!H18mskq=a0`4W`4{K=eJLj?S2%t00xjt{sEl<2W^U(78 zZbs1cud*~og3Ha&s^|6HAjBwtR4$kNM39EFlQoU|_aT+`K$)Cw#ufj+l?sx|*VxA2 zI?plQ%i!qMH9xvdHNV*w62O_%0TKBKE}BQe7Ryc!(iMh|=h*n*>F|p1dLvq!g{n9dFUGE9TStnjl~^~>Y}IH_+$YV42CkIl~bnc@-opoG7)b$M}FN2>T!F4 zN~^LoLO$gD-+{ds>#|&CJ&*YmcR2?*eHnR}KYOXnkLSAx!OgN}!PZ2RRUtVYEs_H?)!=>5eW z*1vnl_{pGx*1WpCHFF;_y-+nvKRicP*Wr-$vr^r?d+JX{jOUa#V28CYzm>*(AR&vG1ELVI&ms| zx+QgXp*LIQTb5$fdfl22X<1oWcxv&edY|e~>)e|{#rf$suq%~8c!1dj&>s#eDfdQOO zJMWF5CLi)`#e(D9^yQJjXURlJ2P?o_T{^)R?{+`zey}<4f`PAu%`$LJ3Mh%beVl1{@+)KZ! zGBOXCJyDE3oCr`u7&uJi+g~*h6ModZT1;1sM@|&>n^4_*tONf#c?4T9_k+aS+!oSW zbA+(#%X#0gNDF-U3>=TX(gd4Y&$P_=!pWKr!p(3^%|s6O!0DumLe!}}YOyZpj@N~Y z)Rq;ajy?MzvXtY0OTN~Knf=yZ*CKL3@(8Mch;$?D=Net3%}@B4%h9w*;yKtg#Y97q z^+!3$r(JHM;cJ~Op5U>m6wY}_D4P{6{}n7Lpp_5YUWlQB67{qYL_|<2;f(R&`Igd; z-b142LjzhUV22gb9i0%{ZTZz*%4IPLzHaAT5)}9@Ktjd#R_tp;MDI~e(wySu-m8Q? z|MqZyE%ufg878J>g@vWkoz`)75E>{Nj{ol`b0t4P2UJoDD}9Rl`O^we^8v(}jR6gu z6Al|$ng|^Zx=o~N6RQ&?Ob>SudTMwXdeD#l?oQoYTcO_-_KG2z+`eiB7OV!>q#Wjq|a!*WE6V{HBG* zNDy3o&MR5usT>c0GA9=)F`-Ahh%h?i8$KR^I4GoTvVw72S zWc9Cy2sY}t2PLVqo5bWx4Fyua|BHX?#X!6j6$48>YF)8QH7IL#4IeziT8~NYE-Vz2B?sI z&jii=Zy4n|H19jjoZjdXlb+Y#xC0$hVgFn2#gFH1wtb z2fOj*=28n}Ac=*6rC*S6zM5<@He;H@aptNEM>4eb!lM zvEi==b+{oY4f3lL;2GBxUV=S~?F@{`gdOk0oDd{OU@KGjy9E~l&G@(r((P|i%qS#V z=MOd#$~Aw62(PlTlvF45I}7~HZ>Gq@S=GUkE=+0;Xm7LG#%f{s7-Q8%JpOXs|0{xo z1r6fE@)d3Xm9rw3b@CAw_MajxETW#9xcb_y%ELgtc5Bc zV(R=l8Ff5sYAuMkf{!XoNlD;CV@i+YzdQbpY57bBVQw>0Ccjb0{;WF3RYHl%nXd_V zC367w4za50ty_xmv?f#M5Xa4Z^J^b?n;;nqU~S-?__l=2!ovM|*fw4}0v{Rb?Fl;b zes&ZdcGfkq_l<^#^w|WUPLam_8@z_etPk~%JIIiO+rFdLIe8AeiRv#lYMrmJl+*@3 zbVm05NlDXPq!}rSPJYj|I1R(HfcbWFb{BtSwt^#W{{7SRXrQuZi9OL5mGtWo=>xyP z=G0XDqz)^HK?7P$b5yQlBi@xJ_N&J~v=+gk$muZJ8EFhr^Zvwm2@CC`1R!@F78kIY zy9$RVcn6Y!ajbZ|`qc*b^+?|wUnQ|HbrQgH_VnmiyIutE%^W7!~cnxcujLHh| z*S808Q9X;NbSYm0!-km^qx^kShnmBB$%fiX?RW0D%sBXi-`#9`Ib7s^y4>m6>j@HP3X5ubL!{uv_aBvGfo?f$tmJEG2uR4wIh#0 zz{Tof73*8bsle%4X{5tim2uO(c<}u$3G3E>udK+uTfH&5q^dD-I?c7yVu4$<08<`b zGCElx6N@p2LDTR?!@y*}y7`{0CAX!S zvh%FtB3N+!f9yPX`#2GW=Ze-lkz0&CRIAp1hdN7x#K+C|; zde@ws;6ICU$d&$&&gFDKN%7}%nwFWJoy7!r`+qaT3#}dt-#QG*>&IKFbI2&>R+*&b|bIy3aZb;ySH?7{J;=3e?l_zYLxb5%hti6855quec=1U zEU^Ht8Ap5AP0y6(!m5G-5(x4ja?UoGcMRJDl~4UaH!Ge%!Hw-+HD&t>1JC1)=J$4^ z<%%Gf`dQo1@S4!go1|VxtE=|8A3rKpLoWC}-=IS243uFx=KlOq0=?S8{?S@!t44mC z3imziO;rN1*f@+0TI-y%BKWn@I$b*2TZ^kTE_4MWHAT$dV!E-dQ;rIS^@oo&mzI~7 zqUzx?$_)n{4q1>3D#Q2J`?{CVj(JzV?Mx=cr{ivM+owls%FrZ?@!beAQE;y@I$Sb2 zd;BqV9$KMU%}joVBb82>uJF|tAQTVM*3;t}2XD7*{TyK2W@)L4%2q?GG%F(`<1&-L zH!)HM5oT2QZ|^OY+~Q)56B+^>SEG4o&as>{`yKmlLr|@ZWJ#SJbY-40+)WP`e7b75 z@PhDqxUlUIa~-gwG@m^?2%o5749k=m<~`fw?eT-pq72S)`K6{`Uc6cpNLZ8V zc9Yy4vgpB#vclB946<4(o5NR^CnIw*bRUnudK@8<>1| zB^_X4^$gbUmXQx`jIa6XBnnt}hVS_-D4Rsa@|wKs6SFXagyb6@+G2d(vFY$sOE1R} zI)lpK!IybhKJ5GME130NO>t_X%{H6|UbE3c;*)|1KnDa~z>*gDq=kc~7q-2)A-SV# z{mH|)5*8*^t9^yCii*nO5#zI2^4y{#bswU?8zM@sDaEjHteRmr%B*Sy%pa+_r+k$< z+mceAf9F;3->qP9m2(RUI-{4oVPU=h+$CuMx}O!Q1V~3oXR&?Gp4jJe6=)$C^dew4 z8#;c$T|9yo{PoI7tWVIGM=%S2GTEh5L#iIy<{0)f=yNU}!HZ(FnA1Oh)&d>+LCOkp z6Bm(8AJrR6!SW?b3=2mT6wg!fJy`HMCO%ZwsXpZk165WXbpJTt zuwhZucexf^K(5zqYid7uFpcS;2JzN^SQ49Y0UVp*<1x53KMVx&`BXpSsOFl1rLlUSTNr=8W9Z}hkNcWG zGL3b^Y6LF2hOu!dpe?Avq)tV$;@z9%J_%^?BYn~a2J~O2*26h&B4DYBp=bgtE*lSQ zFLk5_`uYTySAI0h)r9QtJIWmJM0B z!SoKbPVGm6)AI)jUEX+@omSY6u2X#L-WaGtXX{&gdEK(FoWlDA1oQ7-7OixxeSIZ; zPq$KMs^;H)`^nn?pF#v1IQ|FW%<4;Sq1!hv2>?n^)?F_xOLGKx@s- z7l`s6u+3viK*7&a<&MP*s~4|&)ENiU-z34fF{Yj!FlpuYuI|SZ{J9zY#Yx%Y%T<6&9(2a(>rzu z4PGqIo+8@YI{v*^pL2Sq$dU5u^wjrw*;?uw>@yv%yu35~*dLy6ZaQO7A+Ucx^ZV!3 zndg6!jKRk^@Jb4g*vTCx!u$q6(c;q51!HS*xtgxAv9VW@_=r_!a>BM4Y#v4!Sdz!& zb9{_70S5^Tbg~M8;Lb+GD9^_*W&jQmc`@`lNeR5hV5B0$>)k^%SW~QES7a*^aWtwZRV*M zdjS%-+y$64Z;(&46e! zn{w>r-|o!yqmyi7XjUP8=+TuXFfm;RS%%!TAQ=`9*eigV+hZnW4eV-6f$>f083wk* zXVF9y9Uc9lBJd<}TKI}jN3kSFf?Ly-VVI>SI`{9hmHi71z$&-#Z13#E?{4`EO{1LO zQe6tHFHHFY6j;p@-3nlXp}%RbeKroOfs>OHQ&ieG=<@q5xWv$jDKNqM8}woS+-Zr? z`u)$#^k;aX4pdi%KU?RNb{4;rFO6;YY1%sBcnn*D2xv$+fh+EeywqWL(Vk6HYK}*8 z5c&tv(s6I<=_{2a;oPvN#j+<*y1fJ&KYSGb&rUOP@EVOX8}Xhg*_N(UO63^xK3iDx zm3-qm{gHZ~8dq3O3K)P=|7gR>XoDi=!16o-B+S1P9-tckPIxt`lhWB8PqjzbGp=Iq zkJcJYMv5)`T|v>H*JC*E>leG6QfDmfDR9+kAUN+ylW5 zO9~X0dfpJzztJ`dbxVaV2&v?Lnk#s&{x~_|sP2Tqoq}398E6~#8zj7o3omD?ti!iQRbVp`1At5@IH zVQ0?GaCSo!%(^oCS$?F*?B#Y@p^r+Uq)+wXLB^dM@8%0&5B62SoztE0%UBvKc^IUv zp>f#=2;O%Y*Pz;&efX>%;>aGD?bq#wOJv0yC(%&B=2e7pVWg_miK|xrmIr*W-2gk& zV8eMh4meLh6e6bFc9;coOHVk=*a`=^ea?<12HjGI-=fmqV8SFDkhO>$U5Qnd*wJ2q z%|Khq9VUb_oH@JUqYfjbiedoJVTI8JoRR7wtVrjtgWkKt*6$a3b1?B7oaLe0n?HF; z5B42R_8`KH1?>*bs&RXp&DqwT3u@vKJz^a9;+at*Qzk5X&tQ0!FRaH$6;$?JstdJhr5VrG4wnk!SZ($j_Fm$XDq+GIOcWFo7pII7#m+M2i~rTd z-rcNmV@dpI8HC1@vGGa1W9H3S9m5#||G(H5YO2_K@!bU{EkK^vLKBA*p*61eJz~PXIq1dfdpoV?Zc?7 z_(K~=URc^Z!6f+qoQc5S%20np!XXW9G5?pblIs!u%R5pytest tests --mpl-generate-path=tests/mpl-baseline +# >pytest --mpl-generate-path=fastf1/tests/mpl-baseline @pytest.mark.f1telapi @@ -61,14 +61,17 @@ def test_doc_example_delta_time(): fig, ax = plt.subplots() ax.plot(lec.telemetry['Distance'], lec.telemetry['Speed'], - color=fastf1.plotting.team_color(lec['Team'])) + color=fastf1.plotting.get_team_color(lec['Team'], + session=session)) ax.plot(ham.telemetry['Distance'], ham.telemetry['Speed'], - color=fastf1.plotting.team_color(ham['Team'])) + color=fastf1.plotting.get_team_color(ham['Team'], + session=session)) twin = ax.twinx() delta_time, ham_car_data, lec_car_data = fastf1.utils.delta_time(ham, lec) ham_car_data = ham_car_data.add_distance() twin.plot(ham_car_data['Distance'], delta_time, '--', - color=fastf1.plotting.team_color(lec['Team'])) + color=fastf1.plotting.get_team_color(lec['Team'], + session=session)) return fig diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 84b8a01e0..6c602d258 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -1,32 +1,398 @@ +import matplotlib.pyplot as plt import pytest -from fastf1.plotting import ( - DRIVER_COLORS, - DRIVER_TRANSLATE, - TEAM_COLORS, - TEAM_TRANSLATE +import fastf1 +import fastf1.plotting +from fastf1.plotting._constants import season2023 +from fastf1.plotting._constants.base import Compounds + + +OFFICIAL_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.Official +OFFICIAL_RB_COLOR = season2023.Teams['red bull'].TeamColor.Official +DEFAULT_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.Default +DEFAULT_RB_COLOR = season2023.Teams['red bull'].TeamColor.Default + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('VER', 'max verstappen'), # test abbreviation + ('HAM', 'lewis hamilton'), + ('max verstappen', 'max verstappen'), # exact name match + ('lewis hamilton', 'lewis hamilton'), + ('verstappen', 'max verstappen'), # exact partial name match + ('hamilton', 'lewis hamilton'), + ('verstaapen', 'max verstappen'), # test fuzzy (typos) + ('hamiltime', 'lewis hamilton'), + ) +) +def test_internal_get_driver(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + driver = fastf1.plotting._interface._get_driver(identifier, session) + assert driver.normalized_value == expected + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('red bull', 'red bull'), # exact name match + ('mercedes', 'mercedes'), + ('bull', 'red bull'), # exact partial name match + ('haas', 'haas'), + ('Red Bull Racing', 'red bull'), # exact match with full name + ('Haas F1 Team', 'haas'), + ('merciless', 'mercedes'), # test fuzzy (typos) + ('alfadauri', 'alphatauri'), + ) ) +def test_internal_get_team(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + team = fastf1.plotting._interface._get_team(identifier, session) + assert team.normalized_value == expected + +def test_fuzzy_driver_team_key_error(): + session = fastf1.get_session(2023, 10, 'R') + + with pytest.raises(KeyError): + _ = fastf1.plotting._interface._get_team('andretti', session) -def test_team_colors_dict_warning(): with pytest.raises(KeyError): - with pytest.warns(UserWarning): - TEAM_COLORS['Ferrari'] + _ = fastf1.plotting._interface._get_driver('toto wolf', session) + + +@pytest.mark.parametrize( + "identifier, kwargs, expected", + ( + ('red bull', {'colormap': 'default'}, DEFAULT_RB_COLOR), + ('mercedes', {'colormap': 'default'}, DEFAULT_MERC_COLOR), + ('mercedes', {'colormap': 'official'}, OFFICIAL_MERC_COLOR), + ) +) +def test_internal_get_team_color(identifier, kwargs, expected): + session = fastf1.get_session(2023, 10, 'R') + color = fastf1.plotting._interface._get_team_color( + identifier, session, **kwargs + ) + assert color == expected + + +def test_internal_get_team_color_exceptions(): + session = fastf1.get_session(2023, 10, 'R') + with pytest.raises(ValueError, match="Invalid colormap"): + fastf1.plotting._interface._get_team_color( + 'mercedes', session, colormap='bullshit' + ) + + +@pytest.mark.parametrize( + "identifier, kwargs, expected", + ( + ('Red Bull', {'short': False}, 'Red Bull Racing'), + ('Red Bull', {'short': True}, 'Red Bull'), + ('merciless', {'short': True}, 'Mercedes'), # test fuzzy (typos) + ) +) +def test_get_team_name(identifier, kwargs, expected): + session = fastf1.get_session(2023, 10, 'R') + name = fastf1.plotting.get_team_name(identifier, session, **kwargs) + assert name == expected + + +@pytest.mark.parametrize( + "identifier, kwargs, expected", + ( + ('max verstappen', {'short': False}, 'Red Bull Racing'), # long + ('max verstappen', {'short': True}, 'Red Bull'), # test short + ('HAM', {'short': True}, 'Mercedes'), # test abbreviation + ('verstaapen', {'short': True}, 'Red Bull'), # test fuzzy (typos) + ) +) +def test_get_team_name_by_driver(identifier, kwargs, expected): + session = fastf1.get_session(2023, 10, 'R') + name = fastf1.plotting.get_team_name_by_driver( + identifier, session, **kwargs + ) + assert name == expected + + +@pytest.mark.parametrize( + "identifier, kwargs, expected", + ( + ('red bull', {'colormap': 'default'}, + DEFAULT_RB_COLOR), + ('mercedes', {'colormap': 'default'}, + DEFAULT_MERC_COLOR), + ('mercedes', {'colormap': 'official'}, + OFFICIAL_MERC_COLOR), + ) +) +def test_get_team_color(identifier, kwargs, expected): + session = fastf1.get_session(2023, 10, 'R') + color = fastf1.plotting.get_team_color( + identifier, session, **kwargs + ) + assert color == expected + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('VER', 'Max Verstappen'), # test abbreviation + ('HAM', 'Lewis Hamilton'), + ('max verstappen', 'Max Verstappen'), # exact name match + ('lewis hamilton', 'Lewis Hamilton'), + ('verstappen', 'Max Verstappen'), # exact partial name match + ('hamilton', 'Lewis Hamilton'), + ('verstaapen', 'Max Verstappen'), # test fuzzy (typos) + ('hamiltime', 'Lewis Hamilton'), + ) +) +def test_get_driver_name(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + name = fastf1.plotting.get_driver_name(identifier, session) + assert name == expected + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('VER', 'VER'), # test abbreviation + ('HAM', 'HAM'), + ('max verstappen', 'VER'), # exact name match + ('lewis hamilton', 'HAM'), + ('verstappen', 'VER'), # exact partial name match + ('hamilton', 'HAM'), + ('verstaapen', 'VER'), # test fuzzy (typos) + ('hamiltime', 'HAM'), + ) +) +def test_get_driver_abbreviation(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + abb = fastf1.plotting.get_driver_abbreviation(identifier, session) + assert abb == expected + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('red bull', ['Max Verstappen', 'Sergio Perez']), # exact name match + ('mercedes', ['Lewis Hamilton', 'George Russell']), + ) +) +def test_get_driver_names_by_team(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + names = fastf1.plotting.get_driver_names_by_team(identifier, session) + for name in expected: + assert name in names + assert len(names) == len(expected) + + +@pytest.mark.parametrize( + "identifier, expected", + ( + ('red bull', ['VER', 'PER']), # exact name match + ('mercedes', ['HAM', 'RUS']), + ) +) +def test_get_driver_abbreviations_by_team(identifier, expected): + session = fastf1.get_session(2023, 10, 'R') + abbs = fastf1.plotting.get_driver_abbreviations_by_team(identifier, session) + for abb in expected: + assert abb in abbs + assert len(abbs) == len(expected) + + +@pytest.mark.parametrize( + "identifier, kwargs, expected", + ( + ('verstappen', {'colormap': 'default'}, + DEFAULT_RB_COLOR), + ('perez', {'colormap': 'default'}, + DEFAULT_RB_COLOR), + ('hamilton', {'colormap': 'default'}, + DEFAULT_MERC_COLOR), + ('hamilton', {'colormap': 'official'}, + OFFICIAL_MERC_COLOR), + ) +) +def test_get_driver_color(identifier, kwargs, expected): + session = fastf1.get_session(2023, 10, 'R') + color = fastf1.plotting.get_driver_color( + identifier, session, **kwargs + ) + assert color == expected + + +@pytest.mark.parametrize( + "identifier, style, colormap, expected", + ( + ('verstappen', 'linestyle', 'default', + {'linestyle': 'solid'} + ), + ('perez', ['marker'], 'default', + {'marker': 'o'} + ), + ('verstappen', ['marker', 'color'], 'default', + {'marker': 'x', 'color': DEFAULT_RB_COLOR} + ), + ('hamilton', ['edgecolor', 'facecolor'], 'official', + {'edgecolor': OFFICIAL_MERC_COLOR, + 'facecolor': OFFICIAL_MERC_COLOR}), + + ) +) +def test_get_driver_style_default_styles( + identifier, style, colormap, expected +): + session = fastf1.get_session(2023, 10, 'R') + color = fastf1.plotting.get_driver_style( + identifier, style, session, colormap=colormap + ) + assert color == expected + + +def test_get_driver_style_custom_style(): + session = fastf1.get_session(2023, 10, 'R') + + custom_style = ( + {'color': '#00ff00', 'rain': 'yes', 'snow': False, 'skycolor': 'auto'}, + {'rain': 'no', 'snow': True, 'sun': 100, 'edgecolor': 'auto'}, + ) + + ver_style = fastf1.plotting.get_driver_style( + 'verstappen', + custom_style, + session, + colormap='default', + additional_color_kws=('skycolor', ) # register custom color key + ) + + assert ver_style == { + 'color': '#00ff00', # static color on color keyword + 'rain': 'yes', # string option + 'snow': False, # bool option + # 'sun': 100 # no sun option + 'skycolor': DEFAULT_RB_COLOR, # auto color on custom registered key + } + + per_style = fastf1.plotting.get_driver_style( + 'perez', + custom_style, + session, + colormap='default', + additional_color_kws=('skycolor', ) + ) + + assert per_style == { + # 'color': '#00ff00', # no color entry + 'rain': 'no', # string option + 'snow': True, # bool option + 'sun': 100, # int option + # 'skycolor': DEFAULT_RB_COLOR_0, no skycolor entry + 'edgecolor': DEFAULT_RB_COLOR, # auto color on default key + } + + +def test_get_compound_color(): + session = fastf1.get_session(2023, 10, 'R') + assert (fastf1.plotting.get_compound_color('HARD', session) + == season2023.CompoundColors[Compounds.Hard]) + + assert (fastf1.plotting.get_compound_color('sOfT', session) + == season2023.CompoundColors[Compounds.Soft]) + + with pytest.raises(KeyError): + fastf1.plotting.get_compound_color('HYPERSOFT', session) + + +def test_get_compound_mapping(): + session = fastf1.get_session(2023, 10, 'R') + assert (fastf1.plotting.get_compound_mapping(session) + == season2023.CompoundColors) + + +def test_get_driver_color_mapping(): + session = fastf1.get_session(2023, 10, 'R') + + default = fastf1.plotting.get_driver_color_mapping(session, + colormap='default') + assert default['VER'] == default['PER'] == DEFAULT_RB_COLOR + assert default['HAM'] == default['RUS'] == DEFAULT_MERC_COLOR + assert len(default) == 20 + + official = fastf1.plotting.get_driver_color_mapping(session, + colormap='official') + assert official['VER'] == official['PER'] == OFFICIAL_RB_COLOR + assert official['HAM'] == official['RUS'] == OFFICIAL_MERC_COLOR + assert len(default) == 20 + + +def test_list_team_names(): + session = fastf1.get_session(2023, 10, 'R') + names = fastf1.plotting.list_team_names(session) + + assert 'Red Bull Racing' in names + assert 'Haas F1 Team' in names + assert 'Aston Martin' in names + assert len(names) == 10 + + +def test_list_short_team_names(): + session = fastf1.get_session(2023, 10, 'R') + names = fastf1.plotting.list_short_team_names(session) + + assert 'Red Bull' in names + assert 'Haas' in names + assert 'Aston Martin' in names + assert len(names) == 10 + + +def test_list_driver_abbreviations(): + session = fastf1.get_session(2023, 10, 'R') + abbs = fastf1.plotting.list_driver_abbreviations(session) + + assert 'VER' in abbs + assert 'RUS' in abbs + assert len(abbs) == 20 + + +def test_list_driver_names(): + session = fastf1.get_session(2023, 10, 'R') + names = fastf1.plotting.list_driver_names(session) + + assert 'Max Verstappen' in names + assert 'George Russell' in names + assert len(names) == 20 + + +def test_list_compounds(): + session = fastf1.get_session(2023, 10, 'R') + compounds = fastf1.plotting.list_compounds(session) + + reference = ('HARD', 'MEDIUM', 'SOFT', 'INTERMEDIATE', 'WET', + 'TEST-UNKNOWN', 'UNKNOWN') + + for compound in reference: + assert compound in compounds - with pytest.warns(UserWarning): - TEAM_COLORS.get('Ferrari', None) + assert len(compounds) == len(reference) - TEAM_COLORS['ferrari'] - TEAM_COLORS.get('ferrari', None) +def test_add_sorted_lapnumber_axis(): + session = fastf1.get_session(2023, 10, 'R') + ax = plt.figure().subplots() -def test_team_color_name_abbreviation_integrity(): - for value in TEAM_TRANSLATE.values(): - assert value in TEAM_COLORS - assert len(TEAM_COLORS) == len(TEAM_TRANSLATE) + ax.plot(0, 0, label='HAM') + ax.plot(0, 0, label='RUS') + ax.plot(0, 0, label='PER') + ax.plot(0, 0, label='VER') + legend = fastf1.plotting.add_sorted_driver_legend(ax, session) -def test_driver_color_name_abbreviation_integrity(): - for value in DRIVER_TRANSLATE.values(): - assert value in DRIVER_COLORS - assert len(DRIVER_COLORS) == len(DRIVER_TRANSLATE) + # sorting is generally done by driver number to guarantee consistency + # in 2023, VER was #1, so he is first, then followed by PER; + # Red Bull as a team before Mercedes, again because VER has the lower number + # within Mercedes, Hamilton has the lower number + assert ([txt.get_text() for txt in legend.texts] + == ['VER', 'PER', 'HAM', 'RUS']) diff --git a/fastf1/tests/test_plotting_deprecated.py b/fastf1/tests/test_plotting_deprecated.py new file mode 100644 index 000000000..4beb77e96 --- /dev/null +++ b/fastf1/tests/test_plotting_deprecated.py @@ -0,0 +1,115 @@ +import warnings + +import pytest + +import fastf1.plotting + + +with warnings.catch_warnings(): + warnings.simplefilter("ignore", FutureWarning) + from fastf1.plotting import ( + DRIVER_COLORS, + DRIVER_TRANSLATE, + TEAM_COLORS, + TEAM_TRANSLATE, + COLOR_PALETTE, + COMPOUND_COLORS + ) + +import matplotlib.pyplot as plt + + +@pytest.mark.parametrize( + "property_name", + ('DRIVER_COLORS', 'DRIVER_TRANSLATE', + 'TEAM_COLORS', 'TEAM_TRANSLATE', + 'COLOR_PALETTE', 'COMPOUND_COLORS') +) +def test_all_warn_deprecated(property_name): + with pytest.warns(FutureWarning, match="is deprecated"): + obj = getattr(fastf1.plotting, property_name) + assert isinstance(obj, (dict, list)) + + +def test_driver_colors_driver_translate(): + for abb, name in DRIVER_TRANSLATE.items(): + assert len(abb) == 3 + assert abb.isalpha() and abb.isupper() + assert len(name) > 3 + assert name.replace(' ', '').isalpha() and name.islower() + + assert name in DRIVER_COLORS + color = DRIVER_COLORS[name] + assert color.startswith('#') + assert len(color) == 7 + _ = int(color[1:], base=16) # ensure that it's a valid hex color + + +def test_team_colors_team_translate(): + for abb, name in TEAM_TRANSLATE.items(): + assert (len(abb) == 3) or (len(abb) == 2) + assert abb.isalpha() and abb.isupper() + assert (len(name) > 3) or (name.lower() == 'rb') + assert name.replace(' ', '').isalpha() and name.islower() + + assert name in TEAM_COLORS + color = TEAM_COLORS[name] + assert color.startswith('#') + assert len(color) == 7 + _ = int(color[1:], base=16) # ensure that it's a valid hex color + + +def test_compound_colors(): + for compound, color in COMPOUND_COLORS.items(): + assert len(compound) >= 3 + assert compound.replace('-', '').isalpha() + assert compound.replace('-', '').isupper() + + assert color.startswith('#') + assert len(color) == 7 + _ = int(color[1:], base=16) # ensure that it's a valid hex color + + +def test_color_palette(): + assert len(COLOR_PALETTE) == 7 + for color in COLOR_PALETTE: + assert color.startswith('#') + assert len(color) == 7 + _ = int(color[1:], base=16) # ensure that it's a valid hex color + + +@pytest.mark.parametrize( + "func_name", + ("setup_mpl", "driver_color", "team_color", "lapnumber_axis") +) +def test_functions_exist(func_name): + assert hasattr(fastf1.plotting, func_name) + func = getattr(fastf1.plotting, func_name) + assert callable(func) + + +def test_driver_color(): + with pytest.warns(FutureWarning, match="is deprecated"): + color_ver = fastf1.plotting.driver_color('VER') + color_per = fastf1.plotting.driver_color('PER') + + assert color_ver.startswith('#') + assert len(color_ver) == 7 + _ = int(color_ver[1:], base=16) # ensure that it's a valid hex color + + assert color_per != color_ver + + +def test_team_color(): + with pytest.warns(FutureWarning, match="is deprecated"): + color = fastf1.plotting.team_color('ferrari') + + assert color.startswith('#') + assert len(color) == 7 + _ = int(color[1:], base=16) # ensure that it's a valid hex color + + +def test_lapnumber_axis(): + ax = plt.figure().subplots() + with pytest.warns(FutureWarning, match="is deprecated"): + fastf1.plotting.lapnumber_axis(ax) diff --git a/fastf1/utils.py b/fastf1/utils.py index fb2a02ea1..4e35f0314 100644 --- a/fastf1/utils.py +++ b/fastf1/utils.py @@ -50,7 +50,7 @@ def delta_time( from fastf1 import utils from matplotlib import pyplot as plt - plotting.setup_mpl() + plotting.setup_mpl(misc_mpl_mods=False, color_scheme='fastf1') session = ff1.get_session(2021, 'Emilia Romagna', 'Q') session.load() @@ -62,11 +62,11 @@ def delta_time( fig, ax = plt.subplots() # use telemetry returned by .delta_time for best accuracy, - # this ensure the same applied interpolation and resampling + # this ensures the same applied interpolation and resampling ax.plot(ref_tel['Distance'], ref_tel['Speed'], - color=plotting.team_color(ham['Team'])) + color=plotting.get_team_color(ham['Team'], session)) ax.plot(compare_tel['Distance'], compare_tel['Speed'], - color=plotting.team_color(lec['Team'])) + color=plotting.get_team_color(lec['Team'], session)) twin = ax.twinx() twin.plot(ref_tel['Distance'], delta_time, '--', color='white') From 910d94274cf02ef190a087cb75d6d0502d344046 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 12 May 2024 15:29:28 +0200 Subject: [PATCH 16/31] fix missing section in docs --- docs/plotting.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/plotting.rst b/docs/plotting.rst index 2db05783f..9844dc192 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -120,6 +120,20 @@ The following module-level attributes are deprecated since version 3.4.0 and will be removed in a future release. +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + driver_color, + lapnumber_axis, + team_color, + COMPOUND_COLORS, + DRIVER_TRANSLATE, + DRIVER_COLORS, + TEAM_COLORS, + TEAM_TRANSLATE, + COLOR_PALETTE From 6044648a772685d33b442dca9b558354fd5ab1dd Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 12 May 2024 15:37:06 +0200 Subject: [PATCH 17/31] trigger release workflow on prerelease --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 70afc957d..5292ceaaf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: Create Release on: release: - types: [released] + types: [released, prereleased] workflow_dispatch: jobs: From f6eefdcd7dfdbbd6677658e3356aff175baa0b83 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 12 May 2024 15:57:34 +0200 Subject: [PATCH 18/31] fix common words not removed from team name in new function --- fastf1/plotting/_interface.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index 5d30ce491..75ce2ece3 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -69,6 +69,11 @@ def _get_team(identifier: str, session: Session) -> _Team: dtm = _get_driver_team_mapping(session) identifier = _normalize_string(identifier).lower() + # remove common non-unique words + for word in ('racing', 'team', 'f1', 'scuderia'): + identifier = identifier.replace(word, "") + identifier = identifier.replace(" ", "") + # check for an exact team name match if identifier in dtm.teams_by_normalized.keys(): return dtm.teams_by_normalized[identifier] From 2c5642adf1d9637a118088c52bae92b1b52edf5a Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:37:00 +0200 Subject: [PATCH 19/31] refactor and unify fuzzy matching --- fastf1/events.py | 60 +++--------- fastf1/internals/fuzzy.py | 115 +++++++++++++++++++++++ fastf1/plotting/__init__.py | 2 +- fastf1/plotting/_constants/season2024.py | 2 +- fastf1/plotting/_interface.py | 35 +++++-- 5 files changed, 161 insertions(+), 53 deletions(-) create mode 100644 fastf1/internals/fuzzy.py diff --git a/fastf1/events.py b/fastf1/events.py index a88e3fff4..309d09426 100644 --- a/fastf1/events.py +++ b/fastf1/events.py @@ -199,21 +199,12 @@ ) import dateutil.parser - - -with warnings.catch_warnings(): - warnings.filterwarnings( - 'ignore', message="Using slow pure-python SequenceMatcher" - ) - # suppress that warning, it's confusing at best here, we don't need fast - # sequence matching and the installation (on windows) requires some effort - from rapidfuzz import fuzz - import pandas as pd import fastf1._api import fastf1.ergast from fastf1.core import Session +from fastf1.internals.fuzzy import fuzzy_matcher from fastf1.internals.pandas_base import ( BaseDataFrame, BaseSeries @@ -943,50 +934,29 @@ def _remove_common_words(event_name): def _matcher_strings(ev): strings = list() - if 'Location' in ev: + if ('Location' in ev) and ev['Location']: strings.append(ev['Location'].casefold()) - if 'Country' in ev: + if ('Country' in ev) and ev['Country']: strings.append(ev['Country'].casefold()) - if 'EventName' in ev: + if ('EventName' in ev) and ev['EventName']: strings.append(_remove_common_words(ev["EventName"])) - if 'OfficialEventName' in ev: + if ('OfficialEventName' in ev) and ev['OfficialEventName']: strings.append(_remove_common_words(ev["OfficialEventName"])) return strings user_input = name name = _remove_common_words(name) - full_partial_match_indices = [] - # check partial matches first - # if there is either zero or multiple 100% matches - # fall back to the full ratio - for i, event in self.iterrows(): - if any([name in val for val in _matcher_strings(event)]): - full_partial_match_indices.append(i) - - if len(full_partial_match_indices) == 1: - return self.loc[full_partial_match_indices[0]] - - max_ratio = 0 - max_index = 0 - - for i, event in self.loc[full_partial_match_indices - or self.index].iterrows(): - ratio = max( - [fuzz.ratio(val, name) - for val in _matcher_strings(event)] - ) - if ratio > max_ratio: - max_ratio = ratio - max_index = i - - if max_ratio != 100: - _logger.warning(( - "Correcting user input " - f"'{user_input}' to'{self.loc[max_index].EventName}'" - ) - ) - return self.loc[max_index] + reference = [_matcher_strings(event) for _, event in self.iterrows()] + + index, exact = fuzzy_matcher(name, reference) + event = self.iloc[index] + + if not exact: + _logger.warning(f"Correcting user input '{user_input}' to " + f"'{event.EventName}'") + + return event def get_event_by_name( self, diff --git a/fastf1/internals/fuzzy.py b/fastf1/internals/fuzzy.py new file mode 100644 index 000000000..d190f7089 --- /dev/null +++ b/fastf1/internals/fuzzy.py @@ -0,0 +1,115 @@ +import warnings +from typing import Sequence + +import numpy as np + + +with warnings.catch_warnings(): + warnings.filterwarnings( + 'ignore', message="Using slow pure-python SequenceMatcher" + ) + # suppress that warning, it's confusing at best here, we don't need fast + # sequence matching and the installation (on windows) requires some effort + from rapidfuzz import fuzz + + +def fuzzy_matcher( + query: str, + reference: Sequence[Sequence[str]], + abs_confidence: float = 0.0, + rel_confidence: float = 0.0 +) -> (int, bool): + """ + Match a query string to a reference list of tuples of strings using fuzzy + string matching. + + The reference is a list of tuples where each tuple is one element. The + tuples contain one or multiple feature strings. The idea is that each + element can be described by multiple feature strings. The function tries to + find the best matching element in the reference list for the query string. + + The function first checks for exact substring matches with the individual + feature strings. If there is exactly one reference tuple, where the query + is a substring of a feature string, this index is returned as accurate an + "accurate match". Else, the function uses fuzzy string matching to find the + best match in the reference list. The index of the best matching element is + returned as an "inaccurate match". + + Args: + query: The query string to match. + reference: A list of tuples where each tuple contains one or multiple + feature strings. + abs_confidence: The minimum absolute confidence that the match must + have when fuzzy matched. Must be a value between 0.0 and 1.0, where + 1.0 is equivalent to a perfect match. Set to 0.0 to disable. + If the best match has a lower confidence, a KeyError is raised. + rel_confidence: The minimum relative confidence that the match must + have (compared with the second-best match). Must be a value greater + than 0.0, where 0.5 would mean that the best match must have a 50% + higher score than the second-best match. Set to 0.0 to disable. + If the best match has a lower relative confidence, a KeyError is + raised. + + Returns: + (int, bool): Index of the best matching element in the reference list + and a boolean indicating if the match is accurate or not. + + """ + # Check for exact substring matches with the individual feature strings + # first. If there is exactly one reference tuple, where the query is a + # substring of a feature string, return this index as accurate match. + full_partial_match_indices = [] + for i, feature_strings in enumerate(reference): + if any([query in val for val in feature_strings]): + full_partial_match_indices.append(i) + + if len(full_partial_match_indices) == 1: + # return index as accurate match + return full_partial_match_indices[0], True + + # Zero or multiple reference tuples had substring matches, so we need to + # do fuzzy matching + reference = np.array(reference) + ratios = np.zeros_like(reference, dtype=int) + + # If we have multiple substring matches, we only fuzzy match on these, + # else we fuzzy match on all reference tuples + if full_partial_match_indices: + candidate_indices = full_partial_match_indices + else: + candidate_indices = range(len(reference)) + + # Calculate the fuzz ratio for each feature string in each reference tuple + for i in candidate_indices: + feature_strings = reference[i] + ratios[i] = [fuzz.ratio(val, query) for val in feature_strings] + + max_ratio = np.max(ratios) + max_row_ratios = np.max(ratios, axis=1) + # if there are multiple rows with the same maximum ratio, we need to remove + # the corresponding ratios from the comparison so that we can match based + # on the remaining feature string ratios + if np.sum(max_row_ratios == max_ratio) > 1: + # get counts of all unique ratios and remove all that are not unique + # in the array by setting them to zero + unique, counts = np.unique(reference, return_counts=True) + count_dict = dict(zip(unique, counts)) + mask = ((np.vectorize(count_dict.get)(reference) > 1) + & (ratios == max_ratio)) + ratios[mask] = 0 + + # get the index of the row that contains the maximum ratio + max_index = np.argmax(ratios) // ratios.shape[1] + + # optional confidence checks + if abs_confidence and (max_ratio < (abs_confidence * 100)): + raise KeyError + + if rel_confidence and (max_ratio / np.partition(ratios.flatten(), -2)[-2] + < (1 + rel_confidence)): + # max ratio divided by second-largest ratio is less + # than 1 + rel_confidence + raise KeyError + + # return index as inaccurate match + return max_index, False diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py index 6b4d3c67e..1577d673b 100644 --- a/fastf1/plotting/__init__.py +++ b/fastf1/plotting/__init__.py @@ -139,7 +139,7 @@ def __getattr__(name): _DEPR_TEAM_COLORS: Dict[str, str] = { # str(key.value): val for key, val # in _Constants['2024'].Colormaps[_Colormaps.Default].items() - name: team.TeamColor.Default for name, team + name.replace("kick ", ""): team.TeamColor.Default for name, team in _Constants['2024'].Teams.items() } TEAM_COLORS: Dict[str, str] diff --git a/fastf1/plotting/_constants/season2024.py b/fastf1/plotting/_constants/season2024.py index c87826a45..fb363064c 100644 --- a/fastf1/plotting/_constants/season2024.py +++ b/fastf1/plotting/_constants/season2024.py @@ -64,7 +64,7 @@ Default='#0600ef' ) ), - 'sauber': Team( + 'kick sauber': Team( ShortName='Sauber', TeamColor=TeamColors( Official='#52e252', diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index 75ce2ece3..1c541236a 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -9,11 +9,12 @@ import matplotlib.axes from fastf1.core import Session +from fastf1.internals.fuzzy import fuzzy_matcher from fastf1.plotting._backend import _load_drivers_from_f1_livetiming from fastf1.plotting._base import ( _Driver, _DriverTeamMapping, - _fuzzy_matcher, + _logger, _normalize_string, _Team ) @@ -60,8 +61,19 @@ def _get_driver(identifier: str, session: Session) -> _Driver: return dtm.drivers_by_normalized[normalized_driver] # do fuzzy string matching - normalized_driver = _fuzzy_matcher(identifier, - list(dtm.drivers_by_normalized.keys())) + drivers = list(dtm.drivers_by_normalized.values()) + strings = [[driver.normalized_value.casefold().replace(" ", ""), ] + for driver in drivers] + query = identifier.casefold().replace(" ", "") + index, exact = fuzzy_matcher(query, strings, + abs_confidence=0.35, + rel_confidence=0.30) + normalized_driver = drivers[index].normalized_value + + if not exact: + _logger.warning(f"Correcting user input '{identifier}' to " + f"'{normalized_driver}'") + return dtm.drivers_by_normalized[normalized_driver] @@ -85,9 +97,20 @@ def _get_team(identifier: str, session: Session) -> _Team: return dtm.teams_by_normalized[normalized] # do fuzzy string match - team_name = _fuzzy_matcher(identifier, - list(dtm.teams_by_normalized.keys())) - return dtm.teams_by_normalized[team_name] + teams = list(dtm.teams_by_normalized.values()) + strings = [[team.normalized_value.casefold().replace(" ", ""), ] + for team in teams] + query = identifier.casefold().replace(" ", "") + index, exact = fuzzy_matcher(query, strings, + abs_confidence=0.35, + rel_confidence=0.30) + normalized_team_name = teams[index].normalized_value + + if not exact: + _logger.warning(f"Correcting user input '{identifier}' to " + f"'{normalized_team_name}'") + + return dtm.teams_by_normalized[normalized_team_name] def _get_driver_color( From 2aa91773562a09fa0498564f2fc5a23b41088b3d Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:16:30 +0200 Subject: [PATCH 20/31] more fuzzy refactoring, implement exact_match --- fastf1/events.py | 2 +- fastf1/internals/fuzzy.py | 42 +++++---- fastf1/plotting/_interface.py | 155 ++++++++++++++++++++++++++-------- fastf1/tests/test_plotting.py | 76 +++++++++++------ 4 files changed, 198 insertions(+), 77 deletions(-) diff --git a/fastf1/events.py b/fastf1/events.py index 309d09426..a935141c8 100644 --- a/fastf1/events.py +++ b/fastf1/events.py @@ -930,7 +930,7 @@ def _remove_common_words(event_name): for word in common_words: event_name = event_name.replace(word, "") - return event_name.replace(" ", "") + return event_name def _matcher_strings(ev): strings = list() diff --git a/fastf1/internals/fuzzy.py b/fastf1/internals/fuzzy.py index d190f7089..4a5406464 100644 --- a/fastf1/internals/fuzzy.py +++ b/fastf1/internals/fuzzy.py @@ -1,5 +1,5 @@ import warnings -from typing import Sequence +from typing import List import numpy as np @@ -15,30 +15,31 @@ def fuzzy_matcher( query: str, - reference: Sequence[Sequence[str]], + reference: List[List[str]], abs_confidence: float = 0.0, rel_confidence: float = 0.0 ) -> (int, bool): """ - Match a query string to a reference list of tuples of strings using fuzzy + Match a query string to a reference list of lists of strings using fuzzy string matching. - The reference is a list of tuples where each tuple is one element. The - tuples contain one or multiple feature strings. The idea is that each - element can be described by multiple feature strings. The function tries to - find the best matching element in the reference list for the query string. + The reference is a list of sub-lists where each sub-list represents one + element. The sub-lists contain one or multiple feature strings. The idea is + that each element can be described by multiple feature strings. The + function tries to find the best matching element in the reference list + for the given query string. The function first checks for exact substring matches with the individual - feature strings. If there is exactly one reference tuple, where the query - is a substring of a feature string, this index is returned as accurate an + feature strings. If there is exactly one sub-list, where the query + is a substring of a feature string, this index is returned as an "accurate match". Else, the function uses fuzzy string matching to find the best match in the reference list. The index of the best matching element is - returned as an "inaccurate match". + then returned as an "inaccurate match". Args: query: The query string to match. - reference: A list of tuples where each tuple contains one or multiple - feature strings. + reference: A list of lists where each sub-list contains one or multiple + feature strings describing an element. abs_confidence: The minimum absolute confidence that the match must have when fuzzy matched. Must be a value between 0.0 and 1.0, where 1.0 is equivalent to a perfect match. Set to 0.0 to disable. @@ -51,10 +52,17 @@ def fuzzy_matcher( raised. Returns: - (int, bool): Index of the best matching element in the reference list - and a boolean indicating if the match is accurate or not. + (int, bool): Index of the best matching element in the + reference (outer) list and a boolean indicating if the match is + accurate or not. """ + # Preprocess the query and reference strings + query = query.casefold().replace(" ", "") + for i in range(len(reference)): + for j in range(len(reference[i])): + reference[i][j] = reference[i][j].casefold().replace(" ", "") + # Check for exact substring matches with the individual feature strings # first. If there is exactly one reference tuple, where the query is a # substring of a feature string, return this index as accurate match. @@ -103,13 +111,15 @@ def fuzzy_matcher( # optional confidence checks if abs_confidence and (max_ratio < (abs_confidence * 100)): - raise KeyError + raise KeyError(f"Found no match for '{query}' with sufficient " + f"absolute confidence") if rel_confidence and (max_ratio / np.partition(ratios.flatten(), -2)[-2] < (1 + rel_confidence)): # max ratio divided by second-largest ratio is less # than 1 + rel_confidence - raise KeyError + raise KeyError(f"Found no match for '{query}' with sufficient " + f"relative confidence") # return index as inaccurate match return max_index, False diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index 1c541236a..a886b536b 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -43,7 +43,15 @@ def _get_driver_team_mapping( return _DRIVER_TEAM_MAPPINGS[api_path] -def _get_driver(identifier: str, session: Session) -> _Driver: +def _get_driver( + identifier: str, session: Session, *, exact_match: bool = False +) -> _Driver: + if exact_match: + return _get_driver_exact(identifier, session) + return _get_driver_fuzzy(identifier, session) + + +def _get_driver_fuzzy(identifier: str, session: Session) -> _Driver: dtm = _get_driver_team_mapping(session) identifier = _normalize_string(identifier).lower() @@ -62,10 +70,9 @@ def _get_driver(identifier: str, session: Session) -> _Driver: # do fuzzy string matching drivers = list(dtm.drivers_by_normalized.values()) - strings = [[driver.normalized_value.casefold().replace(" ", ""), ] - for driver in drivers] - query = identifier.casefold().replace(" ", "") - index, exact = fuzzy_matcher(query, strings, + strings = [[driver.normalized_value, ] for driver in drivers] + index, exact = fuzzy_matcher(query=identifier, + reference=strings, abs_confidence=0.35, rel_confidence=0.30) normalized_driver = drivers[index].normalized_value @@ -77,14 +84,36 @@ def _get_driver(identifier: str, session: Session) -> _Driver: return dtm.drivers_by_normalized[normalized_driver] -def _get_team(identifier: str, session: Session) -> _Team: +def _get_driver_exact(identifier: str, session: Session) -> _Driver: + dtm = _get_driver_team_mapping(session) + identifier = _normalize_string(identifier).lower() + + # try driver abbreviation first + if (abb := identifier.upper()) in dtm.drivers_by_abbreviation: + return dtm.drivers_by_abbreviation[abb] + + # check for an exact driver name match + if identifier in dtm.drivers_by_normalized: + return dtm.drivers_by_normalized[identifier] + + raise KeyError(f"No driver found for '{identifier}' (exact match only)") + + +def _get_team( + identifier: str, session: Session, *, exact_match=False +) -> _Team: + if exact_match: + return _get_team_exact(identifier, session) + return _get_team_fuzzy(identifier, session) + + +def _get_team_fuzzy(identifier: str, session: Session) -> _Team: dtm = _get_driver_team_mapping(session) identifier = _normalize_string(identifier).lower() # remove common non-unique words for word in ('racing', 'team', 'f1', 'scuderia'): identifier = identifier.replace(word, "") - identifier = identifier.replace(" ", "") # check for an exact team name match if identifier in dtm.teams_by_normalized.keys(): @@ -92,16 +121,15 @@ def _get_team(identifier: str, session: Session) -> _Team: # check full match with full team name or for exact partial string # match with normalized team name - for normalized, full in dtm.teams_by_normalized.items(): - if (identifier == full) or (identifier in normalized): + for normalized, team in dtm.teams_by_normalized.items(): + if (identifier == team.value.casefold()) or (identifier in normalized): return dtm.teams_by_normalized[normalized] # do fuzzy string match teams = list(dtm.teams_by_normalized.values()) - strings = [[team.normalized_value.casefold().replace(" ", ""), ] - for team in teams] - query = identifier.casefold().replace(" ", "") - index, exact = fuzzy_matcher(query, strings, + strings = [[team.normalized_value, ] for team in teams] + index, exact = fuzzy_matcher(query=identifier, + reference=strings, abs_confidence=0.35, rel_confidence=0.30) normalized_team_name = teams[index].normalized_value @@ -113,31 +141,53 @@ def _get_team(identifier: str, session: Session) -> _Team: return dtm.teams_by_normalized[normalized_team_name] +def _get_team_exact(identifier: str, session: Session) -> _Team: + dtm = _get_driver_team_mapping(session) + identifier = _normalize_string(identifier).lower() + + # check for an exact normalized team name match + if identifier in dtm.teams_by_normalized.keys(): + return dtm.teams_by_normalized[identifier] + + # check full match with full team name + for normalized, full in dtm.teams_by_normalized.items(): + if identifier == full.value.casefold(): + return dtm.teams_by_normalized[normalized] + + raise KeyError(f"No team found for '{identifier}' (exact match only)") + + def _get_driver_color( identifier: str, session: Session, *, colormap: str = 'default', + exact_match: bool = False, _variants: bool = False ) -> str: - driver = _get_driver(identifier, session) + driver = _get_driver(identifier, session, exact_match=exact_match) team_name = driver.team.normalized_value - return _get_team_color(team_name, session, colormap=colormap) + return _get_team_color(team_name, session, colormap=colormap, + exact_match=True) def _get_team_color( - identifier: str, - session: Session, - *, - colormap: str = 'default', + identifier: str, + session: Session, + *, + colormap: str = 'default', + exact_match: bool = False ) -> str: dtm = _get_driver_team_mapping(session) if dtm.year not in Constants.keys(): raise ValueError(f"No team colors for year '{dtm.year}'") - team_name = _get_team(identifier, session).normalized_value + team_name = _get_team( + identifier, session, exact_match=exact_match + ).normalized_value + team_consts = Constants[dtm.year].Teams[team_name] if colormap == 'default': @@ -152,7 +202,8 @@ def get_team_name( identifier: str, session: Session, *, - short: bool = False + short: bool = False, + exact_match: bool = False ) -> str: """ Get a full team name based on a recognizable and identifiable part of @@ -167,8 +218,10 @@ def get_team_name( identifier: a recognizable part of the team name session: the session for which the data should be obtained short: if True, a shortened version of the team name will be returned + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - team = _get_team(identifier, session) + team = _get_team(identifier, session, exact_match=exact_match) if short: dtm = _get_driver_team_mapping(session) @@ -183,6 +236,7 @@ def get_team_name_by_driver( session: Session, *, short: bool = False, + exact_match: bool = False ) -> str: """ Get a full team name based on a driver's abbreviation or based on a @@ -196,8 +250,10 @@ def get_team_name_by_driver( identifier: driver abbreviation or recognizable part of the driver name session: the session for which the data should be obtained short: if True, a shortened version of the team name will be returned + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - driver = _get_driver(identifier, session) + driver = _get_driver(identifier, session, exact_match=exact_match) team = driver.team if short: @@ -213,6 +269,7 @@ def get_team_color( session: Session, *, colormap: str = 'default', + exact_match: bool = False ) -> str: """ Get a team color based on a recognizable and identifiable part of @@ -224,14 +281,20 @@ def get_team_color( identifier: a recognizable part of the team name session: the session for which the data should be obtained colormap: one of ``'default'`` or ``'official'`` + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) Returns: A hexadecimal RGB color code """ - return _get_team_color(identifier, session, colormap=colormap) + return _get_team_color(identifier, session, + colormap=colormap, + exact_match=exact_match) -def get_driver_name(identifier: str, session: Session) -> str: +def get_driver_name( + identifier: str, session: Session, *, exact_match: bool = False +) -> str: """ Get a full driver name based on the driver's abbreviation or based on a recognizable and identifiable part of the driver's name. @@ -239,12 +302,16 @@ def get_driver_name(identifier: str, session: Session) -> str: Args: identifier: driver abbreviation or recognizable part of the driver name session: the session for which the data should be obtained + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - driver = _get_driver(identifier, session) + driver = _get_driver(identifier, session, exact_match=exact_match) return driver.value -def get_driver_abbreviation(identifier, session: Session) -> str: +def get_driver_abbreviation( + identifier: str, session: Session, *, exact_match: bool = False +) -> str: """ Get a driver's abbreviation based on a recognizable and identifiable part of the driver's name. @@ -257,12 +324,16 @@ def get_driver_abbreviation(identifier, session: Session) -> str: identifier: recognizable part of the driver's name (or the driver's abbreviation) session: the session for which the data should be obtained + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - driver = _get_driver(identifier, session) + driver = _get_driver(identifier, session, exact_match=exact_match) return driver.abbreviation -def get_driver_names_by_team(identifier: str, session: Session) -> List[str]: +def get_driver_names_by_team( + identifier: str, session: Session, *, exact_match: bool = False +) -> List[str]: """ Get a list of full names of all drivers that drove for a team in a given session based on a recognizable and identifiable part of the team name. @@ -270,13 +341,15 @@ def get_driver_names_by_team(identifier: str, session: Session) -> List[str]: Args: identifier: a recognizable part of the team name session: the session for which the data should be obtained + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - team = _get_team(identifier, session) + team = _get_team(identifier, session, exact_match=exact_match) return [driver.value for driver in team.drivers] def get_driver_abbreviations_by_team( - identifier: str, session: Session + identifier: str, session: Session, *, exact_match: bool = False ) -> List[str]: """ Get a list of abbreviations of all drivers that drove for a team in a given @@ -285,8 +358,10 @@ def get_driver_abbreviations_by_team( Args: identifier: a recognizable part of the team name session: the session for which the data should be obtained + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) """ - team = _get_team(identifier, session) + team = _get_team(identifier, session, exact_match=exact_match) return [driver.abbreviation for driver in team.drivers] @@ -295,6 +370,7 @@ def get_driver_color( session: Session, *, colormap: str = 'default', + exact_match: bool = False ) -> str: """ Get the color that is associated with a driver based on the driver's @@ -315,6 +391,8 @@ def get_driver_color( identifier: driver abbreviation or recognizable part of the driver name session: the session for which the data should be obtained colormap: one of ``'default'`` or ``'official'`` + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) Returns: A hexadecimal RGB color code @@ -329,7 +407,8 @@ def get_driver_style( session: Session, *, colormap: str = 'default', - additional_color_kws: Union[list, tuple] = () + additional_color_kws: Union[list, tuple] = (), + exact_match: bool = False ) -> Dict[str, Any]: """ Get a plotting style that is unique for a driver based on the driver's @@ -434,6 +513,8 @@ def get_driver_style( additional_color_kws: A list of keys that should additionally be treated as colors. This is most usefull for making the magic ``'auto'`` color work with custom styling options. + exact_match: match the identifier exactly (case-insensitive, special + characters are converted to their nearest ASCII equivalent) Returns: a dictionary of plot style arguments that can be directly passed to a matplotlib plot function using the ``**`` expansion operator @@ -466,7 +547,7 @@ def get_driver_style( *additional_color_kws ) - driver = _get_driver(identifier, session) + driver = _get_driver(identifier, session, exact_match=exact_match) team = driver.team idx = team.drivers.index(driver) @@ -486,7 +567,8 @@ def get_driver_style( if opt in color_kwargs: value = _get_team_color(team.normalized_value, session, - colormap=colormap) + colormap=colormap, + exact_match=True) elif opt in stylers: value = stylers[opt][idx] else: @@ -512,7 +594,8 @@ def get_driver_style( if plot_style.get(kwarg, None) == 'auto': color = _get_team_color(team.normalized_value, session, - colormap=colormap) + colormap=colormap, + exact_match=True) plot_style[kwarg] = color return plot_style diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 6c602d258..3d870152e 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -14,41 +14,69 @@ @pytest.mark.parametrize( - "identifier, expected", + "use_exact", (True, False) +) +@pytest.mark.parametrize( + "identifier, expected, can_match_exact", ( - ('VER', 'max verstappen'), # test abbreviation - ('HAM', 'lewis hamilton'), - ('max verstappen', 'max verstappen'), # exact name match - ('lewis hamilton', 'lewis hamilton'), - ('verstappen', 'max verstappen'), # exact partial name match - ('hamilton', 'lewis hamilton'), - ('verstaapen', 'max verstappen'), # test fuzzy (typos) - ('hamiltime', 'lewis hamilton'), + ('VER', 'max verstappen', True), # test abbreviation + ('HAM', 'lewis hamilton', True), + ('max verstappen', 'max verstappen', True), # exact name match + ('lewis hamilton', 'lewis hamilton', True), + ('verstappen', 'max verstappen', False), # partial name match + ('hamilton', 'lewis hamilton', False), + ('verstaapen', 'max verstappen', False), # test fuzzy (typos) + ('hamiltime', 'lewis hamilton', False), ) ) -def test_internal_get_driver(identifier, expected): +def test_internal_get_driver(identifier, expected, can_match_exact, use_exact): session = fastf1.get_session(2023, 10, 'R') - driver = fastf1.plotting._interface._get_driver(identifier, session) - assert driver.normalized_value == expected + + if use_exact and not can_match_exact: + with pytest.raises(KeyError, match="No driver found"): + _ = fastf1.plotting._interface._get_driver( + identifier, session, exact_match=use_exact + ) + return + + else: + driver = fastf1.plotting._interface._get_driver( + identifier, session, exact_match=use_exact + ) + assert driver.normalized_value == expected @pytest.mark.parametrize( - "identifier, expected", + "use_exact", (True, False) +) +@pytest.mark.parametrize( + "identifier, expected, can_match_exact", ( - ('red bull', 'red bull'), # exact name match - ('mercedes', 'mercedes'), - ('bull', 'red bull'), # exact partial name match - ('haas', 'haas'), - ('Red Bull Racing', 'red bull'), # exact match with full name - ('Haas F1 Team', 'haas'), - ('merciless', 'mercedes'), # test fuzzy (typos) - ('alfadauri', 'alphatauri'), + ('red bull', 'red bull', True), # exact name match + ('mercedes', 'mercedes', True), + ('bull', 'red bull', False), # partial name match + ('haas', 'haas', True), + ('Red Bull Racing', 'red bull', True), # exact match with full name + ('Haas F1 Team', 'haas', True), + ('merciless', 'mercedes', False), # test fuzzy (typos) + ('alfadauri', 'alphatauri', False), ) ) -def test_internal_get_team(identifier, expected): +def test_internal_get_team(identifier, expected, can_match_exact, use_exact): session = fastf1.get_session(2023, 10, 'R') - team = fastf1.plotting._interface._get_team(identifier, session) - assert team.normalized_value == expected + + if use_exact and not can_match_exact: + with pytest.raises(KeyError, match="No team found"): + _ = fastf1.plotting._interface._get_team( + identifier, session, exact_match=use_exact + ) + return + + else: + team = fastf1.plotting._interface._get_team( + identifier, session, exact_match=use_exact + ) + assert team.normalized_value == expected def test_fuzzy_driver_team_key_error(): From 860053e18dae50fd5d5fd4a25dcc3e477cf91060 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:32:22 +0200 Subject: [PATCH 21/31] fix doc example formatting --- fastf1/plotting/_interface.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index a886b536b..bcb8a7c12 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -452,7 +452,10 @@ def get_driver_style( color. But both drivers get assigned a different marker style, so they can be uniquely identified in the plot. - Example:: + Example: + + .. doctest:: + >>> from fastf1 import get_session >>> from fastf1.plotting import get_driver_style >>> session = get_session(2023, 10, 'R') @@ -491,14 +494,17 @@ def get_driver_style( 3. Each style dictionary can contain arbitrary keys and value. Therefore, you are not limited to any particular plotting library. - Example:: + Example: + + .. doctest:: + >>> from fastf1 import get_session >>> from fastf1.plotting import get_driver_style >>> session = get_session(2023, 10, 'R') - >>> my_styles = [ \ - {'linestyle': 'solid', 'color': 'auto', 'custom_arg': True}, \ - {'linestyle': 'dotted', 'color': '#FF0060', 'other_arg': 10} \ - ] + >>> my_styles = [ + ... {'linestyle': 'solid', 'color': 'auto', 'custom_arg': True}, + ... {'linestyle': 'dotted', 'color': '#FF0060', 'other_arg': 10} + ... ] >>> get_driver_style('ALO', my_styles, session) {'linestyle': 'solid', 'color': '#00665e', 'custom_arg': True} >>> get_driver_style('STR', my_styles, session) From 50d545d0ca0a1912c8d93e30af3d3f29e0d07ab0 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:14:08 +0200 Subject: [PATCH 22/31] allow setting the default colormap, rename colormaps --- docs/plotting.rst | 6 ++++-- fastf1/plotting/__init__.py | 4 +++- fastf1/plotting/_interface.py | 38 ++++++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/docs/plotting.rst b/docs/plotting.rst index 9844dc192..7aa8acfe3 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -22,9 +22,11 @@ Team Colormaps Currently, two team colormaps are supported. Each colormap provides one color for each team. Colors are constant over the course of a season. All functions that return colors for teams or drivers accept an optional ``colormap`` -argument. +argument. If this argument is not provided, the default colormap is used. +The default colormap can be changed by using +:func:`~fastf1.plotting.set_default_colormap`. -The ``'default'`` colormap is FastF1's default colormap. These colors are teams' +The ``'fastf1'`` colormap is FastF1's default colormap. These colors are teams' primary colors or accent colors as they are used by the teams on their website or in promotional material. The colors are chosen to maximize readability in plots by creating a stronger contrast while still being associated with the diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py index 1577d673b..e5b8bb650 100644 --- a/fastf1/plotting/__init__.py +++ b/fastf1/plotting/__init__.py @@ -30,7 +30,8 @@ list_driver_abbreviations, list_driver_names, list_short_team_names, - list_team_names + list_team_names, + set_default_colormap ) from fastf1.plotting._plotting import ( # noqa: F401 _COLOR_PALETTE, @@ -61,6 +62,7 @@ 'list_driver_names', 'list_team_names', 'list_short_team_names', + 'set_default_colormap', 'setup_mpl', # imported, legacy diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index bcb8a7c12..ec9c51783 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -2,6 +2,7 @@ Any, Dict, List, + Literal, Sequence, Union ) @@ -22,6 +23,7 @@ from fastf1.plotting._constants import Constants as _Constants +_DEFAULT_COLOR_MAP: Literal['fastf1', 'official'] = 'fastf1' _DRIVER_TEAM_MAPPINGS = dict() @@ -191,6 +193,9 @@ def _get_team_color( team_consts = Constants[dtm.year].Teams[team_name] if colormap == 'default': + colormap = _DEFAULT_COLOR_MAP + + if colormap == 'fastf1': return team_consts.TeamColor.Default elif colormap == 'official': return team_consts.TeamColor.Official @@ -280,7 +285,9 @@ def get_team_color( Args: identifier: a recognizable part of the team name session: the session for which the data should be obtained - colormap: one of ``'default'`` or ``'official'`` + colormap: one of ``'default'``, ``'fastf1'`` or ``'official'``. + The default colormap is ``'fastf1'``. Use + :func:`~fastf1.plotting.set_default_colormap` to change it. exact_match: match the identifier exactly (case-insensitive, special characters are converted to their nearest ASCII equivalent) @@ -390,7 +397,9 @@ def get_driver_color( Args: identifier: driver abbreviation or recognizable part of the driver name session: the session for which the data should be obtained - colormap: one of ``'default'`` or ``'official'`` + colormap: one of ``'default'``, ``'fastf1'`` or ``'official'``. + The default colormap is ``'fastf1'``. Use + :func:`~fastf1.plotting.set_default_colormap` to change it. exact_match: match the identifier exactly (case-insensitive, special characters are converted to their nearest ASCII equivalent) @@ -515,7 +524,9 @@ def get_driver_style( style: list of matplotlib plot arguments that should be used for styling or a list of custom style dictionaries session: the session for which the data should be obtained - colormap: one of ``'default'`` or ``'official'`` + colormap: one of ``'default'``, ``'fastf1'`` or ``'official'``. + The default colormap is ``'fastf1'``. Use + :func:`~fastf1.plotting.set_default_colormap` to change it. additional_color_kws: A list of keys that should additionally be treated as colors. This is most usefull for making the magic ``'auto'`` color work with custom styling options. @@ -646,14 +657,18 @@ def get_driver_color_mapping( Args: session: the session for which the data should be obtained - colormap: one of ``'default'`` or ``'official'`` - + colormap: one of ``'default'``, ``'fastf1'`` or ``'official'``. + The default colormap is ``'fastf1'``. Use + :func:`~fastf1.plotting.set_default_colormap` to change it. Returns: dictionary mapping driver abbreviations to RGB hex colors """ dtm = _get_driver_team_mapping(session) if colormap == 'default': + colormap = _DEFAULT_COLOR_MAP + + if colormap == 'fastf1': colors = { abb: (Constants[dtm.year] .Teams[driver.team.normalized_value] @@ -758,3 +773,16 @@ def add_sorted_driver_legend(ax: matplotlib.axes.Axes, session: Session): labels_new.append(elem[3]) return ax.legend(handles_new, labels_new) + + +def set_default_colormap(colormap: str): + """ + Set the default colormap that is used for color lookups. + + Args: + colormap: one of ``'fastf1'`` or ``'official'`` + """ + global _DEFAULT_COLOR_MAP + if colormap not in ('fastf1', 'official'): + raise ValueError(f"Invalid colormap '{colormap}'") + _DEFAULT_COLOR_MAP = colormap From e96623ff000b9fc8a0f305256dc67a2ae4f814a9 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:20:40 +0200 Subject: [PATCH 23/31] rename colormap in internals as well --- docs/_plots/colormap_overview.py | 2 +- fastf1/plotting/__init__.py | 2 +- fastf1/plotting/_constants/base.py | 2 +- fastf1/plotting/_constants/season2018.py | 22 +++++++++++----------- fastf1/plotting/_constants/season2019.py | 20 ++++++++++---------- fastf1/plotting/_constants/season2020.py | 20 ++++++++++---------- fastf1/plotting/_constants/season2021.py | 20 ++++++++++---------- fastf1/plotting/_constants/season2022.py | 20 ++++++++++---------- fastf1/plotting/_constants/season2023.py | 20 ++++++++++---------- fastf1/plotting/_constants/season2024.py | 20 ++++++++++---------- fastf1/plotting/_interface.py | 4 ++-- fastf1/tests/test_plotting.py | 4 ++-- 12 files changed, 78 insertions(+), 78 deletions(-) diff --git a/docs/_plots/colormap_overview.py b/docs/_plots/colormap_overview.py index 0250dccca..ad09f48f3 100644 --- a/docs/_plots/colormap_overview.py +++ b/docs/_plots/colormap_overview.py @@ -26,7 +26,7 @@ for j, (name, team) in enumerate(teams.items()): x_labels.append(team.ShortName) - default_colors.append(team.TeamColor.Default) + default_colors.append(team.TeamColor.FastF1) official_colors.append(team.TeamColor.Official) x_ranges.append((j + 0.5, 1)) diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py index e5b8bb650..0b2d0e639 100644 --- a/fastf1/plotting/__init__.py +++ b/fastf1/plotting/__init__.py @@ -141,7 +141,7 @@ def __getattr__(name): _DEPR_TEAM_COLORS: Dict[str, str] = { # str(key.value): val for key, val # in _Constants['2024'].Colormaps[_Colormaps.Default].items() - name.replace("kick ", ""): team.TeamColor.Default for name, team + name.replace("kick ", ""): team.TeamColor.FastF1 for name, team in _Constants['2024'].Teams.items() } TEAM_COLORS: Dict[str, str] diff --git a/fastf1/plotting/_constants/base.py b/fastf1/plotting/_constants/base.py index 18edbaee5..c13798b06 100644 --- a/fastf1/plotting/_constants/base.py +++ b/fastf1/plotting/_constants/base.py @@ -19,7 +19,7 @@ class Compounds: @dataclass(frozen=True) class TeamColors: Official: str - Default: str + FastF1: str @dataclass(frozen=True) diff --git a/fastf1/plotting/_constants/season2018.py b/fastf1/plotting/_constants/season2018.py index 42e88cae8..210cd30c3 100644 --- a/fastf1/plotting/_constants/season2018.py +++ b/fastf1/plotting/_constants/season2018.py @@ -12,77 +12,77 @@ ShortName='Ferrari', TeamColor=TeamColors( Official='#dc0000', - Default='#dc0000' + FastF1='#dc0000' ) ), 'force india': Team( ShortName='Force India', TeamColor=TeamColors( Official='#f596c8', - Default='#ff87bc' + FastF1='#ff87bc' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#828282', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#ff8000', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#00d2be', - Default='#00f5d0' + FastF1='#00f5d0' ) ), 'racing point': Team( ShortName='Racing Point', TeamColor=TeamColors( Official='#f596c8', - Default='#ff87bc' + FastF1='#ff87bc' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#1e41ff', - Default='#1e41ff' + FastF1='#1e41ff' ) ), 'renault': Team( ShortName='Renault', TeamColor=TeamColors( Official='#fff500', - Default='#fff500' + FastF1='#fff500' ) ), 'sauber': Team( ShortName='Sauber', TeamColor=TeamColors( Official='#9b0000', - Default='#900000' + FastF1='#900000' ) ), 'toro rosso': Team( ShortName='Toro Rosso', TeamColor=TeamColors( Official='#469bff', - Default='#2b4562' + FastF1='#2b4562' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#ffffff', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2019.py b/fastf1/plotting/_constants/season2019.py index 8929e61d1..19c296f6c 100644 --- a/fastf1/plotting/_constants/season2019.py +++ b/fastf1/plotting/_constants/season2019.py @@ -12,70 +12,70 @@ ShortName='Alfa Romeo', TeamColor=TeamColors( Official='#9b0000', - Default='#900000' + FastF1='#900000' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#bd9e57', - Default='#bd9e57' + FastF1='#bd9e57' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#dc0000', - Default='#da291c' + FastF1='#da291c' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#ff8700', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#00d2be', - Default='#00d2be' + FastF1='#00d2be' ) ), 'racing point': Team( ShortName='Racing Point', TeamColor=TeamColors( Official='#f596c8', - Default='#ff87bc' + FastF1='#ff87bc' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#1e41ff', - Default='#1e41ff' + FastF1='#1e41ff' ) ), 'renault': Team( ShortName='Renault', TeamColor=TeamColors( Official='#fff500', - Default='#fff500' + FastF1='#fff500' ) ), 'toro rosso': Team( ShortName='Toro Rosso', TeamColor=TeamColors( Official='#469bff', - Default='#2b4562' + FastF1='#2b4562' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#ffffff', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2020.py b/fastf1/plotting/_constants/season2020.py index 5eb1905b9..d4cd71606 100644 --- a/fastf1/plotting/_constants/season2020.py +++ b/fastf1/plotting/_constants/season2020.py @@ -12,70 +12,70 @@ ShortName='Alfa Romeo', TeamColor=TeamColors( Official='#9B0000', - Default='#900000' + FastF1='#900000' ) ), 'alphatauri': Team( ShortName='AlphaTauri', TeamColor=TeamColors( Official='#ffffff', - Default='#2b4562' + FastF1='#2b4562' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#dc0000', - Default='#dc0000' + FastF1='#dc0000' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#787878', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#ff8700', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#00d2be', - Default='#00d2be' + FastF1='#00d2be' ) ), 'racing point': Team( ShortName='Racing Point', TeamColor=TeamColors( Official='#f596c8', - Default='#ff87bc' + FastF1='#ff87bc' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#1e41ff', - Default='#1e41ff' + FastF1='#1e41ff' ) ), 'renault': Team( ShortName='Renault', TeamColor=TeamColors( Official='#fff500', - Default='#fff500' + FastF1='#fff500' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#0082fa', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2021.py b/fastf1/plotting/_constants/season2021.py index fb195b6b9..1807ae553 100644 --- a/fastf1/plotting/_constants/season2021.py +++ b/fastf1/plotting/_constants/season2021.py @@ -12,70 +12,70 @@ ShortName='Alfa Romeo', TeamColor=TeamColors( Official='#900000', - Default='#900000' + FastF1='#900000' ) ), 'alphatauri': Team( ShortName='AlphaTauri', TeamColor=TeamColors( Official='#2b4562', - Default='#2b4562' + FastF1='#2b4562' ) ), 'alpine': Team( ShortName='Alpine', TeamColor=TeamColors( Official='#0090ff', - Default='#0755ab' + FastF1='#0755ab' ) ), 'aston martin': Team( ShortName='Aston Martin', TeamColor=TeamColors( Official='#006f62', - Default='#00665e' + FastF1='#00665e' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#dc0004', - Default='#dc0004' + FastF1='#dc0004' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#ffffff', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#ff9800', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#00d2be', - Default='#00f5d0' + FastF1='#00f5d0' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#0600ef', - Default='#0600ef' + FastF1='#0600ef' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#005aff', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2022.py b/fastf1/plotting/_constants/season2022.py index b5a258e38..a6bc7bc4e 100644 --- a/fastf1/plotting/_constants/season2022.py +++ b/fastf1/plotting/_constants/season2022.py @@ -12,70 +12,70 @@ ShortName='Alfa Romeo', TeamColor=TeamColors( Official='#b12039', - Default='#900000' + FastF1='#900000' ) ), 'alphatauri': Team( ShortName='AlphaTauri', TeamColor=TeamColors( Official='#4e7c9b', - Default='#2b4562' + FastF1='#2b4562' ) ), 'alpine': Team( ShortName='Alpine', TeamColor=TeamColors( Official='#2293d1', - Default='#fe86bc' + FastF1='#fe86bc' ) ), 'aston martin': Team( ShortName='Aston Martin', TeamColor=TeamColors( Official='#2d826d', - Default='#00665e' + FastF1='#00665e' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#ed1c24', - Default='#da291c' + FastF1='#da291c' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#b6babd', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#f58020', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#6cd3bf', - Default='#00f5d0' + FastF1='#00f5d0' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#1e5bc6', - Default='#0600ef' + FastF1='#0600ef' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#37bedd', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2023.py b/fastf1/plotting/_constants/season2023.py index 92e9628dd..7ba57cc8d 100644 --- a/fastf1/plotting/_constants/season2023.py +++ b/fastf1/plotting/_constants/season2023.py @@ -12,70 +12,70 @@ ShortName='Alfa Romeo', TeamColor=TeamColors( Official='#C92D4B', - Default='#900000' + FastF1='#900000' ) ), 'alphatauri': Team( ShortName='AlphaTauri', TeamColor=TeamColors( Official='#5E8FAA', - Default='#2b4562' + FastF1='#2b4562' ) ), 'alpine': Team( ShortName='Alpine', TeamColor=TeamColors( Official='#2293D1', - Default='#fe86bc' + FastF1='#fe86bc' ) ), 'aston martin': Team( ShortName='Aston Martin', TeamColor=TeamColors( Official='#358C75', - Default='#00665e' + FastF1='#00665e' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#F91536', - Default='#da291c' + FastF1='#da291c' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#b6babd', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#F58020', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#6CD3BF', - Default='#00f5d0' + FastF1='#00f5d0' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#3671C6', - Default='#0600ef' + FastF1='#0600ef' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#37BEDD', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_constants/season2024.py b/fastf1/plotting/_constants/season2024.py index fb363064c..3e93c258e 100644 --- a/fastf1/plotting/_constants/season2024.py +++ b/fastf1/plotting/_constants/season2024.py @@ -12,70 +12,70 @@ ShortName='Alpine', TeamColor=TeamColors( Official='#0093cc', - Default='#ff87bc' + FastF1='#ff87bc' ) ), 'aston martin': Team( ShortName='Aston Martin', TeamColor=TeamColors( Official='#229971', - Default='#00665f' + FastF1='#00665f' ) ), 'ferrari': Team( ShortName='Ferrari', TeamColor=TeamColors( Official='#e8002d', - Default='#e8002d' + FastF1='#e8002d' ) ), 'haas': Team( ShortName='Haas', TeamColor=TeamColors( Official='#b6babd', - Default='#b6babd' + FastF1='#b6babd' ) ), 'mclaren': Team( ShortName='McLaren', TeamColor=TeamColors( Official='#ff8000', - Default='#ff8000' + FastF1='#ff8000' ) ), 'mercedes': Team( ShortName='Mercedes', TeamColor=TeamColors( Official='#27f4d2', - Default='#27f4d2' + FastF1='#27f4d2' ) ), 'rb': Team( ShortName='RB', TeamColor=TeamColors( Official='#6692ff', - Default='#364aa9' + FastF1='#364aa9' ) ), 'red bull': Team( ShortName='Red Bull', TeamColor=TeamColors( Official='#3671c6', - Default='#0600ef' + FastF1='#0600ef' ) ), 'kick sauber': Team( ShortName='Sauber', TeamColor=TeamColors( Official='#52e252', - Default='#00e700' + FastF1='#00e700' ) ), 'williams': Team( ShortName='Williams', TeamColor=TeamColors( Official='#64c4ff', - Default='#00a0dd' + FastF1='#00a0dd' ) ) } diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index ec9c51783..f73eb18f8 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -196,7 +196,7 @@ def _get_team_color( colormap = _DEFAULT_COLOR_MAP if colormap == 'fastf1': - return team_consts.TeamColor.Default + return team_consts.TeamColor.FastF1 elif colormap == 'official': return team_consts.TeamColor.Official else: @@ -672,7 +672,7 @@ def get_driver_color_mapping( colors = { abb: (Constants[dtm.year] .Teams[driver.team.normalized_value] - .TeamColor.Default) + .TeamColor.FastF1) for abb, driver in dtm.drivers_by_abbreviation.items() } elif colormap == 'official': diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 3d870152e..470ad2163 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -9,8 +9,8 @@ OFFICIAL_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.Official OFFICIAL_RB_COLOR = season2023.Teams['red bull'].TeamColor.Official -DEFAULT_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.Default -DEFAULT_RB_COLOR = season2023.Teams['red bull'].TeamColor.Default +DEFAULT_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.FastF1 +DEFAULT_RB_COLOR = season2023.Teams['red bull'].TeamColor.FastF1 @pytest.mark.parametrize( From 1c0373777596d2794828bdfa17a06a3b090fa326 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:55:16 +0200 Subject: [PATCH 24/31] dynamically update official team colors + refactoring --- fastf1/plotting/_backend.py | 18 +++++- fastf1/plotting/_base.py | 2 + fastf1/plotting/_constants/__init__.py | 10 +-- fastf1/plotting/_constants/base.py | 12 ++-- fastf1/plotting/_constants/season2018.py | 80 +++++++++++++----------- fastf1/plotting/_constants/season2019.py | 68 ++++++++++---------- fastf1/plotting/_constants/season2020.py | 68 ++++++++++---------- fastf1/plotting/_constants/season2021.py | 68 ++++++++++---------- fastf1/plotting/_constants/season2022.py | 68 ++++++++++---------- fastf1/plotting/_constants/season2023.py | 68 ++++++++++---------- fastf1/plotting/_constants/season2024.py | 68 ++++++++++---------- fastf1/plotting/_interface.py | 37 ++++------- fastf1/tests/test_plotting.py | 6 +- 13 files changed, 305 insertions(+), 268 deletions(-) diff --git a/fastf1/plotting/_backend.py b/fastf1/plotting/_backend.py index 6d9aba34a..24b3efa51 100644 --- a/fastf1/plotting/_backend.py +++ b/fastf1/plotting/_backend.py @@ -1,3 +1,4 @@ +import dataclasses import warnings from typing import ( Dict, @@ -52,9 +53,24 @@ def _load_drivers_from_f1_livetiming( if team not in teams: normalized_full_team_name = _normalize_string(team_name).lower() - for ref_team_name in Constants[year].Teams.keys(): + for ref_team_name, team_consts in Constants[year].Teams.items(): if ref_team_name in normalized_full_team_name: team.normalized_value = ref_team_name + + # copy team constants, update the official color if it + # is available from the API and add the constants to the + # team + if team_color := driver_entry.get('TeamColour'): + replacements = {'Official': f"#{team_color}"} + else: + replacements = {} + colors = dataclasses.replace( + team_consts.TeamColor, **replacements + ) + team.constants = dataclasses.replace( + team_consts, TeamColor=colors + ) + break else: warnings.warn(f"Encountered unknown team '{team_name}' while " diff --git a/fastf1/plotting/_base.py b/fastf1/plotting/_base.py index a651f1999..c980092ed 100644 --- a/fastf1/plotting/_base.py +++ b/fastf1/plotting/_base.py @@ -9,6 +9,7 @@ from rapidfuzz import fuzz from fastf1.logger import get_logger +from fastf1.plotting._constants.base import TeamConst _logger = get_logger(__package__) @@ -24,6 +25,7 @@ class _Driver: class _Team: value: str = '' normalized_value: str = '' + constants: TeamConst = None def __init__(self): super().__init__() diff --git a/fastf1/plotting/_constants/__init__.py b/fastf1/plotting/_constants/__init__.py index 65effa114..fa0282add 100644 --- a/fastf1/plotting/_constants/__init__.py +++ b/fastf1/plotting/_constants/__init__.py @@ -9,15 +9,17 @@ season2023, season2024 ) -from fastf1.plotting._constants.base import BaseSeason +from fastf1.plotting._constants.base import BaseSeasonConst -Constants: Dict[str, BaseSeason] = dict() +Constants: Dict[str, BaseSeasonConst] = dict() for year in range(2018, 2025): season = globals()[f"season{year}"] - Constants[str(year)] = BaseSeason(CompoundColors=season.CompoundColors, - Teams=season.Teams) + Constants[str(year)] = BaseSeasonConst( + CompoundColors=season.CompoundColors, + Teams=season.Teams + ) # Deprecated, will be removed for 2025 diff --git a/fastf1/plotting/_constants/base.py b/fastf1/plotting/_constants/base.py index c13798b06..b492fbaee 100644 --- a/fastf1/plotting/_constants/base.py +++ b/fastf1/plotting/_constants/base.py @@ -2,7 +2,7 @@ from typing import Dict -class Compounds: +class CompoundsConst: HyperSoft = "HYPERSOFT" UltraSoft = "ULTRASOFT" SuperSoft = "SUPERSOFT" @@ -17,18 +17,18 @@ class Compounds: @dataclass(frozen=True) -class TeamColors: +class TeamColorsConst: Official: str FastF1: str @dataclass(frozen=True) -class Team: +class TeamConst: ShortName: str - TeamColor: TeamColors + TeamColor: TeamColorsConst @dataclass(frozen=True) -class BaseSeason: +class BaseSeasonConst: CompoundColors: Dict[str, str] - Teams: Dict[str, Team] + Teams: Dict[str, TeamConst] diff --git a/fastf1/plotting/_constants/season2018.py b/fastf1/plotting/_constants/season2018.py index 210cd30c3..c8bb81280 100644 --- a/fastf1/plotting/_constants/season2018.py +++ b/fastf1/plotting/_constants/season2018.py @@ -1,102 +1,106 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'ferrari': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#dc0000', FastF1='#dc0000' ) ), - 'force india': Team( + 'force india': TeamConst( ShortName='Force India', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#f596c8', FastF1='#ff87bc' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#828282', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ff8000', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#00d2be', FastF1='#00f5d0' ) ), - 'racing point': Team( + 'racing point': TeamConst( ShortName='Racing Point', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#f596c8', FastF1='#ff87bc' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#1e41ff', FastF1='#1e41ff' ) ), - 'renault': Team( + 'renault': TeamConst( ShortName='Renault', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#fff500', FastF1='#fff500' ) ), - 'sauber': Team( + 'sauber': TeamConst( ShortName='Sauber', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#9b0000', FastF1='#900000' ) ), - 'toro rosso': Team( + 'toro rosso': TeamConst( ShortName='Toro Rosso', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#469bff', FastF1='#2b4562' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ffffff', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.HyperSoft: "#feb1c1", - Compounds.UltraSoft: "#b24ba7", - Compounds.SuperSoft: "#fc2b2a", - Compounds.Soft: "#ffd318", - Compounds.Medium: "#f0f0f0", - Compounds.Hard: "#00a2f5", - Compounds.SuperHard: "#fd7d3c", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.HyperSoft: "#feb1c1", + CompoundsConst.UltraSoft: "#b24ba7", + CompoundsConst.SuperSoft: "#fc2b2a", + CompoundsConst.Soft: "#ffd318", + CompoundsConst.Medium: "#f0f0f0", + CompoundsConst.Hard: "#00a2f5", + CompoundsConst.SuperHard: "#fd7d3c", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2019.py b/fastf1/plotting/_constants/season2019.py index 19c296f6c..7c786d602 100644 --- a/fastf1/plotting/_constants/season2019.py +++ b/fastf1/plotting/_constants/season2019.py @@ -1,91 +1,95 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alfa romeo': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alfa romeo': TeamConst( ShortName='Alfa Romeo', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#9b0000', FastF1='#900000' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#bd9e57', FastF1='#bd9e57' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#dc0000', FastF1='#da291c' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ff8700', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#00d2be', FastF1='#00d2be' ) ), - 'racing point': Team( + 'racing point': TeamConst( ShortName='Racing Point', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#f596c8', FastF1='#ff87bc' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#1e41ff', FastF1='#1e41ff' ) ), - 'renault': Team( + 'renault': TeamConst( ShortName='Renault', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#fff500', FastF1='#fff500' ) ), - 'toro rosso': Team( + 'toro rosso': TeamConst( ShortName='Toro Rosso', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#469bff', FastF1='#2b4562' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ffffff', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2020.py b/fastf1/plotting/_constants/season2020.py index d4cd71606..c4f13ddfe 100644 --- a/fastf1/plotting/_constants/season2020.py +++ b/fastf1/plotting/_constants/season2020.py @@ -1,91 +1,95 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alfa romeo': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alfa romeo': TeamConst( ShortName='Alfa Romeo', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#9B0000', FastF1='#900000' ) ), - 'alphatauri': Team( + 'alphatauri': TeamConst( ShortName='AlphaTauri', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ffffff', FastF1='#2b4562' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#dc0000', FastF1='#dc0000' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#787878', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ff8700', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#00d2be', FastF1='#00d2be' ) ), - 'racing point': Team( + 'racing point': TeamConst( ShortName='Racing Point', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#f596c8', FastF1='#ff87bc' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#1e41ff', FastF1='#1e41ff' ) ), - 'renault': Team( + 'renault': TeamConst( ShortName='Renault', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#fff500', FastF1='#fff500' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#0082fa', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2021.py b/fastf1/plotting/_constants/season2021.py index 1807ae553..3a03b274e 100644 --- a/fastf1/plotting/_constants/season2021.py +++ b/fastf1/plotting/_constants/season2021.py @@ -1,91 +1,95 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alfa romeo': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alfa romeo': TeamConst( ShortName='Alfa Romeo', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#900000', FastF1='#900000' ) ), - 'alphatauri': Team( + 'alphatauri': TeamConst( ShortName='AlphaTauri', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#2b4562', FastF1='#2b4562' ) ), - 'alpine': Team( + 'alpine': TeamConst( ShortName='Alpine', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#0090ff', FastF1='#0755ab' ) ), - 'aston martin': Team( + 'aston martin': TeamConst( ShortName='Aston Martin', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#006f62', FastF1='#00665e' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#dc0004', FastF1='#dc0004' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ffffff', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ff9800', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#00d2be', FastF1='#00f5d0' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#0600ef', FastF1='#0600ef' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#005aff', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2022.py b/fastf1/plotting/_constants/season2022.py index a6bc7bc4e..4f09b282c 100644 --- a/fastf1/plotting/_constants/season2022.py +++ b/fastf1/plotting/_constants/season2022.py @@ -1,91 +1,95 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alfa romeo': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alfa romeo': TeamConst( ShortName='Alfa Romeo', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#b12039', FastF1='#900000' ) ), - 'alphatauri': Team( + 'alphatauri': TeamConst( ShortName='AlphaTauri', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#4e7c9b', FastF1='#2b4562' ) ), - 'alpine': Team( + 'alpine': TeamConst( ShortName='Alpine', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#2293d1', FastF1='#fe86bc' ) ), - 'aston martin': Team( + 'aston martin': TeamConst( ShortName='Aston Martin', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#2d826d', FastF1='#00665e' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ed1c24', FastF1='#da291c' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#b6babd', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#f58020', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#6cd3bf', FastF1='#00f5d0' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#1e5bc6', FastF1='#0600ef' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#37bedd', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2023.py b/fastf1/plotting/_constants/season2023.py index 7ba57cc8d..be88f828e 100644 --- a/fastf1/plotting/_constants/season2023.py +++ b/fastf1/plotting/_constants/season2023.py @@ -1,91 +1,95 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alfa romeo': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alfa romeo': TeamConst( ShortName='Alfa Romeo', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#C92D4B', FastF1='#900000' ) ), - 'alphatauri': Team( + 'alphatauri': TeamConst( ShortName='AlphaTauri', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#5E8FAA', FastF1='#2b4562' ) ), - 'alpine': Team( + 'alpine': TeamConst( ShortName='Alpine', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#2293D1', FastF1='#fe86bc' ) ), - 'aston martin': Team( + 'aston martin': TeamConst( ShortName='Aston Martin', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#358C75', FastF1='#00665e' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#F91536', FastF1='#da291c' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#b6babd', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#F58020', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#6CD3BF', FastF1='#00f5d0' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#3671C6', FastF1='#0600ef' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#37BEDD', FastF1='#00a0dd' ) ) } -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_constants/season2024.py b/fastf1/plotting/_constants/season2024.py index 3e93c258e..8d45dcbcc 100644 --- a/fastf1/plotting/_constants/season2024.py +++ b/fastf1/plotting/_constants/season2024.py @@ -1,79 +1,83 @@ from typing import Dict from fastf1.plotting._constants.base import ( - Compounds, - Team, - TeamColors + CompoundsConst, + TeamColorsConst, + TeamConst ) -Teams: Dict[str, Team] = { - 'alpine': Team( +# NOTE: the team constants are copied when loading the driver-team-mapping +# and values may be modified there, it the used API provides different values + + +Teams: Dict[str, TeamConst] = { + 'alpine': TeamConst( ShortName='Alpine', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#0093cc', FastF1='#ff87bc' ) ), - 'aston martin': Team( + 'aston martin': TeamConst( ShortName='Aston Martin', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#229971', FastF1='#00665f' ) ), - 'ferrari': Team( + 'ferrari': TeamConst( ShortName='Ferrari', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#e8002d', FastF1='#e8002d' ) ), - 'haas': Team( + 'haas': TeamConst( ShortName='Haas', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#b6babd', FastF1='#b6babd' ) ), - 'mclaren': Team( + 'mclaren': TeamConst( ShortName='McLaren', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#ff8000', FastF1='#ff8000' ) ), - 'mercedes': Team( + 'mercedes': TeamConst( ShortName='Mercedes', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#27f4d2', FastF1='#27f4d2' ) ), - 'rb': Team( + 'rb': TeamConst( ShortName='RB', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#6692ff', FastF1='#364aa9' ) ), - 'red bull': Team( + 'red bull': TeamConst( ShortName='Red Bull', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#3671c6', FastF1='#0600ef' ) ), - 'kick sauber': Team( + 'kick sauber': TeamConst( ShortName='Sauber', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#52e252', FastF1='#00e700' ) ), - 'williams': Team( + 'williams': TeamConst( ShortName='Williams', - TeamColor=TeamColors( + TeamColor=TeamColorsConst( Official='#64c4ff', FastF1='#00a0dd' ) @@ -81,12 +85,12 @@ } # TODO: future proofing? -CompoundColors: Dict[Compounds, str] = { - Compounds.Soft: "#da291c", - Compounds.Medium: "#ffd12e", - Compounds.Hard: "#f0f0ec", - Compounds.Intermediate: "#43b02a", - Compounds.Wet: "#0067ad", - Compounds.Unknown: "#00ffff", - Compounds.TestUnknown: "#434649" +CompoundColors: Dict[CompoundsConst, str] = { + CompoundsConst.Soft: "#da291c", + CompoundsConst.Medium: "#ffd12e", + CompoundsConst.Hard: "#f0f0ec", + CompoundsConst.Intermediate: "#43b02a", + CompoundsConst.Wet: "#0067ad", + CompoundsConst.Unknown: "#00ffff", + CompoundsConst.TestUnknown: "#434649" } diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index f73eb18f8..f130b2fc8 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -19,7 +19,6 @@ _normalize_string, _Team ) -from fastf1.plotting._constants import Constants from fastf1.plotting._constants import Constants as _Constants @@ -183,22 +182,20 @@ def _get_team_color( ) -> str: dtm = _get_driver_team_mapping(session) - if dtm.year not in Constants.keys(): + if dtm.year not in _Constants.keys(): raise ValueError(f"No team colors for year '{dtm.year}'") - team_name = _get_team( + team = _get_team( identifier, session, exact_match=exact_match - ).normalized_value - - team_consts = Constants[dtm.year].Teams[team_name] + ) if colormap == 'default': colormap = _DEFAULT_COLOR_MAP if colormap == 'fastf1': - return team_consts.TeamColor.FastF1 + return team.constants.TeamColor.FastF1 elif colormap == 'official': - return team_consts.TeamColor.Official + return team.constants.TeamColor.Official else: raise ValueError(f"Invalid colormap '{colormap}'") @@ -229,9 +226,7 @@ def get_team_name( team = _get_team(identifier, session, exact_match=exact_match) if short: - dtm = _get_driver_team_mapping(session) - team_consts = Constants[dtm.year].Teams[team.normalized_value] - return team_consts.ShortName + return team.constants.ShortName return team.value @@ -262,9 +257,7 @@ def get_team_name_by_driver( team = driver.team if short: - dtm = _get_driver_team_mapping(session) - team_consts = Constants[dtm.year].Teams[team.normalized_value] - return team_consts.ShortName + return team.constants.ShortName return team.value @@ -645,7 +638,7 @@ def get_compound_mapping(session: Session) -> Dict[str, str]: dictionary mapping compound names to RGB hex colors """ year = str(session.event['EventDate'].year) - return Constants[year].CompoundColors.copy() + return _Constants[year].CompoundColors.copy() def get_driver_color_mapping( @@ -670,16 +663,12 @@ def get_driver_color_mapping( if colormap == 'fastf1': colors = { - abb: (Constants[dtm.year] - .Teams[driver.team.normalized_value] - .TeamColor.FastF1) + abb: driver.team.constants.TeamColor.FastF1 for abb, driver in dtm.drivers_by_abbreviation.items() } elif colormap == 'official': colors = { - abb: (Constants[dtm.year] - .Teams[driver.team.normalized_value] - .TeamColor.Official) + abb: driver.team.constants.TeamColor.Official for abb, driver in dtm.drivers_by_abbreviation.items() } else: @@ -697,8 +686,8 @@ def list_team_names(session: Session) -> List[str]: def list_short_team_names(session: Session) -> List[str]: """Returns a list of short team names of all teams in the ``session``.""" dtm = _get_driver_team_mapping(session) - return list(Constants[dtm.year].Teams[team].ShortName - for team in dtm.teams_by_normalized.keys()) + return list(team.constants.ShortName + for team in dtm.teams_by_normalized.values()) def list_driver_abbreviations(session: Session) -> List[str]: @@ -716,7 +705,7 @@ def list_driver_names(session: Session) -> List[str]: def list_compounds(session: Session) -> List[str]: """Returns a list of all compound names for this season (not session).""" year = str(session.event['EventDate'].year) - return list(Constants[year].CompoundColors.keys()) + return list(_Constants[year].CompoundColors.keys()) def add_sorted_driver_legend(ax: matplotlib.axes.Axes, session: Session): diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 470ad2163..50bbc571c 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -4,7 +4,7 @@ import fastf1 import fastf1.plotting from fastf1.plotting._constants import season2023 -from fastf1.plotting._constants.base import Compounds +from fastf1.plotting._constants.base import CompoundsConst OFFICIAL_MERC_COLOR = season2023.Teams['mercedes'].TeamColor.Official @@ -325,10 +325,10 @@ def test_get_driver_style_custom_style(): def test_get_compound_color(): session = fastf1.get_session(2023, 10, 'R') assert (fastf1.plotting.get_compound_color('HARD', session) - == season2023.CompoundColors[Compounds.Hard]) + == season2023.CompoundColors[CompoundsConst.Hard]) assert (fastf1.plotting.get_compound_color('sOfT', session) - == season2023.CompoundColors[Compounds.Soft]) + == season2023.CompoundColors[CompoundsConst.Soft]) with pytest.raises(KeyError): fastf1.plotting.get_compound_color('HYPERSOFT', session) From 6c94a3ef647a1746e99177fcd150dcac19a55baf Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:57:35 +0200 Subject: [PATCH 25/31] remove forgotten old fuzzy matcher --- fastf1/plotting/_base.py | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/fastf1/plotting/_base.py b/fastf1/plotting/_base.py index c980092ed..e1a4cdfc2 100644 --- a/fastf1/plotting/_base.py +++ b/fastf1/plotting/_base.py @@ -1,13 +1,9 @@ import unicodedata from typing import ( Dict, - List, - Sequence, - TypeVar + List ) -from rapidfuzz import fuzz - from fastf1.logger import get_logger from fastf1.plotting._constants.base import TeamConst @@ -52,32 +48,6 @@ def __init__( self.teams_by_normalized[team.normalized_value] = team -S = TypeVar('S', bound=str) - - -def _fuzzy_matcher(identifier: str, reference: Sequence[S]) -> S: - # do fuzzy string matching - key_ratios = list() - for existing_key in reference: - ratio = fuzz.ratio(identifier, existing_key) - key_ratios.append((ratio, existing_key)) - key_ratios.sort(reverse=True) - if ((key_ratios[0][0] < 35) - or (key_ratios[0][0] / key_ratios[1][0] < 1.2)): - # ensure that the best match has a minimum accuracy (35 out of - # 100) and that it has a minimum confidence (at least 20% - # better than second best) - raise KeyError - if key_ratios[0][0] != 100: - _logger.warning( - ("Correcting invalid user input " - f"'{identifier}' to '{key_ratios[0][1]}'." - ) - ) - best_matched_key = key_ratios[0][1] - return best_matched_key - - def _normalize_string(name: str) -> str: # removes accents from a string and returns the closest possible # ascii representation (https://stackoverflow.com/a/518232) From 2ded0c02c551755fd7ebbf4950c78d5e329c7bcf Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:36:39 +0200 Subject: [PATCH 26/31] add functionality for overriding team constants --- fastf1/plotting/__init__.py | 2 ++ fastf1/plotting/_interface.py | 43 +++++++++++++++++++++++++++++++++++ fastf1/tests/test_plotting.py | 28 +++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py index 0b2d0e639..274f220e1 100644 --- a/fastf1/plotting/__init__.py +++ b/fastf1/plotting/__init__.py @@ -31,6 +31,7 @@ list_driver_names, list_short_team_names, list_team_names, + override_team_constants, set_default_colormap ) from fastf1.plotting._plotting import ( # noqa: F401 @@ -62,6 +63,7 @@ 'list_driver_names', 'list_team_names', 'list_short_team_names', + 'override_team_constants', 'set_default_colormap', 'setup_mpl', diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index f130b2fc8..bc4d4c45a 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -1,8 +1,10 @@ +import dataclasses from typing import ( Any, Dict, List, Literal, + Optional, Sequence, Union ) @@ -775,3 +777,44 @@ def set_default_colormap(colormap: str): if colormap not in ('fastf1', 'official'): raise ValueError(f"Invalid colormap '{colormap}'") _DEFAULT_COLOR_MAP = colormap + + +def override_team_constants( + identifier: str, + session: Session, + *, + short_name: Optional[str] = None, + official_color: Optional[str] = None, + fastf1_color: Optional[str] = None +): + """ + Override the default team constants for a specific team. + + This function is intended for advanced users who want to customize the + default team constants. The changes are only applied for the current + session and do not persist. + + Args: + identifier: A part of the team name. Note that this function does + not support fuzzy matching and will raise a ``KeyError`` if no + exact and unambiguous match is found! + session: The session for which the override should be applied + short_name: New value for the short name of the team + official_color: New value for the team color in the "official" + color map; must be a hexadecimal RGB color code + fastf1_color: New value for the team color in the "fastf1" color map; + must be a hexadecimal RGB color code + """ + team = _get_team(identifier, session, exact_match=True) + + colors = team.constants.TeamColor + if official_color is not None: + colors = dataclasses.replace(colors, Official=official_color) + if fastf1_color is not None: + colors = dataclasses.replace(colors, FastF1=fastf1_color) + if (official_color is not None) or (fastf1_color is not None): + team.constants = dataclasses.replace(team.constants, TeamColor=colors) + + if short_name is not None: + team.constants = dataclasses.replace(team.constants, + ShortName=short_name) diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 50bbc571c..2f44e929d 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -424,3 +424,31 @@ def test_add_sorted_lapnumber_axis(): # within Mercedes, Hamilton has the lower number assert ([txt.get_text() for txt in legend.texts] == ['VER', 'PER', 'HAM', 'RUS']) + + +def test_override_team_constants(): + session = fastf1.get_session(2023, 10, 'R') + fastf1.plotting.override_team_constants( + 'Haas', session, + short_name='Gene', + fastf1_color='#badbad', + official_color='#bada55' + ) + + assert fastf1.plotting.get_team_name('Haas', session) == 'Haas F1 Team' + assert fastf1.plotting.get_team_name('Haas', session, short=True) == 'Gene' + + assert fastf1.plotting.get_team_color( + 'Haas', session, colormap='fastf1' + ) == '#badbad' + + assert fastf1.plotting.get_team_color( + 'Haas', session, colormap='official' + ) == '#bada55' + + # cleanup: explicitly clear the driver-team-mapping to avoid side effects + # in other tests + fastf1.plotting._interface._DRIVER_TEAM_MAPPINGS = dict() + + if fastf1.plotting.get_team_name('Haas', session, short=True) != 'Haas': + raise RuntimeError("Test cleanup failed!") From b585cbd28b1c395ada7087a32baa2c0292841371 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:37:57 +0200 Subject: [PATCH 27/31] fix slightly incorrect example in docs --- fastf1/plotting/_interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index bc4d4c45a..39b44ef0f 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -215,8 +215,8 @@ def get_team_name( Alternatively, a shortened version of the team name can be returned. The short version is intended for saving space when annotating plots and may - skip parts of the official team name, for example "Scuderia Ferrari" - becomes just "Ferrari". + skip parts of the official team name, for example "Haas F1 Team" + becomes just "Haas". Args: identifier: a recognizable part of the team name From 6407c135ceac38661988c59c8fbf6d5e2ee82c49 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:52:35 +0200 Subject: [PATCH 28/31] add missing functions to doc summary --- docs/plotting.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/plotting.rst b/docs/plotting.rst index 7aa8acfe3..f0954bae2 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -98,6 +98,7 @@ List all Names and Abbreviations for Drivers/Teams in a Session :autosummary-members: get_compound_mapping, get_driver_color_mapping, + list_compounds, list_driver_abbreviations, list_driver_names, list_short_team_names, @@ -112,7 +113,19 @@ Plot Styling :no-members: :autosummary: :autosummary-members: - add_sorted_driver_legend + add_sorted_driver_legend, + set_default_colormap + + +Advanced Functionality +^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: fastf1.plotting + :noindex: + :no-members: + :autosummary: + :autosummary-members: + override_team_constants Deprecated Functionality From a9d23cf30adaff0bb03c1df1279453cad2ed222e Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:58:42 +0200 Subject: [PATCH 29/31] api consistency re team names --- fastf1/plotting/__init__.py | 2 -- fastf1/plotting/_interface.py | 36 +++++++++++++++++++++-------------- fastf1/tests/test_plotting.py | 2 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/fastf1/plotting/__init__.py b/fastf1/plotting/__init__.py index 274f220e1..691d8ce99 100644 --- a/fastf1/plotting/__init__.py +++ b/fastf1/plotting/__init__.py @@ -29,7 +29,6 @@ list_compounds, list_driver_abbreviations, list_driver_names, - list_short_team_names, list_team_names, override_team_constants, set_default_colormap @@ -62,7 +61,6 @@ 'list_driver_abbreviations', 'list_driver_names', 'list_team_names', - 'list_short_team_names', 'override_team_constants', 'set_default_colormap', 'setup_mpl', diff --git a/fastf1/plotting/_interface.py b/fastf1/plotting/_interface.py index 39b44ef0f..8663e5935 100644 --- a/fastf1/plotting/_interface.py +++ b/fastf1/plotting/_interface.py @@ -210,13 +210,12 @@ def get_team_name( exact_match: bool = False ) -> str: """ - Get a full team name based on a recognizable and identifiable part of - the team name. + Get a full or shortened team name based on a recognizable and identifiable + part of the team name. - Alternatively, a shortened version of the team name can be returned. The - short version is intended for saving space when annotating plots and may - skip parts of the official team name, for example "Haas F1 Team" - becomes just "Haas". + The short version of the team name is intended for saving space when + annotating plots and may skip parts of the official team name, for example + "Haas F1 Team" becomes just "Haas". Args: identifier: a recognizable part of the team name @@ -679,17 +678,26 @@ def get_driver_color_mapping( return colors -def list_team_names(session: Session) -> List[str]: - """Returns a list of full team names of all teams in the ``session``.""" - dtm = _get_driver_team_mapping(session) - return list(team.value for team in dtm.teams_by_normalized.values()) +def list_team_names(session: Session, *, short: bool = False) -> List[str]: + """Returns a list of team names of all teams in the ``session``. + By default, the full team names are returned. Use the ``short`` argument + to get shortened versions of the team names instead. + + Args: + session: the session for which the data should be obtained + short: if True, a list of the shortened team names is returned -def list_short_team_names(session: Session) -> List[str]: - """Returns a list of short team names of all teams in the ``session``.""" + Returns: + a list of team names + """ dtm = _get_driver_team_mapping(session) - return list(team.constants.ShortName - for team in dtm.teams_by_normalized.values()) + + if short: + return list(team.constants.ShortName + for team in dtm.teams_by_normalized.values()) + + return list(team.value for team in dtm.teams_by_normalized.values()) def list_driver_abbreviations(session: Session) -> List[str]: diff --git a/fastf1/tests/test_plotting.py b/fastf1/tests/test_plotting.py index 2f44e929d..493c49bad 100644 --- a/fastf1/tests/test_plotting.py +++ b/fastf1/tests/test_plotting.py @@ -368,7 +368,7 @@ def test_list_team_names(): def test_list_short_team_names(): session = fastf1.get_session(2023, 10, 'R') - names = fastf1.plotting.list_short_team_names(session) + names = fastf1.plotting.list_team_names(session, short=True) assert 'Red Bull' in names assert 'Haas' in names From 4e789b416b05937e53d6abc3d8fcad8afa57fd32 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sat, 6 Jul 2024 00:01:47 +0200 Subject: [PATCH 30/31] update legacy constants to match current public API --- fastf1/plotting/_constants/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastf1/plotting/_constants/__init__.py b/fastf1/plotting/_constants/__init__.py index fa0282add..34fe5fbc4 100644 --- a/fastf1/plotting/_constants/__init__.py +++ b/fastf1/plotting/_constants/__init__.py @@ -89,6 +89,7 @@ "alexander albon": "#005aff", "logan sargeant": "#012564", "zak osullivan": "#1b3d97", + "franco colapinto": "#639aff" } @@ -113,4 +114,4 @@ 'HAM': 'lewis hamilton', 'RUS': 'george russell', 'VES': 'frederik vesti', 'ALB': 'alexander albon', 'SAR': 'logan sargeant', - 'OSU': 'zak osullivan'} + 'OSU': 'zak osullivan', 'COL': 'franco colapinto'} From d9d8a72c012e32616bdaaaf3c3f43a641d833e7f Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:18:54 +0200 Subject: [PATCH 31/31] fix doc build warning --- docs/plotting.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/plotting.rst b/docs/plotting.rst index f0954bae2..61fe2e060 100644 --- a/docs/plotting.rst +++ b/docs/plotting.rst @@ -101,7 +101,6 @@ List all Names and Abbreviations for Drivers/Teams in a Session list_compounds, list_driver_abbreviations, list_driver_names, - list_short_team_names, list_team_names