You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在violinplot后插入regplot?组合绘图位置偏移问题求助

解决regplot与violinplot组合绘制时的位置偏移问题

问题原因

同时使用sns.regplot()和sns.violinplot()时,两者对x轴变量的处理逻辑存在差异:

  • regplot将Magnitudes视为数值变量,会根据数值实际大小在x轴上定位
  • violinplot将Magnitudes视为分类变量,会把每个类别均匀分布在x轴上

这种处理方式的不同直接导致两个图层位置偏移。

修复方案

方法1:让regplot匹配分类变量的位置

先绘制violinplot获取分类位置,再将regplot的x值映射为对应分类索引,确保两者位置对齐:

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

# 替换为你的真实数据
magnitudes = np.random.choice([1,2,3,4], size=100)
lengths = np.random.exponential(scale=10, size=100)
widths = np.random.exponential(scale=8, size=100)

df = pd.DataFrame({'Magnitudes': magnitudes, 'Lengths': np.log10(lengths), 'Widths': np.log10(widths)})

palette = sns.color_palette("Set2", len(df['Magnitudes'].unique()))
sns.set_style("darkgrid", {"grid.color": ".6", "grid.linestyle": ":"})

plt.figure(figsize=(10,8))

# 第一个子图:Lengths vs Magnitude
plt.subplot(2, 1, 1)
# 先绘制violinplot并获取轴对象
violin_ax = sns.violinplot(x='Magnitudes', y='Lengths', data=df, palette=palette, alpha=0.5, hue='Magnitudes', legend=False)
# 获取x轴分类的坐标位置
x_positions = np.array([tick.get_loc() for tick in violin_ax.get_xticks()])
# 将Magnitudes转换为分类索引
df['x_category'] = pd.Categorical(df['Magnitudes']).codes
# 绘制regplot,使用分类索引作为x
sns.regplot(x='x_category', y='Lengths', data=df, scatter_kws={"alpha": 0.0}, ax=violin_ax)
# 重置x轴标签为原始Magnitudes值
plt.xticks(x_positions, df['Magnitudes'].unique())
plt.title('Violin Plot of Lengths vs Magnitude')
plt.xlabel('Magnitude')
plt.ylabel('Lengths')

# 第二个子图:Widths vs Magnitude
plt.subplot(2, 1, 2)
violin_ax2 = sns.violinplot(x='Magnitudes', y='Widths', data=df, palette=palette, alpha=0.5, hue='Magnitudes', legend=False)
x_positions2 = np.array([tick.get_loc() for tick in violin_ax2.get_xticks()])
df['x_category2'] = pd.Categorical(df['Magnitudes']).codes
sns.regplot(x='x_category2', y='Widths', data=df, scatter_kws={"alpha": 0.0}, ax=violin_ax2)
plt.xticks(x_positions2, df['Magnitudes'].unique())
plt.title('Violin Plot of Widths vs Magnitude')
plt.xlabel('Magnitude')
plt.ylabel('Widths')

plt.tight_layout()
plt.show()

方法2:用catplot统一基础图层

使用sns.catplot()绘制小提琴图,再为每个子图添加回归线,逻辑更简洁:

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

# 替换为你的真实数据
magnitudes = np.random.choice([1,2,3,4], size=100)
lengths = np.random.exponential(scale=10, size=100)
widths = np.random.exponential(scale=8, size=100)

df = pd.DataFrame({'Magnitudes': magnitudes, 'Lengths': np.log10(lengths), 'Widths': np.log10(widths)})

palette = sns.color_palette("Set2", len(df['Magnitudes'].unique()))
sns.set_style("darkgrid", {"grid.color": ".6", "grid.linestyle": ":"})

# 绘制Lengths的图
g = sns.catplot(data=df, x='Magnitudes', y='Lengths', kind='violin', palette=palette, alpha=0.5, hue='Magnitudes', legend=False)
for ax in g.axes.flat:
    # 将Magnitudes转为分类索引
    x_cat = pd.Categorical(df['Magnitudes']).codes
    sns.regplot(x=x_cat, y=df['Lengths'], data=df, scatter_kws={"alpha":0.0}, ax=ax)
    ax.set_xticks(ax.get_xticks())
    ax.set_xticklabels(df['Magnitudes'].unique())
g.fig.suptitle('Violin Plot of Lengths vs Magnitude', y=1.02)

# 绘制Widths的图
g2 = sns.catplot(data=df, x='Magnitudes', y='Widths', kind='violin', palette=palette, alpha=0.5, hue='Magnitudes', legend=False)
for ax in g2.axes.flat:
    x_cat = pd.Categorical(df['Magnitudes']).codes
    sns.regplot(x=x_cat, y=df['Widths'], data=df, scatter_kws={"alpha":0.0}, ax=ax)
    ax.set_xticks(ax.get_xticks())
    ax.set_xticklabels(df['Magnitudes'].unique())
g2.fig.suptitle('Violin Plot of Widths vs Magnitude', y=1.02)

plt.show()

效果说明

两种方法都能让回归线精准对齐每个小提琴图的中心,彻底解决位置偏移问题。

内容的提问来源于stack exchange,提问作者Alex Villarroel Carrasco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:19:59