【问题标题】:setting spacing between grouped bar plots in matplotlib在 matplotlib 中设置分组条形图之间的间距
【发布时间】:2012-07-22 04:30:12
【问题描述】:

我正在尝试按照图库中的示例在 matplotlib 中制作分组条形图。我使用以下内容:

import matplotlib.pyplot as plt
plt.figure(figsize=(7,7), dpi=300)
xticks = [0.1, 1.1]
groups = [[1.04, 0.96],
          [1.69, 4.02]]
group_labels = ["G1", "G2"]
num_items = len(group_labels)
ind = arange(num_items)
width = 0.1
s = plt.subplot(1,1,1)
for num, vals in enumerate(groups):
    print "plotting: ", vals
    group_len = len(vals)
    gene_rects = plt.bar(ind, vals, width,
                         align="center")
    ind = ind + width
num_groups = len(group_labels)
# Make label centered with respect to group of bars
# Is there a less complicated way?
offset = (num_groups / 2.) * width
xticks = arange(num_groups) + offset
s.set_xticks(xticks)
print "xticks: ", xticks
plt.xlim([0 - width, max(xticks) + (num_groups * width)])
s.set_xticklabels(group_labels)

我的问题是:

  1. 如何控制条形组之间的间距?现在间距很大,看起来很傻。请注意,我不想让条形变宽 - 我希望它们具有相同的宽度,但要靠得更近。

  2. 如何让标签在条形组下方居中?我试图提出一些算术计算来将 xlabels 定位在正确的位置(参见上面的代码),但它仍然有点偏离......感觉有点像编写绘图库而不是使用绘图库。如何解决这个问题? (matplotlib 是否有包装器或内置实用程序,这是默认行为?)

编辑: 回复@mlgill:谢谢您的回答。您的代码当然要优雅得多,但仍然存在相同的问题,即条形的宽度和组之间的间距不是单独控制的。您的图表看起来是正确的,但条形太宽了 - 它看起来像 Excel 图表 - 我想让条形变细。

宽度和边距现在已链接,所以如果我尝试:

margin = 0.60
width = (1.-2.*margin)/num_items

它使酒吧变得更瘦,但使团队相距甚远,因此情节再次看起来不正确。

如何制作一个带两个参数的分组条形图函数:每个条形的宽度和条形组之间的间距,并像您的代码一样正确绘制它,即 x 轴标签居中于下方组?

我认为由于用户必须计算特定的低级布局数量,例如边距和宽度,我们仍然基本上是在编写一个绘图库:)

【问题讨论】:

    标签: python numpy plot matplotlib scipy


    【解决方案1】:

    其实我觉得这个问题最好通过调整figsizewidth来解决;这是figsize=(2,7)width=0.3 的输出:

    顺便说一句,如果您使用 pandas 包装器,这种类型的事情会变得很多简单(我还导入了 seaborn,这不是解决方案所必需的,但会使情节在我看来更漂亮、更现代):

    import pandas as pd        
    import seaborn 
    seaborn.set() 
    
    df = pd.DataFrame(groups, index=group_labels)
    df.plot(kind='bar', legend=False, width=0.8, figsize=(2,5))
    plt.show()
    

    【讨论】:

    • 非常好的答案。 +1 提供海运建议。谢谢
    【解决方案2】:

    这两个问题的诀窍是理解 Matplotlib 中的条形图期望每个系列(G1、G2)的总宽度为“1.0”,计算两边的边距。因此,设置边距可能是最简单的,然后根据每个系列有多少条来计算每个条的宽度。在您的情况下,每个系列有两个条形图。

    假设您将每个条形左对齐,而不是像您所做的那样将它们居中对齐,此设置将导致 x 轴上从 0.0 到 1.0、1.0 到 2.0 等范围的系列。因此,每个系列的确切中心,也就是您希望标签出现的位置,将位于 0.5、1.5 等处。

    我已经清理了你的代码,因为有很多无关的变量。见里面的 cmets。

    import matplotlib.pyplot as plt
    import numpy as np
    
    plt.figure(figsize=(7,7), dpi=300)
    
    groups = [[1.04, 0.96],
              [1.69, 4.02]]
    group_labels = ["G1", "G2"]
    num_items = len(group_labels)
    # This needs to be a numpy range for xdata calculations
    # to work.
    ind = np.arange(num_items)
    
    # Bar graphs expect a total width of "1.0" per group
    # Thus, you should make the sum of the two margins
    # plus the sum of the width for each entry equal 1.0.
    # One way of doing that is shown below. You can make
    # The margins smaller if they're still too big.
    margin = 0.05
    width = (1.-2.*margin)/num_items
    
    s = plt.subplot(1,1,1)
    for num, vals in enumerate(groups):
        print "plotting: ", vals
        # The position of the xdata must be calculated for each of the two data series
        xdata = ind+margin+(num*width)
        # Removing the "align=center" feature will left align graphs, which is what
        # this method of calculating positions assumes
        gene_rects = plt.bar(xdata, vals, width)
    
    
    # You should no longer need to manually set the plot limit since everything 
    # is scaled to one.
    # Also the ticks should be much simpler now that each group of bars extends from
    # 0.0 to 1.0, 1.0 to 2.0, and so forth and, thus, are centered at 0.5, 1.5, etc.
    s.set_xticks(ind+0.5)
    s.set_xticklabels(group_labels)
    

    【讨论】:

    • 另外,请注意,一旦我的 cmets 被删除,命令的数量就会大大减少。虽然我认为 Matplotlib 的条形图功能可以在某些方面进行小幅改进,但这肯定不再像编写绘图库一样。 :)
    • 感谢您的评论,我在主帖的编辑中回复了您。
    • 从你上面写的,听起来你要么希望整个图形的宽度更小(这可以在创建图形的行中设置),要么希望边距本身更大,这将保持纵横比相同。您还可以调整宽度和 xdata 计算,以便每个条之间有一个边距。实现这一点只需要基本的代数。除了这三个想法,我不知道你在问什么。
    • 关于您对 Matplotlib 的抱怨,它是一个非常强大的绘图库,我在最近的两篇科学出版物中使用了它。但如果你觉得它太复杂或“太像编写自己的绘图库”,没有人会阻止你尝试其他东西。
    • 我想你也可以在图表的最左端和最右端添加一个额外的边距。如果我们停下来思考这实际上意味着什么,最简单的方法是将 x 限制从 (0.,2.) 设置为 (-1.,3.)。您拥有在原始脚本中设置 xlimits 的功能,所以我认为您可以弄清楚如何做到这一点。
    【解决方案3】:

    我阅读了 Paul Ivanov 在Nabble 上发布的答案,该答案可能会以较低的复杂性解决此问题。只需将索引设置如下。这将增加分组列之间的间距。

    ind = np.arange(0,12,2)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-25
      • 2013-12-25
      相关资源
      最近更新 更多