求助:Matplotlib中Colorbar图例标签字体大小不一致问题
解决Matplotlib Colorbar刻度标签字体大小不一致问题
我使用Python的Matplotlib进行数据可视化,colorbar图例通过颜色对应不同数值,但发现colorbar的刻度标签字体大小不一致,既降低了可读性,也影响图表整体美观。
尝试通过colorbar对象的set_label和set_tick_params方法显式设置字体大小后,问题仍未解决,现寻求可行的解决建议。
相关代码
import pathlib from typing import Union, Dict, Optional import osmnx as ox from matplotlib import pyplot as plt, colors, cm from matplotlib.font_manager import FontProperties from matplotlib.ticker import FuncFormatter from configs.default import get_default_config from preprocessing.graph_loader import GraphLoader root_dir = pathlib.Path(__file__).parent.parent.absolute() class GraphMapper: def __init__(self): self.config = get_default_config()['ds'] self.graph = GraphLoader().graph def plot_dict_on_graph_as_heatmap( self, dictionary: Dict, title: str, filename: Optional[str] = None, font: str = 'Consolas', # 'Times New Roman', fontsize: int = 25 ) -> None: cmap = plt.cm.inferno maximum_value = max([dictionary[k] for k in dictionary.keys()]) minimum_value = max(min(dictionary.values()), 1) norm = colors.LogNorm(vmin=minimum_value, vmax=maximum_value) sm = cm.ScalarMappable(norm=norm, cmap=cmap) node_color = [ sm.to_rgba(dictionary[n]) if dictionary[n] > 0 else sm.to_rgba(minimum_value) for n in self.graph.nodes(data=False) ] node_size = [10 if dictionary[n] > 0 else 0 for n in self.graph.nodes(data=False)] # noinspection PyTypeChecker fig, ax = ox.plot_graph( self.graph, node_size=node_size, edge_linewidth=.5, node_color=node_color, edge_color='#333333', bgcolor='w', show=False, close=False, ) cbar = plt.colorbar(sm, ax=ax, shrink=0.8, pad=0.01) font_properties = FontProperties( family=font, size=fontsize, ) if title != '': cbar.set_label(title, fontproperties=font_properties) # formatter = FuncFormatter(lambda x, _: r"${:.0f} \times 10^3$".format(x / 1e3)) # cbar.ax.yaxis.set_major_formatter(formatter) # cbar.ax.tick_params(labelsize=fontsize) # cbar.ax.yaxis.set_tick_params(pad=fontsize) cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), fontproperties=font_properties) plt.subplots_adjust( left=0.01, bottom=0.01, right=0.99, top=0.99, wspace=0.01, hspace=0.01 ) if filename is not None: plt.savefig(root_dir / "visualizations" / (str(filename) + ".pdf"), bbox_inches='tight') plt.show()
输出问题
输出的colorbar中,仅10^3格式符合预期,其他数值的字体大小不一致。
已尝试的方法
- 使用
FontProperties设置统一字体属性 - 遍历每个刻度标签单独设置字体:
或for label in cbar.ax.yaxis.get_ticklabels(): label.set_fontproperties(fontprops)cbar.set_ticklabels([label.get_text() for label in cbar.ax.get_yticklabels()], fontproperties=fontprops) - 使用格式化器统一标签格式:
formatter = FuncFormatter(lambda x, pos: f'{x:.0f}') cbar.ax.yaxis.set_major_formatter(formatter) cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), fontproperties=fontprops)
解决建议
核心原因
由于使用了LogNorm对数归一化,Matplotlib会自动为对数刻度的10幂次标签启用TeX渲染生成上标,这部分标签的字体属性未被统一覆盖,导致大小不一致。直接调用set_yticklabels会干扰自动格式生成,反而加剧问题。
方案1:统一设置轴的所有字体属性(推荐)
不要单独修改ticklabels,直接为colorbar的轴整体设置字体属性,确保包括TeX渲染的上标在内的所有元素都使用统一配置:
# 替换原代码中cbar.ax.set_yticklabels(...)的部分 font_properties = FontProperties(family=font, size=fontsize) # 设置colorbar标题字体 if title != '': cbar.set_label(title, fontproperties=font_properties) # 统一设置所有刻度标签和轴标签的字体 for label in cbar.ax.get_yticklabels() + [cbar.ax.yaxis.label]: label.set_fontproperties(font_properties) # 同时设置刻度标签大小(双重保障) cbar.ax.tick_params(labelsize=fontsize)
方案2:自定义对数格式化器,手动控制标签格式
自己实现对数刻度的格式化逻辑,避免Matplotlib自动生成混合格式的标签:
import numpy as np from matplotlib.ticker import FuncFormatter # 自定义对数格式函数 def custom_log_formatter(x, pos): if x <= 0: return "0" exponent = int(np.floor(np.log10(x))) coeff = x / (10 ** exponent) # 统一格式为"数字 × 10^指数"或"10^指数" if np.isclose(coeff, 1): return f"$10^{{{exponent}}}$" else: return f"${coeff:.0f} \\times 10^{{{exponent}}}$" # 应用格式化器 formatter = FuncFormatter(custom_log_formatter) cbar.ax.yaxis.set_major_formatter(formatter) # 统一设置字体 font_properties = FontProperties(family=font, size=fontsize) cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), fontproperties=font_properties) cbar.ax.tick_params(labelsize=fontsize) if title != '': cbar.set_label(title, fontproperties=font_properties)
方案3:关闭TeX渲染(如果不需要上标格式)
如果不需要上标样式,直接关闭Matplotlib的TeX渲染,让所有标签使用普通字体:
# 在代码开头添加 plt.rcParams['text.usetex'] = False # 然后正常设置字体属性 font_properties = FontProperties(family=font, size=fontsize) cbar.set_label(title, fontproperties=font_properties) cbar.ax.set_yticklabels(cbar.ax.get_yticklabels(), fontproperties=font_properties) cbar.ax.tick_params(labelsize=fontsize)
内容的提问来源于stack exchange,提问作者Julian47723705
相关产品推荐
相关产品推荐

