如何使用Seaborn绘制双Y轴柱状图?
实现Seaborn分面子图的双Y轴柱状图
要在按季节分面的子图中实现双Y轴柱状图,核心思路是利用FacetGrid遍历每个子图,为每个子图创建双Y轴(主轴+次轴),分别绘制y1和y2的柱状图,同时调整柱子位置避免重叠。
关键步骤说明
- 搭建分面框架:先初始化按季节拆分的子图结构,不直接指定绘图类型,方便后续自定义双Y轴内容
- 自定义双轴绘图逻辑:
- 设置柱子宽度,通过X轴位置偏移让同一BMP类别的
y1、y2柱子并排显示 - 主轴绘制
y1数据,绑定对应轴标签和颜色;次轴通过twinx()创建,独立绘制y2数据并设置专属样式 - 合并两个轴的图例,避免图例分散
- 设置柱子宽度,通过X轴位置偏移让同一BMP类别的
- 统一布局风格:保留原代码中移除多余边框、调整子图间距的设置,保证视觉一致性
完整代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 创建数据框 GWWs_eff_df = pd.DataFrame({ 'BMP': ['CC', 'CC','CC', 'CC','GWWs','GWWs','GWWs','GWWs'], 'y1': [97,78,31,21,34,40,33,60], 'y2': [100,85,85,94,45,67,89,90], 'Season': ['Spring (Mar-Apr-May)', 'Summer (Jun-Jul-Aug)', 'Fall (Sep-Oct-Nov)', 'Winter (Dec-Jan-Feb)', 'Spring (Mar-Apr-May)', 'Summer (Jun-Jul-Aug)', 'Fall (Sep-Oct-Nov)', 'Winter (Dec-Jan-Feb)'] }) sns.set_style('whitegrid') # 创建分面子图框架 g = sns.FacetGrid(GWWs_eff_df, col="Season", height=4, aspect=.6) def plot_double_y(ax, data): bar_width = 0.35 x = np.arange(len(data['BMP'].unique())) # 获取BMP类别索引 # 左侧Y轴:绘制y1的柱状图 ax.bar(x - bar_width/2, data[data['BMP']=='CC']['y1'], width=bar_width, label='CC (y1)', color='#1f77b4') ax.bar(x + bar_width/2, data[data['BMP']=='GWWs']['y1'], width=bar_width, label='GWWs (y1)', color='#ff7f0e') ax.set_ylabel('y1 数值', color='#1f77b4') ax.tick_params(axis='y', labelcolor='#1f77b4') ax.set_xlabel(data['Season'].iloc[0]) ax.set_xticks(x) ax.set_xticklabels(['CC', 'GWWs']) # 右侧Y轴:创建次轴并绘制y2的柱状图 ax2 = ax.twinx() ax2.bar(x - bar_width/2, data[data['BMP']=='CC']['y2'], width=bar_width, label='CC (y2)', color='#2ca02c') ax2.bar(x + bar_width/2, data[data['BMP']=='GWWs']['y2'], width=bar_width, label='GWWs (y2)', color='#d62728') ax2.set_ylabel('y2 数值', color='#2ca02c') ax2.tick_params(axis='y', labelcolor='#2ca02c') # 合并图例 handles1, labels1 = ax.get_legend_handles_labels() handles2, labels2 = ax2.get_legend_handles_labels() ax.legend(handles1 + handles2, labels1 + labels2, loc='upper right') # 将绘图函数应用到每个子图 g.map_dataframe(plot_double_y) # 移除非第一个子图的左侧边框 for ax in g.axes.flat[1:]: sns.despine(ax=ax, left=True) # 调整子图间距和边距 plt.subplots_adjust(wspace=0, bottom=0.18, left=0.06) plt.show()
效果说明
- 每个季节子图都包含独立双Y轴:左侧对应
y1数据,右侧对应y2数据 - 同一BMP类别的
y1、y2柱子并排展示,不同BMP用颜色区分,图例清晰覆盖所有数据系列 - 保留原代码的布局风格,子图之间无缝衔接,边距适配标签显示需求
内容的提问来源于stack exchange,提问作者hamid mohebzadeh
相关产品推荐
相关产品推荐

