【问题标题】:How do I increase the gap of 3D bar chart in y-axis (matplotlib question)?如何增加 3D 条形图在 y 轴上的间隙(matplotlib 问题)?
【发布时间】:2021-06-23 14:07:15
【问题描述】:

我有一个 4*7 3D 条形图,我想在其中增加 y 轴上 7 个条形的间距或间距。

下面是我的代码:

import pandas as pd
import matplotlib.pyplot as plt  
from mpl_toolkits.mplot3d import axes3d
import numpy as np


# Set plotting style
plt.style.use('seaborn-white')

dz=[]
z0 = np.array([ 1.,  3.,  11.,   8.,   7.,   6.,   6.,   6.,   5.,   4.,
                3.,   11.,   10.,  1.,  1.,  7., 1.,  3.,  11.,   8.,
                8.,   7.,   6.,   6., 1.,  1.,  7., 1.,])
dz.append(z0)

z1 =[ 5.,   5.,   8.,   4.,   2.,   0.,   0.,   0.,   0.,   0.,   0.,
      1.,   6.,  5.,   7.,   2., 1.,  3.,  11.,   8., 8.,   7.,   6.,   6.,
      1.,  1.,  7., 1.,]

dz.append(z1)

z2 =[ 15.,   5.,   8.,   2.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
      3.,   5.,  2.,   7.,   2., 1.,  3.,  11.,   8., 8.,   7.,   6.,   6.,
      1.,  1.,  7., 1.,]

dz.append(z2)

_zpos = z0*0


xlabels = pd.Index(['X01', 'X02', 'X03', 'X04'], dtype='object')

ylabels = pd.Index(['Y01', 'Y02', 'Y03', 'Y04', 'Y05', 'Y06', 'Y07'], dtype='object')

x = np.arange(xlabels.shape[0])

y = np.arange(ylabels.shape[0])

x_M, y_M = np.meshgrid(x, y, copy=False)

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

# Making the intervals in the axes match with their respective entries
ax.w_xaxis.set_ticks(x + 0.5/2.)
ax.w_yaxis.set_ticks(y + 0.5/2.)

# Renaming the ticks as they were before
ax.w_xaxis.set_ticklabels(xlabels)
ax.w_yaxis.set_ticklabels(ylabels)

# Labeling the 3 dimensions
ax.set_xlabel('X label')
ax.set_ylabel('Y label')
ax.set_zlabel('Z label')

# Choosing the range of values to be extended in the set colormap
values = np.linspace(0.2, 1., x_M.ravel().shape[0])

# Selecting an appropriate colormap

colors = ['#FFC04C', 'blue', '#3e9a19', 
          '#599be5','#bf666f','#a235bf','#848381','#fb90d6','#fb9125']

# Increase the number of segment to 3 by changing the X in 'range(X)' to 3.
for i in range(3):
    ax.bar3d(x_M.ravel(), y_M.ravel(), _zpos, dx=0.3, dy=0.3, dz=dz[i], 
              color=colors[i])
    _zpos += dz[i]
 

#plt.gca().invert_xaxis()
#plt.gca().invert_yaxis()
Segment1_proxy         = plt.Rectangle((0, 0), 1, 1, fc="#FFC04C")   
Segment2_proxy         = plt.Rectangle((0, 0), 1, 1, fc="blue")
Segment3_proxy         = plt.Rectangle((0, 0), 1, 1, fc="#3e9a19")

ax.legend([Segment1_proxy,
           Segment2_proxy,
           Segment3_proxy],['Segment1',
                            'Segment2',
                            'Segment3'
         ])
plt.show()

我试图寻找解决方案,但找不到与 3D 条形图相关的任何解决方案。我想这些二维条形图的解决方案不能在这里应用(或者我可能错了),因此我不确定从哪里开始(一天前刚开始学习 matplotlib)。有人可以帮忙吗?

以下帖子于 2021 年 3 月 31 日编辑

感谢 Yozhikoff 为上述问题提供解决方案,但希望改进可视化...

我增加了x轴之间的间隙,即通过将语法更改为来增加X01和X02之间的间隙

ax.set_box_aspect((10, 3, 1)) 

for i in range(3):
    ax.bar3d(x_M.ravel(), y_M.ravel(), _zpos, dx=0.03, dy=0.3, dz=dz[i], 
              color=colors[i], lightsource=ls)
    _zpos += dz[i]

然后生成下图:

您可能会看到 z 轴被挤压,但如果我将 ax.set_box_aspect 的值更改为 (30,3,5),x 轴之间的差距似乎并没有增加太多,整体身材变小了。

有什么建议吗?

