You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Three lectures render Chinese plot labels as tofu — no matplotlib font configuration #205
Three lectures set Chinese text on matplotlib figures but carry no font configuration, so matplotlib falls back to DejaVu Sans, which has no CJK coverage. The labels render as tofu — blank rectangles — in a valid PNG, and nothing fails.
Lecture
Chinese plot text
How it broke
divergence_measures.md
7 sites, e.g. plt.ylabel('密度'), axes[0].set_xlabel('KL散度 KL(f, g)')
never had a block; labels hand-added 2025-09-12, after the blanket font pass
kesten_processes.md
4 sites, e.g. ax.set_ylabel("收益率"), ax.set_xlabel("日期")
regression — block deleted by resync da7b176 (#190), labels kept
jv.md
via titles = [r"$s$策略", r"$\phi$策略", "价值函数"]
block stripped by resync
Fix
Add the edition's standard block to each, above first plotting use:
FONTPATH="fonts/SourceHanSerifSC-SemiBold.otf"mpl.font_manager.fontManager.addfont(FONTPATH)
plt.rcParams['font.family'] = ['Source Han Serif SC']
Note fonts/, not _fonts/ — this edition keeps the asset at lectures/fonts/SourceHanSerifSC-SemiBold.otf and the other 103 configured lectures all use that path.
Context
Not yet visible to readers: this edition last published 2025-11-06 and the breakage is post-dated, so the live site still serves pre-resync content. That is timing, not safety — it ships on the next publish.
Root cause and the recommendation against reverting to usetex are in the program review: project-translation reports/2026-07-24-cjk-font-rendering-review.md. Engine side is action-translation#107 — the resync drops i18n adaptations. A further ~12 lectures here use matplotlib with English labels and no config, which becomes tofu the moment anyone localises a label.
CI cannot currently catch any of this: the missing-glyph warning is raised in the kernel subprocess, so -W never sees it.
A runtime scan of the published site adds two pages, one of which is already fixed in main.
bin/check-tofu in project-translation reads the missing-glyph warnings out of the published HTML, where myst-nb renders the kernel's UserWarning as stderr output. Against https://quantecon.github.io/lecture-python.zh-cn (87 pages — the deployment is behind main, which has 121):
already fixed in main — its block was added by resync aa9ccb7 on 2026-07-19, after publish-2025nov06, so this resolves on the next publish
ols
一与之亡人入关图均对平年征收数死殖民率的系者间阶险风():
not yet explained
ols.md has carried the font block since c4c4b86 (2025-03-18), well before publish-2025nov06, so the block was live at publish and the labels still lost their glyphs. I have not diagnosed why. Worth checking for a later rcParams reset in the same document, a figure drawn before the block's cell, or an execution failure that skipped it — matplotlib.md in the programming edition turned out to be the first of those (plt.style.use() resets font.family), so that is the first thing to rule out.
Method note
Source-level analysis found divergence_measures, kesten_processes and jv here; the runtime scan found divergence_measures, ols and stats_examples. The overlap is one. Static analysis catches source defects including unpublished ones; runtime catches what readers actually see, plus labels built dynamically. Keep both.
Activity
mmcky commentedon Jul 24, 2026
A runtime scan of the published site adds two pages, one of which is already fixed in
main.bin/check-tofuinproject-translationreads the missing-glyph warnings out of the published HTML, where myst-nb renders the kernel'sUserWarningas stderr output. Against https://quantecon.github.io/lecture-python.zh-cn (87 pages — the deployment is behindmain, which has 121):divergence_measuresstats_examplesmain— its block was added by resyncaa9ccb7on 2026-07-19, afterpublish-2025nov06, so this resolves on the next publisholsols.mdhas carried the font block sincec4c4b86(2025-03-18), well beforepublish-2025nov06, so the block was live at publish and the labels still lost their glyphs. I have not diagnosed why. Worth checking for a later rcParams reset in the same document, a figure drawn before the block's cell, or an execution failure that skipped it —matplotlib.mdin the programming edition turned out to be the first of those (plt.style.use()resetsfont.family), so that is the first thing to rule out.Method note
Source-level analysis found
divergence_measures,kesten_processesandjvhere; the runtime scan founddivergence_measures,olsandstats_examples. The overlap is one. Static analysis catches source defects including unpublished ones; runtime catches what readers actually see, plus labels built dynamically. Keep both.Fix tofu in Chinese figure labels, and give font.family a fallback (#206
Register the CJK font in util_rand_resp (#274)