mpltweak
像在 PPT 里调多图排版一样调 matplotlib。
拖面板、多选对齐 / 均分、边缘吸附、悬停改字号、cartopy 重图切线框、一键裁白边。 你调图的时候,脚本一个字都不动;等你点头,它才把那几个数字精确写回原文件。
pip install mpltweak · 只依赖 matplotlib(交互窗口另需 PyQt5 或 TkAgg)
它解决什么问题
科研绘图脚本里,最耗时的从来不是数据,是排版:子图挡住轴标签、间距不匀、 左边缘差 0.02、图例压住曲线、字号在论文里太小……而这一切只能靠 「改一个数字 → 重跑脚本 → 等几十秒 → 看 PNG → 再改」的循环。
mpltweak 把这段循环变成肉眼 + 鼠标:
改代码 → 重跑 → 看图 → 再改 ... ← 传统方式
──────────────────────────────────────
mpltweak fig1.py → 拖 → mpltweak apply --write ← 三步
它只管样式和位置,不发明内容——文字、数据、图形仍完全由你的代码决定。
30 秒看懂
| 步骤 | 命令 | 发生了什么 |
|---|---|---|
| ① 开窗调图 | mpltweak fig1.py |
脚本照常执行(写了 matplotlib.use('Agg') 也不用改),弹出交互窗口 |
| ② 拖、对齐、改字号 | 鼠标 + 几个键 | 只在内存里生效,代码零改动 |
| ③ 关窗 | 关闭窗口 | 只写 <脚本目录>/.tweak_params/fig1.json,代码依然没动 |
| ④ 预览 | mpltweak apply fig1.py |
打印改动清单(只读,不落盘) |
| ⑤ 写回 | mpltweak apply fig1.py --write |
原位改那几个数字 + 备份 + 重跑验证,失败自动回滚 |
第 ⑤ 步长这样(真实运行输出 + 真实 diff):
演示
拖动 + 边缘吸附 拖动时显示 ghost 预览与对齐参考线,靠近对齐位置自动贴合 |
多选对齐 / 均分 Ctrl 加选三个面板 → 一键左对齐 + 垂直均分,从"随手写的参数"变整齐一列 |
悬停改字号 鼠标悬停标题、轴标签、刻度或图例,按 + / - 直接调 |
重图切线框(空格) cartopy 全球图全量重绘 494ms → 169ms,排版时不再卡 |
安装
pip install mpltweak # 内核(可做写回 / 自检,无需窗口)
pip install "mpltweak[qt]" # 带 PyQt5 交互窗口(Windows / Linux 推荐)
环境自检:
mpltweak doctor # Python / matplotlib 版本、可用后端、字体等
脚本里写了
matplotlib.use('Agg')(科研脚本批量出图的常见写法)不需要改—— 启动器会临时接管后端,savefig的结果与原来完全一致。
键位速查
| 操作 | 作用 |
|---|---|
| 拖面板 / 拖边框、角 | 移动 / PPT 式缩放(对边固定;锁长宽比的轴自动等比) |
| Ctrl+点击(或 Shift+点击) | 多选加选 / 减选;拖空白处橡皮筋框选 |
| Ctrl+Shift+L/R/T/B/C/M | 对齐:左 / 右 / 上 / 下 / 水平居中 / 垂直居中 |
| Ctrl+Shift+H / V | 均分:水平 / 垂直(两端不动,中间等间距) |
| Ctrl+Z / Ctrl+Y(或 Ctrl+Shift+Z) | 撤销 / 重做 |
悬停文字后 + / - |
标题、轴标签、刻度、图例、colorbar 的字号 |
| 空格 | 线条模式(只留边框与文字,隐藏数据图元)——重图排版提速 |
| Ctrl+F | 适配画布到内容(裁掉四周白边,子图像素不变) |
| 方向键 / Shift+方向键 | 移动面板(PPT 习惯)/ 微调尺寸(中心不动) |
| 拖 colorbar 长轴端点 / 细条边 / 中点 | 调长度 / 调厚度 / 整条平移 |
| 拖图例 | 8 个标准位预览 + 松手吸附 |
[ ] · c · C · g · s · x y |
线宽 / 线色 / colormap / 网格 / 边框 / 线性对数轴 |
n · e · ? |
吸附开关 / 手动导出 / 帮助 |
| 拖窗口边缘 | 改画布尺寸(写回 figsize) |
⚠️ 开窗前请切到英文输入法:中文输入法打开时,
c/s/g/x/y等字母快捷键会被输入法吞掉。
为什么不一样
同赛道已经有做得不错的工具(例如 Tavotto,AGPL-3.0)。 差别不在"能不能拖",在改完的东西去哪:
| mpltweak | Tavotto | |
|---|---|---|
| 形态 | pip 包 + CLI(mpltweak / mpltweak apply) |
桌面安装包(自带 Python)+ Codex 插件 |
| 排版手感 | PPT 式:多选、对齐、均分、吸附、裁白边、线条模式 | 图内对象编辑 + 毫米级拼版 |
| 改动去向 | AST 确定性写回原脚本(可 diff、可 review、有备份、有验证) | sidecar override,脚本永不修改 |
| 参数格式 | 公开 JSON 规范(version 3),agent 可直接读写 | 私有 layout / override 文件 |
| 期刊预检 | 暂无 | 有(栏宽、字号下限、DPI 的 profile 校验) |
| 矢量导出 | 由你的脚本自己 savefig |
PDF / PNG / TIFF 同源导出 |
| 依赖 | matplotlib(窗口另需 PyQt5 / Tk) | 自带 pinned runtime |
"零侵入"我们照写,但含义更严格:调图全程不改代码、不加 import、不生成副文件——
参数静默落在 .tweak_params/*.json。写回是你显式点头后的动作,而且只改代码里
原有的那些数字(add_axes([...]) 就改那 4 个数),不插一长串调整块。
可靠性:三层验证
--write 不是"盲改",每一步都可回滚:
- 能跑通 —— 改完用 Agg 无头重跑,退出码非 0 直接回滚;
- 改对了 —— 重跑后 dump 目标图状态,与参数里的位置 / 字号 / grid / spines / clim 逐项比对;"跑通了但布局没落到目标图"会被判失败;
- 换锚点重试 —— 图号对应的
savefig→ 主锚点 → 脚本尾,全部失败才回滚。
备份写在 .tweak_params/<脚本>.tweak.bak(不散落到代码目录),绝不留下改坏的脚本;
慢脚本超时不会被误判为失败(只提示手动确认)。
.tweak_params/*.json 规范(version 3)
参数文件是公开格式——可以手工改,也可以让 AI / agent 直接生成,--write 一样能落实:
{
"version": 3,
"script": "fig1.py",
"figsize_px": [1500, 700], // 画布逻辑像素(未 resize 为 null)
"figsize_in": [15.0, 7.0], // 写回 figsize 的英寸数
"axes": [
{
"index": 0, // = fig.axes 顺序
"pos": [0.048, 0.655, 0.30, 0.215], // [x0, y0, w, h],figure 归一化坐标
"aspect_locked": false,
"title_fontsize": 9.0,
"label_fontsize": 8.0,
"tick_fontsize": 8.0,
"grid": false,
"spines": { "top": false, "right": false },
"xscale": "linear",
"yscale": "linear",
"is_colorbar": false,
"clim": [-2.0, 2.0],
"cmap": "RdBu_r",
"lines": [ { "index": 0, "linewidth": 1.2, "color": "#0F4D92" } ],
"legend": { "loc": "upper right", "fontsize": 8.0 }
}
]
}
局限(先看这里再决定用不用)
- AST 写回不是万能的:动态构造的布局(位置来自变量或循环计算)无法原位替换,
会退化为块方式(
--style block)或需要手动落实; - 原位写回只改代码里已有的项:参数里有
grid=True但代码里没有grid(...)时, 它会明确告诉你"保持原样",不会擅自插入新语句; - 没有期刊预检(栏宽 / 字号下限 / DPI profile),也没有矢量导出——这两件事留给你的
savefig与投稿流程; - 图例只吸 8 个标准位,不支持自由坐标;
- 需要交互后端(Qt 或 Tk);纯服务器环境只能跑
apply与doctor。
开发
git clone https://github.com/shdbl/mpltweak && cd mpltweak
pip install -e .
python tests/test_tweak.py # 交互内核
python tests/test_events.py # 事件路径
python tests/test_redo.py # 撤销 / 重做
python tests/test_writeback.py # AST 写回 + 三层验证
python tools/crosscheck.py # 环境 / API 兼容性自检
src/mpltweak/
├── cli.py # mpltweak <脚本> | apply | doctor
├── launch.py # 跑脚本 → 挂窗口 → 关窗存参数
├── toolbox.py # 交互内核(Tweak 控制器,纯 matplotlib 事件)
├── params.py # 参数 JSON 规范(version 3)
├── apply.py # 改动清单 / 写回入口
├── writeback.py # AST 定位 + 原位 / 块写回
└── verify.py # 语义验证(重跑后逐项比对)
toolbox.py 也可作嵌入 API(from mpltweak.toolbox import gaitu),
但主推 CLI——用户脚本里不该出现本工具的任何痕迹。
License
MIT
Metadata
Release files for mpltweak 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mpltweak-0.1.0.tar.gz | 635.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mpltweak-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.2 MB
Release files / mpltweak-0.1.0.tar.gz
| Download URL | mpltweak-0.1.0.tar.gz |
|---|---|
| Size | 635.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c11a3e77343b3a3c589ee9979df32390c7738266e2d8d046a4b0774f26f37d1a
|
|
BLAKE2b-256 checksum How to use checksums |
935052de520ceb06fe3c65919339faba0ae68ef1d0e021a505d65797a2e23816
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.19
|
Release files / mpltweak-0.1.0-py3-none-any.whl
| Download URL | mpltweak-0.1.0-py3-none-any.whl |
|---|---|
| Size | 611.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
26b13bce86f79caf5b7797141125a81c25be7c502b148f29d4bd3ce9d819aabb
|
|
BLAKE2b-256 checksum How to use checksums |
773f6712da90ef9eaca1952cd87938a51490950045c6066f7ec0c3842761124e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.19
|