user6202102
user6202102

Reputation: 13

How do I color individual sections of a 3d sphere in Python

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:-

enter image description here

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

Answers (2)

roadrunner66
roadrunner66

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()

enter image description here

Upvotes: 1

armatita
armatita

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:

enter image description here

Upvotes: 1

Related Questions