Reputation: 81
Using: [python] [numpy] [matplotlib]
So I have a 3D array to create a scatter plot making a n * n * n cube. Those points have different values of potential represented by colors.
size = 11
z = y = x = size
potential = np.zeros((z, y, x))
Positive = 10
Negative = -10
""" ------- Positive Polo --------- """
polox = poloy = poloz = [1,2]
polos=[polox,poloy,poloz]
polop = [list(x) for x in np.stack(np.meshgrid(*polos)).T.reshape(-1,len(polos))] # Positive polos list
for coord in polop:
potential[coord] = Positive
""" ------- Negative Polo --------- """
polo2x = polo2y = polo2z = [size-3,size-2]
polos2=[polo2x,polo2y,polo2z]
polon = [list(x) for x in np.stack(np.meshgrid(*polos2)).T.reshape(-1,len(polos2))] # Negative polos list
for coord in polon:
potential[coord] = Negative
I have 2 polos of values -10 and 10 at the start and the rest of the points are calculated like this: (the mean of the surrounding points, no diagonals):
for z in range(1,size):
for y in range(1,size):
for x in range(1,size):
if [z,y,x] in polop:
potential[z,y,x] = Positive # If positive polo, keeps potential
elif [z,y,x] in polon:
potential[z,y,x] = Negative # If negative polo, keeps potential
elif z!=size-1 and y!=size-1 and x!=size-1: # Sets the potential to the mean potential of neighbors
potential[z][y][x] = (potential[z][y][x+1] + potential[z][y][x-1] + potential[z][y+1][x] + potential[z][y-1][x] + potential[z+1][y][x] + potential[z-1][y][x]) / 6
And for the outer cells:
for z in range(0,size):
for y in range(0,size):
for x in range(0,size):
potential[z,y,0] = potential[z,y,2]
potential[z,0,x] = potential[z,2,x]
potential[0,y,x] = potential[2,y,x]
if z == size-1:
potential[size-1,y,x] = potential[size-3,y,x]
elif y == size-1:
potential[z,size-1,x] = potential[z,size-3,x]
elif x == size-1:
potential[z,y,size-1] = potential[z,y,size-3]
What I need is to show a surface connecting the points that have the same value interval 'same colors' (like from 0 to 2.5).
I know that there are a lot of questions like this, but I can't adapt to my code, it either doesn't show (such as this) or it's not the same problem or it's not with python (as this one), that's why I'm asking again. It can also be shown as a lot of subplots each with a surface.
Note: My 3D array is such that if I type print(potential[1,1,1]) it shows the value of that cell that, as you can see in the image below, is 10. And that's what I use to show the colors.
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
z,y,x = potential.nonzero()
cube = ax.scatter(x, y, z, zdir='z', c=potential[z,y,x], cmap=plt.cm.rainbow) # Plot the cube
cbar = fig.colorbar(cube, shrink=0.6, aspect=5) # Add a color bar which maps values to colors.
Upvotes: 2
Views: 4553
Reputation: 3245
It would be beneficial for you to create a Minimum, Complete and Verifiable Example to make assistance easier.
It's still not clear to me how you mean to calculate your potential, nor how you mean to generate your surface, so I have included trivial functions.
The code below will generate a 3D Scatterplot of coloured points and a Surface with the average value of the colour.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
def fn(x, y):
"""Custom fuction to determine the colour (potential?) of the point"""
return (x + y) / 2 # use average as a placeholder
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
size = 11 # range 0 to 10
# Make the 3D grid
X, Y, Z = np.meshgrid(np.arange(0, size, 1),
np.arange(0, size, 1),
np.arange(0, size, 1))
# calculate a colour for point(x,y,z)
zs = np.array([fn(x, y) for x, y in zip(np.ravel(X), np.ravel(Y))])
ZZ = zs.reshape(X.shape) # this is used below
# create the surface
xx, yy = np.meshgrid(np.arange(0, size, 1), np.arange(0, size, 1))
# Calcule the surface Z value, e.g. average of the colours calculated above
zzs = np.array([np.average(ZZ[x][y]) for x, y in zip(np.ravel(xx), np.ravel(yy))])
zz= zzs.reshape(xx.shape)
cube = ax.scatter(X, Y, Z, zdir='z', c=zs, cmap=plt.cm.rainbow)
surf = ax.plot_surface(xx, yy, zz, cmap=plt.cm.rainbow)
cbar = fig.colorbar(cube, shrink=0.6, aspect=5) # Add a color bar
plt.show()
The image generated will look something like this:
EDIT: With your additional code, I'm able to replicate your cube.
Then use the following code to generate a surface:
xx, yy = np.meshgrid(np.arange(0, size, 1), np.arange(0, size, 1))
#define potential range
min_p = 1.0
max_p = 4.0
zz = np.zeros((size, size))
for i in range(size): # X
for j in range(size): # Y
for k in range(size): # Z
p = potential[k,j,i]
if min_p < p < max_p:
zz[j][i] = p # stop at the first element to meet the conditions
break # break to use the first value in range
Then to plot this surface:
surf = ax.plot_surface(xx, yy, zz, cmap=plt.cm.rainbow)
Note: include vmin and vmax keyword args to keep the same scale, I've left those out so the surface deviations are more visible. I also set the alpha on the cube to 0.2 to make it easier to see the surface.
Upvotes: 1