在一个图中叠加三个直方图

时间:2019-09-24 16:57:50

标签: python pandas matplotlib histogram

我正在尝试使用Pandas DataFrame中的数据来绘制类似的内容。日期是介于0到100之间的数字,代表百分比。我有3栏代表3个不同的类别,每个类别都有百分比值。

我想要得到什么:

perfect hist example

使用此代码后,我会得到什么:

df_margins = pd.read_excel("path to excel file")
df_margins.reset_index(drop=True, inplace=True)
df_margins_sort = pd.DataFrame(np.sort(df_margins.values, axis=0), index=df_margins.index, columns=df_margins.columns)
df_margins_sort.hist( alpha=0.5)

result 1

尝试使用seaborn库,我得到了:

x = df_margins_sort["safety_margin_distribution_0"].tolist()
y = df_margins_sort["safety_margin_distribution_5"].tolist()
z = df_margins_sort["safety_margin_distribution_10"].tolist()
ggg = [x,y,z]
fig, ax = plt.subplots()
for a in ggg:
    sns.distplot(a, bins=range(1, 100, 10), ax=ax, kde=False)
ax.set_xlim([0, 100])

seaborn results

我要绘制的数据的屏幕截图: data example

79.6657 8.3008  12.0334
28  72  0       
51.4077 48.5923 0
84.1176 2.7451  13.1373
79.5455 1.0101  19.4444
51.9205 48.0795 0
57.2877 6.5906  36.1217
71.2589 11.4014 17.3397
56.2624 43.7376 0
76.4228 0   23.5772
51.8473 6.6502  41.5025
74.8555 25.1445 0
85.8254 14.1746 0
63.2754 0.7444  35.9801

3 个答案:

答案 0 :(得分:2)

您可以尝试在同一轴上绘制各个历史记录:

np.random.seed(1)
df = pd.DataFrame(np.random.randint(0,10,(100,3)), columns=list('abc'))

fig, ax = plt.subplots()

for col in df.columns:
    df[col].hist(alpha=0.3, ax=ax, label=col)

ax.legend()

输出,顺便说一句,它看起来像您的原始输出:

enter image description here

答案 1 :(得分:1)

使用seaborn

您的数据:

 safety_margin_distribution_5  safety_margin_distribution_10  safety_margin_distribution_0
                      79.6657                         8.3008                       12.0334
                      28.0000                        72.0000                        0.0000
                      51.4077                        48.5923                        0.0000
                      84.1176                         2.7451                       13.1373
                      79.5455                         1.0101                       19.4444
                      51.9205                        48.0795                        0.0000
                      57.2877                         6.5906                       36.1217
                      71.2589                        11.4014                       17.3397
                      56.2624                        43.7376                        0.0000
                      76.4228                         0.0000                       23.5772
                      51.8473                         6.6502                       41.5025
                      74.8555                        25.1445                        0.0000
                      85.8254                        14.1746                        0.0000
                      63.2754                         0.7444                       35.9801

代码

  • seaborn.distplot
  • 最初尝试使用seaborn的关键问题是没有提供label并且没有致电plt.legend()
  • 不必像[x, y, z]那样为每一列创建单独的对象
import seaborn as sns
import pandas as pd
import matplotlib.pyplt as plt

plt.figure(figsize=(7, 6))
for col in df.columns:
    sns.distplot(df[col], label=col,
                 bins=range(0, 101, 10),
                 kde=False, hist_kws=dict(edgecolor='black'))

plt.xlabel('Value Range')
plt.ylabel('Frequency')
plt.legend()
plt.xticks(range(0, 101, 10))
plt.show()

enter image description here

  • bins的{​​{1}}参数设置垃圾箱的大小,但是要在刻度线上加上标签,请使用distplot

答案 2 :(得分:0)

我想提出一种不同的方法。它不能避免先天不足,但可以避免循环。

工作流程就在其中:读入数据,转换为整齐(长)格式,然后将直方图映射到深海的Facet Grid:

从io导入StringIO 进口大熊猫 进口seaborn

seaborn.set(style ='ticks')

data = StringIO("""\
safety_margin_distribution_5  safety_margin_distribution_10  safety_margin_distribution_0
                      79.6657                         8.3008                       12.0334
                      28.0000                        72.0000                        0.0000
                      51.4077                        48.5923                        0.0000
                      84.1176                         2.7451                       13.1373
                      79.5455                         1.0101                       19.4444
                      51.9205                        48.0795                        0.0000
                      57.2877                         6.5906                       36.1217
                      71.2589                        11.4014                       17.3397
                      56.2624                        43.7376                        0.0000
                      76.4228                         0.0000                       23.5772
                      51.8473                         6.6502                       41.5025
                      74.8555                        25.1445                        0.0000
                      85.8254                        14.1746                        0.0000
                      63.2754                         0.7444                       35.9801
""")

df = (
    pandas.read_csv(data, sep='\s+')
        .stack()
        .to_frame('Safety Margin')
        .reset_index(level=0, drop=True)
        .assign(Distribution=lambda df: df.index.str.rsplit('_', 1).map(lambda x: int(x[-1])))
        .reset_index(drop=True)
        .pipe((seaborn.FacetGrid, 'data'), hue='Distribution', size=5)
        .map(seaborn.distplot, 'Safety Margin', kde=False, bins=range(0, 100, 5))
        .add_legend()
)

我并不是说这比基于循环的答案更好。但是使用整洁的数据并在构面网格上进行映射可能会有好处(例如,如果您决定将图进一步分为行和列)