xy2pct 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
xy2pct-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JUSAAATIN
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
xy2pct-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: xy2pct
3
+ Version: 0.1.0
4
+ Summary: Convert track coordinates to percentages along a lap
5
+ Author-email: jusaaatin <jusaaatin@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 JUSAAATIN
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Keywords: xy2pct,f1,percentages,coordinates,track,lap,data,analysis
28
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: License :: OSI Approved :: MIT License
30
+ Classifier: Programming Language :: Python
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Operating System :: MacOS :: MacOS X
33
+ Classifier: Operating System :: Microsoft :: Windows
34
+ Classifier: Intended Audience :: Education
35
+ Classifier: Intended Audience :: Developers
36
+ Requires-Python: >=3.10
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Requires-Dist: numpy
40
+ Requires-Dist: matplotlib
41
+ Dynamic: license-file
42
+
43
+ workflow:
44
+
45
+ 1. use [generatelaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/generatelaparray.py) to spit out a file with x, y, and z coordinates for the track
46
+ 2. manually delete extra data points and assign relevant ones to pit lane
47
+ 3. use [parselaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/parselaparray.py) to check work (sample code to also go from file to array)
48
+ 4. use [xy2pct.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/xy2pct.py) to convert any coordinate to a percentage along the track
xy2pct-0.1.0/README.md ADDED
@@ -0,0 +1,6 @@
1
+ workflow:
2
+
3
+ 1. use [generatelaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/generatelaparray.py) to spit out a file with x, y, and z coordinates for the track
4
+ 2. manually delete extra data points and assign relevant ones to pit lane
5
+ 3. use [parselaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/parselaparray.py) to check work (sample code to also go from file to array)
6
+ 4. use [xy2pct.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/xy2pct.py) to convert any coordinate to a percentage along the track
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xy2pct"
7
+ version = "0.1.0"
8
+ description = "Convert track coordinates to percentages along a lap"
9
+ readme = "README.md"
10
+ authors = [{ name = "jusaaatin", email = "jusaaatin@gmail.com" }]
11
+ license = { file = "LICENSE" }
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python",
16
+ "Programming Language :: Python :: 3",
17
+ "Operating System :: MacOS :: MacOS X",
18
+ "Operating System :: Microsoft :: Windows",
19
+ "Intended Audience :: Education",
20
+ "Intended Audience :: Developers"
21
+ ]
22
+ keywords = ["xy2pct", "f1", "percentages", "coordinates", "track", "lap", "data", "analysis"]
23
+ requires-python = ">=3.10"
24
+ dependencies = [
25
+ "numpy",
26
+ "matplotlib",
27
+ ]
28
+
29
+ [tool.setuptools]
30
+ package-dir = {"" = "src"}
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["src"]
34
+
xy2pct-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ # __init__.py
2
+
3
+ import os
4
+ import src.xy2pct.xy2pct as xy2pct
5
+
6
+ # Version of the xy2pct package
7
+ __version__ = "0.1.0"
@@ -0,0 +1,32 @@
1
+ from urllib.request import urlopen
2
+ import json
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+
6
+ allx = []
7
+ ally = []
8
+
9
+ response = urlopen('https://api.openf1.org/v1/location?session_key=9939&date>2025-07-27T13:00:00.000&date<2025-07-27T13:20:00.000')
10
+ data = json.loads(response.read().decode('utf-8'))
11
+ for each in data:
12
+ allx.append(each['x'])
13
+ ally.append(each['y'])
14
+
15
+
16
+
17
+ def plot(x, y):
18
+ x_values = np.asarray(x)
19
+ y_values = np.asarray(y)
20
+ plt.plot(x_values, y_values, 'o')
21
+ plt.axhline(0, color='black', linewidth=0.5, linestyle='--')
22
+ plt.axvline(0, color='black', linewidth=0.5, linestyle='--')
23
+ plt.show()
24
+
25
+ command = input("Type 'stop' to terminate: ")
26
+ if command == 'stop':
27
+ #stop application
28
+ print("Terminating application.")
29
+ exit()
30
+
31
+
32
+ plot(allx, ally)
@@ -0,0 +1,79 @@
1
+ from urllib.request import urlopen
2
+ import json
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ from datetime import datetime, timedelta
6
+ from pathlib import Path
7
+
8
+ circuit_short_name = 'Singapore'
9
+ clearanceGap = 50
10
+
11
+ # get session id, date start, and date end
12
+ def getSessionInfo(circuit_short_name):
13
+ baselink = f'https://api.openf1.org/v1/sessions?circuit_short_name={circuit_short_name}&session_type=Qualifying&year=2025'
14
+ response = urlopen(baselink)
15
+ data = json.loads(response.read().decode('utf-8'))
16
+ session_id = data[0]['session_key']
17
+ date_start = data[0]['date_start']
18
+ print(date_start)
19
+ return session_id, date_start
20
+
21
+ # uses sessionid and start date to spit out array of coordinates in a lap
22
+ def getCoordinateArray(session_id, date_start):
23
+ date_end = datetime.fromisoformat(date_start) + timedelta(minutes=30)
24
+ coordinates = []
25
+ link = f'https://api.openf1.org/v1/location?driver_number=4&session_key={session_id}&date>{date_start}&date<{date_end.isoformat()}'
26
+ response = urlopen(link)
27
+ data = json.loads(response.read().decode('utf-8'))
28
+ for item in data:
29
+ datapack = 'x: {x}, y: {y}, z: {z}'.format(x=item['x'], y=item['y'], z=item['z'])
30
+ #delete all x=0 y=0 pairs
31
+ if item['x'] == 0 and item['y'] == 0:
32
+ continue
33
+ #make it so that datapack checks that each x y pair is not in +-clearanceGap of any in coordinates
34
+ is_unique = True
35
+ for existing in coordinates:
36
+ existing_x, existing_y, *_ = existing.split(', ')
37
+ if abs(float(existing_x.split(': ')[1]) - float(item['x'])) <= clearanceGap and abs(float(existing_y.split(': ')[1]) - float(item['y'])) <= clearanceGap:
38
+ is_unique = False
39
+ break
40
+ if is_unique:
41
+ coordinates.append(datapack)
42
+ return coordinates
43
+
44
+ # plots lap
45
+ def plot(coordinates):
46
+ x_values = []
47
+ y_values = []
48
+ for coordinate in coordinates:
49
+ x, y, *_ = coordinate.split(', ')
50
+ x_values.append(float(x.split(': ')[1]))
51
+ y_values.append(float(y.split(': ')[1]))
52
+ #make first and last color red and the rest gradient from light blue to dark blue
53
+ colors = ['red'] + [plt.cm.viridis(i) for i in np.linspace(0, 1, len(x_values) - 2)] + ['orange']
54
+ for i in range(len(x_values)):
55
+ plt.scatter(x_values[i], y_values[i], c=[colors[i]], marker='o')
56
+ plt.axhline(0, color='black', linewidth=0.5, linestyle='--')
57
+ plt.axvline(0, color='black', linewidth=0.5, linestyle='--')
58
+ plt.title(f"{circuit_short_name} Lap Array")
59
+ plt.show()
60
+
61
+ #generates file with track and pit lane coordinates
62
+ def exportToFile(coordinates, circuit_short_name):
63
+ folder = Path("expy")
64
+ folder.mkdir(exist_ok=True)
65
+ filename = folder / f"{circuit_short_name}.txt"
66
+ with open(filename, "w") as f:
67
+ f.write("Track\n")
68
+ f.write("\n".join(coordinates))
69
+ f.write("\n\nPit Lane")
70
+
71
+
72
+
73
+ def generateLapArray():
74
+ coordinatearray = getCoordinateArray(*getSessionInfo(circuit_short_name))
75
+ exportToFile(coordinatearray, circuit_short_name)
76
+
77
+ plot(coordinatearray)
78
+
79
+ generateLapArray()
@@ -0,0 +1,93 @@
1
+ from pathlib import Path
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ from matplotlib.widgets import Button
5
+
6
+ circuit_short_name = "Belgium"
7
+
8
+ #imports expy files and turns them into separate track and pitlane coordinate arrays
9
+ def fileToArray(circuit_short_name):
10
+ folder = Path("expy")
11
+ folder.mkdir(exist_ok=True)
12
+ file_path = folder / f"{circuit_short_name}.txt"
13
+
14
+ if not file_path.exists():
15
+ print(f"File {file_path} does not exist.")
16
+ return [], []
17
+
18
+ with open(file_path, "r") as file:
19
+ lines = file.readlines()
20
+
21
+ track_coordinates = []
22
+ pit_lane_coordinates = []
23
+ current_section = None
24
+
25
+ for line in lines:
26
+ line = line.strip()
27
+
28
+ if line == "":
29
+ continue #ignore blank lines
30
+ if line == "Track":
31
+ current_section = "track"
32
+ elif line == "Pit Lane":
33
+ current_section = "pit_lane"
34
+ elif current_section == "track":
35
+ track_coordinates.append(line)
36
+ elif current_section == "pit_lane":
37
+ pit_lane_coordinates.append(line)
38
+
39
+ return track_coordinates, pit_lane_coordinates
40
+
41
+ # plots track and pit lane coordinates
42
+ def draw_plot(ax, track_coordinates, pit_lane_coordinates):
43
+ ax.clear()
44
+
45
+ x_values = []
46
+ y_values = []
47
+
48
+ for coordinate in track_coordinates:
49
+ x, y, *_ = coordinate.split(", ")
50
+ x_values.append(float(x.split(": ")[1]))
51
+ y_values.append(float(y.split(": ")[1]))
52
+
53
+ for coordinate in pit_lane_coordinates:
54
+ x, y, *_ = coordinate.split(", ")
55
+ x_values.append(float(x.split(": ")[1]))
56
+ y_values.append(float(y.split(": ")[1]))
57
+
58
+ point_colors = (
59
+ [plt.cm.winter(i) for i in np.linspace(0, 1, len(track_coordinates))]
60
+ + [plt.cm.autumn(i) for i in np.linspace(0, 1, len(pit_lane_coordinates))]
61
+ )
62
+
63
+ for i in range(len(x_values)):
64
+ ax.scatter(x_values[i], y_values[i], c=[point_colors[i]], marker="o")
65
+
66
+ ax.axhline(0, color="black", linewidth=0.5, linestyle="--")
67
+ ax.axvline(0, color="black", linewidth=0.5, linestyle="--")
68
+ ax.set_title(f"{circuit_short_name} Track and Pit Lane")
69
+
70
+
71
+ def plot(circuit_short_name):
72
+ fig, ax = plt.subplots()
73
+ plt.subplots_adjust(bottom=0.2)
74
+
75
+ track_coordinates, pit_lane_coordinates = fileToArray(circuit_short_name)
76
+ draw_plot(ax, track_coordinates, pit_lane_coordinates)
77
+
78
+ button_ax = plt.axes([0.4, 0.05, 0.2, 0.075])
79
+ reload_button = Button(button_ax, "Reload")
80
+
81
+ def reload(event):
82
+ track_coordinates, pit_lane_coordinates = fileToArray(circuit_short_name)
83
+ draw_plot(ax, track_coordinates, pit_lane_coordinates)
84
+ fig.canvas.draw_idle()
85
+
86
+ reload_button.on_clicked(reload)
87
+
88
+ plt.show()
89
+
90
+ def parseLapArray():
91
+ plot(circuit_short_name)
92
+
93
+ parseLapArray()
@@ -0,0 +1,117 @@
1
+ from pathlib import Path
2
+ import numpy as np
3
+ import re
4
+ import matplotlib.pyplot as plt
5
+ from matplotlib.widgets import Button
6
+
7
+ circuit_short_name = "Spa-Francorchamps"
8
+ debug = True
9
+ x = -3930
10
+ y = -1640
11
+ z = 0
12
+
13
+ def fileToArray(circuit_short_name):
14
+ folder = Path("expy")
15
+ folder.mkdir(exist_ok=True)
16
+ file_path = folder / f"{circuit_short_name}.txt"
17
+
18
+ if not file_path.exists():
19
+ print(f"File {file_path} does not exist.")
20
+ return [], []
21
+
22
+ with open(file_path, "r") as file:
23
+ lines = file.readlines()
24
+
25
+ track_coordinates = []
26
+ pit_lane_coordinates = []
27
+ current_section = None
28
+
29
+ for line in lines:
30
+ line = line.strip()
31
+
32
+ if line == "":
33
+ continue
34
+ if line == "Track":
35
+ current_section = "track"
36
+ elif line == "Pit Lane":
37
+ current_section = "pit_lane"
38
+ elif current_section == "track":
39
+ track_coordinates.append(line)
40
+ elif current_section == "pit_lane":
41
+ pit_lane_coordinates.append(line)
42
+
43
+ return track_coordinates, pit_lane_coordinates
44
+
45
+ def to_xyz_array(coords):
46
+ return np.array([
47
+ [float(x), float(y), float(z) if z is not None else 0.0]
48
+ for x, y, z in re.findall(
49
+ r"x:\s*(-?\d+(?:\.\d+)?),\s*y:\s*(-?\d+(?:\.\d+)?)(?:,\s*z:\s*(-?\d+(?:\.\d+)?))?",
50
+ "\n".join(coords),
51
+ )
52
+ ])
53
+
54
+ def xy2pct(x, y, z=None, circuit_short_name=None): #takes coordinates and finds the % along the track/pit lane it is
55
+ if isinstance(z, str) and circuit_short_name is None:
56
+ circuit_short_name = z
57
+ z = None
58
+
59
+ if circuit_short_name is None:
60
+ circuit_short_name = globals()["circuit_short_name"]
61
+
62
+ track_coordinates, pit_lane_coordinates = fileToArray(circuit_short_name)
63
+ track = to_xyz_array(track_coordinates)
64
+ pit = to_xyz_array(pit_lane_coordinates)
65
+
66
+ if z is None:
67
+ point = np.array([x, y])
68
+ track_compare = track[:, :2]
69
+ pit_compare = pit[:, :2]
70
+ else:
71
+ point = np.array([x, y, z])
72
+ track_compare = track
73
+ pit_compare = pit
74
+
75
+ track_i = np.argmin(np.sum((track_compare - point) ** 2, axis=1))
76
+ pit_i = np.argmin(np.sum((pit_compare - point) ** 2, axis=1))
77
+
78
+ track_dist = np.sum((track_compare[track_i] - point) ** 2)
79
+ pit_dist = np.sum((pit_compare[pit_i] - point) ** 2)
80
+
81
+ onTrack = track_dist <= pit_dist
82
+
83
+ coords = track if onTrack else pit
84
+ index = track_i if onTrack else pit_i
85
+
86
+ highlighted = coords[index]
87
+ percentage = index / len(coords) * 100
88
+
89
+ if z is None:
90
+ print(f"highlighted coordinate: x={highlighted[0]}, y={highlighted[1]}")
91
+ else:
92
+ print(f"highlighted coordinate: x={highlighted[0]}, y={highlighted[1]}, z={highlighted[2]}")
93
+ print(f"onTrack: {onTrack}")
94
+
95
+ if debug:
96
+ return onTrack, percentage, highlighted
97
+ else:
98
+ return onTrack, percentage
99
+
100
+ def plot(x, y, highlighted, track_coordinates, pit_lane_coordinates):
101
+ track = to_xyz_array(track_coordinates)
102
+ pit = to_xyz_array(pit_lane_coordinates)
103
+
104
+ plt.scatter(track[:, 0], track[:, 1], color='blue', label='Track')
105
+ plt.scatter(pit[:, 0], pit[:, 1], color='green', label='Pit Lane')
106
+ plt.scatter(x, y, color='red', label='Input Point', zorder=5)
107
+ plt.scatter(highlighted[0], highlighted[1], color='orange', label='Highlighted Point', zorder=5)
108
+ plt.axhline(0, color='black', linewidth=0.5, linestyle='--')
109
+ plt.axvline(0, color='black', linewidth=0.5, linestyle='--')
110
+ plt.legend()
111
+ plt.show()
112
+
113
+ print(xy2pct(x, y, z, circuit_short_name))
114
+
115
+
116
+ if debug:
117
+ plot(x, y, xy2pct(x, y, z, circuit_short_name)[2], *fileToArray(circuit_short_name))
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.4
2
+ Name: xy2pct
3
+ Version: 0.1.0
4
+ Summary: Convert track coordinates to percentages along a lap
5
+ Author-email: jusaaatin <jusaaatin@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 JUSAAATIN
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Keywords: xy2pct,f1,percentages,coordinates,track,lap,data,analysis
28
+ Classifier: Development Status :: 4 - Beta
29
+ Classifier: License :: OSI Approved :: MIT License
30
+ Classifier: Programming Language :: Python
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Operating System :: MacOS :: MacOS X
33
+ Classifier: Operating System :: Microsoft :: Windows
34
+ Classifier: Intended Audience :: Education
35
+ Classifier: Intended Audience :: Developers
36
+ Requires-Python: >=3.10
37
+ Description-Content-Type: text/markdown
38
+ License-File: LICENSE
39
+ Requires-Dist: numpy
40
+ Requires-Dist: matplotlib
41
+ Dynamic: license-file
42
+
43
+ workflow:
44
+
45
+ 1. use [generatelaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/generatelaparray.py) to spit out a file with x, y, and z coordinates for the track
46
+ 2. manually delete extra data points and assign relevant ones to pit lane
47
+ 3. use [parselaparray.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/parselaparray.py) to check work (sample code to also go from file to array)
48
+ 4. use [xy2pct.py](https://github.com/jusaaatin/f1-xy2pct/blob/main/xy2pct.py) to convert any coordinate to a percentage along the track
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/xy2pct/__init__.py
5
+ src/xy2pct/xy2pct.py
6
+ src/xy2pct.egg-info/PKG-INFO
7
+ src/xy2pct.egg-info/SOURCES.txt
8
+ src/xy2pct.egg-info/dependency_links.txt
9
+ src/xy2pct.egg-info/requires.txt
10
+ src/xy2pct.egg-info/top_level.txt
11
+ src/xy2pct/mapgeneration/belgiumtrackmap.py
12
+ src/xy2pct/mapgeneration/generatelaparray.py
13
+ src/xy2pct/mapgeneration/parselaparray.py
@@ -0,0 +1,2 @@
1
+ numpy
2
+ matplotlib
@@ -0,0 +1 @@
1
+ xy2pct