ChatGPT and 3D Race Graphs
Experiments with the Middlesex Fells Skyline Trail Analyzer
Building on my previous post on Custom GPTs and their application to a Middlesex Fells Skyline Trail Analyzer. I wanted to see if my Custom GPT was able to support 3D graphing of the Skyline Trail. Yes, it did.
Customized GPTs are an option currently available to ChatGPT Pro users. Users can create a ChatGPT front-end customized with privately held data and knowledge. In this case, my privately held data is my race performance data. At this time the Middlesex Fells Trail Analyzer is customized with five years of my race data from the TARC Winter Classic.
Figure 2 is the Middlesex Fells Trail Analyzer’s front-end webpage.
Tonight, I experimented with asking ChatGPT for 3D displays of its custom route data. Figure 3 provides a first cut of a 3D plot of 5 years of race data of the Middlesex Fells Skyline trail.
I then asked ChatGPT:
“Can you show the 3d representation in 3 graphs from different angles”
It responded with Figure 4, appearing as perspectives taken from XYZ axes. That was not quite what I had in mind. For Figure 5 I asked:
“Can you show the 3d representation in 3 graphs from different isometric angles”
Figure 5. was closer.
These are still early days for ChatGPT, Custom GPTs, and our collaboration. I haven’t yet developed firm ideas on what I want in terms of a 3D route-data display from the Middlesex Fells Trails Analyzer. The point, however, is that ChatGPT using Custom GPT data (combined with the Code Interpreter) facilitates experimentation.
A note about ChatGPT and its use here. I used ChatGPT Pro which crucially for here has access to the Code Interpreter. To produce these graphs, ChatGPT is using its Large Language Model (LLM) not for the answer but to generate the Python code that will be executed in the Code Interpreter to provide the answer (see Appendix for the code used here).
Appendix - Sample Code Generated by ChatGPT used here
import xml.etree.ElementTree as ET
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Function to extract latitude, longitude, and elevation from a GPX file
def extract_gpx_data(file_path):
tree = ET.parse(file_path)
root = tree.getroot()
# GPX namespace
ns = {'gpx': 'http://www.topografix.com/GPX/1/1'}
# Extracting data
latitudes = []
longitudes = []
elevations = []
for trkpt in root.findall('.//gpx:trkpt', ns):
latitudes.append(float(trkpt.get('lat')))
longitudes.append(float(trkpt.get('lon')))
elevations.append(float(trkpt.find('./gpx:ele', ns).text))
return latitudes, longitudes, elevations
# File paths
file_paths = [
"/mnt/data/TARC_Winter_Fells_Ultra_2018.gpx",
"/mnt/data/TARC_Winter_Fells_2021.gpx",
"/mnt/data/TARC_Winter_Classic_2023.gpx",
"/mnt/data/TARC_Winter_Fells_2022.gpx",
"/mnt/data/TARC_Winter_Fells_2019_snowyear.gpx"
]
# Extract data from each GPX file
tracks = [extract_gpx_data(path) for path in file_paths]
# Plotting the 3D representation
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# Plot each track
for track in tracks:
ax.plot(track[1], track[0], track[2])
ax.set_xlabel('Longitude')
ax.set_ylabel('Latitude')
ax.set_zlabel('Elevation (m)')
plt.title('3D Representation of TARC Winter Fells Routes')
plt.show()
# Plotting the 3D representation from three different angles
fig = plt.figure(figsize=(18, 6))
# First Angle - Front View
ax1 = fig.add_subplot(131, projection='3d')
for track in tracks:
ax1.plot(track[1], track[0], track[2])
ax1.view_init(elev=10, azim=-90) # Front view
ax1.set_xlabel('Longitude')
ax1.set_ylabel('Latitude')
ax1.set_zlabel('Elevation (m)')
ax1.set_title('Front View')
# Second Angle - Top View
ax2 = fig.add_subplot(132, projection='3d')
for track in tracks:
ax2.plot(track[1], track[0], track[2])
ax2.view_init(elev=90, azim=-90) # Top view
ax2.set_xlabel('Longitude')
ax2.set_ylabel('Latitude')
ax2.set_zlabel('Elevation (m)')
ax2.set_title('Top View')
# Third Angle - Side View
ax3 = fig.add_subplot(133, projection='3d')
for track in tracks:
ax3.plot(track[1], track[0], track[2])
ax3.view_init(elev=10, azim=0) # Side view
ax3.set_xlabel('Longitude')
ax3.set_ylabel('Latitude')
ax3.set_zlabel('Elevation (m)')
ax3.set_title('Side View')
plt.tight_layout()
plt.show()
# Plotting the 3D representation from three different isometric angles
fig = plt.figure(figsize=(18, 6))
# Isometric Angle 1
ax1 = fig.add_subplot(131, projection='3d')
for track in tracks:
ax1.plot(track[1], track[0], track[2])
ax1.view_init(elev=30, azim=45) # Isometric view
ax1.set_xlabel('Longitude')
ax1.set_ylabel('Latitude')
ax1.set_zlabel('Elevation (m)')
ax1.set_title('Isometric View 1')
# Isometric Angle 2
ax2 = fig.add_subplot(132, projection='3d')
for track in tracks:
ax2.plot(track[1], track[0], track[2])
ax2.view_init(elev=30, azim=135) # Different isometric view
ax2.set_xlabel('Longitude')
ax2.set_ylabel('Latitude')
ax2.set_zlabel('Elevation (m)')
ax2.set_title('Isometric View 2')
# Isometric Angle 3
ax3 = fig.add_subplot(133, projection='3d')
for track in tracks:
ax3.plot(track[1], track[0], track[2])
ax3.view_init(elev=30, azim=225) # Another isometric view
ax3.set_xlabel('Longitude')
ax3.set_ylabel('Latitude')
ax3.set_zlabel('Elevation (m)')
ax3.set_title('Isometric View 3')
plt.tight_layout()
plt.show()






