使用pandas绘制多个重叠的直方图

5

我有两个不同的数据框,每个数据框有19个变量,我正在绘制一个多重图,其中包含每个变量的直方图,如下所示:

fig, ax = plt.subplots(figsize=(19,10), dpi=50)
dataframe1.hist(ax=ax, layout=(3,7), alpha=0.5)

fig, ax = plt.subplots(figsize=(19,10), dpi=50)
dataframe2.hist(ax=ax, layout=(3,7), alpha=0.5)

这会生成两张图片,每张图片内包含19个直方图。我想尝试的是绘制一张图片,在同一个子图中共享这些直方图。
我尝试过这样做:
fig, ax = plt.subplots(figsize=(19,10), dpi=50)
dataframe1.hist(ax=ax, layout=(3,7), alpha=0.5, label='x')
dataframe2.hist(ax=ax, layout=(3,7), alpha=0.5, label='y', color='red')

但是它只会画最后一个。这是一个类似的例子:如何使用matplotlib同时绘制两个直方图,但我该如何将其应用于我的19个子图中呢?
欢迎提出任何想法,提前感谢!

enter image description here

P.S:我目前正在使用带有%matplotlib notebook选项的Jupyter Notebooks


1
我理解得没错吧,您想在同一组坐标轴上显示19个直方图? - asongtoruin
我刚刚添加了其中一张图片。我希望每个子图都有两个直方图,而不是一个。感谢您的理解和尝试! - Sergiodiaz53
2个回答

10

你的问题是在plt.subplots函数中只创建了一个Axes对象,但实际上需要21个(3x7)。由于提供的子图数量与请求的子图数量不匹配,因此pandas会创建新的子图。因为这发生了两次,你只看到第二组直方图。

你可以完全省略对subplots的调用,让pandas完成所有工作。对hist的调用返回所有需要的子图,然后可以在第二个hist调用中使用它们。

编辑

我意识到,如果所需绘制的图的数量实际上不等于网格单元格的数量(在本例中为3x9=21),则必须传递确切数量的要绘制的子图(在本例中为19)。然而,对df.hist的调用会为每个网格单元格返回一个子图(即21个),并且显然隐藏了未使用的子图。因此,你必须仅将所有返回的子图的子集传递给第二次对hist的调用。最简单的方法是将子图的2d数组转换为1d数组,然后使用该数组进行切片,例如`axes.ravel()[:19]`。我已相应地编辑了代码:

import numpy as np
from matplotlib import pyplot as plt
import pandas as pd

length=19

loc = np.random.randint(0,50,size=length)
scale = np.random.rand(length)*10
dist = np.random.normal(loc=loc, scale=scale, size=(100,length))
df1 = pd.DataFrame(data=list(dist))


axes = df1.hist(layout=(3,7), alpha=0.5, label='x')

loc = np.random.randint(0,50,size=length)
scale = np.random.rand(length)*10
dist = np.random.normal(loc=loc, scale=scale, size=(100,length))
df2 = pd.DataFrame(data=list(dist))

df2.hist(ax=axes.ravel()[:length], layout=(3,7), alpha=0.5, label='x',color='r')

plt.show()

这将产生以下输出:

上述代码的结果


我认为你的意思是 ax=axes 而不是 ax=res - asongtoruin
@asongtoruin 你说得对。感谢你的帮助,我会在代码中修复它。 - Thomas Kühn
谢谢!这正是我需要的,但带有45度或90度的x标签。我尝试过像plt.set_xticklabels(rotation=90)这样的东西,但没有成功。你知道如何进行这种更改吗? - Bruno Ambrozio
@BrunoAmbrozio,pandas.hist内置了关键字以实现此功能。例如,xrot=45将所有 x 轴标签逆时针旋转 45 度。请注意,旋转刻度标签可能会使它们与相邻的子图重叠,因此您可能需要在脚本末尾(但在plt.show()之前)添加一个额外的 plt.gcf().tight_layout() - Thomas Kühn
@BrunoAmbrozio 如果你不想使用 pandas.hist 功能,你必须为每个子图单独设置旋转角度。例如,请参考此帖子(标题为“面向对象”部分)中的说明。 - Thomas Kühn
df2.hist 中,layout 参数是不必要的。此外,在 df1.hist 中,可以添加参数 sharey=True,因为这可以提高可读性(减少标签)并且对于所有变量具有相同(或类似)数量值的情况,可以增强可比性。 - Patrick FitzGerald

3
当您调用subplots函数时,可以指定所需的行数和列数。在这种情况下,您需要3行7列。但是,由于您的数据框中只有19个可绘制的数据,.plot函数无法处理21个轴。因此,我们需要将这些轴展平为一个列表,并将其转换为可变列表,这样就可以同时从图形和轴集合中删除最后两个元素,方法是使用.pop()函数。
fig, axes = plt.subplots(figsize=(19,10), dpi=50, nrows=3, ncols=7)
flat_axes = list(axes.reshape(-1))
fig.delaxes(flat_axes.pop(-1))
fig.delaxes(flat_axes.pop(-1))

dataframe1.hist(ax=flat_axes, alpha=0.5, label='x')
dataframe2.hist(ax=flat_axes, alpha=0.5, label='x',color='r')

如果没有你的解释,这段代码非常整洁但很难理解。 - jtlz2

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