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

如何使用Seaborn绘制双Y轴柱状图?

实现Seaborn分面子图的双Y轴柱状图

要在按季节分面的子图中实现双Y轴柱状图,核心思路是利用FacetGrid遍历每个子图,为每个子图创建双Y轴(主轴+次轴),分别绘制y1和y2的柱状图,同时调整柱子位置避免重叠。

关键步骤说明

  • 搭建分面框架:先初始化按季节拆分的子图结构,不直接指定绘图类型,方便后续自定义双Y轴内容
  • 自定义双轴绘图逻辑:
    • 设置柱子宽度,通过X轴位置偏移让同一BMP类别的y1、y2柱子并排显示
    • 主轴绘制y1数据,绑定对应轴标签和颜色;次轴通过twinx()创建,独立绘制y2数据并设置专属样式
    • 合并两个轴的图例,避免图例分散
  • 统一布局风格:保留原代码中移除多余边框、调整子图间距的设置,保证视觉一致性

完整代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:27:43