戰(zhàn)指南)
1. 項(xiàng)目概述為什么matplotlib中文顯示是個(gè)“老大難”問題如果你用Python的matplotlib畫過圖并且嘗試過在圖表里添加中文標(biāo)簽、標(biāo)題那你大概率踩過這個(gè)坑圖表上本該顯示中文的地方變成了一堆方框“□□□”或者亂碼。這幾乎是每個(gè)數(shù)據(jù)可視化開發(fā)者入門時(shí)必經(jīng)的“洗禮”。我剛開始用matplotlib做項(xiàng)目匯報(bào)時(shí)就被這個(gè)問題折騰得不輕生成的圖表里公司名稱、產(chǎn)品分類全是小方塊拿給領(lǐng)導(dǎo)看簡直尷尬到腳趾摳地。這個(gè)問題之所以經(jīng)典且棘手根源在于matplotlib的默認(rèn)字體配置。matplotlib在渲染文本時(shí)默認(rèn)會(huì)使用一套名為“DejaVu Sans”的英文字體。這套字體很優(yōu)秀線條清晰數(shù)學(xué)符號支持完備但它有一個(gè)致命缺陷不包含中文字形。當(dāng)matplotlib遇到中文字符時(shí)它在這個(gè)字體庫里找不到對應(yīng)的圖形就只能用缺失字符的占位符通常是方框來顯示。這和你用Word打開一個(gè)文檔但電腦里沒裝相應(yīng)字體時(shí)看到的情況是一個(gè)道理。更深一層看這其實(shí)是一個(gè)“環(huán)境適配”問題。你的代碼可能在你的Windows電腦上跑得好好的但一旦部署到Linux服務(wù)器上或者分享給用Mac的同事中文顯示就可能再次崩潰。因?yàn)椴煌僮飨到y(tǒng)預(yù)裝的字體、字體文件的路徑都截然不同。所以解決matplotlib中文顯示從來不是找到一種“唯一正確”的方法而是要掌握一套在不同場景下都能“因地制宜”的解決方案。這也是為什么網(wǎng)上會(huì)有那么多不同的教程有的讓你改配置文件有的讓你動(dòng)態(tài)加載字體讓人眼花繚亂。接下來我會(huì)結(jié)合我過去在Windows、Linux服務(wù)器以及為團(tuán)隊(duì)配置統(tǒng)一開發(fā)環(huán)境時(shí)遇到的各種情況為你徹底拆解四種最核心、最實(shí)用的解決方法。從“圖省事”的臨時(shí)方案到“一勞永逸”的全局配置再到應(yīng)對復(fù)雜生產(chǎn)環(huán)境的策略我們一個(gè)個(gè)來盤清楚。無論你是剛?cè)腴T的新手還是需要部署到生產(chǎn)環(huán)境的老手這篇文章都能給你一個(gè)清晰的路線圖。2. 核心思路拆解四種方法的定位與選型邏輯面對中文顯示問題很多教程一上來就扔給你一段代碼但很少告訴你為什么用這種以及什么時(shí)候該用另一種。這導(dǎo)致很多人雖然暫時(shí)解決了問題但換了個(gè)環(huán)境或項(xiàng)目又懵了。我把解決方案歸納為四種每一種都有其明確的適用場景和優(yōu)缺點(diǎn)。理解它們的定位你才能做出最合適的選擇。2.1 方法一rcParams動(dòng)態(tài)設(shè)置臨時(shí)救急這是最快速、最直接的“快餐式”解決方案。它的核心思想是在當(dāng)前的Python腳本或Jupyter Notebook單元格中通過修改matplotlib的運(yùn)行時(shí)配置參數(shù)rcParams臨時(shí)指定一個(gè)包含中文字體的字體來用。這個(gè)方法最大的特點(diǎn)是作用域僅限于當(dāng)前運(yùn)行的代碼上下文。你在這里改了畫出來的圖有中文你新開一個(gè)腳本或者重啟了內(nèi)核設(shè)置就失效了一切恢復(fù)原樣。適用場景快速驗(yàn)證、一次性腳本、在Jupyter Notebook里做交互式數(shù)據(jù)分析時(shí)想馬上看到中文效果。當(dāng)你只是想“試試看”的時(shí)候這是最省事的。優(yōu)點(diǎn)無需安裝任何額外字體無需修改系統(tǒng)或matplotlib的配置文件代碼即配即用不影響其他項(xiàng)目或環(huán)境。缺點(diǎn)配置無法持久化每次運(yùn)行都需要執(zhí)行這段設(shè)置代碼。如果字體文件路徑指定不對尤其在跨平臺(tái)時(shí)還是會(huì)失敗。2.2 方法二修改matplotlib配置文件一勞永逸如果說方法一是“租房子”那方法二就是“買房子”。它通過直接修改matplotlib的全局配置文件matplotlibrc來改變其默認(rèn)的字體行為。這個(gè)文件是matplotlib在安裝時(shí)就生成好的里面定義了所有默認(rèn)的繪圖參數(shù)包括字體。修改它意味著對所有使用該matplotlib環(huán)境比如某個(gè)特定的Python虛擬環(huán)境的腳本生效。適用場景個(gè)人開發(fā)機(jī)器上你希望所有matplotlib繪圖都默認(rèn)支持中文不想在每個(gè)腳本里重復(fù)寫配置代碼。適合固定工作環(huán)境下的長期使用。優(yōu)點(diǎn)一次配置終身受益在該環(huán)境下。徹底擺脫中文顯示問題代碼干凈無需冗余配置語句。缺點(diǎn)需要你找到并編輯一個(gè)文本配置文件對新手稍有門檻。并且如果你有多個(gè)Python環(huán)境比如conda env1, env2你需要分別配置每個(gè)環(huán)境下的matplotlib。字體文件仍需存在于系統(tǒng)可識(shí)別的路徑中。2.3 方法三程序內(nèi)指定字體路徑并注冊靈活精準(zhǔn)這是一個(gè)更“工程化”的思路。它不依賴系統(tǒng)字體路徑也不修改全局配置而是讓你的Python程序“自帶字體”。具體做法是將特定的中文字體文件如.ttf或.otf放在你的項(xiàng)目目錄里然后在代碼中通過matplotlib.font_manager模塊將這個(gè)字體文件的絕對路徑動(dòng)態(tài)地加載并注冊到當(dāng)前會(huì)話的字體管理器中。適用場景項(xiàng)目需要跨平臺(tái)、跨環(huán)境部署時(shí)例如你的代碼要在Windows開發(fā)機(jī)、Linux測試機(jī)和Mac同事電腦上都能正確運(yùn)行。或者你的項(xiàng)目對字體有特定要求如使用“思源黑體”、“阿里巴巴普惠體”等品牌字體必須確保渲染一致性。優(yōu)點(diǎn)可移植性極強(qiáng)。字體隨著項(xiàng)目代碼一起走環(huán)境隔離性好能確保在任何地方渲染效果一致。是專業(yè)項(xiàng)目、團(tuán)隊(duì)協(xié)作的首選方案。缺點(diǎn)步驟稍多需要管理字體文件。如果字體文件很大可能會(huì)略微增加項(xiàng)目體積。2.4 方法四使用系統(tǒng)字體別名取巧兼容這是一個(gè)相對“取巧”但非常實(shí)用的方法尤其適合Windows用戶。matplotlib的字體管理器在尋找字體時(shí)不僅看文件名還會(huì)看字體的“家族名”family name。一些常見的中文字體在系統(tǒng)里注冊的家族名可能是英文的。例如Windows自帶的“微軟雅黑”其字體家族名是‘Microsoft YaHei’。通過rcParams直接設(shè)置這個(gè)家族名matplotlib就能在系統(tǒng)字體庫中找到它。適用場景Windows系統(tǒng)用戶且使用系統(tǒng)自帶的常見中文字體如微軟雅黑、宋體、黑體。想用方法一的簡便但又希望指定一個(gè)更通用的字體名。優(yōu)點(diǎn)配置簡單無需關(guān)心字體文件的具體路徑。只要系統(tǒng)里有這個(gè)字體就行。缺點(diǎn)嚴(yán)重依賴操作系統(tǒng)和已安裝的字體。在Linux或macOS上很可能沒有“Microsoft YaHei”這個(gè)字體導(dǎo)致回退到默認(rèn)字體而失敗。因此這個(gè)方法在跨平臺(tái)場景下基本不可用。為了讓你更直觀地對比我整理了這四種方法的核心差異方法核心操作作用范圍持久性跨平臺(tái)友好性推薦使用場景1. rcParams動(dòng)態(tài)設(shè)置代碼中設(shè)置plt.rcParams[‘font.sans-serif’]當(dāng)前運(yùn)行環(huán)境臨時(shí)會(huì)話級低依賴路徑快速測試、一次性腳本2. 修改配置文件編輯matplotlibrc文件整個(gè)matplotlib環(huán)境永久環(huán)境級中需各環(huán)境配置個(gè)人固定開發(fā)環(huán)境3. 指定字體路徑注冊使用font_manager.FontProperties或addfont當(dāng)前程序臨時(shí)程序級高字體隨項(xiàng)目走團(tuán)隊(duì)協(xié)作、項(xiàng)目部署4. 使用系統(tǒng)字體別名設(shè)置rcParams為字體家族名當(dāng)前運(yùn)行環(huán)境臨時(shí)會(huì)話級極低僅限特定系統(tǒng)Windows單機(jī)環(huán)境注意方法三指定字體路徑是生產(chǎn)環(huán)境最佳實(shí)踐的基石。它保證了你的可視化輸出不因運(yùn)行環(huán)境的差異而改變是交付穩(wěn)定可靠項(xiàng)目的關(guān)鍵。3. 四種方法的詳細(xì)實(shí)操指南理論說清楚了我們直接上代碼看看每一種方法具體怎么操作以及操作時(shí)會(huì)遇到哪些“坑”。3.1 方法一rcParams動(dòng)態(tài)設(shè)置——即用即走這是最基礎(chǔ)的代碼示例。假設(shè)我們想在折線圖上標(biāo)注幾個(gè)中文城市名。import matplotlib.pyplot as plt import numpy as np # 關(guān)鍵步驟在繪圖前設(shè)置rcParams plt.rcParams[font.sans-serif] [SimHei] # 用來正常顯示中文標(biāo)簽 plt.rcParams[axes.unicode_minus] False # 用來正常顯示負(fù)號 # 準(zhǔn)備數(shù)據(jù) x np.arange(5) y np.random.randn(5) cities [北京, 上海, 廣州, 深圳, 杭州] # 中文標(biāo)簽 # 繪圖 plt.figure(figsize(8, 5)) plt.plot(x, y, markero) plt.xticks(x, cities) # 設(shè)置x軸刻度標(biāo)簽為中文城市名 plt.xlabel(城市) plt.ylabel(指標(biāo)值) plt.title(各城市指標(biāo)對比圖) plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() plt.show()代碼解讀與避坑plt.rcParams[font.sans-serif] [SimHei]這行代碼告訴matplotlib當(dāng)需要渲染無襯線sans-serif字體時(shí)優(yōu)先使用“黑體”SimHei。你可以把這個(gè)列表改成其他字體名如[Microsoft YaHei]微軟雅黑、[KaiTi]楷體。列表意味著備選如果第一個(gè)字體找不到會(huì)嘗試第二個(gè)。plt.rcParams[axes.unicode_minus] False這行至關(guān)重要極易被忽略默認(rèn)情況下matplotlib用特定的字體渲染負(fù)號。當(dāng)中文字體替換后這個(gè)負(fù)號字體可能不兼容導(dǎo)致負(fù)號也顯示為方框。設(shè)置為False后負(fù)號會(huì)用普通的ASCII字符‘-’渲染確保能正常顯示。“坑”在哪里‘SimHei’這個(gè)字符串是字體名稱不是字體文件名。它必須是你操作系統(tǒng)已安裝且能被matplotlib識(shí)別的字體名稱。在Windows上SimHei黑體和Microsoft YaHei微軟雅黑通常是預(yù)裝的。但在全新的Linux或macOS上很可能沒有。此時(shí)你需要先安裝中文字體包如fonts-wqy-microhei或者使用方法三。實(shí)操心得我習(xí)慣在Jupyter Notebook的第一個(gè)單元格就運(yùn)行這兩行設(shè)置相當(dāng)于為整個(gè)Notebook會(huì)話設(shè)置了中文環(huán)境。但如果是寫.py腳本給別人用就要考慮對方的系統(tǒng)是否有這個(gè)字體了。3.2 方法二修改matplotlib配置文件——永久生效這個(gè)方法的目標(biāo)是找到并修改matplotlibrc文件。第一步定位配置文件在Python交互環(huán)境中運(yùn)行以下代碼可以找到當(dāng)前生效的matplotlibrc文件路徑import matplotlib print(matplotlib.matplotlib_fname())輸出結(jié)果可能類似于/usr/local/lib/python3.9/site-packages/matplotlib/mpl-data/matplotlibrc或C:\Python39\Lib\site-packages\matplotlib\mpl-data\matplotlibrc。第二步備份與編輯強(qiáng)烈建議先備份這個(gè)文件。用文本編輯器如VS Code、Notepad打開該文件。在文件中搜索font.sans-serif和axes.unicode_minus。你會(huì)找到類似這樣的行#font.sans-serif: DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif #axes.unicode_minus: True注意它們默認(rèn)是被注釋掉的以#開頭。你需要取消注釋并修改font.sans-serif: SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif axes.unicode_minus: False我在font.sans-serif列表的最前面加上了SimHei這樣matplotlib會(huì)優(yōu)先使用黑體。第三步驗(yàn)證修改保存后需要重啟你的Python內(nèi)核或重新啟動(dòng)Python解釋器讓配置生效。之后你無需在任何腳本中寫rcParams設(shè)置直接繪圖就會(huì)默認(rèn)使用中文。注意這個(gè)方法修改的是當(dāng)前Python環(huán)境下的matplotlib配置。如果你使用conda或venv創(chuàng)建了多個(gè)虛擬環(huán)境每個(gè)環(huán)境都有自己獨(dú)立的matplotlib包和配置文件需要分別修改。這也是為什么它“一勞永逸”但僅限于本環(huán)境。3.3 方法三指定字體路徑并注冊——項(xiàng)目級最佳實(shí)踐這是我最推薦在正式項(xiàng)目中使用的方法它能完美解決環(huán)境差異問題。假設(shè)你的項(xiàng)目目錄下有一個(gè)fonts文件夾里面放了你從網(wǎng)上下載的“思源黑體”文件SourceHanSansSC-Regular.otf。操作步驟import matplotlib.pyplot as plt import matplotlib.font_manager as fm from pathlib import Path import numpy as np # 1. 指定字體文件路徑 font_path Path(__file__).parent / fonts / SourceHanSansSC-Regular.otf # 如果是動(dòng)態(tài)獲取當(dāng)前腳本所在目錄的兄弟目錄下的字體文件上述方法很可靠。 # 也可以直接使用絕對路徑但可移植性變差。 # 2. 將字體文件注冊到matplotlib的字體管理器中 # 方法A (適用于matplotlib 3.2): 使用 addfont fm.fontManager.addfont(str(font_path)) font_prop fm.FontProperties(fnamestr(font_path)) font_name font_prop.get_name() # 獲取注冊后的字體家族名 # 方法B (通用方法): 直接創(chuàng)建FontProperties對象并應(yīng)用于rcParams # font_prop fm.FontProperties(fnamestr(font_path)) # font_name font_prop.get_name() # plt.rcParams[font.sans-serif] [font_name] # 3. 設(shè)置全局字體 plt.rcParams[font.sans-serif] [font_name] plt.rcParams[axes.unicode_minus] False # 4. 驗(yàn)證繪圖 plt.figure(figsize(8,5)) x [1,2,3,4] y [10, 15, 13, 18] labels [第一季度, 第二季度, 第三季度, 第四季度] plt.plot(x, y, o-, label銷售額) plt.xticks(x, labels) plt.xlabel(時(shí)間) plt.ylabel(銷售額萬元) plt.title(2023年季度銷售額趨勢, fontpropertiesfont_prop) # 也可以單獨(dú)為某個(gè)元素指定字體 plt.legend() plt.grid(True, linestyle:, alpha0.6) plt.tight_layout() plt.show() print(f已成功注冊并使用字體: {font_name})核心原理與避坑addfontvsFontPropertiesaddfont是較新版本3.2提供的API它將字體直接添加到全局的fontManager中之后就可以像使用系統(tǒng)字體一樣通過家族名調(diào)用。FontProperties對象則是字體的一個(gè)描述符你可以把它傳遞給具體的文本對象如title(..., fontpropertiesfont_prop)。為了全局生效我們通常用addfont獲取家族名后再設(shè)置到rcParams。路徑處理使用pathlib.Path來構(gòu)建路徑是跨平臺(tái)Windows/Linux/macOS的好習(xí)慣。Path(__file__).parent能獲取當(dāng)前腳本文件所在的目錄。字體文件格式確保你的字體文件是.ttf(TrueType) 或.otf(OpenType) 格式這是matplotlib普遍支持的。緩存問題matplotlib會(huì)緩存字體列表以提升性能。如果你在同一個(gè)會(huì)話中多次運(yùn)行注冊字體的代碼或者修改了字體文件可能需要清除緩存fm._rebuild()。更簡單的方法是重啟內(nèi)核。實(shí)操心得在團(tuán)隊(duì)項(xiàng)目中我會(huì)在項(xiàng)目的config.py或初始化模塊里集中進(jìn)行字體注冊和rcParams設(shè)置。這樣項(xiàng)目內(nèi)所有繪圖腳本import config后就自動(dòng)擁有了統(tǒng)一的中文渲染能力。部署到服務(wù)器時(shí)只需要確保fonts目錄隨代碼一起上傳即可。3.4 方法四使用系統(tǒng)字體別名——Windows用戶的捷徑這個(gè)方法本質(zhì)上是方法一的特例但它依賴的是字體在系統(tǒng)注冊的“家族名”而不是文件名。在Windows PowerShell或命令提示符中你可以用以下命令查看已安裝的字體名# 這不是Python代碼是系統(tǒng)命令 Get-WmiObject -Class Win32_Font | Select-Object Name你會(huì)看到很多如Microsoft YaHei、SimSun、SimHei這樣的名字。然后在Python中直接使用import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei] # 使用微軟雅黑 plt.rcParams[axes.unicode_minus] False # ... 繪圖代碼這個(gè)方法簡單到令人發(fā)指但請時(shí)刻記住它的致命弱點(diǎn)Microsoft YaHei這個(gè)字體名只存在于Windows系統(tǒng)。你的代碼在Linux服務(wù)器上運(yùn)行時(shí)會(huì)因找不到該字體而失敗。因此它僅適用于確定不會(huì)跨平臺(tái)的個(gè)人小型腳本。4. 進(jìn)階技巧與深度問題排查掌握了基本方法我們來看看一些更復(fù)雜的場景和那些讓人頭疼的“玄學(xué)”問題。4.1 多字體回退與樣式設(shè)置有時(shí)你希望中文字體用雅黑但數(shù)字和英文保留原生的DejaVu Sans因?yàn)楹笳邔?shù)學(xué)公式和字母間距的渲染可能更優(yōu)。這可以通過設(shè)置rcParams時(shí)指定多個(gè)字體來實(shí)現(xiàn)回退。plt.rcParams[font.sans-serif] [Microsoft YaHei, DejaVu Sans]matplotlib會(huì)按列表順序查找字體。當(dāng)中文“北京”在Microsoft YaHei中找到后就用它渲染當(dāng)遇到數(shù)字“123”或字母“abc”時(shí)雖然Microsoft YaHei也有但整個(gè)文本塊會(huì)統(tǒng)一使用第一種能找到所有字符的字體。更精細(xì)的控制需要用到Text對象的fontproperties參數(shù)但這通常過于繁瑣全局回退列表在大多數(shù)情況下已足夠。4.2 字體緩存導(dǎo)致的“幽靈”問題這是最讓人崩潰的情況之一你明明已經(jīng)正確安裝了字體或者更換了新的字體文件但matplotlib依然顯示舊字體或報(bào)錯(cuò)。這幾乎都是字體緩存font cache在作祟。matplotlib為了加速會(huì)把掃描到的字體信息緩存到文件里通常位于~/.matplotlib/fontlist-xxx.json。當(dāng)你新增、刪除或更改字體后這個(gè)緩存文件沒有更新matplotlib就感知不到變化。解決方案手動(dòng)刪除緩存文件找到緩存目錄可以通過print(matplotlib.get_cachedir())查看刪除里面所有以fontlist開頭的.json文件。下次導(dǎo)入matplotlib時(shí)它會(huì)重新掃描生成緩存。使用代碼強(qiáng)制重建在導(dǎo)入pyplot后立即執(zhí)行import matplotlib.font_manager as fm fm._rebuild() # 注意這是一個(gè)內(nèi)部API未來版本可能變更或者更安全的方式是設(shè)置環(huán)境變量在程序啟動(dòng)前清除緩存import os os.environ[MPLCONFIGDIR] /tmp/matplotlib_temp_cache # Linux/macOS # 或者強(qiáng)制不緩存 # matplotlib.rcParams[font.cache] False # (如果該參數(shù)存在)重啟大法在Jupyter中最徹底的方法是重啟內(nèi)核Kernel - Restart。在腳本中就是重新運(yùn)行程序。踩坑實(shí)錄有一次我在服務(wù)器上部署用Docker構(gòu)建鏡像時(shí)拷貝了新的字體文件但運(yùn)行容器后中文還是方框。折騰了兩小時(shí)才發(fā)現(xiàn)Docker鏡像構(gòu)建過程中某層已經(jīng)生成了matplotlib緩存而我的字體文件是在后面幾層才加入的。最后的解決辦法是在Dockerfile中拷貝字體文件后緊接著運(yùn)行一行RUN python -c import matplotlib.font_manager; matplotlib.font_manager._rebuild()來重建緩存。4.3 在非桌面環(huán)境服務(wù)器、Docker中部署在生產(chǎn)環(huán)境如Linux服務(wù)器、Docker容器中通常沒有圖形界面也沒有預(yù)裝中文字體。你需要安裝系統(tǒng)級中文字體包Ubuntu/Debian:apt-get install -y fonts-wqy-microhei文泉驛微米黑CentOS/RHEL:yum install -y wqy-microhei-fontsAlpine Linux:apk add --no-cache wqy-zenhei安裝后方法一或方法二通常就能生效需要知道字體名如WenQuanYi Micro Hei。Docker中的最佳實(shí)踐對應(yīng)方法三 在Dockerfile中將你的項(xiàng)目中文字體文件拷貝到容器內(nèi)并在代碼中通過絕對路徑注冊。這是最可控的方式。FROM python:3.9-slim RUN apt-get update apt-get install -y ... # 安裝其他依賴 COPY ./fonts/SourceHanSansSC-Regular.otf /usr/share/fonts/opentype/ COPY ./app /app WORKDIR /app RUN python -c import matplotlib; print(Matplotlib config:, matplotlib.matplotlib_fname()) # 可選重建字體緩存 RUN python -c import matplotlib.font_manager; matplotlib.font_manager._rebuild() CMD [python, main.py]在你的main.py中使用/usr/share/fonts/opentype/SourceHanSansSC-Regular.otf這個(gè)絕對路徑來注冊字體。4.4 檢查與調(diào)試字體列表當(dāng)你懷疑字體設(shè)置沒生效時(shí)不要瞎猜用代碼把matplotlib看到的字體都打印出來看看。import matplotlib.font_manager as fm # 獲取所有可用字體的信息 font_list fm.findSystemFonts() print(f系統(tǒng)字體數(shù)量: {len(font_list)}) # 查看前10個(gè)字體路徑 for fpath in font_list[:10]: print(fpath) # 獲取已注冊的字體家族名列表 font_names [f.name for f in fm.fontManager.ttflist] print(f\n已注冊字體家族名示例 (前20個(gè)):) for name in sorted(set(font_names))[:20]: print(f - {name}) # 檢查特定字體是否存在 target_font Microsoft YaHei if target_font in font_names: print(f\n? 字體 {target_font} 已可用。) else: print(f\n? 字體 {target_font} 未找到。)這個(gè)調(diào)試腳本能幫你確認(rèn)1字體文件是否在系統(tǒng)掃描路徑內(nèi)2字體是否成功注冊到了matplotlib的字體管理器里。5. 常見問題與排查技巧實(shí)錄即使按照步驟操作你可能還是會(huì)遇到一些奇怪的問題。下面是我和同事們多年踩坑總結(jié)出來的“排錯(cuò)手冊”。問題1設(shè)置了中文字體但負(fù)號‘-’還是顯示為方框。原因只設(shè)置了font.sans-serif忘了設(shè)置axes.unicode_minus False。解決確保這兩行配置總是成對出現(xiàn)。plt.rcParams[font.sans-serif] [YourChineseFont] plt.rcParams[axes.unicode_minus] False # 這行不能少問題2在Jupyter Notebook中修改了matplotlibrc文件但重啟Notebook后還是沒效果。原因Jupyter內(nèi)核可能緩存了舊的matplotlib配置或者你修改的不是當(dāng)前內(nèi)核所用Python環(huán)境下的配置文件。解決在Notebook中運(yùn)行import matplotlib; print(matplotlib.__file__)確認(rèn)你使用的matplotlib包的位置。然后去對應(yīng)的mpl-data目錄下修改matplotlibrc。修改配置文件后必須重啟Jupyter內(nèi)核Kernel - Restart而不僅僅是重新運(yùn)行單元格。更徹底的方法是重啟整個(gè)Jupyter Lab或Jupyter Notebook服務(wù)。問題3使用addfont注冊字體后plt.title()正常但plt.legend()的圖例中文還是方框。原因legend()函數(shù)默認(rèn)可能使用另一套字體設(shè)置或者你在設(shè)置全局rcParams之前就已經(jīng)創(chuàng)建了legend對象在舊版本matplotlib中對象創(chuàng)建時(shí)會(huì)鎖定當(dāng)時(shí)的字體設(shè)置。解決確保字體注冊和rcParams的設(shè)置放在所有繪圖代碼之前越早越好。嘗試顯式指定圖例的字體屬性plt.legend(prop{family: font_name})。檢查是否有多處設(shè)置被覆蓋。有時(shí)在代碼后面不小心又調(diào)用了rcParams重置了字體。問題4在VS Code等編輯器里運(yùn)行腳本圖表彈窗能顯示中文但保存為圖片如plt.savefig(figure.png)后圖片里的中文是方框。原因這是最經(jīng)典的“后端”Backend差異問題。matplotlib在交互式顯示彈窗和保存文件時(shí)可能使用不同的渲染后端。某些后端如‘a(chǎn)gg’在初始化時(shí)加載的字體列表可能與交互式后端如‘TkAgg’不同。解決最可靠的方法在代碼最開頭在導(dǎo)入pyplot之前就強(qiáng)制指定后端并設(shè)置字體。import matplotlib matplotlib.use(Agg) # 強(qiáng)制使用Agg后端常用于無頭環(huán)境保存圖片 # 或者 matplotlib.use(TkAgg) # 使用Tkinter后端 import matplotlib.pyplot as plt # 然后立即進(jìn)行字體注冊和rcParams設(shè)置確保你的字體注冊代碼在plt.savefig()之前已經(jīng)執(zhí)行并生效。對于保存圖片方法三指定字體路徑注冊的可靠性遠(yuǎn)高于依賴系統(tǒng)字體的方法。問題5所有方法都試了中文還是方框但打印字體列表明明有我要的字體。原因字體文件本身可能損壞或者字體名family name與你代碼中指定的名字有細(xì)微差別如多了一個(gè)空格、大小寫問題。解決使用FontProperties對象來獲取準(zhǔn)確的字體名fp fm.FontProperties(fname/path/to/your_font.ttf) actual_name fp.get_name() print(f字體文件的實(shí)際家族名是: {actual_name}) plt.rcParams[font.sans-serif] [actual_name] # 使用這個(gè)準(zhǔn)確的名字嘗試換一個(gè)字體文件。從知名開源字體網(wǎng)站如Google Fonts、思源字體項(xiàng)目下載一份新的。在極端情況下可能是matplotlib的bug或與特定版本的兼容性問題。嘗試升級或降級matplotlib版本。最后分享一個(gè)我個(gè)人的習(xí)慣對于任何一個(gè)新的數(shù)據(jù)分析或可視化項(xiàng)目我?guī)缀醵紩?huì)在項(xiàng)目根目錄下創(chuàng)建一個(gè)assets/fonts文件夾放入項(xiàng)目選定的中文字體通常是開源免費(fèi)的思源黑體或霞鶩文楷然后在項(xiàng)目的入口腳本或配置模塊中第一件事就是使用方法三注冊這個(gè)字體。這樣做雖然前期多了幾步但它徹底消滅了中文顯示這個(gè)“環(huán)境依賴”問題讓項(xiàng)目在任何人的電腦上、在任何服務(wù)器上運(yùn)行的結(jié)果都完全一致為團(tuán)隊(duì)協(xié)作和持續(xù)集成掃清了一個(gè)大障礙。這種確定性的收益遠(yuǎn)大于初期的一點(diǎn)配置成本。