如何在Matplotlib的3D柱形图上绘制渐变填充。

5

现在有一些以3D柱状图表示的统计数据(x,y)。每个柱子的高度代表(x,y)平面方格内点的密度。目前,我可以为每个柱子设置不同的颜色。但是,我想在3D柱状图上使用渐变色,类似于cmap的颜色映射方式,这样柱子将根据密度进行渐变填充。

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

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

# height of the bars
z = np.ones((4, 4)) * np.arange(4)
# position of the bars
xpos, ypos = np.meshgrid(np.arange(4), np.arange(4))

xpos = xpos.flatten('F')

ypos = ypos.flatten('F')

zpos = np.zeros_like(xpos)


dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = z.flatten()

ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')

plt.show()

输出上述代码:

在这里输入图片描述

1个回答

9
首先,我要说的是,当涉及到复杂的3D图形时,matplotlib可能不是最佳选择。
话虽如此,在条形图上没有内置方法可以产生不同颜色的条形。
因此,我们需要以某种方式模拟条形。下面是一种可能的解决方案。在这里,我们使用plot_surface绘制一个包含渐变的条形图。

enter image description here

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors 
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111, projection= Axes3D.name)

def make_bar(ax, x0=0, y0=0, width = 0.5, height=1 , cmap="viridis",  
              norm=matplotlib.colors.Normalize(vmin=0, vmax=1), **kwargs ):
    # Make data
    u = np.linspace(0, 2*np.pi, 4+1)+np.pi/4.
    v_ = np.linspace(np.pi/4., 3./4*np.pi, 100)
    v = np.linspace(0, np.pi, len(v_)+2 )
    v[0] = 0 ;  v[-1] = np.pi; v[1:-1] = v_
    x = np.outer(np.cos(u), np.sin(v))
    y = np.outer(np.sin(u), np.sin(v))
    z = np.outer(np.ones(np.size(u)), np.cos(v))

    xthr = np.sin(np.pi/4.)**2 ;  zthr = np.sin(np.pi/4.)
    x[x > xthr] = xthr; x[x < -xthr] = -xthr
    y[y > xthr] = xthr; y[y < -xthr] = -xthr
    z[z > zthr] = zthr  ; z[z < -zthr] = -zthr

    x *= 1./xthr*width; y *= 1./xthr*width
    z += zthr
    z *= height/(2.*zthr)
    #translate
    x += x0; y += y0
    #plot
    ax.plot_surface(x, y, z, cmap=cmap, norm=norm, **kwargs)

def make_bars(ax, x, y, height, width=1):
    widths = np.array(width)*np.ones_like(x)
    x = np.array(x).flatten()
    y = np.array(y).flatten()

    h = np.array(height).flatten()
    w = np.array(widths).flatten()
    norm = matplotlib.colors.Normalize(vmin=0, vmax=h.max())
    for i in range(len(x.flatten())):
        make_bar(ax, x0=x[i], y0=y[i], width = w[i] , height=h[i], norm=norm)


X, Y = np.meshgrid([1,2,3], [2,3,4])
Z = np.sin(X*Y)+1.5

make_bars(ax, X,Y,Z, width=0.2, )
plt.show()

重新考虑一下,使用球面坐标可能不是最好的选择;使用柱面坐标可能更有效率。但我认为重点已经传达出来了。 - ImportanceOfBeingErnest
我想知道是否可以使用数组或81个值来完成此示例。我有一个包含81个值的数组,并希望在(x,y)(9,9)网格中使用您的渐进色彩梯度绘制3D条形图。我的数组是flux = [0.0,0.0,0.0,0.00523951,0.00536901,0.00533961,0.0,0.0,0.0,................... ],我将其重塑为data_2d = np.reshape(flux,(9,9))以获取9,9数组。如何像您那样获得每个条形图中的渐进颜色的条形图?能否请指导一下?谢谢。 - Sharif Abu Darda
请您查看我上面的评论。我想知道这是否可能。能否给予指导? - Sharif Abu Darda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接