With thanks to misho88
on reddit who posted this and advised to look at using matplotlib.tri.Triangulation
and tricontourf
the following works:
import numpy as np
import matplotlib.tri as tri
from vpython import vector, triangle, vertex, vec
import matplotlib.pyplot as plt
# Function to convert spherical to Cartesian coordinates
def spherical_to_cartesian(lat, lon, radius=3):
lons = np.radians(lon)
lats = np.radians(lat)
x = radius * np.cos(lats) * np.cos(lons)
y = radius * np.cos(lats) * np.sin(lons)
z = radius * np.sin(lats)
return np.array([x, y, z])
shape = (721, 1440)
lats = np.linspace(-90, 90, shape[0])
lons = np.linspace(-180, 180, shape[1])
min_temp = -30
max_temp = 50
temps = np.random.uniform(min_temp, max_temp, size=shape)
lons_grid, lats_grid = np.meshgrid(lons, lats)
new_lons = np.linspace(lons.min(), lons.max(), 72)
new_lats = np.linspace(lats.min(), lats.max(), 36)
new_lons_grid, new_lats_grid = np.meshgrid(new_lons, new_lats)
radius = 3
lats_flat = lats_grid.flatten()
lons_flat = lons_grid.flatten()
temps_flat = temps.flatten()
# Randomly sample a subset of the points
num_samples = 10000 # Adjust this number to control triangle density
indices = np.random.choice(len(lats_flat), size=num_samples, replace=False)
lats_sampled = lats_flat[indices]
lons_sampled = lons_flat[indices]
temps_sampled = temps_flat[indices]
triang = tri.Triangulation(lons_sampled, lats_sampled)
fig, ax = plt.subplots()
contour = ax.tricontourf(triang, temps_sampled, levels=100, cmap='inferno')
plt.colorbar(contour)
plt.close(fig)
for tri_indices in triang.triangles:
vertices = []
for idx in tri_indices:
xi, yi, zi = spherical_to_cartesian(lats_sampled[idx], lons_sampled[idx])
temp = temps_sampled[idx]
color_value = plt.cm.inferno((temp - min_temp) / (max_temp - min_temp))
vertices.append(vertex(pos=vector(xi, yi, zi), color=vec(*color_value[:3])))
triangle(v0=vertices[0], v1=vertices[1], v2=vertices[2])
import time
while True:
time.sleep(0.03)