在matplotlib中,如何绘制多个数据集的条形图以将最小的条形图放在前面?

时间:2010-02-03 18:18:54

标签: python matplotlib plot

我想在条形图上放置多个数据集,并阻止较小的条形图被较大的条形图遮挡,我不想偏移它们。例如,

bar(0,1。)

bar(0,2。)

仅显示第二个高度为2.0的条,第一个条是隐藏的。有没有办法让matplotlib绘制顶部最小的条形图?注意我不想要堆积条形图或偏移x方向的条形。

我可以按照条形高度从所有数据集中订购所有数据,并按此顺序逐个绘制每个条形图,但我更愿意单独绘制每个条形图而不是依次绘制每个数据集有没有人知道这样做的方法?

非常感谢

3 个答案:

答案 0 :(得分:4)

我知道这是一个老问题,但我出于自己的目的遇到它,因为它似乎是我一遍又一遍地做的事情,我把一个包装器用于组合函数(这就是我'将要使用;对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一起使用的任何其他关键字参数。

答案 1 :(得分:3)

bar方法将返回matplotlib.patches.Rectangle对象。该对象具有set_zorder方法。将第一个的zorder设置为高于第二个将使其位于顶部。

你可以通过检查它们是否处于相同的x和zordering高度来“轻松”排序元素的z顺序。

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()

alt text http://img697.imageshack.us/img697/8381/tmpp.png

答案 2 :(得分: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)
... 

您可以按顺序绘制它们,或者执行zorder

编辑:

我把它调了一下。基本上,关键是在调用bar之前将每个条的数据从最大到最小排序。但是你可以稍后再回去做set_zorder等。实际上,我保存了从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()