返回

Matplotlib双Y轴颜色设置全攻略:边框、刻度及标签

python

Matplotlib 双 Y 轴颜色设置:主轴、次轴、刻度、标签、边框全攻略

碰到了一个 Matplotlib 画图的颜色设置问题。我需要画两个数据集,分别对应左右两个 Y 轴,并用不同的颜色区分。 更进一步,我希望左、右两侧的以下元素都用对应的颜色:

  • 左、右垂直边框(spine)
  • 刻度(主刻度和次刻度)
  • 刻度标签

找了一圈没找到完整的解决方案。用 pandas.plotsecondary-y 选项,或者 Matplotlib 的 twinx 来创建次级 Y 轴很容易画出数据,但颜色设置很麻烦。

来看个完整的代码示例:

import matplotlib.pyplot as plt
import matplotlib as mpl
import pandas as pd

df = pd.DataFrame(data={'Series A':[1,1.25,1.5,1.75,2],'Series B':[11,10.75,10.5,10.25,10]})

fig1,ax = plt.subplots()
#  在 ax 上画 Series A
df['Series A'].plot(ax=ax,style='o-',lw=0.5,legend=False,color='b',ylim=(0,3));
ax.set_xlabel('x')
ax.set_ylabel('Y values')
# 生成次级 Y 轴
ax2 = ax.twinx()
# 在 ax2 上画 Series B
df['Series B'].plot(ax=ax2,style='^-',legend=False,lw=0.5,color='g',ylim=(9,12));
plt.show();

到这儿,两个数据集已经正确地画出来了。接下来搞颜色。我加了这两行:

ax.tick_params(axis='y', colors='b',which='both')
ax2.tick_params(axis='y', colors='g',which='both')

这基本搞定了大部分:刻度和刻度标签的颜色都对了。但是边框的颜色没变。

我试过 ax.spines['left'].set_color('orange'),但没用。这是咋回事?

所以我有两个问题:

  • 次级轴的参数访问器是啥(比如,我想改刻度之类的)?
  • 怎么让边框的颜色也变了?

问题产生原因分析

核心在于理解 Matplotlib 中主轴 (primary axis) 和次轴 (secondary axis) 的关系,以及如何访问和修改它们的属性。 twinx() 创建的 ax2 并不是 ax 的一个直接子属性,而是一个共享 X 轴的独立坐标轴。ax.spines['left'] 只能访问 ax 自身的左边框,对 ax2 无效。

解决方案

1. 访问次级轴属性

ax2 是一个独立的 Axes 对象,它有自己的 spinestick_params 等属性。 直接通过 ax2 访问和修改这些属性即可。

2. 设置边框颜色

要设置 ax2 的右边框颜色,直接用 ax2.spines['right'].set_color()。同理,设置 ax 的左边框用 ax.spines['left'].set_color()

3. 设置刻度和刻度标签颜色

上面示例中的 tick_params 使用方法是正确的,直接用就行:

ax.tick_params(axis='y', colors='b',which='both')
ax2.tick_params(axis='y', colors='g',which='both')

which='both' 表示同时修改主刻度和次刻度。

4. 完整代码示例

把上面的方法组合起来,完整的代码如下:

import matplotlib.pyplot as plt
import matplotlib as mpl
import pandas as pd

df = pd.DataFrame(data={'Series A':[1,1.25,1.5,1.75,2],'Series B':[11,10.75,10.5,10.25,10]})

fig1,ax = plt.subplots()
# 在 ax 上画 Series A
df['Series A'].plot(ax=ax,style='o-',lw=0.5,legend=False,color='b',ylim=(0,3));
ax.set_xlabel('x')
ax.set_ylabel('Y values')
# 生成次级 Y 轴
ax2 = ax.twinx()
# 在 ax2 上画 Series B
df['Series B'].plot(ax=ax2,style='^-',legend=False,lw=0.5,color='g',ylim=(9,12));

# 设置颜色
ax.spines['left'].set_color('blue')  # 修正:边框用明确的颜色名称
ax.tick_params(axis='y', colors='blue',which='both') # 修正:用明确的颜色名称
ax2.spines['right'].set_color('green') # 修正:用明确的颜色名称
ax2.tick_params(axis='y', colors='green',which='both') #修正:用明确的颜色名称

plt.show();

5. 更精细的控制:分别设置主次刻度

如果需要对主刻度和次刻度进行更精细的控制(比如不同的颜色或大小),可以使用 which='major'which='minor' 分别设置。

#  只设置主刻度颜色
ax.tick_params(axis='y', colors='blue', which='major')
# 只设置次刻度颜色
ax2.tick_params(axis='y', colors='lightgreen', which='minor')

6. 使用 set_tick_params(不推荐,仅作说明)

虽然也能用 ax2.yaxis.set_tick_params(),但不推荐。因为 tick_params() 更简洁,而且能同时设置多个属性。set_tick_params()是旧版本的方法。

# 不推荐!
# ax2.yaxis.set_tick_params(colors='g')

7. 控制 Spine 的可见性

有些时候,咱们可能想要隐藏某一边框。 可以利用set_visible()这个功能来让某些Spine隐藏起来:

ax2.spines['right'].set_visible(True) #让右侧的spine显示
ax.spines['top'].set_visible(False)   #让上方的spine消失

8. 统一修改样式:rcParams

如果需要对全局的绘图样式进行统一修改,可以使用 matplotlib.rcParams。比如,修改所有线条的默认宽度:

mpl.rcParams['lines.linewidth'] = 2

这会影响之后所有 plot 命令的线条宽度。注意,rcParams 的修改是全局的,会影响整个程序的绘图样式。

9. 进阶: 创建自定义的双Y轴函数.

假如你在很多地方都需要创建类似结构的双Y轴图表, 反复写上面的代码太麻烦。可以考虑封装成一个函数:

import matplotlib.pyplot as plt
import pandas as pd

def plot_dual_y_axis(df, col1, col2, color1='blue', color2='green', fig_size=(10,6)):
    """
    绘制双 Y 轴图表,并设置颜色。

    参数:
        df: 包含数据的 Pandas DataFrame。
        col1: 第一个 Y 轴的数据列名。
        col2: 第二个 Y 轴的数据列名。
        color1: 第一个 Y 轴的颜色。
        color2: 第二个 Y 轴的颜色。

    返回值:
         fig, ax, ax2 (matplotlib figure and axes objects)
    """

    fig, ax = plt.subplots(figsize=fig_size)
    ax2 = ax.twinx()

    df[col1].plot(ax=ax, style='o-', lw=0.5, legend=False, color=color1)
    df[col2].plot(ax=ax2, style='^-', legend=False, lw=0.5, color=color2)

    ax.spines['left'].set_color(color1)
    ax.tick_params(axis='y', colors=color1, which='both')
    ax2.spines['right'].set_color(color2)
    ax2.tick_params(axis='y', colors=color2, which='both')
    return fig, ax, ax2

#使用范例:
df = pd.DataFrame(data={'Series A':[1,1.25,1.5,1.75,2],'Series B':[11,10.75,10.5,10.25,10]})
fig, ax, ax2= plot_dual_y_axis(df, 'Series A', 'Series B', color1='magenta',color2='cyan')

ax.set_xlabel("My X label")  # 设置x轴
plt.show()


这个plot_dual_y_axis函数接受数据、列名和颜色作为参数,直接生成配置好颜色的双Y轴图,干净又便捷。