在 twinx 上的 seaborn 中将 x 轴数值与相应的分类变量对齐

Aligning x axis numerical values with corresponding categorical variables in seaborn on twinx

我正在尝试绘制双 x 轴 seaborn 线图,但基于以下代码的输出显示两个 x 轴都卡在角落而不是将值彼此对齐。

我错过了什么?

import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
plt.style.use("fivethirtyeight")

             
fig, ax = plt.subplots(1,1,figsize=(10,10))
ax2 = ax.twinx()
sns.lineplot(x="BUCKET_SEGMENT_1", y= 'Percentage to Bucket Total', data=df, ax=ax)
sns.lineplot(x="PAST_DUE_DAYS", y= 'Percentage to Bucket Total',data=df, ax=ax2)

plt.show()

数据

BUCKET_SEGMENT_1    PAST_DUE_DAYS   BAL Percentage to Bucket Total
0   Bucket1            3.0  878698.045  74.431434
1   Bucket1            4.0  25747.397   2.180971
2   Bucket2            6.0  171683.523  14.54271
3   Bucket2            7.0  55659.448   4.714716
4   Bucket3            8.0  1589.759    0.134662

这是我希望看到的示例

我也尝试过使用 ax 和 ax2 设置限制和 xticks 但没能成功

DF = df.copy()
DF.set_index("BUCKET_SEGMENT_1",inplace=True)
fig, ax = plt.subplots(1,1,figsize=(10,10))
ax2 = ax.twinx()
sns.lineplot(data=DF,x="PAST_DUE_DAYS",y='Percentage to Bucket Total',ax=ax)
sns.lineplot(data=DF.reset_index(),x='BUCKET_SEGMENT_1',y='Percentage to Bucket Total',ax=ax2)
x = int(max(DF.PAST_DUE_DAYS))
ax.set_xlim(0,x)
ax2.set_xticks(DF.index.unique())

要找出发生了什么,首先将两个图绘制在单独的子图中会有所帮助:

import matplotlib.pyplot as plt
import pandas as pd
from io import StringIO

df_str = '''BUCKET_SEGMENT_1    PAST_DUE_DAYS   BAL "Percentage to Bucket Total"
0   Bucket1            3.0  878698.045  74.431434
1   Bucket1            4.0  25747.397   2.180971
2   Bucket2            6.0  171683.523  14.54271
3   Bucket2            7.0  55659.448   4.714716
4   Bucket3            8.0  1589.759    0.134662'''
df = pd.read_csv(StringIO(df_str), delim_whitespace=True)

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(14, 5))
sns.lineplot(x="BUCKET_SEGMENT_1", y='Percentage to Bucket Total', data=df, ax=ax1)
sns.lineplot(x="PAST_DUE_DAYS", y='Percentage to Bucket Total', data=df, ax=ax2)
ax2.set_xticks(df["PAST_DUE_DAYS"])
plt.tight_layout()
plt.show()

左侧子图使用 x 轴的分类桶名称。所有百分比均取平均值,并显示误差带。 Bucket1Bucket2Bucket3,位于内部位置 012

右边的子图使用数字 PAST_DUE_DAYS 位置作为 x 轴。每天只有一个百分比值,所以不需要误差带。

ax.twinx() 将共享 x 轴。这会将第一个子图位置 (0,1,2) 与第二个子图的数字位置 (3,4,6,7,8) 混合。结果是您看到的奇怪情节(显然来自不同的数据框作为示例)。

现在,要将桶标记到数值图中,您可以使用 groupby() 找出位置。使用最小和最大天数,可以定位文本。此外,交替的彩色条带可以使范围可视化。

下面是一些帮助您入门的示例代码:

fig, ax = plt.subplots(figsize=(10, 5))
sns.lineplot(x="PAST_DUE_DAYS", y='Percentage to Bucket Total', data=df, ax=ax)
colors = ['red', 'green']
previous_max_days = 0
for (group_name, group_data), color in zip(df.groupby("BUCKET_SEGMENT_1"), colors * len(df)):
    # min_days = group_data['PAST_DUE_DAYS'].min() - 0.5
    min_days = previous_max_days
    max_days = group_data['PAST_DUE_DAYS'].max() + 0.5
    ax.axvspan(min_days, max_days, color=color, alpha=0.1)
    ax.text((min_days + max_days) / 2, 0.9, group_name, ha='center', fontsize=20, color=color,
            transform=ax.get_xaxis_transform())
    previous_max_days = max_days
plt.show()