为何sns.set与rcParams设置字体大小仅对suptitle生效?如何修复?
箱图字体大小修改失效问题
问题描述
尝试修改批量绘制的箱图中所有字体元素大小,但运行代码后仅图的总标题(suptitle)字体大小变化,其余坐标轴标签、刻度、子图标题等字体均无变化。代码如下:
from pathlib import Path import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt def plot_group(df, nrow, ncol, size, plot_title): sns.set(style="darkgrid") plt.rcParams['font.size'] = size fig, axes = plt.subplots(nrow, ncol, figsize=(15, 10), tight_layout=True) fig.suptitle(plot_title) n_boxplots = 2 for i in range(nrow): for j in range(ncol): current_ax = axes[i, j] sns.boxplot(data=df[['foo','bar']], palette="Set2", ax=current_ax) current_ax.set_title("foo", fontsize=18) plt.savefig(f'font_size_{size}.png', dpi=75) plt.close(fig) nrow = 3 ncol = 3 rng = np.random.default_rng(0) arr = rng.random((30, 2)) df = pd.DataFrame(data=arr, columns=['foo', 'bar']) for size in [14, 22]: plot_title = f"Font size = {size}" plot_group(df, nrow, ncol, size, plot_title)
原因分析
- Seaborn样式覆盖了rcParams设置:
sns.set(style="darkgrid")会重置matplotlib的默认参数,包括字体相关配置,之后设置的plt.rcParams['font.size']会被Seaborn的样式参数覆盖,无法生效。 - 子图标题硬编码固定大小:代码中
current_ax.set_title("foo", fontsize=18)直接指定了固定的18号字体,不会随传入的size参数变化。 - 部分字体元素需要单独指定参数:
font.size是基础字体大小,但坐标轴标签、刻度等元素依赖于更具体的rcParams项(比如axes.labelsize、xtick.labelsize等),仅设置font.size无法覆盖所有元素。
修复方案
方案1:调整rcParams顺序+统一配置字体参数
把plt.rcParams设置放在sn.set()之后,补充全量字体相关rc参数,并去掉子图标题的硬编码字体大小:
from pathlib import Path import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt def plot_group(df, nrow, ncol, size, plot_title): sns.set(style="darkgrid") # 统一设置所有字体相关的rc参数 plt.rcParams.update({ 'font.size': size, 'axes.labelsize': size, 'axes.titlesize': size, 'xtick.labelsize': size, 'ytick.labelsize': size, 'figure.titlesize': size # 对应suptitle的大小 }) fig, axes = plt.subplots(nrow, ncol, figsize=(15, 10), tight_layout=True) fig.suptitle(plot_title) n_boxplots = 2 for i in range(nrow): for j in range(ncol): current_ax = axes[i, j] sns.boxplot(data=df[['foo','bar']], palette="Set2", ax=current_ax) current_ax.set_title("foo") # 不再硬编码fontsize,使用rcParams设置 plt.savefig(f'font_size_{size}.png', dpi=75) plt.close(fig) nrow = 3 ncol = 3 rng = np.random.default_rng(0) arr = rng.random((30, 2)) df = pd.DataFrame(data=arr, columns=['foo', 'bar']) for size in [14, 22]: plot_title = f"Font size = {size}" plot_group(df, nrow, ncol, size, plot_title)
方案2:使用Seaborn的set_context方法
Seaborn提供的set_context()可以便捷统一调整绘图元素大小,配合set_style()使用更符合Seaborn使用习惯:
from pathlib import Path import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt def plot_group(df, nrow, ncol, size, plot_title): sns.set(style="darkgrid") # 使用set_context设置字体大小,base_fontsize对应基础字体大小 sns.set_context("notebook", base_fontsize=size) fig, axes = plt.subplots(nrow, ncol, figsize=(15, 10), tight_layout=True) fig.suptitle(plot_title) n_boxplots = 2 for i in range(nrow): for j in range(ncol): current_ax = axes[i, j] sns.boxplot(data=df[['foo','bar']], palette="Set2", ax=current_ax) current_ax.set_title("foo") # 继承context中的字体大小 plt.savefig(f'font_size_{size}.png', dpi=75) plt.close(fig) nrow = 3 ncol = 3 rng = np.random.default_rng(0) arr = rng.random((30, 2)) df = pd.DataFrame(data=arr, columns=['foo', 'bar']) for size in [14, 22]: plot_title = f"Font size = {size}" plot_group(df, nrow, ncol, size, plot_title)
说明
两种方案都能实现所有字体元素随传入的size参数变化:
- 方案1更灵活,可单独控制不同元素的字体大小;
- 方案2设置更简洁,符合Seaborn的生态使用逻辑。
内容的提问来源于stack exchange,提问作者DeltaIV
相关产品推荐
相关产品推荐

