Reputation: 13
I have created a 3d plot of a sphere in python using Mathplotlib using the code below
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0,2*np.pi, 32)
v = np.linspace(0, np.pi, 16)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
ax.plot_surface(x, y, z, rstride=4, cstride=4, color='b')
plt.show()
Picture of plot:-
I would like to color each individual box a different color. I have tried to use a color map, but I was only able to change the color based on the z value with this.
Any suggestions would be greatly appreciated. I am open to using other tools or languages to accomplish this task, but I need the boxes to be the same size.
Upvotes: 1
Views: 1325
Reputation: 7941
@Armatita's solution is very elegant, especially if you have a mapping function. I upvoted it :).
Another solution for arbitrary shapes can be done with Poly3DCollection
. Now you could import actual data and the surfaces could be arbitray in space and wouldn't have to connect.
For comparison, however I used the same sphere. I edited the answer to assign the color as a function of the two angles based on your comments below.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
r=1 # radius of sphere
phi = np.linspace(0,360, 12)/180.0*np.pi
theta = np.linspace(-90,90,7)/180.0*np.pi
# make up some function like OP (original poster) suggested:
# numerical value in the range of 20-40.
vars=[]
for i in range(len(phi)-1):
for j in range(len(theta)-1):
vars.append( (i*j* - i +j)/25+40) # min at 20, max at 40
# set colors as function of data in vars
# less than 25 as red, from 25-35 as yellow
# and anything greater than 35 as green. –
cols=[]
for var in vars:
if var <25:
col='r'
elif 25<=var<=35:
col='y'
else:
col='g'
cols.append(col)
verts2 = []
for i in range(len(phi)-1):
for j in range(len(theta)-1):
cp0= r*np.cos(phi[i])
cp1= r*np.cos(phi[i+1])
sp0= r*np.sin(phi[i])
sp1= r*np.sin(phi[i+1])
ct0= np.cos(theta[j])
ct1= np.cos(theta[j+1])
st0= r*np.sin(theta[j])
st1= r*np.sin(theta[j+1])
verts=[]
verts.append((cp0*ct0, sp0*ct0, st0))
verts.append((cp1*ct0, sp1*ct0, st0))
verts.append((cp1*ct1, sp1*ct1, st1))
verts.append((cp0*ct1, sp0*ct1, st1))
verts2.append(verts )
poly3= Poly3DCollection(verts2 ,facecolor= cols)
poly3.set_alpha(0.9)
ax.add_collection3d(poly3)
ax.set_xlabel('X')
ax.set_xlim3d(-1, 1)
ax.set_ylabel('Y')
ax.set_ylim3d(-1, 1)
ax.set_zlabel('Z')
ax.set_zlim3d(-1, 1)
plt.show()
Upvotes: 1
Reputation: 13465
Besides the link given in comments it's possible to directly map a variable to the colormap. Check your example adapted with a solution:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
u = np.linspace(0,2*np.pi, 32)
v = np.linspace(0, np.pi, 16)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
C = np.cos(x)
ax.plot_surface(x, y, z, facecolors = cm.jet(C), rstride=4, cstride=4) # Look how I gave a variable to the facecolors.
plt.show()
, this particularly bad example results in this:
Upvotes: 1