【问题标题】:How to use secondary Y-axis for multiple subplots in seaborn如何在seaborn中为多个子图使用辅助Y轴
【发布时间】:2022-01-17 07:49:58
【问题描述】:

我有两个具有多列的数据框。我已使用 pd.wide_to_long 将 DataFrame 转换为长格式

df1 = pd.wide_to_long(df_1.reset_index(), ['dvr','r'], i='index', j='Sample ID').reset_index()
df2 = pd.wide_to_long(df_2.reset_index(), ['dvlnr','r'], i='index', j='Sample ID').reset_index()

我想创建子图,并且由于其优雅的格式功能而倾向于使用 seaborn。 这是我生成带有辅助 Y 轴的子图的代码。

ax= sns.relplot(data=df1, x='r', y='dvlnr', col='Sample ID',  col_wrap=2, kind="line", height=4, aspect=1.5)
ax1 = plt.twinx()
ax1= sns.relplot(data=df2, x='r', y='dvr', ax=ax, col='Sample ID',  col_wrap=2, kind="line", height=4, aspect=1.5) 

但我总是得到ValueError: Could not interpret value 'dvr' for parameter 'y'

我已经检查了几个示例[eg1]eg2,但我能够找出解决方案,因为我正在寻找具有辅助轴的多个子图。 有没有办法解决这个问题?提前致谢!

【问题讨论】:

    标签: python matplotlib seaborn


    【解决方案1】:

    一个问题是您似乎混合了df1df2。你不应该只使用y='dvlnrdf2(反之亦然)吗?

    另一个问题是sns.relplot 不返回ax。相反,它返回一个FacetGrid。对于 FacetGrid,您不能调用 twinx()。您需要通过g = sns.relplot(data=df1, ...) 捕获FacetGrid 并遍历轴,在每个轴上调用twinx 并创建单独的散点图。如果数据范围足够相似,您可以合并数据框并使用hue 一次性绘制它们。

    以下是一些示例代码,适用于数据范围差异太大而无法在同一 y 轴上绘制的情况:

    import matplotlib.pyplot as plt
    import seaborn as sns
    import pandas as pd
    import numpy as np
    
    df1 = pd.DataFrame({'r': np.random.randint(1, 31, 200),
                        'dvr': np.random.uniform(100, 1000, 200),
                        'Sample ID': np.random.randint(1, 5, 200)})
    df2 = pd.DataFrame({'r': np.random.randint(1, 31, 300),
                        'dvlnr': np.random.uniform(1, 10, 300),
                        'Sample ID': np.random.randint(1, 5, 300)})
    
    g = sns.relplot(data=df1, x='r', y='dvr', col='Sample ID', col_wrap=2, kind="line", height=4, aspect=1.5,
                    color='dodgerblue')
    
    for sample_id, ax in g.axes_dict.items():  # axes_dict is new in seaborn 0.11.2
        ax1 = ax.twinx()
        sns.lineplot(data=df2[df2['Sample ID'] == sample_id], x='r', y='dvlnr', color='crimson', ax=ax1)
    
    plt.tight_layout()
    plt.show()
    

    如果 y 数据的范围足够相似,您可以使用 hue= 合并数据框并一次性绘制所有内容。 (这种方法也适用于更多数据帧。)

    • 需要添加一个新列(例如“源”)以指示原始数据框
    • 两个数据框中的对应列需要相同的名称

    下面是一些示例代码:

    import matplotlib.pyplot as plt
    import seaborn as sns
    import pandas as pd
    import numpy as np
    
    df1 = pd.DataFrame({'r1': np.random.randint(1, 31, 200),
                        'dvr1': np.random.uniform(100, 1000, 200),
                        'Sample ID': np.random.randint(1, 5, 200)})
    df2 = pd.DataFrame({'r1': np.random.randint(1, 31, 300),
                        'dvlnr1': np.random.uniform(300, 1200, 300),
                        'Sample ID': np.random.randint(1, 5, 300)})
    
    # add an extra column to tell to which df the data belongs
    df1['source'] = 'dvr'
    # the corresponding columns in both df need to have the same name for the merge
    df2 = df2.rename(columns={'dvlnr1': 'dvr1'})
    df2['source'] = 'dvrnr'
    df_merged = pd.concat([df1, df2]).reset_index()
    
    g = sns.relplot(data=df_merged, x='r1', y='dvr1', hue='source', col='Sample ID', col_wrap=2,
                    kind="line", height=4, aspect=1.5, palette='turbo')
    plt.subplots_adjust(bottom=0.06, left=0.06)  # plt.tight_layout() doesn't work due to legend
    plt.show()
    

    【讨论】:

    • 亲爱的@JohanC,数据范围是相同的,但每个数据框都有多个列,例如。对于df1: dvlnr1, r1, dvlr2, r2... df2: dvr1, r1; dvr2, r2.. 的情况也是如此。但是两个数据框的r 列是相同的(相同)。如果我合并,它将看起来像df_new=dvr1, dvlnr1, r1; dvr2, dvlr2, r2....goes upto 26。虽然您已经回答了这个问题,但您能否告诉我如何使用hue 一次性绘制它们来实现这一点?感谢您的回答。
    猜你喜欢
    • 1970-01-01
    • 2021-05-04
    • 2022-06-14
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    相关资源
    最近更新 更多