def plot_tesseroid_layer(tesseroid_layer, add_sphere=True):
"""Plot a tesseroid using PyVista. This plots 1 large tesseroid, then adds some
grid lines to denote each separate tesseroid.
"""
# extract tesseroids from the layer
tesseroids = tesseroid_layer.tesseroid_layer._to_tesseroids()
density = tesseroid_layer.tesseroid_layer._obj.density.values
# discard thin tesseroids
mask = tesseroid_layer.tesseroid_layer._get_nonans_mask(property_name="density")
density = density[mask]
# tesseroids = _discard_thin_tesseroids(
# tesseroids,
# density,
# 1,
# )[0]
# get arrays of boundaries
lon_mins = [i[0] for i in tesseroids]
lon_maxs = [i[1] for i in tesseroids]
lat_mins = [i[2] for i in tesseroids]
lat_maxs = [i[3] for i in tesseroids]
r_inners = [i[4] for i in tesseroids]
r_outers = [i[5] for i in tesseroids]
# # transform latitudes to be centered at north pole
# mean_lat = np.mean(np.array([lat_mins, lat_maxs]))
# print(mean_lat)
# lat_mins = [90-np.abs(x-mean_lat) for x in lat_mins]
# lat_maxs = [90-np.abs(x-mean_lat) for x in lat_maxs]
# print(min(lat_mins), max(lat_maxs))
# phi (latitude) is defined as 0 at north pole and 180 at south pole in PyVista
min_phis = [90 - x for x in lat_maxs]
max_phis = [90 - x for x in lat_mins]
# transform latitudes to be centered at north pole
# mean_phi = np.mean(np.array([min_phis, max_phis]))
# min_phis = [np.abs(x-mean_phi) for x in min_phis]
# max_phis = [np.abs(x-mean_phi) for x in max_phis]
# print(min(min_phis), max(max_phis))
# # transform longitudes to be centered at 0deg
# mean_lon = np.mean(np.array([lon_mins, lon_maxs]))
# lon_mins = [x-(mean_lon) for x in lon_mins]
# lon_maxs = [x-(mean_lon) for x in lon_maxs]
mean_theta = np.mean(np.array([lon_mins, lon_maxs]))
mean_phi = np.mean(np.array([min_phis, max_phis]))
plotter = pv.Plotter()
if add_sphere:
# Create and plot the semi-transparent shell of a sphere
sphere_mesh = pv.Sphere(radius=np.mean([r_outers, r_inners]))
plotter.add_mesh(sphere_mesh, color="white", style="wireframe", opacity=0.1)
# loop through each tesseroid, generate its mesh, and append to a list
meshes = []
edges = []
for i, _j in enumerate(tesseroids):
# Create a solid sphere sector (tesseroid)
tesseroid_mesh = pv.SolidSphere(
outer_radius=r_outers[i],
inner_radius=r_inners[i],
start_theta=lon_mins[i], # longitude
end_theta=lon_maxs[i], # longitude
start_phi=min_phis[i], # latitude
end_phi=max_phis[i], # latitude
phi_resolution=5, # resolutions of 2 will be flat faces
theta_resolution=5,
radius_resolution=5,
)
plotter.add_mesh(
tesseroid_mesh,
# color="lightblue",
scalars=[density[i]] * tesseroid_mesh.n_cells,
cmap="viridis",
show_edges=False,
opacity=1,
)
meshes.append(tesseroid_mesh)
tesseroid_edge = pv.SolidSphere(
outer_radius=r_outers[i],
inner_radius=r_inners[i],
start_theta=lon_mins[i], # longitude
end_theta=lon_maxs[i], # longitude
start_phi=min_phis[i], # latitude
end_phi=max_phis[i], # latitude
phi_resolution=2,
theta_resolution=2,
radius_resolution=2,
)
edge = tesseroid_edge.extract_feature_edges()
edges.append(edge)
transform = pv.Transform()
transform.rotate_x(-mean_phi) # rotate so latitude is at north pole
# transform.rotate_z(180-mean_theta) # rotate so longitude is at prime meridian (180)
# # plot merged mesh of all tesseroids
# mesh = pv.merge(meshes)
# # mesh = mesh.transform(transform, inplace=False)
# print(mesh)
# plotter.add_mesh(
# mesh,
# color="lightblue",
# cmap="viridis",
# show_edges=False,
# opacity=1,
# )
# plot merged edges of all tesseroids
edges = pv.merge(edges)
# edges = edges.transform(transform, inplace=False)
plotter.add_mesh(edges, line_width=2, color="black")
# r = r_outer_max*10
# phi = 90
# theta = np.mean(np.array([lon_min, lon_max]))
# print(r, phi, theta)
# print(pv.spherical_to_cartesian(r, phi, theta))
# set camera to look at equator from prime meridian
# cam_pos = pv.grid_from_sph_coords(
# phi = 0, # latitude
# theta = 90, # longitude
# # phi = [mean_phi], # latitude
# r = [np.max(r_outers)*3], # distance from the origin
# )
# plotter.set_position(cam_pos.points)
# plotter.camera_position = [
# (0.0, 0.0, 1.0),
# (0.0, 0.0, 0.0),
# (0.0, 1.0, 0.0)
# ]
# plotter.camera_position = 'yz' # looking directly at prime meridian and equator
mean_radius = np.mean([r_outers, r_inners])
plotter.camera_position = "yz" # looking directly at prime meridian and equator
# plotter.camera.distance=12e6
plotter.camera.distance = mean_radius * 1.5
plotter.camera.clipping_range = (mean_radius * 0.5, mean_radius * 3)
plotter.camera.azimuth = mean_theta - 90
plotter.camera.roll = mean_phi + 90
plotter.camera.elevation = 10
plotter.add_axes()
# plotter.show_grid()
# plotter.show()
return plotter
While working on #617 I tried to match all functionality between the prisms and tesseroids. One of the remaining differences between the two is the visualization function for prisms, which doesn't exist for tesseroids.
I think they are even more important for tesseroids, since they are conceptually more complex than prisms, so being able to plot an individual tesseroid, or a tesseroid layer, would be a useful feature.
Below are a few possible starting points for functions:
Plot a single tesseroid:
`plot_tesseroid` function
Which is used like this:
Plot multiple tesseroids:
`plot_tesseroid` function
Which is used like this:
or like this:
Plot layer of tesseroids:
`plot_tesseroid` function
Which is used like this: