Transparency for Poly3DCollection plot in matplotlib

前端 未结 5 1281
无人共我
无人共我 2020-11-30 06:25

I am trying to draw some objects with the fabulous Matplotlib package for Python. These objects consist of points implemented with plt.scatter() and patches imp

相关标签:
5条回答
  • 2020-11-30 06:32

    I found a nice workaround: After plotting the data, do another plot on top with the same color and lighter line style. Instead of Poly3DCollection I use Line3DCollection, so no faces are plotted. The result looks very much as anticipated.

    See below the new plot and the script creating it.

    enter image description here

    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    
    x = [0, 2, 1, 1]
    y = [0, 0, 1, 0]
    z = [0, 0, 0, 1]
    
    vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]
    
    tupleList = list(zip(x, y, z))
    
    poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
    ax.scatter(x,y,z)
    ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5))
    ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.2, linestyles=':'))
    
    plt.show()
    
    0 讨论(0)
  • 2020-11-30 06:36

    Thanks a lot Chilichiller and Julian. Your examples are very useful to me at present, because I am working on a little project about 3D representation of matrices with matplotlib, and Poly3DCollection seems suitable for the task.

    A little note, that maybe can be useful to future readers. Running your examples in Python 3 gives TypeError: 'zip' object is not subscriptable.

    The simplest solution is to wrap the return value of zip in a call to list() (as indicated by "Dive Into Python 3": http://www.diveintopython3.net/porting-code-to-python-3-with-2to3.html).

    0 讨论(0)
  • 2020-11-30 06:42

    Here is a version that uses only one call to Poly3DCollection, where edgecolors='k' controls the color of the line and facecolors='w' controls the color of the faces. Note how Matplotlib colors the edges behind the polygon in a lighter gray color.

    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    
    x = [0, 2, 1, 1]
    y = [0, 0, 1, 0]
    z = [0, 0, 0, 1]
    
    vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]
    
    tupleList = list(zip(x, y, z))
    
    poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
    ax.scatter(x,y,z)
    ax.add_collection3d(Poly3DCollection(poly3d, edgecolors='k', facecolors='w', linewidths=1, alpha=0.5))
    
    plt.show()
    

    Caution The API for Poly3DCollection is rather confusing: the accepted keyword arguments are all of colors, edgecolor, edgecolors, facecolor, and facecolors (using aliases and decorators to define multiple kwargs to mean the same thing, where the "s" is optional for facecolor and edgecolor).

    0 讨论(0)
  • 2020-11-30 06:47

    This bug has been fixed in the new matplotlib. I'm running version 1.5.1.

    You can see your version by running python, then doing:

    import matplotlib
    matplotlib.__version__
    

    You can get matplotlib using pip. If you're on Ubuntu, run this from a terminal:

    sudo apt-get install python-pip
    sudo pip install matplotlib
    
    0 讨论(0)
  • 2020-11-30 06:53

    I made a slight modification to the OP code and got the transparency working. It appears that the facecolors argument of Poly3DCollection overrides the transparency argument, so the solution was to set the color in a separate call to either Poly3DCollection.set_color or Poly3DCollection.set_facecolor:

    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d.art3d import Poly3DCollection
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    
    x = [0, 2, 1, 1]
    y = [0, 0, 1, 0]
    z = [0, 0, 0, 1]
    
    vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]
    
    tupleList = zip(x, y, z)
    
    poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
    ax.scatter(x,y,z)
    collection = Poly3DCollection(poly3d, linewidths=1, alpha=0.2)
    face_color = [0.5, 0.5, 1] # alternative: matplotlib.colors.rgb2hex([0.5, 0.5, 1])
    collection.set_facecolor(face_color)
    ax.add_collection3d(collection)
    
    plt.show()
    

    Interestingly, if you explicitly set the edge color with collection.set_edgecolor('k'), the edges will also honor the transparency setting.

    0 讨论(0)
提交回复
热议问题