【问题标题】:Overlay three histograms in one plot在一张图中叠加三个直方图
【发布时间】:2020-01-24 20:34:11
【问题描述】:

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

我想得到什么:

我使用这段代码得到了什么:

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)

尝试使用 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])

我正在尝试绘制的数据的屏幕截图:

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

【问题讨论】:

  • 请以文本形式包含您的数据。
  • @QuangHoang 将数据添加为文本。
  • 第二个情节有什么问题?
  • @PaulH 在第二个图中看起来我有超过 3 个类别。另外,我想避免使用 seaborn。

标签: python pandas matplotlib histogram


【解决方案1】:

我想提出一种不同的方法。它不会避免 seaborn,但确实避免了循环。

工作流程就在那里:读入数据,转换成整洁(长)格式,然后将直方图映射到 seaborn Facet Grid:

从 io 导入 StringIO 进口熊猫 进口海运

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

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

【讨论】:

    【解决方案2】:

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

    • distplotbins 参数设置 bin 大小,但要在刻度线上强制使用标签,请使用 plt.xticks

    【讨论】:

    • 这看起来很像 OP 的现有情节。除了人物美学,它有什么不同?
    • @PaulH OP 显示的第一个图是“我想得到什么”。 OP 想要,但无法制作第一个情节。此外,OP 首先将每一列保存到一个列表中,然后尝试绘制它。这个答案正确使用 seaborn 并产生了所需的情节,特别是按照 OP 的要求。
    • 但是第二个情节有什么问题?直方图计算的美学或数值结果?澄清一下——“第二个情节”是指 OP 第二次尝试制作“我想要得到的”情节
    • @PaulH 我认为 OP 只是没有使用 labelplt.legend() 并且数据框列被不必要地分配给新对象。
    • @Trenton_M 非常感谢。我的 seaborn 情节的问题是它看起来非常难以理解,我不知道如何编辑它以实际检查它是否符合我的要求。乍一看,我似乎绘制了多个类别。
    【解决方案3】:

    您可以尝试将单个 hist 绘制到同一轴上:

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

    输出,顺便说一下,看起来像你的 seaborn 输出:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-23
      • 2017-02-24
      • 1970-01-01
      • 1970-01-01
      • 2013-05-07
      • 2012-11-02
      • 1970-01-01
      • 2020-05-16
      相关资源
      最近更新 更多