""" plot_pub skill — 出版级 matplotlib rcParams 一键设置。 LLM 通过 `from skills.plot_pub.style import apply_pub_style; apply_pub_style()` 使用。 """ from __future__ import annotations import warnings import matplotlib import matplotlib.pyplot as plt from matplotlib import font_manager # 中文字体候选,按平台优先级排 _CHINESE_FONTS = [ "SimHei", # Windows 黑体 "Microsoft YaHei", # Windows 雅黑 "WenQuanYi Micro Hei", # Linux "Heiti TC", # macOS "Arial Unicode MS", # macOS 兜底 ] def _find_chinese_font() -> str | None: """从候选清单里挑系统装了的第一个,都没有返 None。""" installed = {f.name for f in font_manager.fontManager.ttflist} for name in _CHINESE_FONTS: if name in installed: return name return None def apply_pub_style( chinese: bool = True, dpi: int = 150, font_size: int = 10, linewidth: float = 1.2, cmap: str = "viridis", ) -> None: """ 一键设置出版级 matplotlib rcParams。 Args: chinese: True 时加载中文字体,失败 warn 但不抛(图继续画,中文显示方块) dpi: 屏幕显示 dpi。保存图请用 savefig(..., dpi=300) 单独指定 font_size: 基础字号,论文双栏图标准 10pt linewidth: 线粗,出版图细些更精致 cmap: 默认 colormap,viridis / plasma / cividis 是色觉友好选择 """ rc = matplotlib.rcParams # ---- 字体 ---- if chinese: font = _find_chinese_font() if font: # 中文字体放第一位,后面接 Arial / DejaVu 处理英文 rc["font.sans-serif"] = [font, "Arial", "DejaVu Sans"] else: warnings.warn( "[plot_pub] 未找到中文字体(候选: " + ", ".join(_CHINESE_FONTS) + ")。中文将显示为方块。" + "Windows 控制面板 → 字体,Linux 装 wqy-microhei 包。", RuntimeWarning, stacklevel=2, ) rc["font.sans-serif"] = ["Arial", "DejaVu Sans"] else: rc["font.sans-serif"] = ["Arial", "DejaVu Sans"] rc["axes.unicode_minus"] = False # 负号不显示成方块 rc["font.family"] = "sans-serif" rc["font.size"] = font_size # ---- 尺寸 / dpi ---- rc["figure.dpi"] = dpi rc["savefig.dpi"] = 300 # 默认保存高 dpi,临时图用 savefig(..., dpi=...) 覆盖 rc["savefig.bbox"] = "tight" rc["savefig.pad_inches"] = 0.05 # ---- 线条 ---- rc["lines.linewidth"] = linewidth rc["lines.markersize"] = 4 rc["axes.linewidth"] = 0.8 # ---- 刻度 ---- rc["xtick.direction"] = "in" # 期刊偏好刻度朝内 rc["ytick.direction"] = "in" rc["xtick.major.size"] = 4 rc["ytick.major.size"] = 4 rc["xtick.minor.size"] = 2 rc["ytick.minor.size"] = 2 rc["xtick.minor.visible"] = True rc["ytick.minor.visible"] = True # ---- legend ---- rc["legend.frameon"] = False # 出版图 legend 无框 rc["legend.fontsize"] = font_size - 1 # ---- colormap ---- rc["image.cmap"] = cmap # ---- 数学字体 ---- rc["mathtext.fontset"] = "stix" # 跟 Times / Arial 配,公式不突兀 # ---- 兜底:防止 PDF 嵌入 Type 3 字体(期刊要求 Type 42) ---- rc["pdf.fonttype"] = 42 rc["ps.fonttype"] = 42 def reset_style() -> None: """还原 matplotlib 默认 rcParams(测试 / 切换主题时用)。""" matplotlib.rcdefaults()