【问题标题】:Is there a way to add hatch marks on a seaborn displot using a kernal density estimation plot?有没有办法使用核密度估计图在 seaborn distplot 上添加影线标记?
【发布时间】:2021-04-22 13:57:14
【问题描述】:

我正在尽力将以下四个图组合成三个图,并使用颜色和影线标记显示 (a) 和 (b) 与 (c) 和 (d) 的不同之处。所有四个绿色图都是相同的参数,只是相应地分组。橙色和蓝色也一样。

以下是我使用melt 函数创建每个单独图的方式:

df_CohDmg
Out[13]: 
        Region          Age60 CohDmg          value
0    Posterior  Age $\leq$ 60     tn    1844.377999
1    Posterior  Age $\leq$ 60     tn     654.815766
2      Equator  Age $\leq$ 60     tn  287073.028315
3      Equator  Age $\leq$ 60     tn  301519.815540
4    Posterior  Age $\leq$ 60     tn     838.798937
..         ...            ...    ...            ...
112  Posterior  Age $\leq$ 60     tt   11185.849816
113    Equator     Age $>$ 60     tt   15345.033316
114  Posterior     Age $>$ 60     tt      62.232998
115    Equator     Age $>$ 60     tt     490.447922
116    Equator     Age $>$ 60     tt   11468.986366

[117 rows x 4 columns]
df_CohDmg = pd.melt(md, id_vars=[R, A60], 
                    value_vars=['tn', 'ts', 'tt'], 
                    var_name='CohDmg')

def CohDmgDistPlot(dataSubset=None, figName=None, hue=None, hue_order=None, 
                   labels=None):
    f, ax = plt.subplots()
    
    sns.set_context("paper", rc={"font.size":12, "axes.titlesize":8, 
                                 "axes.labelsize":12})
    
    ax = sns.displot(data=dataSubset, hue=hue, hue_order=hue_order, 
                     x='value', kind="kde", fill=True, legend=False, height=5, 
                     aspect=1.6, bw_adjust=1, log_scale=True)
    ax.set(xlabel='Cohesive Damage Initiation Parameters [Pa]', 
           ylabel='Kernel Density Estimation')
    
    if labels != None:
        # Legend
        plt.legend(labels=labels, loc='best').set_title("Parameter")
    
    # Set limits so all plots are the same scale
    ax.set(ylim=(0, 0.3))
    ax.set(xlim=(8*10**-1, 4*10**7))
    
    ax.savefig(os.path.join(SF, 'Cohesive_Damage_Initiation_Distribution' + 
                            '{}.pdf'.format(figName)), 
               bbox_inches='tight')
    
    plt.close(f)

我在这里定义的这个函数是我调用每个数据子集的方式:


# Simplify plots
labels = [r'$t_{n}$', r'$t_{s}$', r'$t_{t}$']
hue = 'CohDmg'
hue_order = [Eq, Po]

CohDmgDistPlot(df_CohDmg, figName='', labels=labels, hue=hue)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R] == Po)], figName='_Posterior', 
               hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R] == Eq)], figName='_Equator', 
               hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[A60] == Aleq60)], figName='_AgeLeq60', 
               hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[A60] == Ag60)], figName='_Ageg60', 
               hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R]   == Po) & (df_CohDmg[A60] == Aleq60)], 
            figName='_Posterior_Leq60', hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R]   == Po) & (df_CohDmg[A60] == Ag60)], 
            figName='_Posterior_g60', hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R]   == Eq) & (df_CohDmg[A60] == Aleq60)], 
            figName='_Equator_Leq60', hue=hue, labels=labels)

CohDmgDistPlot(df_CohDmg[(df_CohDmg[R]   == Eq) & (df_CohDmg[A60] == Ag60)], 
            figName='_Equator_g60', hue=hue, labels=labels)

理想情况下,我会使用成对的颜色来表示 (a) 和 (b),并使用阴影标记来表示 (b) 和 (d)。

非常感谢您,因为我能够弄清楚这一点。

【问题讨论】:

  • 我唯一能想到的就是melt 将所有内容放在一个列中?
  • 我是否理解正确,您想将 12 条 kde 曲线绘制到单个子图上?当它们重叠这么多时,那不会非常拥挤吗?
  • 所以在考虑了更多情况之后,我只需要在一个绘图上使用 4 条 kde 曲线(所有四个绿色、蓝色和橙色)。本质上是三个情节。我会更新问题。

标签: pandas matplotlib seaborn


【解决方案1】:

这是一个包含 3 个子图的示例。每个子图首先获得一个区域的kdeplot,然后使用不同颜色的另一个区域获得kdeplot。每个人kdeplot 使用hue 来区分年龄。此外,这些年龄组是堆叠的,而不是相互叠加。此外,一个年龄段的人会孵化。

需要进行一些操作才能获得正确的图例。 set_hach 在图例句柄上和在形成kdeplot 的多边形上都被调用。堆叠首先创建最后一个年龄组,所以阴影需要反转列表。

可能有许多变化,这也取决于您要显示的内容以及图表重叠的程度。例如,可以创建一个新列,将 hue 的两列组合在一起,它们都可以堆叠而不是相互叠加。

另请注意,kdeplot 有一个参数common_norm,默认为True,并根据组的大小缩小每个色调组的图形。

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

regions = ['Posterior', 'Equator']
ages = ['Age $\leq$ 60 ', 'Age $>$ 60 ']
coh_dmgs = ['tn', 'ts', 'tt']

df_CohDmg = pd.DataFrame({'Region': np.random.choice(regions, 200),
                          'Age60': np.random.choice(ages, 200),
                          'CohDmg': np.random.choice(coh_dmgs, 200),
                          'value': np.random.randn(20, 10).cumsum(axis=0).ravel() * 20 + 100})
