Fix Chinese font rendering in Streamlit charts

This commit is contained in:
admin
2026-06-03 09:49:45 +08:00
parent 37faa967e1
commit a1e1d71f66

54
app.py
View File

@@ -10,7 +10,9 @@ import json
from pathlib import Path
from typing import Dict, List, Sequence, Tuple
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import font_manager
import numpy as np
import streamlit as st
@@ -73,6 +75,46 @@ CUSTOM_CSS = """
"""
def configure_matplotlib_cjk_font() -> None:
"""配置 Matplotlib 中文字体。
Streamlit 自身用浏览器字体渲染中文通常没有问题Matplotlib 图像会走
后端字体管理,如果默认 DejaVu Sans 不含中文字形,就会显示成方块。
"""
candidate_paths = [
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc",
"/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",
]
candidate_names = [
"Noto Sans CJK SC",
"Noto Sans CJK JP",
"Droid Sans Fallback",
"WenQuanYi Micro Hei",
"Source Han Sans SC",
"SimHei",
]
discovered_names: List[str] = []
for path_str in candidate_paths:
path = Path(path_str)
if not path.exists():
continue
try:
font_manager.fontManager.addfont(str(path))
discovered_names.append(font_manager.FontProperties(fname=str(path)).get_name())
except Exception:
continue
mpl.rcParams["font.family"] = "sans-serif"
mpl.rcParams["font.sans-serif"] = [*discovered_names, *candidate_names, "DejaVu Sans"]
mpl.rcParams["axes.unicode_minus"] = False
configure_matplotlib_cjk_font()
def _require_nibabel():
try:
import nibabel as nib # type: ignore
@@ -199,7 +241,7 @@ def render_image(image: np.ndarray, caption: str, cmap: str = "gray") -> None:
ax.imshow(orient_for_display(image), cmap=cmap, interpolation="nearest")
ax.set_title(caption, fontsize=10)
ax.axis("off")
st.pyplot(fig, use_container_width=True)
st.pyplot(fig, width="stretch")
plt.close(fig)
@@ -208,7 +250,7 @@ def render_rgb(image: np.ndarray, caption: str) -> None:
ax.imshow(orient_for_display(image), interpolation="nearest")
ax.set_title(caption, fontsize=10)
ax.axis("off")
st.pyplot(fig, use_container_width=True)
st.pyplot(fig, width="stretch")
plt.close(fig)
@@ -220,7 +262,7 @@ def render_heatmap_overlay(base_slice: np.ndarray, mag_slice: np.ndarray, alpha:
ax.set_title(caption, fontsize=10)
ax.axis("off")
fig.colorbar(im, ax=ax, fraction=0.046, pad=0.02)
st.pyplot(fig, use_container_width=True)
st.pyplot(fig, width="stretch")
plt.close(fig)
@@ -321,7 +363,7 @@ def render_metric_charts(fixed_xyz: np.ndarray, moving_xyz: np.ndarray, warped_x
axes[1].set_xlabel("Slice")
axes[1].grid(alpha=0.22)
axes[1].legend(frameon=False)
st.pyplot(fig, use_container_width=True)
st.pyplot(fig, width="stretch")
plt.close(fig)
if ddf_xyz is not None:
@@ -332,7 +374,7 @@ def render_metric_charts(fixed_xyz: np.ndarray, moving_xyz: np.ndarray, warped_x
ax.set_xlabel("mm")
ax.set_ylabel("Voxel count")
ax.grid(axis="y", alpha=0.2)
st.pyplot(fig2, use_container_width=True)
st.pyplot(fig2, width="stretch")
plt.close(fig2)
@@ -370,7 +412,7 @@ def main() -> None:
out_dir = st.text_input("输出目录", value=str(INFERENCE_DIR))
display_max_voxels = st.slider("Web显示体素上限", 2_000_000, 30_000_000, 14_000_000, 1_000_000)
start = st.button("开始推理", type="primary", use_container_width=True)
start = st.button("开始推理", type="primary", width="stretch")
if start:
with st.spinner("推理运行中"):
try: