Dman - 1 year ago 56

Python Question

I am trying to color each individual face of a cylinder, however I am not sure how to go about it, I have tried the following:

`for i in range(10):`

col.append([])

for i in range(10):

for j in range(20):

col[i].append(plt.cm.Blues(0.4))

ax.plot_surface(X, Y, Z,facecolors = col,edgecolor = "red")

I want each face to be assigned its own color, so I would think I would supply an array of colors for each of the faces in a 2d array.

But this gives an error:

`in plot_surface`

colset.append(fcolors[rs][cs])

IndexError: list index out of range

Here is the full code:

`import numpy as np`

from matplotlib import cm

from matplotlib import pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

from scipy.linalg import norm

from mpl_toolkits.mplot3d.art3d import Poly3DCollection

fig = plt.figure()

ax = fig.add_subplot(111, projection='3d')

origin = np.array([0, 0, 0])

#axis and radius

p0 = np.array([1, 3, 2])

p1 = np.array([8, 5, 9])

R = 5

#vector in direction of axis

v = p1 - p0

#find magnitude of vector

mag = norm(v)

#unit vector in direction of axis

v = v / mag

#make some vector not in the same direction as v

not_v = np.array([1, 0, 0])

if (v == not_v).all():

not_v = np.array([0, 1, 0])

#make vector perpendicular to v

n1 = np.cross(v, not_v)

#normalize n1

n1 /= norm(n1)

#make unit vector perpendicular to v and n1

n2 = np.cross(v, n1)

#surface ranges over t from 0 to length of axis and 0 to 2*pi

t = np.linspace(0, mag, 200)

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

#use meshgrid to make 2d arrays

t, theta = np.meshgrid(t, theta)

#generate coordinates for surface

X, Y, Z = [p0[i] + v[i] * t + R * np.sin(theta) * n1[i] + R * np.cos(theta) * n2[i] for i in [0, 1, 2]]

col = []

for i in range(10):

col.append([])

for i in range(10):

for j in range(20):

col[i].append(plt.cm.Blues(0.4))

ax.plot_surface(X, Y, Z,facecolors = col,edgecolor = "red")

#plot axis

ax.plot(*zip(p0, p1), color = 'red')

ax.set_xlim(0, 10)

ax.set_ylim(0, 10)

ax.set_zlim(0, 10)

plt.axis('off')

ax.axes.get_xaxis().set_visible(False)

ax.axes.get_yaxis().set_visible(False)

plt.show()

Answer Source

Your `Z`

array is of size `100x200`

, yet you are only specifying `10x20`

colors. A quicker way to make `col`

(with the right dimensions) might be something like:

```
col1 = plt.cm.Blues(np.linspace(0,1,200)) # linear gradient along the t-axis
col1 = np.repeat(col1[np.newaxis,:, :], 100, axis=0) # expand over the theta-axis
col2 = plt.cm.Blues(np.linspace(0,1,100)) # linear gradient along the theta-axis
col2 = np.repeat(col2[:, np.newaxis, :], 200, axis=1) # expand over the t-axis
ax=plt.subplot(121, projection='3d')
ax.plot_surface(X, Y, Z, facecolors=col1)
ax=plt.subplot(122, projection='3d')
ax.plot_surface(X, Y, Z, facecolors=col2)
```

Which produces: