Matplotlib - 已经分组的数据如何绘制阶梯状直方图

17

我想使用已经分组的数据生成直方图。我一直在尝试使用bar(),但似乎无法弄清如何制作像示例中的这个阶梯状直方图,而不是填充直方图。

输入图像描述

4个回答

8
你可以通过偏移数据并使用plot来作弊:
from matplotlib import pyplot
import numpy as np

#sample data:
x = np.arange(30)
y = np.cumsum(np.arange(30))
#offset the x for horizontal, repeat the y for vertical:
x = np.ravel(zip(x,x+1))
y = np.ravel(zip(y,y))

pyplot.plot(x,y)
pyplot.savefig('plt.png')

故事情节: enter image description here

23
我找到了第二种方法。只需在plot()中设置ls =“steps”即可。虽然感谢你的回答! - madtowneast
@madtowneast,你那条评论值得更多的赞。那真是一个隐藏的功能。http://matplotlib.org/api/artist_api.html#matplotlib.lines.Line2D.set_linestyle - kratsg
多年后,对于像我一样来到这里寻找答案的人,@madtowneast的评论更新是使用<pyplot>.step()而不是现在已被移除的plot()中的"steps"。 - undefined

3

最简单的解决方案是将您的分组数据集转换为未分组的加权数据集(元素数量== bin数量)。未分组的数据集将由等于bin中心的数据值和等于每个bin中数值的权重组成。例如,假设您的分组数据如下:

binedges = [0.0, 1.0, 2.0, 3.0]
ybinned = [11., 22., 33.]

相应的加权数据集将是,
y =       [0.5, 1.5, 2.5]
weights = [11., 22., 33.]

注意,使用bin中心的选择是任意的,您可以使用bin内的任何点。一旦生成了未分组的数据集,就可以使用正常的matplotlib直方图绘图(即Axes.hist)。
以下是python中的示例实现:
def plot_binned_data(axes, binedges, data,
               *args, **kwargs):
    #The dataset values are the bin centres
    x = (binedges[1:] + binedges[:-1]) / 2.0
    #The weights are the y-values of the input binned data
    weights = data
    return axes.hist(x, bins=binedges, weights=weights,
               *args, **kwargs)

现在您可以完全访问所有Axes.Histogram绘图选项,包括histtype="step"以创建所需的阶梯状直方图。

使用此函数的示例如下:

import numpy
import matplotlib.pyplot as plt

#Create a dataset
dataset = numpy.random.normal(size=100)
#Bin the dataset
binedges = numpy.linspace(-5.0, 5.0, num=10)
y, binedges = numpy.histogram(dataset, binedges)

#Plot the dataset
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plot_binned_data(ax, binedges, y, histtype="step")
plt.show()

希望这可以帮到你!

0

由于某些原因,当我尝试关闭最后一个 bin 时,它没有被正确地关闭。如果最后一行被显示出来,从之前的答案中无法看出这一点,因此我决定编写自己的函数来实现我想要的功能。

def make_bar_contour_plot(ax,x_input,y_input):

    x = list(np.ravel(zip(x_input[:-1],x_input[:-1]+1)))[1:]
    x += [x[-1]+20] + [300] 
    y = list(np.ravel(zip(y_input,y_input))) +[0]
    ax.plot(x,y,ls='steps')

    return ax

添加的20300是我的binsize和结束值,如果有人想使用它们,需要进行调整。x_inputy_input是从np.histogram返回的值。我的结果图(蓝色为轮廓线,用上述函数绘制。红色为相同数据的条形图):

My result in contourplotting a histogram


0

http://matplotlib.sourceforge.net/examples/pylab_examples/histogram_demo_extended.html的源代码中,这是他们绘制图形的方式:

[省略]

你想要的部分似乎是:

pylab.hist(x, bins=bins, histtype='step')
                            ^
                        right here

编辑:如果你想知道hist()函数是如何工作的,可以查看源代码——它在matplotlib/axes.py文件中的第7407行开始定义。

继续往下看到7724行,

x = np.zeros( 2*len(bins), np.float )
y = np.zeros( 2*len(bins), np.float )

对于N个条形,bins是一个numpy.ndarray,它包含N+1个值,这些值是每个条形的边缘。它们成对出现(这就是fraxel在下面使用np.ravel所做的),并将数据点向左移动半个条形以使它们居中。

x[0::2], x[1::2] = bins, bins
x -= 0.5*(bins[1]-bins[0])

设置每个条形的高度,成对但相对于x值偏移一个单位,以产生阶梯效果

# n is an array of arrays containing the number of items per bar
patches = []    # from line 7676
for m, c in zip(n, color):
    y[1:-1:2], y[2::2] = m, m
    patches.append(self.fill(x, y, closed=False, edgecolor=c, fill=False))

self.fill部分实际上是绘制线条的。


据我理解,示例中的数据尚未分组。我已经有了分组数据,因此hist()无法帮助。 - madtowneast
@Jonas Wielicki:给出的代码得到了他所询问的图像。这怎么不适用呢? - Hugh Bothwell
@HughBothwell 他将数据分成了箱子,而不是未分组的数据。经过您的编辑,对我来说看起来可以使用。 - Jonas Schäfer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接