Skip to content

Commit 17d7cee

Browse files
Add Chinese fonts guide: cross-platform setup, SimSun analysis, Render deployment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9a3e98f commit 17d7cee

1 file changed

Lines changed: 377 additions & 0 deletions

File tree

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
# Chinese Font Guide for StatsPAI (中文字体指南)
2+
3+
## Quick Start
4+
5+
```python
6+
import statspai as sp
7+
sp.use_chinese() # One-line fix, auto-detects the best Chinese font on your system
8+
```
9+
10+
---
11+
12+
## 1. Cross-Platform Chinese Font Family
13+
14+
All platforms have "宋体" (Song/Serif CJK), but they are designed by different companies:
15+
16+
```
17+
宋体风格 (Serif CJK)
18+
├── Apple: Songti SC / TC macOS 预装
19+
├── Microsoft: SimSun / NSimSun Windows 预装
20+
├── Google: Noto Serif CJK SC 开源,全平台可安装
21+
├── Adobe: Source Han Serif 与 Noto 同源
22+
└── SinoType: STSong (华文宋体) macOS 预装,商业授权
23+
```
24+
25+
### Platform Availability
26+
27+
| Font | macOS | Windows | Linux | License |
28+
|------|:-----:|:-------:|:-----:|---------|
29+
| **Songti SC** (宋体-简) | Pre-installed | - | - | Apple proprietary |
30+
| **SimSun** (宋体) | - | Pre-installed | Manual install | Microsoft proprietary |
31+
| **NSimSun** (新宋体) | - | Pre-installed | Manual install | Microsoft proprietary |
32+
| **Noto Serif CJK SC** (思源宋体) | Installable | Installable | `apt install` | **Open source (OFL)** |
33+
| **STSong** (华文宋体) | Pre-installed | With Office | - | SinoType proprietary |
34+
| **AR PL UMing** | - | - | `apt install` | Open source (Arphic) |
35+
36+
### Visual Similarity to SimSun (微软宋体)
37+
38+
| Font | Similarity | Notes |
39+
|------|:----------:|-------|
40+
| **NSimSun** | ~99% | Monospace variant of SimSun, same designer |
41+
| **STSong** | ~85% | Slightly thicker strokes, more rounded |
42+
| **AR PL UMing** | ~75% | Open source imitation, rougher details |
43+
| **Noto Serif CJK SC** | ~65% | Modern redesign, more elegant, better typography |
44+
| **Songti SC** | ~60% | Apple design, thicker strokes |
45+
46+
### Key Differences: Songti SC vs SimSun vs Noto Serif CJK
47+
48+
| Feature | Songti SC (Apple) | SimSun (Microsoft) | Noto Serif CJK (Google) |
49+
|---------|:-----------------:|:------------------:|:-----------------------:|
50+
| Designer | Apple | Zhongyi (中易) | Adobe (西塚涼子) |
51+
| Design era | 2000s | 1990s | 2017 |
52+
| Strokes | Thicker, rounded | Thin, sharp | Balanced, modern |
53+
| Character count | ~30,000 | ~28,000 | ~65,000+ |
54+
| Font weights | 1 | 1 | **7** (ExtraLight to Black) |
55+
| Screen optimization | Retina displays | Low-res bitmap hints | High-res screens |
56+
| Best for | macOS screen | Windows/print legacy | Cross-platform, modern |
57+
58+
---
59+
60+
## 2. StatsPAI Chinese Font Usage
61+
62+
### Auto Mode (Recommended)
63+
64+
```python
65+
import statspai as sp
66+
67+
sp.use_chinese() # Auto-detect best available font
68+
sp.use_chinese('serif') # Prefer 宋体 (Songti SC / SimSun / Noto Serif CJK)
69+
sp.use_chinese('sans') # Prefer 黑体 (PingFang / SimHei / Noto Sans CJK)
70+
sp.use_chinese('SimSun') # Use a specific font
71+
```
72+
73+
### Font Presets for Academic Publishing
74+
75+
```python
76+
from statspai.plots.interactive import FigureEditor
77+
78+
editor = FigureEditor(fig=fig)
79+
80+
# Chinese thesis standard (中文学位论文)
81+
# Auto-detects: Songti SC (Mac) / SimSun (Win) / Noto Serif CJK (Linux)
82+
editor.apply_font_preset('Chinese Thesis (中文学位论文)')
83+
84+
# Chinese journal (中文期刊)
85+
editor.apply_font_preset('Chinese Journal (中文期刊)')
86+
87+
# Chinese slides (中文PPT) — uses sans-serif (黑体/苹方)
88+
editor.apply_font_preset('Chinese Slide (中文PPT)')
89+
```
90+
91+
### What StatsPAI Does Automatically
92+
93+
When you select a Chinese font, StatsPAI:
94+
1. Sets `font.family` to the correct family (serif/sans-serif)
95+
2. Puts the Chinese font first in the preference list
96+
3. Sets `axes.unicode_minus = False` (fixes the minus sign "−" display issue)
97+
4. Generates reproducible code that includes all these settings
98+
99+
---
100+
101+
## 3. Installing Chinese Fonts
102+
103+
### macOS
104+
105+
Chinese fonts are **pre-installed**. No action needed:
106+
- Songti SC (宋体), PingFang SC (苹方), Heiti TC (黑体), Kaiti SC (楷体), etc.
107+
108+
Just call `sp.use_chinese()`.
109+
110+
### Windows
111+
112+
SimSun (宋体) and SimHei (黑体) are **pre-installed**. No action needed.
113+
114+
Just call `sp.use_chinese()`.
115+
116+
### Linux (Ubuntu / Debian)
117+
118+
```bash
119+
# Option 1: Open source Noto CJK fonts (RECOMMENDED)
120+
sudo apt install fonts-noto-cjk fonts-noto-cjk-extra
121+
122+
# Option 2: WenQuanYi (文泉驿)
123+
sudo apt install fonts-wqy-microhei fonts-wqy-zenhei
124+
125+
# Option 3: Arphic (文鼎)
126+
sudo apt install fonts-arphic-uming fonts-arphic-ukai
127+
128+
# After installing, refresh font cache
129+
fc-cache -fv
130+
131+
# Clear matplotlib cache (IMPORTANT!)
132+
python3 -c "
133+
import matplotlib, shutil, os
134+
c = matplotlib.get_cachedir()
135+
if os.path.exists(c): shutil.rmtree(c)
136+
print(f'Cleared: {c}')
137+
"
138+
```
139+
140+
### Linux (Fedora / RHEL)
141+
142+
```bash
143+
sudo dnf install google-noto-serif-cjk-sc-fonts google-noto-sans-cjk-sc-fonts
144+
fc-cache -fv
145+
```
146+
147+
### Linux (Arch)
148+
149+
```bash
150+
sudo pacman -S noto-fonts-cjk
151+
fc-cache -fv
152+
```
153+
154+
---
155+
156+
## 4. Installing SimSun (微软宋体) on Linux
157+
158+
If your journal **strictly requires SimSun**, you need to install it manually.
159+
160+
### Method 1: Copy from Windows
161+
162+
```bash
163+
# 1. From a Windows machine, copy: C:\Windows\Fonts\simsun.ttc (17MB)
164+
# 2. Transfer to Linux server
165+
166+
# 3. Install to user fonts directory (no sudo needed)
167+
mkdir -p ~/.local/share/fonts/
168+
cp simsun.ttc ~/.local/share/fonts/
169+
170+
# 4. Refresh caches
171+
fc-cache -fv
172+
173+
# 5. Clear matplotlib cache
174+
python3 -c "
175+
import matplotlib, shutil, os
176+
c = matplotlib.get_cachedir()
177+
if os.path.exists(c): shutil.rmtree(c)
178+
print(f'Cleared: {c}')
179+
"
180+
181+
# 6. Verify
182+
fc-list | grep -i simsun
183+
# Expected output: /home/user/.local/share/fonts/simsun.ttc: SimSun,宋体:style=Regular
184+
```
185+
186+
### Method 2: Extract via Wine (no Windows machine needed)
187+
188+
```bash
189+
sudo apt install winetricks
190+
winetricks cjkfonts
191+
192+
# Copy the extracted font
193+
cp ~/.wine/drive_c/windows/Fonts/simsun.ttc ~/.local/share/fonts/
194+
fc-cache -fv
195+
```
196+
197+
### Method 3: Download from online sources
198+
199+
Some open font archives host SimSun. Search for "simsun.ttc download" — but verify the license terms for your use case.
200+
201+
---
202+
203+
## 5. Deploying on Render.com (Linux Server)
204+
205+
Render servers have no `sudo` access. Three approaches:
206+
207+
### Approach A: Bundle font file in your repo (SimSun)
208+
209+
Project structure:
210+
```
211+
your-project/
212+
├── fonts/
213+
│ └── simsun.ttc # Copy from Windows
214+
├── render_build.sh
215+
├── requirements.txt
216+
└── app.py
217+
```
218+
219+
`render_build.sh`:
220+
```bash
221+
#!/bin/bash
222+
set -e
223+
224+
pip install -r requirements.txt
225+
226+
# Install fonts to user directory (no sudo needed)
227+
mkdir -p ~/.local/share/fonts/
228+
cp fonts/*.ttc ~/.local/share/fonts/ 2>/dev/null || true
229+
cp fonts/*.ttf ~/.local/share/fonts/ 2>/dev/null || true
230+
fc-cache -fv 2>/dev/null || true
231+
232+
# Clear matplotlib font cache (CRITICAL — matplotlib won't find new fonts without this)
233+
python -c "
234+
import matplotlib, shutil, os
235+
c = matplotlib.get_cachedir()
236+
if os.path.exists(c):
237+
shutil.rmtree(c)
238+
print(f'Cleared matplotlib cache: {c}')
239+
"
240+
```
241+
242+
Render Dashboard → Settings → **Build Command**: `bash render_build.sh`
243+
244+
### Approach B: Download Noto CJK at build time (no font file in repo)
245+
246+
`render_build.sh`:
247+
```bash
248+
#!/bin/bash
249+
set -e
250+
251+
pip install -r requirements.txt
252+
253+
# Download open-source Noto Serif CJK (思源宋体)
254+
mkdir -p ~/.local/share/fonts/
255+
FONT_URL="https://github.com/notofonts/noto-cjk/releases/download/Serif2.003/08_NotoSerifCJKsc.zip"
256+
curl -sL "$FONT_URL" -o /tmp/noto-serif.zip
257+
unzip -o /tmp/noto-serif.zip -d /tmp/noto-serif/
258+
cp /tmp/noto-serif/*.otf ~/.local/share/fonts/ 2>/dev/null || true
259+
260+
# Also download Noto Sans CJK (思源黑体) for sans-serif
261+
SANS_URL="https://github.com/notofonts/noto-cjk/releases/download/Sans2.004/09_NotoSansCJKsc.zip"
262+
curl -sL "$SANS_URL" -o /tmp/noto-sans.zip
263+
unzip -o /tmp/noto-sans.zip -d /tmp/noto-sans/
264+
cp /tmp/noto-sans/*.otf ~/.local/share/fonts/ 2>/dev/null || true
265+
266+
fc-cache -fv 2>/dev/null || true
267+
268+
# Clear matplotlib cache
269+
python -c "
270+
import matplotlib, shutil, os
271+
c = matplotlib.get_cachedir()
272+
if os.path.exists(c):
273+
shutil.rmtree(c)
274+
print(f'Cleared matplotlib cache: {c}')
275+
"
276+
277+
echo "Chinese fonts installed successfully"
278+
```
279+
280+
### Approach C: Dockerfile (if using Docker on Render)
281+
282+
```dockerfile
283+
FROM python:3.11-slim
284+
285+
# Install font utilities + open-source Chinese fonts
286+
RUN apt-get update && \
287+
apt-get install -y fontconfig fonts-noto-cjk && \
288+
rm -rf /var/lib/apt/lists/* && \
289+
fc-cache -fv
290+
291+
# Or use bundled SimSun:
292+
# COPY fonts/simsun.ttc /usr/share/fonts/truetype/
293+
# RUN fc-cache -fv
294+
295+
COPY requirements.txt .
296+
RUN pip install --no-cache-dir -r requirements.txt
297+
298+
# Clear matplotlib cache
299+
RUN python -c "import matplotlib, shutil, os; c=matplotlib.get_cachedir(); shutil.rmtree(c, True)"
300+
301+
COPY . /app
302+
WORKDIR /app
303+
CMD ["python", "app.py"]
304+
```
305+
306+
### After deployment, in your app code:
307+
308+
```python
309+
import statspai as sp
310+
311+
# Auto-detect the installed Chinese font
312+
font = sp.use_chinese()
313+
print(f"Using Chinese font: {font}")
314+
315+
# Now all plots will render Chinese correctly
316+
fig, ax = plt.subplots()
317+
ax.set_title('因果推断效果分析')
318+
ax.set_xlabel('相对处理时间(年)')
319+
ax.set_ylabel('平均处理效应')
320+
```
321+
322+
---
323+
324+
## 6. Troubleshooting
325+
326+
### Problem: Chinese text shows as boxes (□□□□)
327+
328+
```python
329+
# Step 1: Check what fonts are available
330+
import matplotlib.font_manager as fm
331+
cn_fonts = [f.name for f in fm.fontManager.ttflist
332+
if any(kw in f.name for kw in ['Song', 'Hei', 'PingFang', 'Noto', 'Hiragino', 'SimSun'])]
333+
print(f"Chinese fonts found: {cn_fonts}")
334+
335+
# Step 2: If empty, install fonts (see Section 3)
336+
337+
# Step 3: If fonts are installed but still not working, clear cache
338+
import matplotlib, shutil, os
339+
cache = matplotlib.get_cachedir()
340+
shutil.rmtree(cache, ignore_errors=True)
341+
print(f"Cleared cache: {cache}")
342+
# Then restart Python/Jupyter kernel
343+
```
344+
345+
### Problem: Minus sign shows as "−" (square) with Chinese fonts
346+
347+
```python
348+
import matplotlib
349+
matplotlib.rcParams['axes.unicode_minus'] = False # Use hyphen-minus instead
350+
# sp.use_chinese() does this automatically
351+
```
352+
353+
### Problem: Font installed but matplotlib doesn't find it
354+
355+
```bash
356+
# Rebuild matplotlib font cache
357+
python3 -c "
358+
import matplotlib.font_manager as fm
359+
fm._load_fontmanager(try_read_cache=False)
360+
print('Font manager rebuilt')
361+
print(f'Total fonts: {len(fm.fontManager.ttflist)}')
362+
"
363+
```
364+
365+
---
366+
367+
## 7. Recommendation Summary
368+
369+
| Scenario | Recommended Font | Why |
370+
|----------|-----------------|-----|
371+
| Personal use on Mac | `sp.use_chinese()` (auto) | Songti SC pre-installed |
372+
| Personal use on Windows | `sp.use_chinese()` (auto) | SimSun pre-installed |
373+
| Linux desktop | `Noto Serif CJK SC` | Best open-source quality |
374+
| Cloud/server deployment | `Noto Serif CJK SC` | Open source, no license issues |
375+
| Journal requires "宋体" | Install `SimSun` | Copy from Windows |
376+
| Cross-platform reproducible | `Noto Serif CJK SC` | Same font everywhere |
377+
| Presentations/slides | `sp.use_chinese('sans')` | 黑体/苹方 more readable |

0 commit comments

Comments
 (0)