1

I want to add the colormap to show the gradient along x axis but unfortunately the whole figure turns black. I might be lacking something kindly help me in this. Here is the code.

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
import numpy as np

# Create a 3D figure
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Define the vertices of the rectangular rod
vertices = np.array([
    [0, -0.5, -0.5],
    [0, -0.5, 0.5],
    [0, 0.5, 0.5],
    [0, 0.5, -0.5],
    [10, -0.5, -0.5],
    [10, -0.5, 0.5],
    [10, 0.5, 0.5],
    [10, 0.5, -0.5]
])

# Define the faces of the rectangular rod
faces = np.array([
    [0, 1, 2, 3],
    [4, 5, 6, 7],
    [0, 1, 5, 4],
    [1, 2, 6, 5],
    [2, 3, 7, 6],
    [3, 0, 4, 7]
])

# Map the x-coordinate of each vertex to a color in the colormap
x = vertices[:, 0]
norm = plt.Normalize(x.min(), x.max())
colors = cm.gnuplot(norm(x))

# Create a Poly3DCollection object with the vertices, faces, and colors
rect = Poly3DCollection(vertices[faces], alpha=0.8, facecolors=colors, edgecolors='black')

# Add the rectangular rod to the plot
ax.add_collection3d(rect)

# Set the limits of the x, y, and z axes
ax.set_xlim([0, 10])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])

# Add labels to the axes
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

# Show the plot
plt.show()

I have used gunplot colormapping methodto give the gradiant color to the 3d plot but nothing works. Kindly suggest me how to proceed. If there is any other method using which i can create a gradiant with 6 colors that would also be fine.

1 Answers1

1

The first problem here is that the number of entries in the facecolors argument has to match the number of faces, otherwise it looks like matplotlib falls back to picking out the first colour in the list - here, that's black.

The second problem is that you're trying to create a cuboid with just 6 faces, but then colour it with a smooth colourmap. The polygons in matplotlib can only be coloured with a single colour each. So you have to subdivide your cuboid.

Here's my attempt at fixing these two problems! I create a set of points between 0 and 10 and then create vertices at these x-positions. I also construct the array of x-positions directly from the faces, taking an average of the x-position of each of the four vertices making up each face.

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

# Create a 3D figure
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# Define the vertices of the rectangular rod
N_sub = 50  # Set higher for better resolution; lower for better performance!
vertices = np.concatenate([
    np.array([[x, -0.5, -0.5],
              [x, -0.5, 0.5],
              [x, 0.5, 0.5],
              [x, 0.5, -0.5]])
    for x in np.linspace(0, 10, N_sub + 1)], axis=0)

# Define the faces of the rectangular rod
offset = (N_sub) * 4
faces = np.concatenate([
    [[0, 1, 2, 3]],
    *[np.array([[3, 0, 4, 7],
                [0, 1, 5, 4],
                [1, 2, 6, 5],
                [2, 3, 7, 6]]) + 4 * x for x in range(0, N_sub)],
    [[0 + offset, 1 + offset, 2 + offset, 3 + offset]]
], axis=0)

# Map the x-coordinate of each face to a color in the colormap
x = np.array([np.mean([vertices[idx, 0] for idx in face]) for face in faces])
norm = plt.Normalize(x.min(), x.max())
cmap = plt.get_cmap("gnuplot")
colors = cmap(norm(x))

# Create a Poly3DCollection object with the vertices, faces, and colors
rect = Poly3DCollection(vertices[faces], alpha=0.8, facecolors=colors)

# Add the rectangular rod to the plot
ax.add_collection3d(rect)

# Set the limits of the x, y, and z axes
ax.set_xlim([0, 10])
ax.set_ylim([-1, 1])
ax.set_zlim([-1, 1])

# Add labels to the axes
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')

# Show the plot
plt.show()

Hope this helps! I'm not sure I'm able to replicate the black edges however. I tried doing a second cuboid, like your original one, with six faces and facecolor="none" but this threw an error.

PS: I saved you an import by using plt.get_cmap.

Jared
  • 86
  • 7
  • Thats great!. It has solved the pupose. Thank you so much. But there is small doubt, when i try to extend the same graph to some bigger value of lets say x=1000 keeping all other parameter same. The graph gets shrunk in x direction but I want it to get extended along x so that i can bind a horizontal scrollbar to it. As I need to add some more plots on the surface along x direction. So it will not be visible if it gets shrunk. I request you to suggest me how to achieve that. I tred `set_box_aspect` method but it doesn't work for me. I have also tried adjusting fig size but nothing works. – Prashant Priyadarshi Apr 12 '23 at 08:47