如何修改plotnine/matplotlib中指数标签的字体?
解决plotnine对数轴指数标签字体不生效问题
问题现象
使用plotnine绘制带对数刻度Y轴的图表时,通过theme(text=element_text(family="Gill Sans"))全局设置字体后,图表中除Y轴指数标签外的所有文本均正常应用Gill Sans字体,但指数标签仍保留默认字体。
原因分析
问题出在label_log(mathtex=True)参数上:开启mathtex=True后,Y轴的指数标签会以LaTeX数学公式的形式渲染,这类文本会使用matplotlib默认的数学字体,不受plotnine的全局主题字体设置影响。
解决方案
提供两种可行的解决方式:
方式一:自定义标签生成函数(不依赖mathtex)
手动生成指数格式的文本标签,让标签继承全局字体设置:
import plotnine as p9 import pandas as pd import mizani import numpy as np def custom_log_labels(x): # 手动转换为10的指数格式文本 return [f"$10^{{{int(np.log10(val))}}}$" if val != 0 else "0" for val in x] data = { "Degree": [3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6], "Probability": [0.00001, 0.00002, 0.00003, 0.001, 0.002, 0.003, 0.01, 0.02, 0.03, 0.1, 0.2, 0.3], "p": ["p=0.01", "p=0.01", "p=0.01", "p=0.1", "p=0.1", "p=0.1", "p=0.01", "p=0.01", "p=0.01", "p=0.1", "p=0.1", "p=0.1"], "Scheme": ["Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed"], } df = pd.DataFrame(data) x_val = "Degree" y_val = "Probability" y_label = "Degree Probability" g1_val = "p" g2_val = "Scheme" p = ( p9.ggplot(df) + p9.aes(x=x_val, y=y_val, color=g1_val, shape=g2_val, linetype=g2_val, size=g2_val) + p9.geom_point(alpha=0.8) + p9.geom_line(size=0.5) + p9.scale_x_continuous(name=x_val, breaks=[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) # 使用自定义标签函数,替代mathtex渲染 + p9.scale_y_continuous(name=y_label, trans=mizani.transforms.log_trans(10), labels=custom_log_labels) + p9.geom_vline(xintercept=6, size=0.4, linetype="dotted", color="black") + p9.geom_vline(xintercept=3, size=0.4, linetype="dotted", color="black") + p9.scale_shape_manual(name="Algorithm", values=["o", "*", "+"]) + p9.scale_color_manual(name="Rewiring Prob.", values=["red", "blue"]) + p9.scale_linetype_manual(name="Algorithm", values=["none", "none", "solid"]) + p9.scale_size_manual(name="Algorithm", values=[5, 5, 2]) + p9.theme(text=p9.element_text(family="Gill Sans", weight="regular")) ) p
方式二:修改matplotlib全局配置,强制数学文本使用目标字体
通过设置matplotlib的rc参数,让LaTeX渲染的数学文本也使用Gill Sans字体:
import plotnine as p9 import pandas as pd import mizani import matplotlib.pyplot as plt # 设置matplotlib的数学文本字体 plt.rcParams['mathtext.fontset'] = 'custom' plt.rcParams['mathtext.rm'] = 'Gill Sans' plt.rcParams['mathtext.it'] = 'Gill Sans:italic' plt.rcParams['mathtext.bf'] = 'Gill Sans:bold' data = { "Degree": [3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6], "Probability": [0.00001, 0.00002, 0.00003, 0.001, 0.002, 0.003, 0.01, 0.02, 0.03, 0.1, 0.2, 0.3], "p": ["p=0.01", "p=0.01", "p=0.01", "p=0.1", "p=0.1", "p=0.1", "p=0.01", "p=0.01", "p=0.01", "p=0.1", "p=0.1", "p=0.1"], "Scheme": ["Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed", "Theoretical", "Original", "Proposed"], } df = pd.DataFrame(data) x_val = "Degree" y_val = "Probability" y_label = "Degree Probability" g1_val = "p" g2_val = "Scheme" p = ( p9.ggplot(df) + p9.aes(x=x_val, y=y_val, color=g1_val, shape=g2_val, linetype=g2_val, size=g2_val) + p9.geom_point(alpha=0.8) + p9.geom_line(size=0.5) + p9.scale_x_continuous(name=x_val, breaks=[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) + p9.scale_y_continuous(name=y_label, trans=mizani.transforms.log_trans(10), labels=mizani.labels.label_log(mathtex=True)) + p9.geom_vline(xintercept=6, size=0.4, linetype="dotted", color="black") + p9.geom_vline(xintercept=3, size=0.4, linetype="dotted", color="black") + p9.scale_shape_manual(name="Algorithm", values=["o", "*", "+"]) + p9.scale_color_manual(name="Rewiring Prob.", values=["red", "blue"]) + p9.scale_linetype_manual(name="Algorithm", values=["none", "none", "solid"]) + p9.scale_size_manual(name="Algorithm", values=[5, 5, 2]) + p9.theme(text=p9.element_text(family="Gill Sans", weight="regular")) ) p
说明
- 方式一无需依赖LaTeX渲染,直接生成普通文本标签,兼容性更好,但需要自己处理标签格式;
- 方式二保留了mathtex的渲染效果,同时强制数学文本使用目标字体,适合需要保持公式排版风格的场景。
内容的提问来源于stack exchange,提问作者max
相关产品推荐
相关产品推荐

