如何在 seaborn 中为多个子图使用辅助 Y 轴
How to use secondary Y-axis for multiple subplots in seaborn
我有两个包含多列的数据框。我已经使用 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'
我已经检查了几个例子 , 但我能够找到一个解决方案,因为我正在寻找具有辅助轴的多个子图。
有什么办法可以解决这个问题吗?提前致谢!
一个问题是您似乎混合了 df1
和 df2
。您不应该只将 y='dvlnr
与 df2
一起使用(反之亦然)吗?
另一个问题是 sns.relplot
没有 return 和 ax
。相反,它 return 是 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=
一次性绘制所有内容。 (这种方法也适用于更多数据帧。)
- 需要添加一个新列(例如'source')以指示原始数据帧
- 两个数据框中的相应列需要相同的名称
下面是一些示例代码:
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()
我有两个包含多列的数据框。我已经使用 pd.wide_to_long
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'
我已经检查了几个例子
一个问题是您似乎混合了 df1
和 df2
。您不应该只将 y='dvlnr
与 df2
一起使用(反之亦然)吗?
另一个问题是 sns.relplot
没有 return 和 ax
。相反,它 return 是 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=
一次性绘制所有内容。 (这种方法也适用于更多数据帧。)
- 需要添加一个新列(例如'source')以指示原始数据帧
- 两个数据框中的相应列需要相同的名称
下面是一些示例代码:
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()