简体   繁体   English

在matplotlib中设置分组条形图之间的间距

[英]setting spacing between grouped bar plots in matplotlib

I'm trying to make a grouped bar plot in matplotlib, following the example in the gallery. 我正在尝试在matplotlib中创建一个分组的条形图,遵循库中的示例。 I use the following: 我使用以下内容:

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)

在此输入图像描述

My questions are: 我的问题是:

  1. How can I control the space between the groups of bars? 如何控制各组条之间的空间? Right now the spacing is huge and it looks silly. 现在间距很大,看起来很傻。 Note that I do not want to make the bars wider - I want them to have the same width, but be closer together. 请注意,我不想让条形更宽 - 我希望它们具有相同的宽度,但是要靠得更近。

  2. How can I get the labels to be centered below the groups of bars? 如何让标签在条形组下方居中? I tried to come up with some arithmetic calculations to position the xlabels in the right place (see code above) but it's still slightly off... it feels a bit like writing a plotting library rather than using one. 我试图想出一些算术计算来将xlabels定位在正确的位置(参见上面的代码),但它仍然稍微偏离......感觉有点像编写绘图库而不是使用一个。 How can this be fixed? 怎么解决这个问题? (Is there a wrapper or built in utility for matplotlib where this is default behavior?) (matplotlib是否有一个包装器或内置实用程序,这是默认行为?)

EDIT: Reply to @mlgill: thank you for your answer. 编辑:回复@mlgill:谢谢你的回答。 Your code is certainly much more elegant but still has the same issue, namely that the width of the bars and the spacing between the groups are not controlled separately. 您的代码肯定更优雅,但仍然存在相同的问题,即条的宽度和组之间的间距不是单独控制的。 Your graph looks correct but the bars are far too wide -- it looks like an Excel graph -- and I wanted to make the bar thinner. 你的图表看起来是正确的,但条形图太宽了 - 它看起来像一个Excel图形 - 我想让条形更薄。

Width and margin are now linked, so if I try: 现在链接宽度和边距,所以如果我尝试:

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

It makes the bar skinnier, but brings the group far apart, so the plot again does not look right. 这使得酒吧更加苗条,但却让这个群体相距甚远,所以情节再次看起来并不合适。

How can I make a grouped bar plot function that takes two parameters: the width of each bar, and the spacing between the bar groups, and plots it correctly like your code did, ie with the x-axis labels centered below the groups? 如何创建一个带有两个参数的分组条形图功能:每个条形图的宽度,条形图组之间的间距,以及正确编写代码的图形,即x轴标签位于组的下方?

I think that since the user has to compute specific low-level layout quantities like margin and width, we are still basically writing a plotting library :) 我认为,由于用户必须计算特定的低级布局数量,如边距和宽度,我们仍然基本上编写绘图库:)

The trick to both of your questions is understanding that bar graphs in Matplotlib expect each series (G1, G2) to have a total width of "1.0", counting margins on either side. 两个问题的诀窍是要理解Matplotlib中的条形图表示每个系列(G1,G2)的总宽度为“1.0”,计算两侧的边距。 Thus, it's probably easiest to set margins up and then calculate the width of each bar depending on how many of them there are per series. 因此,最简单的方法是设置边距,然后计算每个柱的宽度,具体取决于每个系列中有多少个。 In your case, there are two bars per series. 在您的情况下,每个系列有两个条。

Assuming you left align each bar, instead of center aligning them as you had done, this setup will result in series which span from 0.0 to 1.0, 1.0 to 2.0, and so forth on the x-axis. 假设你左对齐每个条,而不是像你一样对齐它们,这个设置将导致系列在x轴上跨越0.0到1.0,1.0到2.0,依此类推。 Thus, the exact center of each series, which is where you want your labels to appear, will be at 0.5, 1.5, etc. 因此,每个系列的确切中心(您希望标签出现的位置)将为0.5,1.5等。

I've cleaned up your code as there were a lot of extraneous variables. 我已经清理了你的代码,因为有很多无关的变量。 See comments within. 见其中的评论。

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)

从我的代码输出。

Actually I think this problem is best solved by adjusting figsize and width ; 实际上我认为这个问题最好通过调整figsizewidth来解决; here is my output with figsize=(2,7) and width=0.3 : 这是我的输出figsize=(2,7)width=0.3

在此输入图像描述

By the way, this type of thing becomes a lot simpler if you use pandas wrappers (i've also imported seaborn , not necessary for the solution, but makes the plot a lot prettier and more modern looking in my opinion): 顺便说一句,如果你使用这种类型的事情变得简单了很多 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()

在此输入图像描述

I read an answer that Paul Ivanov posted on Nabble that might solve this problem with less complexity. 我读了一篇保罗伊凡诺夫在Nabble上发布的答案,可以解决这个问题而不那么复杂。 Just set the index as below. 只需设置索引如下。 This will increase the spacing between grouped columns. 这将增加分组列之间的间距。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM