把mpf.plot(df)直接跑起来,你得到的大概率是一张“能看但谈不上专业”的图。这个系列前面几篇,我已经把type、style、mav、volume这些高频参数翻来覆去讲过,今天这篇继续盯住 v0.12.6a3 里那批容易被忽略的关键字参数。它们单个拿出来好像都不起眼,组合到一起却能决定整张图是“能看”还是“能发出去”。
mplfinance 的新版本在底层布局上变化不小,很多参数看似没变,实际行为已经不同。尤其涉及日期刻度、面板比例、返回对象这几个场景,老经验未必还适用。这篇我按用途把参数拆成几组:日期刻度、画布布局、数据量保护、返回对象,最后再用一个完整示例把所有参数串起来。适合两类人看:一是刚接触绘图库,拿着默认代码出图但不知道每个参数在干什么的;二是从旧版升级过来,发现出图效果不一样,想系统核对一遍参数边界的老用户。
1. 新版plot()参数地图:这些关键字参数从哪来、在哪生效
1.1 参数不是“传进去就完事”,它们背后有分发逻辑
plot()是门面函数,真正干活的是一堆内部组件。v0.12.6a3 调整了多面板布局的底层实现,很多关键字参数不再是简单塞给plot(),而是由它分发到对应的坐标轴、面板和图表对象。比如panel_ratios控制面板高度,进入内部布局器;datetime_format和update_ticks进入刻度处理器;returnfig则决定整个函数是直接显示还是把图形对象交还给你。
理解了这一点,“为什么我传了某些参数没反应”这类问题就很好排查了。参数没生效,先看它属于哪一层:是影响数据坐标、影响刻度标签、影响面板尺寸,还是影响整张画布。层面对了,参数才谈得上生效。我见过不少人把figsize写成字典或者字符串,结果被底层直接拒绝,也是这个原因——每个参数都有明确的类型要求,plot()并不会帮你做宽容的类型转换。
1.2 这次要展开的参数清单与分类
既然是新版专题的第五篇,我把重点放在几个平时容易被忽略、但组合起来价值很高的参数上。先给一张分类表,后面再逐个展开。
| 参数分组 | 关键字参数 | 主要作用 |
|---|---|---|
| 日期刻度 | datetime_format、xrotation、update_ticks | 控制X轴日期标签格式、旋转角度和刻度更新方式 |
| 画布布局 | figsize、panel_ratios、scale_padding、tight_layout | 控制整体尺寸、子图高度权重、边距和间距 |
| 数据量保护 | warn_too_much_data、max_n_ticks | 控制大数据量告警和刻度标签数量 |
| 返回结构 | returnfig、squeeze | 控制绘图结果是否返回,以及返回对象的形状 |
| 轴标签 | ylabel、ylabel_lower | 设置主图和下方面板的Y轴说明文字 |
这组参数不属于“画什么”的范畴,更多决定“画出来好不好看、能不能继续改”。我在实际项目中,出图脚本里最常反复调的就是这几项。特别是刻度部分,数据跨度和格式串一旦不匹配,整张图的时间轴就乱了。
1.3 参数之间存在隐式依赖,不是独立开关
这些参数往往联动。figsize变大之后,刻度标签的密度会变稀,你可能需要调低max_n_ticks;panel_ratios把成交量面板压得太扁,成交量标签就会被截断;returnfig=True之后,后续保存必须自己调用fig.savefig(),否则图不会出现在任何地方。
所以读参数文档时,我最建议的做法是“组合着看”,而不是单独查某一个参数。后面每一个小节的配置,我都会说明和哪些参数搭配使用,避免你照抄单个参数却始终得不到预期效果。
2. 日期刻度三件套:datetime_format、xrotation、update_ticks的配合逻辑
2.1 datetime_format:日期标签到底按什么格式渲染
datetime_format控制的是坐标轴刻度标签的日期格式。它本质上把格式串交给底层的日期格式化器,所以你需要按 Python 的strftime语法来写。常见的组合有:
'%Y-%m-%d':显示为 2024-06-01,适合跨多个年份的行情;'%m-%d':只显示月日,适合单年内观察;'%b-%d':显示英文缩写月份,比如 Jun-01;'%Y-%m':显示年月,适合周期很长、不需要精确到日的数据。
我在做某个模拟项目时,数据跨度横跨三年,默认格式会把每个刻度都渲染成完整日期,标签密集且重复,根本没法看。改成'%b-%d'之后,视觉上清爽得多,但跨年之后不同年份的同一个月会混淆。后来我干脆保留'%Y-%m',牺牲日粒度换来清晰的年份上下文。
2.2 xrotation:旋转角度只是表象,真正要解决的是重叠
xrotation控制日期标签的旋转角度。默认值通常能应付大多数情况,一旦数据跨度长、面板宽,标签还是容易挤在一起。旋转确实能缓解重叠,但它只是把横向空间换成了斜向空间,标签数量太多时,旋转到 90 度也救不回来。
这里必须连带提一下max_n_ticks。如果你觉得日期标签太挤,与其一味加大旋转角度,不如先减少刻度数量。比如图中只有六个月的数据,X 轴却塞下三十个日期标签,那不管旋转多少度都是灾难。我会把max_n_ticks压到 6 到 10 之间,让坐标轴只显示少数几个关键日期,再配合xrotation=30左右的角度,基本就不会重叠了。
2.3 update_ticks与show_nontrading:非交易日到底怎么画
update_ticks这个参数容易被忽略,但它在处理“非连续日期”时非常关键。默认情况下,mplfinance 会把数据索引里的日期作为刻度位置,坐标轴标签随日期更新。如果你的数据是交易数据,中间会跳过周末和节假日,X 轴上相邻两个数据点之间的间距其实是“一个交易日”,不是“一天”。
这就带来一个经典问题:当数据只有工作日而没有周末时,X 轴上 6 月 30 日之后紧挨着的是 7 月 3 日,视觉上 7 月 1 日和 2 日直接消失了。如果你希望 X 轴反映真实时间间隔,需要配合show_nontrading=True,把非交易日作为空白留出来;如果你只关心交易日的走势,show_nontrading=False更紧凑。
update_ticks和它配合时有个坑:当你显式设置了datetime_format,同时又关闭了刻度更新,坐标轴上的 tick 位置和实际日期标签可能对不上。我之前处理跨年数据时,用'%m-%d'后发现一个刻度跳到了 01-01,但数据里根本没有那个交易日,就是因为 tick 更新逻辑没有和日期格式串同步。现在我的习惯是:只要设置了datetime_format,就显式把update_ticks写成True,让标签跟着数据索引走,避免这类看不见的对齐误差。
2.4 三件套在真实K线上的组合顺序
我一般按这个顺序来调:先看数据跨度,选datetime_format;再根据面板宽度和跨度,设置max_n_ticks控制刻度数量;最后才用xrotation微调旋转角度。如果标签还是重叠,优先增加画布宽度,而不是强行加大旋转角度。日期刻度这块的核心目标是“让读者一眼看懂时间轴”,格式、数量、角度这三个旋钮要一起拧。
3. 画布比例与子图间距:figsize、panel_ratios、scale_padding的实战取舍
3.1 figsize:尺寸决定刻度密度,不是越大越好
figsize控制整张图的宽高。很多初学者喜欢把figsize调得特别大,觉得图越大越清晰。实际上,对同样的数据量来说,图越大,每个刻度之间的像素距离越宽,标签间距变大,反而可能出现“标签孤零零散在两端”的情况。
我的经验是先想清楚这张图用在哪:屏幕阅读、打印、还是嵌入报告。屏幕阅读用(14, 7)左右足够;需要放进文档或演示文稿,(15, 8)更合适;再往上并不会增加信息量,只会增加文件体积。尤其是批量出图时,figsize定得太大,保存的 PNG 文件体积会明显上升,几十张图累积起来就是几 MB 甚至几十 MB 的差异。
3.2 panel_ratios:多面板高度权重的分配方式
panel_ratios是面板高度的权重列表。它只在多面板场景下有意义,典型情况是主K线图下方挂一个成交量图。默认不传时,带成交量的图一般按主图与成交量 6:1 分配高度。如果你觉得成交量部分太矮,可以显式传panel_ratios=(6, 1.5),把成交量权重拉高。
如果你用addplot添加了自定义面板,panel_ratios的列表长度必须和面板总数一致。比如主图、成交量、还有一个指标图,就可以写(6, 1.5, 1)。比例数值不是像素,是相对高度,底层会把总高度按权重分给各面板。这个参数和volume=True是分开的,就算你没有单独设置成交量面板,只要通过addplot创建了第二个面板,也需要给panel_ratios配够数量的权重。
3.3 scale_padding与tight_layout:边距调整的两条路线
scale_padding控制面板之间以及图边缘的留白比例,默认值我觉得在多数场景下偏保守,不会裁掉内容。但当你发现左边价格标签被切掉、右边成交量标签和Y轴说明挤在一起时,可以先调大scale_padding试试。它是一个整体缩放因子,不是具体的像素边距,调的时候要有耐心,每次改 0.05 左右,比大幅度改动更容易定位到合适位置。
tight_layout则走的是自动压缩路线。新版里它接受布尔值或字典,传True时自动调整子图间距,适合多面板、标签多的情况。但要注意:用了tight_layout=True之后,整张图的边距会变得很紧,如果你后续想用fig.suptitle()加总标题,标题可能被推到画布外面。我的做法是让它配合bbox_inches='tight'一起保存,或者在tight_layout的字典参数里传入自定义pad值,给标题留出位置。
3.4 别忘了ylabel和ylabel_lower
ylabel设置主图Y轴标签,ylabel_lower设置下方第一个面板的Y轴标签。有人说传了ylabel没反应,多半是样式本身预留的位置太窄,或者面板比例里下方面板高度不足。我会把ylabel和panel_ratios一起调,标签文字太长时,也顺手把左侧边距通过scale_padding留出来。
4. 大数据绘图不失控:warn_too_much_data、max_n_ticks、squeeze的正确用法
4.1 warn_too_much_data:阈值不是摆设,更不是用来“静音”的
warn_too_much_data用来设置数据量告警阈值。当数据行数超过这个阈值时,绘图函数会提示你当前数据量较大,绘制和交互可能会变慢。新版默认阈值并不低,但具体是多少,不同小版本之间会有差异,所以不要指望记死一个数字就能一劳永逸。
我踩过最大的坑,是为了让提示消失而把这个参数直接调成几十万。结果数据量真的上来之后,出图卡得几乎没法操作,生成的图片文件也大得离谱。现在我的处理方式是:先跑一遍统计,如果是几万根分钟线,就考虑重采样到小时线或日线;如果确实必须保留全量数据,再调高阈值。阈值应该等于“你的机器和你在某个时间能接受的出图耗时”,而不是一个随手写的数字。
4.2 max_n_ticks:刻度数量是性能和可读性的平衡点
max_n_ticks控制X轴最多显示多少个刻度标签。默认样式通常会给一个保守值,但这个值在数据跨度大时依然会显得密集。你可以在调用时直接传入整数覆盖它,比如max_n_ticks=8,X 轴就只显示大约八个标签。
它只影响标签数量,不影响数据点绘制。所以当你要突出走势而不是具体日期时,把它调小很合适;当你要精确读取某一天的价格时,把它调大一些。我在做多面板叠加图时,会在主图层把刻度标签减少,让整个图面干净一点,然后在下方单独放一张数据表补充精确日期。
4.3 squeeze:单面板返回结构的解包陷阱
squeeze是个容易让人困惑的参数,它影响的是绘图函数返回的坐标轴列表的形状。在单面板场景下,如果squeeze=True,返回的坐标轴对象会退化成单个Axes对象,而不是长度为 1 的列表;多面板情况下则始终是列表。
我用returnfig=True做二次编辑时,习惯显式传squeeze=False,这样axlist永远是列表,代码里统一用axes[0]去取主图坐标轴,不会因为面板数量变化而突然出现'Axes' object is not subscriptable这种报错。多面板时squeeze看起来没区别,但它会影响少面板场景的代码兼容性,建议固定成False。
5. 把绘图结果拿回来:returnfig之后的二次编辑空间
5.1 returnfig的返回值结构
returnfig=True时,plot()不再直接调用显示逻辑,而是返回一个元组(fig, axlist)。fig是完整的 Figure 对象,axlist是坐标轴列表。这个设计很像把绘图流程拆成两段:先用绘图库完成标准布局,再交给你做非标准修改。
拿到fig之后,你可以用标准绘图库的接口继续操作:fig.suptitle()加总标题,fig.text()放置说明文字,fig.savefig()导出文件。axlist里的每个坐标轴对应一个面板,主图通常是第一个,后续按绘制顺序排列。
5.2 二次编辑的典型场景
我最常用returnfig的场景有三个:一是给图加总标题和免责声明;二是在纯技术指标图上叠加人工标注;三是批量出图时统一控制保存参数。举个例子,你想在成交量子图上画一条平均成交量的参考线,可以拿到axes[1]之后直接调用axes[1].axhline(...),完全不需要重新参与绘图流程。
如果不用returnfig,这些操作要么得在plot()之前通过addplot传参,要么就得做一次“先猜坐标位置再重新绘制”的脏活。所以我对returnfig的使用原则很简单:只要不是临时看图的脚本,一律开它。
5.3 批量出图时别忘了关闭figure
用returnfig=True之后,图对象由你控制,不再由绘图库自动管理。批量生成几十张图,如果每张都savefig之后不关闭,内存占用会一路往上走。我处理批量任务时会这样收尾:保存之后立刻调用plt.close(fig)。
类似的细节还有一个:既然已经手动拿到了fig,就不要再在循环里额外调用plt.show()。要么显示,要么保存,二选一,否则批量任务跑起来不是弹窗刷屏,就是内存翻倍。我的默认做法是只savefig,不显示,最后把图表统一放到输出目录里核对。
6. 完整示例:从模拟行情到一张专业级K线图的参数组合
6.1 先构造一份能复现的模拟数据
为了让你能直接复现,我用随机数生成一份模拟行情。它只是用来演示绘图接口的样例数据,不是真实行情,也不构成任何投资参考。
import mplfinance as mpf import pandas as pd import numpy as np idx = pd.bdate_range("2022-06-01", periods=120) rng = np.random.default_rng(42) close = 100 + np.cumsum(rng.normal(0, 0.4, size=120)) open_ = close + rng.normal(0, 0.2, size=120) high = np.maximum(open_, close) + np.abs(rng.normal(0, 0.5, size=120)) low = np.minimum(open_, close) - np.abs(rng.normal(0, 0.5, size=120)) volume = rng.integers(5000, 20000, size=120) df = pd.DataFrame({ "Open": open_, "High": high, "Low": low, "Close": close, "Volume": volume, }, index=idx)这份数据有 120 个交易日,跨约五个多月,适合观察日期格式和刻度数量。pd.bdate_range自动跳过周末,刚好能验证update_ticks和show_nontrading的效果。
6.2 一屏拼图的plot调用
下面是完整的绘图调用,我把前几节讲的参数都放在一起。
fig, axes = mpf.plot( df, type="candle", style="yahoo", volume=True, figsize=(15, 8), panel_ratios=(6, 1.8), datetime_format="%m-%d", xrotation=30, update_ticks=True, warn_too_much_data=2000, max_n_ticks=8, scale_padding=0.75, tight_layout=True, ylabel="Price", ylabel_lower="Volume", returnfig=True, squeeze=False, ) fig.suptitle("Demo Chart", fontsize=14) fig.savefig("demo_chart.png", dpi=150, bbox_inches="tight") plt.close(fig)这里我把squeeze=False固定住,后面用axes[0]、axes[1]访问主图和成交量图就不会出问题。panel_ratios=(6, 1.8)给了成交量更高的高度,ylabel_lower才有空间正常显示。
6.3 出图后的常见问题复盘
有一个很常见的现象:设置了datetime_format但标签仍然显示默认格式。检查一下是否同时用了returnfig=True且后续又调用了fig.autofmt_xdate()。这个方法会重新格式化日期刻度,覆盖你在绘图参数里设置的内容。如果有二次格式化需求,要么保留统一格式,要么在调用方法时传入同样的格式串。
另一个现象是成交量标签被截断。多半是panel_ratios给下方面板的高度权重太低,或者figsize高度不够。把权重从 1 调到 1.5 以上,情况会立刻好转。还有tight_layout=True时标签被推出去的问题,保存时加bbox_inches="tight"能兜底,但最好还是在参数阶段先把边距留够。
最后,如果你把绘图参数放进字典统一管理,后续调整会轻松很多:
plot_kwargs = { "type": "candle", "style": "yahoo", "volume": True, "figsize": (15, 8), "panel_ratios": (6, 1.8), "datetime_format": "%m-%d", "xrotation": 30, "update_ticks": True, "warn_too_much_data": 2000, "max_n_ticks": 8, "scale_padding": 0.75, "tight_layout": True, "ylabel": "Price", "ylabel_lower": "Volume", "returnfig": True, "squeeze": False, } fig, axes = mpf.plot(df, **plot_kwargs)把参数集中放一起,比每次调用时临场改几个关键字更直观。版本升级后如果某个参数被改名,你也能在字典里一眼定位到它,而不是去几十行代码里翻找。
6.4 一点个人体会
做完这么多参数组合实验之后,我最大的感触是:绘图的重点是“让人一眼看到关键信息”,不是把每个参数都用上。日期格式、面板比例和刻度数量是决定这张图是否专业的三大要素,风格和颜色反而是其次。
批量出图这个习惯帮我省过很多事。每换一个数据源,先跑一份最小样例,然后把plot_kwargs检查一遍,再进入批量流程。这样既避免了因为数据跨度不同导致日期标签错乱,也不会出现某个面板凭空消失的意外。希望这篇能帮你把 v0.12.6a3 的这几个关键参数真正用起来,少走几步弯路。