matplotlib mathtext 字体警告:字体 'default' 没有字形

matplotlib mathtext font warning: Font 'default' does not have a glyph

当尝试 运行 为 matplotlib.rcParams 设置非默认值的脚本(在下面的最小工作示例中给出)时,我收到 maptplotlib 警告:

$ python example.py
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.
Font 'default' does not have a glyph for '-' [U+2212], substituting with a dummy symbol.

这是在 Ubuntu 20.04 上安装的 Tex Live 2020,可以从 matplotlib 和 Python 3.8.6 从源代码中找到 pyenv

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
$ which latex
/usr/local/texlive/2020/bin/x86_64-linux/latex
$ $(pyenv which python) --version --version
Python 3.8.6 (default, Jan  5 2021, 00:14:15)
[GCC 9.3.0]

但是,当我尝试为最小失败示例构建以下 Docker 图像时,我无法复制错误。

最小Working/Failing示例

以下Dockerfile

FROM ubuntu:20.04

RUN apt-get update -y && \
    apt-get install -y \
        fontconfig \
        fonts-dejavu \
        fonts-freefont-ttf \
        python3 \
        python3-dev \
        python3-pip \
        python3-venv \
        vim && \
        apt-get -y autoclean && \
        apt-get -y autoremove && \
        rm -rf /var/lib/apt/lists/*

RUN python3 -m pip install --upgrade --no-cache-dir pip setuptools wheel && \
    python3 -m pip install --no-cache-dir "mplhep~=0.2.9" && \
    python3 -m pip list

WORKDIR /code

COPY example.py example.py

example.py

import numpy as np
import matplotlib.pyplot as plt
import mplhep


def make_plot(title=None):
    fig, ax = plt.subplots()
    x = np.linspace(0, 10, 101)
    y = np.square(x)
    ax.plot(x, y)
    ax.semilogy()

    ax.set_xlabel("$x$")
    ax.set_ylabel("$x^2$")
    if title is not None:
        ax.set_title(title)

    return fig, ax


def main():
    image_types = ["pdf", "png"]
    fig, ax = make_plot("Default matplotlib settings")

    for type in image_types:
        fig.savefig(f"default.{type}")

    mplhep.style.set_style("ATLAS")
    # above is equivalent to: plt.style.use(mplhep.style.ATLAS)
    fig, ax = make_plot("mplhep ATLAS style")
    for type in image_types:
        fig.savefig(f"ATLAS_style.{type}")


if __name__ == "__main__":
    main()

如果使用

构建
docker build . \
--pull \
-f Dockerfile \
-t matplotlib-font-question:debug-local

给予

$ docker run --rm -ti matplotlib-font-question:debug-local /bin/bash -c "pip list"
Package         Version
--------------- ---------
certifi         2020.12.5
chardet         4.0.0
cycler          0.10.0
idna            2.10
kiwisolver      1.3.1
matplotlib      3.3.3
mplhep          0.2.9
numpy           1.19.5
packaging       20.8
Pillow          8.1.0
pip             20.3.3
pyparsing       2.4.7
python-dateutil 2.8.1
requests        2.25.1
scipy           1.6.0
setuptools      51.1.1
six             1.15.0
urllib3         1.26.2
wheel           0.36.2

然后 运行 和

docker run --rm --user 1000:1000 -v $PWD:$PWD -w $PWD matplotlib-font-question:debug-local /bin/bash -c "python3 /code/example.py"

与本地不同,生成的结果数字不会出现警告或错误。

如果我检查 Docker 图像(没有 LaTeX)上安装的字体库,这会让人感到困惑

$ docker run --rm matplotlib-font-question:debug-local /bin/bash -c "apt list --installed | grep font"

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

fontconfig-config/now 2.13.1-2ubuntu3 all [installed,local]
fontconfig/now 2.13.1-2ubuntu3 amd64 [installed,local]
fonts-dejavu-core/now 2.37-1 all [installed,local]
fonts-dejavu-extra/now 2.37-1 all [installed,local]
fonts-dejavu/now 2.37-1 all [installed,local]
fonts-freefont-ttf/now 20120503-10 all [installed,local]
libfontconfig1/now 2.13.1-2ubuntu3 amd64 [installed,local]

所有找到的字体库也在我的本地机器上找到

$ apt list --installed | grep font | grep "fontconfig\|dejavu"

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

fontconfig-config/focal,focal,now 2.13.1-2ubuntu3 all [installed,automatic]
fontconfig/focal,now 2.13.1-2ubuntu3 amd64 [installed,automatic]
fonts-dejavu-core/focal,focal,now 2.37-1 all [installed,automatic]
fonts-dejavu-extra/focal,focal,now 2.37-1 all [installed]
fonts-dejavu/focal,focal,now 2.37-1 all [installed]
libfontconfig1-dev/focal,now 2.13.1-2ubuntu3 amd64 [installed,automatic]
libfontconfig1/focal,now 2.13.1-2ubuntu3 amd64 [installed]

所以我不清楚为什么当我安装了所有相同的字体以及更多字体时,以及当它们另外提供关于 matplotlib.rcParams:

的相同信息时,为什么我会在本地收到警告

Docker

$ docker run --rm -ti matplotlib-font-question:debug-local
root@2e6cff635604:/code# python3
Python 3.8.5 (default, Jul 28 2020, 12:59:40)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib
>>> import mplhep
>>> mplhep.style.set_style("ATLAS")
>>> for key, value in matplotlib.rcParams.items():
...     if "mathtext" in key:
...             print(key, value)
...
axes.formatter.use_mathtext False
mathtext.bf sans:bold
mathtext.cal cursive
mathtext.default rm
mathtext.fallback cm
mathtext.fallback_to_cm None
mathtext.fontset stixsans
mathtext.it sans:italic
mathtext.rm sans
mathtext.sf sans
mathtext.tt monospace
>>> for key, value in matplotlib.rcParams.items():
...     if "default" in key:
...             print(key, value)
...
mathtext.default rm

本地机器

$ rm ~/.cache/matplotlib/fontlist-v330.json # not a cache issue
$ python
Python 3.8.6 (default, Jan  5 2021, 00:14:15)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib
>>> import mplhep
>>> mplhep.style.set_style("ATLAS")
>>> for key, value in matplotlib.rcParams.items():
...     if "mathtext" in key:
...             print(key, value)
...
axes.formatter.use_mathtext False
mathtext.bf sans:bold
mathtext.cal cursive
mathtext.default rm
mathtext.fallback cm
mathtext.fallback_to_cm None
mathtext.fontset stixsans
mathtext.it sans:italic
mathtext.rm sans
mathtext.sf sans
mathtext.tt monospace
>>> for key, value in matplotlib.rcParams.items():
...     if "default" in key:
...             print(key, value)
...
mathtext.default rm

问题

为什么我的本地机器和 Docker 容器的结果不同? 一般来说,我将如何尝试调试它,因为这是我在调试字体问题时所知道的方法?

相关GitHub 问题

我在 Ubuntu 19.10 之前 运行 解决了这个问题(在下面链接的问题中有描述),但事情只是神奇地开始工作,我不知道我的方法是如何或为什么如果这里没有工作。

修复最终比 just the font list cache 更微妙。我在 matplotlib 缓存

中不仅有 fontlist-v330.json
$ ls -htra ~/.cache/matplotlib/
..  tex.cache  fontlist-v330.json  .

所以用

重建字体列表缓存
import matplotlib.font_manager
matplotlib.font_manager._rebuild()

rm ~/.cache/matplotlib/fontlist-v330.json

还不够。相反 the entire matplotlib cache needs to be updated,这最容易用

完成
rm ~/.cache/matplotlib/*

Why do the results differ between my local machine and the Docker container?

由于 Docker 图片没有以前的历史记录,所以它一开始就没有缓存,所以没有什么可以搞砸的。

How would I go about attempting to debug this in general, as this is about as far as I know how to get when debugging font issues?

我现在要确保在尝试执行任何其他操作之前完全清理并删除缓存。