【问题讨论】:

    标签: python matplotlib 3d bar-chart


    【解决方案1】:

    您可以尝试使用ax.set_box_aspect() 方法。

    fig = plt.figure(figsize=(7, 7))
    ax = fig.add_subplot(111, projection='3d')
    ax.set_box_aspect((1, 3, 1))
    

    与精心挑选的ax.bar3d()dxdy 参数结合使用效果特别好。

    有几种方法可以进一步提高美感:

    1. 使用plt.gca().view_init(elev=15, azim=20) 找到更好的角度
    2. 制作LightSource,以正确的方式突出您的情节
      ls = mpl.colors.LightSource(azdeg=30, altdeg=10)
      ax.bar3d(..., lightsource=ls)
      

    在你的情况下,我会做这样的事情:

    import pandas as pd
    import matplotlib.pyplot as plt  
    from mpl_toolkits.mplot3d import axes3d
    import numpy as np
    import matplotlib as mpl
    
    
    # Set plotting style
    plt.style.use('seaborn-white')
    
    dz=[]
    z0 = np.array([ 1.,  3.,  11.,   8.,   7.,   6.,   6.,   6.,   5.,   4.,
                    3.,   11.,   10.,  1.,  1.,  7., 1.,  3.,  11.,   8.,
                    8.,   7.,   6.,   6., 1.,  1.,  7., 1.,])
    dz.append(z0)
    
    z1 =[ 5.,   5.,   8.,   4.,   2.,   0.,   0.,   0.,   0.,   0.,   0.,
          1.,   6.,  5.,   7.,   2., 1.,  3.,  11.,   8., 8.,   7.,   6.,   6.,
          1.,  1.,  7., 1.,]
    
    dz.append(z1)
    
    z2 =[ 15.,   5.,   8.,   2.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
          3.,   5.,  2.,   7.,   2., 1.,  3.,  11.,   8., 8.,   7.,   6.,   6.,
          1.,  1.,  7., 1.,]
    
    dz.append(z2)
    
    _zpos = z0*0
    
    
    xlabels = pd.Index(['X01', 'X02', 'X03', 'X04'], dtype='object')
    
    ylabels = pd.Index(['Y01', 'Y02', 'Y03', 'Y04', 'Y05', 'Y06', 'Y07'], dtype='object')
    
    x = np.arange(xlabels.shape[0])
    
    y = np.arange(ylabels.shape[0])
    
    x_M, y_M = np.meshgrid(x, y, copy=False)
    
    fig = plt.figure(figsize=(7, 7))
    ax = fig.add_subplot(111, projection='3d')
    ax.set_box_aspect((1, 3.5, 1))
    plt.gca().view_init(15, 20)
    
    ls = mpl.colors.LightSource(azdeg=30, altdeg=10)
    
    # Making the intervals in the axes match with their respective entries
    ax.w_xaxis.set_ticks(x + 0.5/2.)
    ax.w_yaxis.set_ticks(y + 0.5/2.)
    
    # Renaming the ticks as they were before
    ax.w_xaxis.set_ticklabels(xlabels)
    ax.w_yaxis.set_ticklabels(ylabels)
    
    # Labeling the 3 dimensions
    ax.set_xlabel('X label')
    ax.set_ylabel('Y label')
    ax.set_zlabel('Z label')
    
    # Choosing the range of values to be extended in the set colormap
    values = np.linspace(0.2, 1., x_M.ravel().shape[0])
    
    # Selecting an appropriate colormap
    
    colors = ['#FFC04C', 'blue', '#3e9a19', 
              '#599be5','#bf666f','#a235bf','#848381','#fb90d6','#fb9125']
    
    # Increase the number of segment to 3 by changing the X in 'range(X)' to 3.
    for i in range(3):
        ax.bar3d(x_M.ravel(), y_M.ravel(), _zpos, dx=0.2, dy=0.1, dz=dz[i], 
                  color=colors[i], lightsource=ls)
        _zpos += dz[i]
     
    
    Segment1_proxy         = plt.Rectangle((0, 0), 1, 1, fc="#FFC04C")   
    Segment2_proxy         = plt.Rectangle((0, 0), 1, 1, fc="blue")
    Segment3_proxy         = plt.Rectangle((0, 0), 1, 1, fc="#3e9a19")
    
    ax.legend([Segment1_proxy,
               Segment2_proxy,
               Segment3_proxy],['Segment1',
                                'Segment2',
                                'Segment3'
             ])
    
    
    
    plt.show()
    

    Example

    【讨论】:

    • 感谢 Yozhikoff。我尝试增加到 ax.set_box_aspect((1,8,1)) 但比例看起来很奇怪。尝试更改 ax.bar3d() 中的 dx 和 dy 值,并且绘图看起来也不好看。有什么建议吗?
    • 澄清一下——是剧情结构有问题还是只是美学问题?
    • 我已编辑答案以引入更具视觉吸引力的版本。
    • 您好 Yozhikoff,我已编辑问题以包含您提出的解决方案的问题。
    • ax.set_box_aspect((x, y, z)) 定义的不是维度的绝对大小,而是它们的相对比例。因此,如果您从 (10, 3, 1) 开始并希望保持 x/y 比率并拉伸 z,您可以尝试 (10, 3, 2)
    猜你喜欢
    • 2011-10-02
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    相关资源
    最近更新 更多