df_CohDmg.loc[df_CohDmg['Region'] == regions[1], 'value'] += 100
df_CohDmg.loc[df_CohDmg['Age60'] == ages[1], 'value'] += 50
'''
df_CohDmg['Region'] = pd.Categorical(df_CohDmg['Region'], categories=regions)
df_CohDmg['Age60'] = pd.Categorical(df_CohDmg['Age60'], categories=ages)
df_CohDmg['CohDmg'] = pd.Categorical(df_CohDmg['CohDmg'], categories=coh_dmgs)
'''
fig, axs = plt.subplots(ncols=3, figsize=(15, 3), sharex=True, sharey=True)
colors = [plt.cm.tab20.colors[i:i + 2] for i in range(0, len(regions) * 2, 2)]
hatches = ['', '//']
for ax, coh_dmg in zip(axs, coh_dmgs):
    handles = []
    for region, palette in zip(regions, colors):
        sns.kdeplot(data=df_CohDmg[(df_CohDmg['CohDmg'] == coh_dmg) & (df_CohDmg['Region'] == region)],
                    x='value', hue='Age60', hue_order=ages, multiple='stack', palette=palette, ax=ax)
        for h, age, hatch in zip(ax.legend_.legendHandles, ages, hatches):
            h.set_label(f'{region}, {age}')
            h.set_hatch(hatch)
            handles.append(h)
    ax.legend_.remove() # remove the automatic legends
    ax.set_title(f'CohDmg={coh_dmg}')
    for collection, hatch in zip(ax.collections[::-1], hatches * len(regions)):
        collection.set_hatch(hatch)

axs[-1].legend(handles=handles, loc='upper left', bbox_to_anchor=[1.01, 1.01])
plt.tight_layout()
plt.show()

【讨论】:

  • 漂亮!我最终将每个图形拆分并制作了一个函数来传递不同的参数。
【解决方案2】:

在从上面提到的 cmets 学习了如何做到这一点之后,这是我更新的解决方案。它现在是一个传递各种参数的函数。

def KDEplot(data=None, x=None, hue=None, hue_order=None, parameter=None, 
            Regions=None, figName=None, meltCol=None,  xlabel=None, 
            ylabel=None, bw_adjust=None, alpha=None):
    colors = [plt.cm.tab20.colors[i:i + 2] for i in 
              range(0, len(data[R].unique()) * 2, 2)]
    hatches = ['', '//////']
    
    for i in parameter:
        f, ax = plt.subplots(figsize=(9.6, 6))
        sns.set_context("paper", rc={"font.size":12, "axes.titlesize":8, 
                                     "axes.labelsize":12})
        handles = []
        for region, palette in zip(Regions, colors):
            ax = sns.kdeplot(data=data[(data[meltCol] == i) & 
                                       (data[R] == region)], x=x, hue=hue, 
                             hue_order=hue_order, multiple='stack', 
                             palette=palette, ax=ax, log_scale=True, 
                             alpha=alpha, bw_adjust=bw_adjust)
            for h, age, hatch in zip(ax.legend_.legendHandles, hue_order, 
                                     hatches):
                h.set_label(f'{region}, {age}')
                h.set_hatch(hatch)
                handles.append(h)
        ax.legend_.remove() # remove the automatic legends
        ax.set(xlabel=xlabel, ylabel=ylabel)
        for collection, hatch in zip(ax.collections[::-1],
                                     hatches * len(Regions)):
            collection.set_hatch(hatch)
        
        ax.legend(handles=handles, loc='best')
        
        f.savefig(os.path.join(SF, f'{figName}_{i}.pdf'), 
                        bbox_inches='tight')

# Call the function
KDEplot(data=df_EV, x='value', hue=A60, hue_order=[Aleq60, Ag60], 
        parameter=['VE'], Regions=[Eq, Po], 
        figName='Elastic_Modulus', meltCol='EV', 
        xlabel='Elastic Modulus [Pa]', ylabel='Kernel Density Estimation', 
        bw_adjust=0.5, alpha=0.8)

KDEplot(data=df_CohBeh, x='value', hue=A60, hue_order=[Aleq60, Ag60], 
        parameter=['Knn', 'Kss', 'Ktt'], Regions=[Eq, Po], 
        figName='Cohesive_Behavior_', meltCol='CohBeh', 
        xlabel='Cohesive Behavior [Pa]', ylabel='Kernel Density Estimation', 
        bw_adjust=0.5, alpha=0.8)

KDEplot(data=df_CohDmg, x='value', hue=A60, hue_order=[Aleq60, Ag60], 
        parameter=['tn', 'ts', 'tt'], Regions=[Eq, Po], 
        figName='Cohesive_Damage_Initiation_', meltCol='CohDmg', 
        xlabel='Cohesive Damage Initiation [Pa]', 
        ylabel='Kernel Density Estimation', 
        bw_adjust=0.5, alpha=0.8)

KDEplot(data=df_CohFE, x='value', hue=A60, hue_order=[Aleq60, Ag60], 
        parameter=['FE'], Regions=[Eq, Po], 
        figName='Elastic_Modulus', meltCol='CohFE', 
        xlabel='Fracture Energy [J]', ylabel='Kernel Density Estimation', 
        bw_adjust=0.5, alpha=0.8)

这是一个输出的样子:

适用于不同的情况需要更多的工作,但感谢您的帮助!

【讨论】:

    猜你喜欢
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2020-07-28
    • 2019-06-03
    • 2020-11-25
    • 2016-01-21
    相关资源
    最近更新 更多