flowchart LR
rscript[分析脚本 plot 对象] --> bookPlot[book-plot 主题与轴题]
bookPlot --> knitr[knitr ragg_png]
knitr --> pngCheck[check-fig-png 门禁]
knitr --> quartoDocx[quarto-docx Lua 滤镜]
quartoDocx --> wordOut[docx 成品]中文书稿 ggplot 出图规范
纵轴竖排、宋体主题、ragg 设备、图表单元顺序与源图交付
摘要
中文书稿用 knitr + ggplot2 出图,交给出版社时会反复踩到同一批问题:纵轴题侧躺或单位混在竖排串里;Windows 默认 png() 遇上宋体出全白图;Cursor 终端预览报字体或视口错误,被误当成几何图层写错;图注圈号的 $ 漏进成品;源图格式、文件名与书稿图号对不上。本包把 report-tech2026 已经跑通的做法收到 harness scripts/book-plot/。
核心结论:
- 纵轴题满足「自上而下、正向竖排、单位外置」三条。单图用
labs(y = stack_ylab(...))+theme_ylab_stack,分面用geom_text(size.unit = "pt"),翻转图底轴横排,热力图y = NULL。 - knitr 全局
dev = "ragg_png",不开showtext_auto()。渲完用check-fig-png.py扫 figure 目录,近白 PNG 视为失败。 - 交互
print(ggplot)报错先用ggsave(..., device = ragg::agg_png)隔离;能出图就不要改分析脚本。 - Word 图题、表题与图号收紧不在本包,见 Quarto 中文书稿 docx 滤镜。
1. 两套资产的分工
| 问题 | 资产 |
|---|---|
| 纵轴题竖排、单位顶置、宋体 11pt | scripts/book-plot/R/ylab-stack.R |
| 无网格、内向刻度、图例靠下的出版主题 | scripts/book-plot/R/theme-tech.R |
| Windows 空白图 / 中文丢失 | scripts/book-plot/R/knitr-ragg.R + py/check-fig-png.py |
Cursor httpgd 首帧 depth(NULL) |
scripts/book-plot/R/httpgd-warmup.R |
| 「图2- 13」、题注在表内、列宽 | scripts/quarto-docx/(另一套) |
2. 前提
- R ≥ 4.1,ggplot2 ≥ 3.5(
geom_text的size.unit),ragg;字体栈 systemfonts ≥ 1.3 并与 textshaping / ragg 配套(见 httpgd 笔记)。 - 系统已装宋体,族名
simsun(Windows 自带)。macOS / Linux 需自行安装或在source()之后改写ylab_text_family与theme_tech的 family。 check-fig-png.py需 Python 3.8+ 与 Pillow。
3. 复用步骤
3.1 安装
.\scripts\powershell\Install-Harness.ps1 -InstallProfile book-plot -ProjectRoot "D:\path\to\your-repo"文件落在业务仓 scripts/book-plot/。安装不改 _quarto.yml、章 YAML 与 .Rprofile。
3.2 章 setup
source(here::here("scripts/book-plot/R/knitr-ragg.R"))
source(here::here("scripts/book-plot/R/theme-tech.R"))
source(here::here("scripts/book-plot/R/ylab-stack.R"))分析脚本若可能被单独 source,在脚本顶部写 if (!exists("stack_ylab")) source(...),与章 setup 共用同一份文件。
3.3 .Rprofile(可选,仅 Cursor / vscode-R 开 httpgd)
if (interactive() && file.exists("scripts/book-plot/R/httpgd-warmup.R")) {
source("scripts/book-plot/R/httpgd-warmup.R")
}放在 renv/activate.R 之后。
4. 纵轴题
规范与四种布局写在 纵轴题笔记。要点:
- 末尾括号视为单位,
split_ylab_unit()拆出,放在纵轴正上方。 stack_ylab()先保护R&D、RD、AI等缩写,再按字竖排。项目缩写追加到ylab_keep。- 叠加顺序
+ theme_tech + theme_ylab_stack,反过来会被-90盖掉。 - 主题在分析脚本里加完,qmd 只
p <- plot_*。
5. 图表单元与源图
5.1 单元顺序
每张图在章 qmd 里按下列顺序,图号才会与导出文件名一致:
source()该图的分析脚本(若有)。num_fig <- num_fig + 1(表用num_tbl)。fig_cap:中文图题 +<br>+Figure 2-{num_fig}(章号随章)。- 绘图 chunk:
#| label: fig-...,#| fig-cap: !expr fig_cap,对象赋给p。 - 图注与资料来源。
- 源图导出 chunk(
eval: save_xlsx),文件名取当前 chunk label。
num_fig 必须在同一个 knitr 会话里累加,所以不要把一章拆成可独立 render 的子 qmd。正文引用写 见 @fig-...(@ 两侧留空格),图号收紧交给 quarto-docx 的 crossref-tight-num.lua。
5.2 源图交付
- 出版社主格式是 xlsx(可编辑矢量,report-tech2026 用
techme::gg2xlsx;其他项目可换成rvg+officer的等价导出)。png 可选,不要再导 svg:Windows 上 basesvg()常无法启动。 - 文件名:
Figure{章}-{num_fig}-{chunk label}.xlsx,例如Figure2-1-fig-bar-budget-province.xlsx。names_chunk <- knitr::opts_current$get()$label,必须与#| label:一致。 - 章 YAML 用参数开关(如
save_xlsx: TRUE)只在交稿时打开,交稿后改回,避免日常误写盘。 - 交稿核对:导出目录文件序号与书稿「图2-N」一致;
num_fig等于fig-label 个数。
6. 图注圈号与行内 $
图注圈号写成 $\U2460$ 时,Pandoc 把一对 $...$ 当行内公式。收尾 $ 后面不能紧跟阿拉伯数字,否则圈号不成对,美元符漏进 html/docx(成品出现 $④$2025年)。
宜写($ 后空格或汉字):
"$\U2460$ 2018年及以后未统计……"
"$\U2463$在2025年主要为申报……"
不宜写:
"$\U2460$2025年为第一批……"
glue() 里 {year} 紧接收尾 $ 时,展开后同样是数字。真公式(如 $\\times$)也不要紧贴阿拉伯数字。
7. 验收
| 层级 | 命令 | 平台 |
|---|---|---|
| L0 切词 | Rscript scripts/book-plot/test/Rscript/test-ylab-stack.R |
任意 |
| L1 出图 | Rscript scripts/book-plot/test/Rscript/run-l1-ragg.R |
Windows(需宋体) |
| 业务仓渲完 | python scripts/book-plot/py/check-fig-png.py <figure-dir> ... |
任意 |
L1 在独立 R 进程里画单图与分面各一张,经 ragg::agg_png 输出到 test/output/,再跑近白检查。轴题位置与单位顶置仍需目视。
theme_tech 置空了 plot.background。手工 ggsave() 不写 bg = "white" 会得到透明底;check-fig-png.py 把透明像素占比达到 5% 的 PNG 判为失败(Pillow 把透明底合成黑色,不能只靠「是不是近白」)。单独出图写 ggsave(..., device = ragg::agg_png, bg = "white")。knitr 的 ragg_png 本身是白底。沙盒规程见 test/README.md,通用流程见 配置资产验证工作流。
8. 不要做
showtext_auto()与ragg_png叠用。- 用
suppressWarnings()或空filter画出空白 ggplot 交差;缺数据应stop()/warning()。 - 为交互预览报错改
geom_*。 - 为无量纲图编造单位;翻转图左侧再竖排数值题。
- 一次改完全部旧脚本;迁移时一脚本一提交,每个脚本单独
ggsave(ragg)目视。