在matplotlib中,如何绘制多个数据集的条形图使最小的条形在前?
我想把多个数据集放在一个柱状图上,但不想让小的柱子被大的柱子遮住,也不想把它们错开。比如说,
bar(0, 1.)
bar(0, 2.)
这样只会显示第二根柱子,2.0的高度,第一根柱子就被遮住了。有没有办法让matplotlib把小的柱子画在上面?另外,我不想要堆叠柱状图,也不想在x轴上把柱子错开。
我可以把所有数据集的数据按柱子的高度排序,然后一个一个地画出这些柱子,但我更希望能单独画每根柱子,而不是一个数据集接着一个数据集地画。有没有人知道怎么做到这一点?
非常感谢!
3 个回答
1
翻译:
>>> from matplotlib import pylab
>>> data1 = [0.3, 0.9, 0.1]
>>> data2 = [3.0, 0.2, 0.5]
>>> colors = ['b','magenta','cyan']
>>> data_list = [data1,data2]
>>> num_bars = len(data_list)
>>> for i, d in enumerate(data_list):
... for j,value in enumerate(sorted(d,reverse=True)):
... c = colors[j]
... obj_list = pylab.bar(i*0.4,value,width=0.8/num_bars,color=c)
...
你可以按顺序画它们,像这样,或者调整它们的层级顺序。
编辑:
我稍微整理了一下。这基本上是说,在调用 bar 之前,先把每个柱子的数据显示从大到小排序。但你也可以稍后再去调整层级顺序等等。实际上,我会保存 bar() 返回的对象,以防你想查看它们。
import numpy as np
from pylab import *
data = [[6.7, 1.5, 4.5], [2.0, 3.25, 5.7]]
w = 0.5
xlocations = np.array(range(len(data)))+w
colors = ['r','b','cyan']
oL = list()
for x,d in zip(xlocations, data):
for c,value in zip(colors, sorted(d,reverse=True)):
b = bar(x, value, width=w, color=c)
oL.extend(b)
show()
3
这个“bar”方法会返回一个叫做matplotlib.patches.Rectangle的对象。这个对象有一个叫做set_zorder的方法。把第一个对象的zorder设置得比第二个高,就能让它显示在上面。
你可以“轻松”地通过检查它们的x坐标和根据高度来排序元素的zorder。
from matplotlib import pylab
pylab.bar([0, 1], [1.0, 2.0])
pylab.bar([0, 1], [2.0, 1.0])
# loop through all patch objects and collect ones at same x
all_patches = pylab.axes().patches
patch_at_x = {}
for patch in all_patches:
if patch.get_x() not in patch_at_x: patch_at_x[patch.get_x()] = []
patch_at_x[patch.get_x()].append(patch)
# custom sort function, in reverse order of height
def yHeightSort(i,j):
if j.get_height() > i.get_height(): return 1
else: return -1
# loop through sort assign z-order based on sort
for x_pos, patches in patch_at_x.iteritems():
if len(patches) == 1: continue
patches.sort(cmp=yHeightSort)
[patch.set_zorder(patches.index(patch)) for patch in patches]
pylab.show()
6
我知道这个问题已经很老了,但我自己在查资料时遇到了它。因为这看起来是我会反复做的事情,所以我为 hist 函数写了一个封装器(我会用这个;对 bar 的修改应该也很简单):
from matplotlib import pyplot as mpl
from numpy import argsort, linspace
def hist_sorted(*args, **kwargs):
all_ns = []
all_patches = []
labels = kwargs.pop('labels', None)
if not labels:
labels = ['data %d' % (i+1) for i in range(len(args))]
elif len(labels) != len(args):
raise ValueError('length of labels not equal to length of data')
bins = kwargs.pop('bins', linspace(min(min(a) for a in args),
max(max(a) for a in args),
num = 11))
for data, label in zip(args, labels):
ns, bins, patches = mpl.hist(data, bins=bins, label=label, **kwargs)
all_ns.append(ns)
all_patches.append(patches)
z_orders = -argsort(all_ns, axis=0)
for zrow, patchrow in zip(z_orders, all_patches):
assert len(zrow) == len(patchrow)
for z_val, patch in zip(zrow, patchrow):
patch.set_zorder(z_val)
return all_ns, bins, all_patches
这个封装器可以把数据集作为匿名参数传入,同时可以把任何标签作为关键字参数传入(用于图例),还可以使用 hist 函数的其他关键字参数。