Seaborn子图共享X轴时异常及X轴刻度标签问题求助
问题解决:Seaborn共享横轴异常与刻度警告
核心问题原因
sharex=True图表错乱:代码中axes[1] = sns.lineplot(...)直接覆盖了plt.subplots创建的子图对象,破坏了原本的子图布局关联,导致共享横轴功能失效。- 刻度警告与轴标签不一致:
- 柱状图(
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
相关产品推荐
相关产品推荐

