Python Forum

Full Version: Concatenate array for 3D plotting
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
hello everyone,

i am trying to plot this : (first image). It's basically a cylinder with two hemisphere : one on the top of the cylinder and one on the bottom.

I did it by plotting cylinder and the two hemispheres separately. For each, I have 3 arrays : one for X data, one for Y data and one for Z data (so I have 9 array in total).

I would like, to create only 3 arrays that contain :
- one with all X arrays together ;
- one with all Y arrays together ;
- one with all Z arrays together ;
- and plot everything to obtain the same figure ;

I tried with np.concatenate() function but I got this : (second image). We can see that there is a small difference between first and second picture.

How to procede ? Thanks for your help ! :)


Here is my code below :
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

long = 20

fig = plt.figure()
ax = plt.axes(projection='3d')

# PLOTTING CYLINDER

theta = np.linspace(0, 2*np.pi, 100)
z = np.linspace(0, long-2, len(theta))

theta_grid_cylindre, z_grid_cylindre = np.meshgrid(theta, z)

x_grid_cylindre = 1*np.cos(theta_grid_cylindre) + 0
y_grid_cylindre = 1*np.sin(theta_grid_cylindre) + 0
z_grid_cylindre = z_grid_cylindre + 1

#PLOTTING FIRST HEMISPHERE

theta_1 = np.linspace(0, np.pi/2, 100)

x, y = np.meshgrid(theta, theta_1)

x_grid_sphere = np.cos(x)*np.sin(y)
y_grid_sphere = np.sin(x)*np.sin(y)
z_grid_sphere = np.cos(y)+long-1

#PLOTTING SECOND HEMISPHERE

theta_2 = np.linspace(0, np.pi/2, 100)

x_bas, y_bas = np.meshgrid(theta, theta_2)

x_grid_sphere_bas = np.cos(x_bas)*np.sin(y_bas)
y_grid_sphere_bas = np.sin(x_bas)*np.sin(y_bas)
z_grid_sphere_bas = -np.cos(y_bas)+1

# TRYING TO CONCATENATE ALL ARRAY
 
test_x = np.concatenate((x_grid_sphere,x_grid_cylindre,x_grid_sphere_bas),axis=1)
test_y = np.concatenate((y_grid_sphere,y_grid_cylindre,y_grid_sphere_bas),axis=1)
test_z = np.concatenate((z_grid_sphere,z_grid_cylindre,z_grid_sphere_bas),axis=1)

# PLOTTING EACH PIECE SEPARATELY

ax.plot_surface(x_grid_sphere, y_grid_sphere,z_grid_sphere, color ="green", alpha=0.5)
ax.plot_surface(x_grid_cylindre, y_grid_cylindre,z_grid_cylindre, color ="green", alpha=0.5)
ax.plot_surface(x_grid_sphere_bas, y_grid_sphere_bas,z_grid_sphere_bas, color ="green", alpha=0.5)

# TRYING TO PLOT ALL IN ONE

ax.plot_surface(test_x,test_y,test_z, color ="green", alpha=0.5)

plt.show()
I don't think you can do this. You have 3 shapes and you cannot just concatenate the points together to get a surface. The problem you have no way to transition gracefully from one surface to another.

Try joining just the two hemispheres to see what I mean.
import numpy as np
import matplotlib.pyplot as plt

long = 20
fig = plt.figure()
ax = plt.axes(projection='3d')

theta = np.linspace(0, 2*np.pi, 100)

theta_1 = np.linspace(0, np.pi/2, 100)
x, y = np.meshgrid(theta, theta_1)
x_grid_sphere = np.cos(x)*np.sin(y)
y_grid_sphere = np.sin(x)*np.sin(y)
z_grid_sphere = np.cos(y)+long-1

theta_2 = np.linspace(0, np.pi/2, 100)
x_bas, y_bas = np.meshgrid(theta, theta_2)
x_grid_sphere_bas = np.cos(x_bas)*np.sin(y_bas)
y_grid_sphere_bas = np.sin(x_bas)*np.sin(y_bas)
z_grid_sphere_bas = -np.cos(y_bas)+1

test_x = np.concatenate((x_grid_sphere, x_grid_sphere_bas),axis=1)
test_y = np.concatenate((y_grid_sphere, y_grid_sphere_bas),axis=1)
test_z = np.concatenate((z_grid_sphere, z_grid_sphere_bas),axis=1)

ax.plot_surface(test_x,test_y,test_z, color ="green", alpha=0.5)

plt.show()
Now change how the points are concatenated:
test_x = np.concatenate((x_grid_sphere, x_grid_sphere_bas),axis=0)
test_y = np.concatenate((y_grid_sphere, y_grid_sphere_bas),axis=0)
test_z = np.concatenate((z_grid_sphere, z_grid_sphere_bas),axis=0)
A much different plot, but you can see how matplotlib is creating a "transition" surface to go frm one set of points to another.

You can't blame numpy and matplotlib for not being able to plot your "surface". By definition, what you are creating is not a surface at all. At best we could describe it as a piece-wise surface, but I challenge you to define a piece-wise function that will generate points on your surface.