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

Seaborn子图共享X轴时异常及X轴刻度标签问题求助

问题解决:Seaborn共享横轴异常与刻度警告

核心问题原因

  1. sharex=True图表错乱:代码中axes[1] = sns.lineplot(...)直接覆盖了plt.subplots创建的子图对象,破坏了原本的子图布局关联,导致共享横轴功能失效。
  2. 刻度警告与轴标签不一致:
    • 柱状图(barplot)将year视为分类变量,刻度是0-23的索引映射到年份;折线图(lineplot)将year视为数值变量,刻度是连续的年份数值,两者刻度体系不匹配。
    • 直接调用set_ticklabels()但未固定刻度定位器,触发Matplotlib的警告。

修复方案

1. 保留子图对象关联

调用sns.lineplot时,通过ax=axes[1]参数指定子图,不要重新赋值覆盖axes[1]。

2. 统一刻度体系

将年份统一作为分类变量处理,或者显式设置刻度定位器与标签,确保上下轴刻度一致。

3. 正确设置刻度样式

用tick_params()替代直接set_ticklabels()来调整字体、旋转等样式,避免警告;如果需要自定义标签,先通过set_xticks()固定刻度位置。

修正后的完整代码

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

# Generate the years and random integers for 'total' and 'new', where 'total' > 'new' and calculate the cumulative sum for 'trend'
years = np.arange(2000, 2024)
np.random.seed(0)  # Set seed for reproducibility
new_values = np.random.randint(1, 11, size=len(years))
total_values = np.random.randint(2, 21, size=len(years))
total_values = np.maximum(total_values, new_values + 1)
trend_values = np.cumsum(new_values)

# DataFrame
example = pd.DataFrame({
    'year': years.astype(str),  # 转为字符串,统一作为分类变量
    'new': new_values,
    'total': total_values,
    'trend': trend_values
})

# Work on the graph
total_color = 'steelblue'
new_drugs_color = 'skyblue'

# 启用sharex=True,同时保留子图对象
fig, axes = plt.subplots(2, 1, sharex=True, figsize=(10,7), gridspec_kw={'height_ratios': [3, 1.5]})

# 绘制柱状图
sns.barplot(example, x='year', y='total', facecolor=total_color, edgecolor=total_color, lw=1.8, width=0.7, ax=axes[0])
sns.barplot(example, x='year', y='new', color=new_drugs_color, edgecolor=total_color, lw=1.8, width=0.7, hatch="//", ax=axes[0])

# 图例设置
topbar = plt.Rectangle((0,0),1,1,fc=total_color, edgecolor=total_color, lw=1.8)
bottombar = patches.Rectangle((0,0),1,1, facecolor=new_drugs_color, edgecolor=total_color, lw=1.8, hatch="////")
axes[0].legend([topbar, bottombar], ['total', 'newly appeared'], ncol=1, prop={'size':7}, loc='upper left', frameon=False)

# 柱状图数值标签
percentages = [f"{int(new *100 / total)}%" for total, new in zip(total_values, new_values)]
axes[0].bar_label(axes[0].containers[0], fontsize=8, color=total_color, rotation=0, padding=15, fontweight='bold')
axes[0].bar_label(axes[0].containers[0], labels=new_values.astype(int), fontsize=8, color=new_drugs_color, rotation=0, padding=5, fontweight='bold')
axes[0].bar_label(axes[0].containers[1], labels=percentages, fontsize=7, color=new_drugs_color, padding=1.5, rotation=0, fontstyle='italic')

# 调整柱状图布局
axes[0].set_ylim(top=example['total'].max() + 8)
axes[0].margins(y=0.01)
axes[0].set_xlabel('', labelpad=5, fontsize=10)
axes[0].set_ylabel("Count of total", labelpad=15, fontsize=10)
# 用tick_params设置刻度样式,避免警告
axes[0].tick_params(axis='x', rotation=30, ha='right', rotation_mode='anchor', labelsize=8)

# 绘制折线图:指定ax=axes[1],不覆盖对象
sns.lineplot(example, x='year', y='trend', markers=True, marker="o", markersize=4, color=new_drugs_color, ax=axes[1])
axes[1].set_ylabel('Trend of new appearances', labelpad=15)
axes[1].set_ylim(top=example['trend'].max() + 10)
axes[1].margins(y=0.01)
axes[1].set_xlabel("year", labelpad=5, fontsize=10)

# 统一底部轴刻度样式
axes[1].tick_params(axis='x', rotation=30, ha='right', rotation_mode='anchor', labelsize=8)

plt.tight_layout()
plt.title('TITLE', y=1.05, fontsize=11, loc='left')  # 调整title位置,避免偏移

print(axes[0].get_xticklabels())
print(axes[1].get_xticklabels())

plt.show()

关键修复点说明

  • 将year转为字符串类型,让Seaborn的所有绘图函数都将其视为分类变量,确保上下轴刻度完全对齐。
  • 调用sns.lineplot时使用ax=axes[1]参数,保留plt.subplots创建的子图关联,sharex=True可以正常生效。
  • 用tick_params()替代set_ticklabels()来调整刻度的旋转、字体大小等样式,彻底消除Matplotlib的警告。
  • 调整标题的y参数,避免标题位置偏移过高。

内容的提问来源于stack exchange,提问作者Newbielp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:07:03