- When adding
sns.swarmplot
, or a sns.stripplot
, to sns.violinplot
, the limits of the y-axis are changed.
- 使用这两种方法都会发生这种情况显式“轴”接口 https://matplotlib.org/stable/users/explain/api_interfaces.html#the-explicit-axes-interface, and 隐式“pyplot”接口 https://matplotlib.org/stable/users/explain/api_interfaces.html#the-implicit-pyplot-interface,如图所示plot https://i.stack.imgur.com/oJSwd.png.
- Using
sns.catplot
with kind='violin'
, and .map_dataframe
with sns.swarmplot
也产生同样的问题,如此所示plot https://i.stack.imgur.com/maDK2.png.
- 如果绘图,则不会发生这种情况
sns.swarmplot
on sns.boxplot
,如图所示plot https://i.stack.imgur.com/J6c6g.png.
- 测试于
python 3.11.2
, matplotlib 3.7.1
, seaborn 0.12.2
import seaborn as sns
import matplotlib.pyplot as plt
# sample data
df = sns.load_dataset('geyser')
# plot
sns.violinplot(data=df, x='kind', y='duration', inner=None)
print('ylim with 1 plot', plt.ylim())
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3)
print('ylim with both plots', plt.ylim())
ylim with 1 plot (1.079871611291212, 5.607761736565478)
ylim with both plots (1.425, 5.2749999999999995)
解决
- Here are three options to resolve the issue:
- 捕获
ylim
绘制后的值sns.violinplot
,并设置ylim
绘制后的这些值sns.swarmplot
.
- Set
ylim
绘图后达到某个特定值sns.swarmplot
- Plot
sns.swarmplot
then sns.violinplot
.
- To have
ylim
从“原点”开始,使用y_bot = 0
.
- Using matplotlib.pyplot.ylim https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.ylim.html, matplotlib.axes.Axes.set_ylim https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_ylim.html, and matplotlib.axes.Axes.get_ylim https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.get_ylim.html.
1.
sns.violinplot(data=df, x='kind', y='duration', inner=None)
y_bot, y_top = plt.ylim()
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3)
plt.ylim(y_bot, y_top)
2.
sns.violinplot(data=df, x='kind', y='duration', inner=None)
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3)
plt.ylim(1, 6)
3.
# plot
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3)
print('ylim with 1 plot', plt.ylim())
sns.violinplot(data=df, x='kind', y='duration', inner=None)
print('ylim with both plots', plt.ylim())
ylim with 1 plot (1.425, 5.2749999999999995)
ylim with both plots (1.079871611291212, 5.607761736565478)
优先使用explicit界面
- 为什么要明确? https://matplotlib.org/stable/users/explain/api_interfaces.html#why-be-explicit
plt.figure
and .add_subplot
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot()
sns.violinplot(data=df, x='kind', y='duration', inner=None, ax=ax)
y_bot, y_top = ax.get_ylim()
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3, ax=ax)
ax.set_ylim(y_bot, y_top)
plt.subplots
fig, axes = plt.subplots(figsize=(8, 5))
sns.violinplot(data=df, x='kind', y='duration', inner=None, ax=ax)
y_bot, y_top = ax.get_ylim()
sns.swarmplot(data=df, x='kind', y='duration', color='#000000', size=3, ax=ax)
ax.set_ylim(y_bot, y_top)
df[['duration', 'kind']].head()
duration kind
0 3.600 long
1 1.800 short
2 3.333 long
3 2.283 short
4 4.533 long