Fix Chinese font rendering in Streamlit charts
This commit is contained in:
54
app.py
54
app.py
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user