我正在尝试按照图库中的示例在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)
我的问题是:
如何控制酒吧组之间的空间?现在间距很大,看起来很傻。请注意,我不想让条形更宽 - 我希望它们具有相同的宽度,但要靠得更近。
如何让标签在条形组下方居中?我试图想出一些算术计算来将xlabels定位在正确的位置(参见上面的代码),但它仍然稍微偏离......感觉有点像编写绘图库而不是使用一个。怎么解决这个问题? (matplotlib是否有一个包装器或内置实用程序,这是默认行为?)
编辑:回复@mlgill:谢谢你的回答。您的代码肯定更优雅,但仍然存在相同的问题,即条的宽度和组之间的间距不是单独控制的。你的图表看起来是正确的,但条形图太宽了 - 它看起来像一个Excel图形 - 我想让条形更薄。
现在链接了宽度和边距,所以如果我尝试:
margin = 0.60
width = (1.-2.*margin)/num_items
这使得酒吧更加苗条,但让这个小组相距甚远,所以情节再次看起来并不合适。
如何制作一个带有两个参数的分组条形图功能:每个条形图的宽度,条形图组之间的间距,以及正确编码的图形,即x轴标签位于下方组?
我认为,由于用户必须计算特定的低级布局数量,如边距和宽度,我们仍然基本上编写绘图库:)
答案 0 :(得分:17)
你的两个问题的诀窍是要理解Matplotlib中的条形图期望每个系列(G1,G2)的总宽度为“1.0”,计算两边的边距。因此,最简单的方法是设置边距,然后计算每个柱的宽度,具体取决于每个系列中有多少个。在你的情况下,每个系列有两个条。
假设你左对齐每个条形图,而不是像你一样对齐它们,这个设置将导致系列在x轴上跨越0.0到1.0,1.0到2.0,依此类推。因此,每个系列的确切中心(您希望标签出现的位置)将为0.5,1.5等。
我已经清理了你的代码,因为有很多无关的变量。见其中的评论。
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)
答案 1 :(得分:15)
实际上我认为通过调整figsize
和width
可以最好地解决这个问题;这是我的输出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()
答案 2 :(得分:3)
我读到了保罗·伊万诺夫在Nabble上发布的答案,该答案可能会以较低的复杂性解决这个问题。只需设置索引如下。这将增加分组列之间的间距。
ind = np.arange(0,12,2)