简体   繁体   中英

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

在此处输入图片说明

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.

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:

在此处输入图片说明

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

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM