F1 circuit layouts with year-by-year SVGs — manually traced track variations
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

338 рядки
15KB

  1. import requests
  2. import json
  3. import time
  4. import os
  5. # Please convert this list into a dictionary of country -> locality/city -> Circuit name -> layouts (some circuits have multiple layouts)
  6. # it should be available_circuits = { "Argentina": { "Buenos Aires": { "Autódromo Juan y Oscar Gálvez": {1953: "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json", 1954: "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json", ...} } } }
  7. available_circuits = [
  8. "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json",
  9. "France - Rouen - Circuit de Rouen-Les-Essarts - 1957-1968.geo.json",
  10. "Singapore - Singapore - Marina Bay Street Circuit - 2008-.geo.json",
  11. "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1971-1973.geo.json",
  12. "Germany - Berlin - AVUS - 1921-1959.geo.json",
  13. "South Africa - East London - Prince George Circuit - 1934-1967.geo.json",
  14. "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1974-1981.geo.json",
  15. "Germany - Hockenheim - Hockenheimring - 1932-.geo.json",
  16. "South Africa - Kyalami - Kyalami Grand Prix Circuit - 1961-1985.geo.json",
  17. "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1995-1998.geo.json",
  18. "Germany - Nürburg - Nürburgring - 1927-.geo.json",
  19. "South Africa - Kyalami - Kyalami Grand Prix Circuit - 1992-1993.geo.json",
  20. "Australia - Adelaide - Adelaide Street Circuit - 1985-1995.geo.json",
  21. "Great Britain - Aintree - Aintree Circuit - 1954-1962.geo.json",
  22. "Spain - Barcelona - Circuit de Barcelona-Catalunya - 1991-.geo.json",
  23. "Australia - Melbourne - Albert Park Circuit - 1953-.geo.json",
  24. "Great Britain - Brands Hatch - Brands Hatch Circuit - 1964-1974.geo.json",
  25. "Spain - Jarama - Circuito del Jarama - 1967-1981.geo.json",
  26. "Austria - Spielberg - A1 Ring - 1997-2003.geo.json",
  27. "Great Britain - Brands Hatch - Brands Hatch Circuit - 1976-1987.geo.json",
  28. "Spain - Jerez - Circuito de Jerez - 1985-1991.geo.json",
  29. "Austria - Spielberg - Österreichring - 1969-1976.geo.json",
  30. "Great Britain - Silverstone - Silverstone Circuit - 1948-.geo.json",
  31. "Spain - Jerez - Circuito de Jerez - 1994-.geo.json",
  32. "Austria - Spielberg - Österreichring - 1977-1987.geo.json",
  33. "Hungary - Budapest - Hungaroring - 1986-.geo.json",
  34. "Spain - Montjuïc - Montjuïc Circuit - 1969-1975.geo.json",
  35. "Austria - Spielberg - Red Bull Ring - 2014-.geo.json",
  36. "Italy - Imola - Autodromo Enzo e Dino Ferrari - 1953-.geo.json",
  37. "Spain - Pedralbes - Pedralbes Circuit - 1946-1954.geo.json",
  38. "Austria - Zeltweg - Österreichring - 1963-1968.geo.json",
  39. "Italy - Monza - Autodromo Nazionale Monza - 1922-.geo.json",
  40. "Spain - Valencia - Valencia Street Circuit - 2008-2012.geo.json",
  41. "Azerbaijan - Baku - Baku City Circuit - 2016-.geo.json",
  42. "Italy - Pescara - Pescara Circuit - 1924-1957.geo.json",
  43. "Sweden - Anderstorp - Scandinavian Raceway - 1968-1977.geo.json",
  44. "Bahrain - Sakhir - Bahrain International Circuit - 2002-.geo.json",
  45. "Italy - Scarperia e San Piero - Autodromo Internazionale del Mugello - 1914-.geo.json",
  46. "Sweden - Anderstorp - Scandinavian Raceway - 1978-1997.geo.json",
  47. "Bahrain - Sakhir - Bahrain International Circuit - 2010.geo.json",
  48. "Japan - Aida - TI Circuit Aida - 1990-1997.geo.json",
  49. "Switzerland - Bern - Circuit Bremgarten - 1934-1954.geo.json",
  50. "Belgium - Nivelles - Circuit Nivelles-Baulers - 1971-1974.geo.json",
  51. "Japan - Fuji - Fuji Speedway - 1976-1977.geo.json",
  52. "Turkey - Istanbul - Intercity Istanbul Park - 2005-.geo.json",
  53. "Belgium - Spa Francorchamps - Circuit de Spa-Francorchamps - 1950-1978.geo.json",
  54. "Japan - Fuji - Fuji Speedway - 2007-.geo.json",
  55. "United Arab Emirates - Yas Marina - Yas Marina Circuit - 2009-.geo.json",
  56. "Belgium - Spa Francorchamps - Circuit de Spa-Francorchamps - 1983-.geo.json",
  57. "Japan - Suzuka - Suzuka International Racing Course - 1962-.geo.json",
  58. "USA - Austin - Circuit of the Americas - 2012-.geo.json",
  59. "Belgium - Zolder - Circuit Zolder - 1963-.geo.json",
  60. "Malaysia - Sepang - Sepang International Circuit - 1999-.geo.json",
  61. "USA - Dallas - Fair Park - 1984.geo.json",
  62. "Brazil - Jacarepaguá - Autódromo Internacional Nelson Piquet - 1977-.geo.json",
  63. "Mexico - Magdalena Mixhuca - Autódromo Magdalena Mixhuca - 1959-1970.geo.json",
  64. "USA - Detroit - Detroit Street Circuit - 1982-1988.geo.json",
  65. "Brazil - Sao Paulo - Autódromo José Carlos Pace - Interlagos - 1940-.geo.json",
  66. "Mexico - Mexico City - Autódromo Hermanos Rodríguez - 1962-.geo.json",
  67. "USA - Indianapolis - Indianapolis Motor Speedway - 1909-.geo.json",
  68. "Canada - Montreal - Circuit Gilles-Villeneuve - 1978-.geo.json",
  69. "Monaco - Monaco - Circuit de Monaco - 1929-.geo.json",
  70. "USA - Las Vegas - Las Vegas Street Circuit - 2023-.geo.json",
  71. "Canada - Mont-Tremblant - Circuit Mont-Tremblant - 1964-1970.geo.json",
  72. "Morocco - Casablanca - Ain-Diab Circuit - 1957-1958.geo.json",
  73. "USA - Long Beach - Long Beach Grand Prix Circuit - 1976-1981.geo.json",
  74. "Canada - Mosport - Mosport Park - 1961-1977.geo.json",
  75. "Netherlands - Zandvoort - Circuit Zandvoort - 1948-1971.geo.json",
  76. "USA - Long Beach - Long Beach Grand Prix Circuit - 1982.geo.json",
  77. "China - Shanghai - Shanghai International Circuit - 2004-.geo.json",
  78. "Netherlands - Zandvoort - Circuit Zandvoort - 1972-1985.geo.json",
  79. "USA - Long Beach - Long Beach Grand Prix Circuit - 1983.geo.json",
  80. "France - Clermont-Ferrand - Circuit de Charade - 1958-1988.geo.json",
  81. "Netherlands - Zandvoort - Circuit Zandvoort - 2021-.geo.json",
  82. "USA - Miami - Miami International Autodrome - 2022-.geo.json",
  83. "France - Dijon-Prenois - Circuit de Dijon-Prenois - 1972-1984.geo.json",
  84. "Portugal - Estoril - Autódromo do Estoril - 1972-.geo.json",
  85. "USA - Phoenix - Phoenix Street Circuit - 1989-1990.geo.json",
  86. "France - Le Castellet - Circuit Paul Ricard - 1969-.geo.json",
  87. "Portugal - Monsanto - Monsanto Park Circuit - 1954-1959.geo.json",
  88. "USA - Phoenix - Phoenix Street Circuit - 1991.geo.json",
  89. "France - Le Mans - Circuit de la Sarthe - 1923-1966.geo.json",
  90. "Portugal - Oporto - Circuito da Boavista - 1958-1960.geo.json",
  91. "USA - Riverside - Riverside International Raceway - 1960.geo.json",
  92. "France - Magny-Cours - Circuit de Nevers Magny-Cours - 1960-.geo.json",
  93. "Portugal - Portimão - Autódromo Internacional do Algarve - 2008-.geo.json",
  94. "USA - Sebring - Sebring International Raceway - 1959.geo.json",
  95. "France - Reims - Circuit de Reims-Gueux - 1926-1951.geo.json",
  96. "Qatar - Lusail - Losail International Circuit - 2004-.geo.json",
  97. "USA - Watkins Glen - Watkins Glen International - 1948-1980.geo.json",
  98. "France - Reims - Circuit de Reims-Gueux - 1952-.geo.json",
  99. "Russia - Sochi - Sochi Autodrom - 2014-.geo.json",
  100. "France - Rouen - Circuit de Rouen-Les-Essarts - 1952.geo.json",
  101. "Saudi Arabia - Jeddah - Jeddah Corniche Circuit - 2021-.geo.json"
  102. ]
  103. def fetch_all_grand_prix_data():
  104. """
  105. Fetches all Formula 1 Grand Prix data from the Ergast API across multiple pages
  106. and returns the races.
  107. """
  108. base_url = "https://ergast.com/api/f1.json"
  109. limit = 100 # Maximum number of results per page
  110. offset = 0
  111. all_races = []
  112. total_races = None
  113. print("Fetching Grand Prix data from Ergast API...")
  114. while True:
  115. # Construct URL with pagination parameters
  116. url = f"{base_url}?limit={limit}&offset={offset}"
  117. print(f"Fetching data from offset {offset}...")
  118. # Add a small delay to avoid hitting rate limits
  119. time.sleep(0.5)
  120. # Make the request
  121. response = requests.get(url)
  122. # Check if request was successful
  123. if response.status_code != 200:
  124. print(f"Error fetching data: HTTP {response.status_code}")
  125. print(response.text)
  126. break
  127. # Parse the JSON response
  128. data = response.json()
  129. # Get total number of races if not already set
  130. if total_races is None:
  131. total_races = int(data['MRData']['total'])
  132. print(f"Total races to fetch: {total_races}")
  133. # Extract the races from this page
  134. races = data['MRData']['RaceTable'].get('Races', [])
  135. all_races.extend(races)
  136. # Update the offset for the next page
  137. offset += limit
  138. # Check if we've fetched all data
  139. if offset >= total_races:
  140. break
  141. print(f"Successfully fetched {len(all_races)} races.")
  142. return all_races
  143. def get_circuit_file_mapping():
  144. """
  145. Creates a mapping of circuit information to corresponding circuit GeoJSON files.
  146. """
  147. circuit_mapping = {}
  148. # Get circuit files from the circuits directory
  149. circuits_dir = "circuits"
  150. if os.path.exists(circuits_dir):
  151. circuit_files = [f for f in os.listdir(circuits_dir) if f.endswith('.geo.json')]
  152. for file_name in circuit_files:
  153. file_path = os.path.join(circuits_dir, file_name)
  154. try:
  155. with open(file_path, 'r', encoding='utf-8') as f:
  156. data = json.load(f)
  157. if 'features' in data and len(data['features']) > 0:
  158. feature = data['features'][0]
  159. if 'properties' in feature:
  160. props = feature['properties']
  161. if 'id' in props and 'Name' in props and 'Location' in props and 'seasons' in props:
  162. circuit_id = props['id']
  163. circuit_name = props['Name']
  164. location = props['Location']
  165. seasons = props['seasons']
  166. # Create a key for each season this circuit was used
  167. for season in seasons:
  168. key = (circuit_name, location, season)
  169. circuit_mapping[key] = file_name
  170. except Exception as e:
  171. print(f"Error processing circuit file {file_name}: {e}")
  172. return circuit_mapping
  173. def create_grand_prix_data(races, circuit_mapping):
  174. """
  175. Create a dictionary of grand prix organized by name and season.
  176. Format:
  177. {
  178. "Belgian Grand Prix": {
  179. "1953": {
  180. "circuit": "belgium-circuit.geo.json",
  181. "date": "1953-06-22"
  182. }
  183. }
  184. }
  185. """
  186. grand_prix_data = {}
  187. for race in races:
  188. race_name = race.get('raceName', 'Unknown Grand Prix')
  189. season = race.get('season', 'Unknown')
  190. # Create the GP entry if it doesn't exist
  191. if race_name not in grand_prix_data:
  192. grand_prix_data[race_name] = {}
  193. # Extract circuit info
  194. circuit = race.get('Circuit', {})
  195. circuit_name = circuit.get('circuitName', 'Unknown Circuit')
  196. location = circuit.get('Location', {})
  197. locality = location.get('locality', 'Unknown')
  198. # Create season entry
  199. season_entry = {
  200. "date": race.get('date', ''),
  201. "circuit_name": circuit_name,
  202. "location": locality,
  203. "country": location.get('country', 'Unknown'),
  204. "round": race.get('round', '')
  205. }
  206. # Try to match with a circuit file
  207. circuit_key = (circuit_name, locality, int(season))
  208. if circuit_key in circuit_mapping:
  209. season_entry["circuit"] = circuit_mapping[circuit_key]
  210. else:
  211. # Try to find a close match
  212. for (name, loc, year), file_name in circuit_mapping.items():
  213. if name == circuit_name and loc == locality:
  214. season_entry["circuit"] = file_name
  215. break
  216. # Add to the grand prix data
  217. grand_prix_data[race_name][season] = season_entry
  218. return grand_prix_data
  219. def create_seasons_data(races):
  220. """
  221. Create a dictionary of races organized by season and round.
  222. Format:
  223. {
  224. "1950": {
  225. "1": {
  226. "name": "British Grand Prix",
  227. "date": "1950-05-13",
  228. "circuit": {...}
  229. }
  230. }
  231. }
  232. """
  233. seasons_data = {}
  234. for race in races:
  235. season = race.get('season', 'Unknown')
  236. round_num = race.get('round', 'Unknown')
  237. # Create the season entry if it doesn't exist
  238. if season not in seasons_data:
  239. seasons_data[season] = {}
  240. # Extract essential race information
  241. race_name = race.get('raceName', 'Unknown Grand Prix')
  242. circuit = race.get('Circuit', {})
  243. location = circuit.get('Location', {})
  244. # Create race entry
  245. race_entry = {
  246. "name": race_name,
  247. "date": race.get('date', ''),
  248. "time": race.get('time', ''),
  249. "url": race.get('url', ''),
  250. "circuit": {
  251. "name": circuit.get('circuitName', 'Unknown Circuit'),
  252. "url": circuit.get('url', ''),
  253. "location": {
  254. "lat": location.get('lat', ''),
  255. "long": location.get('long', ''),
  256. "locality": location.get('locality', ''),
  257. "country": location.get('country', '')
  258. }
  259. }
  260. }
  261. # Add race results and other data if available
  262. if 'Results' in race:
  263. race_entry['results'] = race['Results']
  264. if 'Qualifying' in race:
  265. race_entry['qualifying'] = race['Qualifying']
  266. if 'Sprint' in race:
  267. race_entry['sprint'] = race['Sprint']
  268. # Add to the seasons data
  269. seasons_data[season][round_num] = race_entry
  270. return seasons_data
  271. def main():
  272. # Fetch all race data
  273. all_races = fetch_all_grand_prix_data()
  274. # Get circuit file mapping
  275. circuit_mapping = get_circuit_file_mapping()
  276. print(f"Found {len(circuit_mapping)} circuit mappings")
  277. # Create grand prix data
  278. grand_prix_data = create_grand_prix_data(all_races, circuit_mapping)
  279. print(f"Created grand prix data with {len(grand_prix_data)} entries")
  280. # Create seasons data
  281. seasons_data = create_seasons_data(all_races)
  282. print(f"Created seasons data with {len(seasons_data)} seasons")
  283. # Save to files
  284. with open('grand_prix.json', 'w', encoding='utf-8') as f:
  285. json.dump(grand_prix_data, f, indent=2, ensure_ascii=False)
  286. print("Saved grand_prix.json")
  287. with open('seasons.json', 'w', encoding='utf-8') as f:
  288. json.dump(seasons_data, f, indent=2, ensure_ascii=False)
  289. print("Saved seasons.json")
  290. if __name__ == "__main__":
  291. main()