Search code examples
pythonmatplotlib3dgeometryvisualization

How to remove a portion from a 3d plane?


I'm plotting in matplotlib. I want to remove a circle on the planes where they intersect with the catenoid surfaces. It's ok to have the intersection hard coded, as long as it looks fine visually.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Parametric equations for the catenoid surface
def catenoid(u, v, a=1):
    x = a * np.cosh(u/a) * np.cos(v)
    y = a * np.cosh(u/a) * np.sin(v)
    z = u
    return x, y, z

# Generate u and v values
u = np.linspace(-2, 2, 100)
v = np.linspace(0, 2 * np.pi, 100)
u, v = np.meshgrid(u, v)

# Create the figure
fig = plt.figure(figsize=(12, 12))
ax = fig.add_subplot(111, projection="3d", computed_zorder=False)
ax.set_box_aspect(aspect=(6, 4, 3))
ax.set_axis_off()

# Plot the first catenoid surface without gridlines
x1, y1, z1 = catenoid(u, v)
surf1 = ax.plot_surface(x1, y1, z1, cmap='viridis', edgecolor='grey', alpha=0.5, vmin=-2, vmax=2)

# Plot the second catenoid surface with an offset along the y-axis without gridlines
x2, y2, z2 = catenoid(u, v)
x2_offset = x2 + 8  # Adjust the offset value as needed
surf2 = ax.plot_surface(x2_offset, y2, z2, cmap='viridis', edgecolor='grey', alpha=0.5, vmin=-2, vmax=2)


# Plot the first plane with top and bottom colors of the first catenoid surface
xx, yy = np.meshgrid(np.linspace(-5, 13, 100), np.linspace(-5, 5, 100))
zz = yy * 0 - 2
ax.plot_surface(xx, yy, zz, zorder=-1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2)
zz = yy * 0 + 2
ax.plot_surface(xx, yy, zz, zorder=1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2)

# Show the plot
plt.show()

Currently, it looks like: enter image description here

I want to get rid of the grey parts, so the plane is not covering the catenoid openings: enter image description here


Solution

  • I have created two circle masks for the planes. Because your graph is symmetrical, for the planes z=2 and z=-2, they have the same mask. When generating the x,y coordinates of the plane, I increased the amount of data to reduce the burrs of the generated mask.

    Here are the codes after the line surf2 = ax.plot_surface..., I have added some comments:

    # Defin x, y of the plane 
    plane_2_x = np.linspace(-5, 13, 1000)
    plane_2_y = np.linspace(-5, 5, 1000)
    
    # Calculate the radius of the circles
    radius = np.max(x1)
    
    # Calculate all the distances of the points in the plane to the center of the circle 
    dist_from_center_1 = np.sqrt((plane_2_x.reshape(-1, 1) - 0)**2 + (plane_2_y.reshape(1, -1)-0)**2) # center is [0, 0]
    mask_1 = dist_from_center_1<=radius # Calculate the first mask
    dist_from_center_2 = np.sqrt((plane_2_x.reshape(-1, 1) - 8)**2 + (plane_2_y.reshape(1, -1)-0)**2) # center is [8, 0]
    mask_2 = dist_from_center_2<=radius # Calculate the second mask
    
    # Plot the first plane with top and bottom colors of the first catenoid surface
    xx, yy = np.meshgrid(plane_2_x, plane_2_y)
    zz = yy * 0 - 2
    zz[np.logical_or(mask_1.T, mask_2.T)] = np.nan # Apply the mask for the plane z=-2
    ax.plot_surface(xx, yy, zz, zorder=-1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2)
    zz = yy * 0 + 2
    zz[np.logical_or(mask_1.T, mask_2.T)] = np.nan # Apply the mask for the plane z=2
    ax.plot_surface(xx, yy, zz, zorder=-1, alpha=0.5, cmap='viridis', edgecolor='none', vmin=-2, vmax=2)
    
    # Show the plot
    plt.show()
    

    Here is result : enter image description here