使用python的頭文件Matplotlib時plt.show【標題字體過小】問題根源與解決方案
- 1. 問題復現
- 2. 問題分析
- 3. 解決方案
- 方案一(`推薦`):使用 `fig.suptitle` 結合 `subplots_adjust`
- 方案二:以保存文件函數`plt.savefig`為準
- 方案三:不使用 `tight_layout` ,完全手動布局
- 4. 總結與建議
1. 問題復現
我們使用python的matplotlib
頭文件時可能會遇到一個現象:在代碼中將**標題-**的fontsize
設置為一個較大的值,但在plt.show()
彈出的交互式窗口中,標題的顯示卻非常小。
比如以下代碼嘗試為一個簡單的條形圖設置一個fontsize=40
的標題。
import matplotlib.pyplot as plt
import pandas as pd
import os
from matplotlib.font_manager import FontPropertiesdef get_chinese_font():"""一個輔助函數,用于獲取系統中可用的中文字體。"""font_path_msyh = r'C:\Windows\Fonts\msyh.ttc'font_path_deng = r'C:\Windows\Fonts\Deng.ttf'if os.path.exists(font_path_msyh):print("成功加載字體:微軟雅黑 (msyh.ttc)")return FontProperties(fname=font_path_msyh)elif os.path.exists(font_path_deng):print("注意: 未找到微軟雅黑,已加載備用字體:等線 (Deng.ttf)")return FontProperties(fname=font_path_deng)else:print("\033[91m錯誤: 微軟雅黑和等線字體均未找到!\033[0m")return FontProperties()# 獲取中文字體并準備數據
my_font = get_chinese_font()
data = {'類別': ['A', 'B', 'C', 'D'], '數值': [10, 25, 18, 32]}
df = pd.DataFrame(data)# --- 問題復現代碼 ---
fig, ax = plt.subplots(figsize=(10, 6))
ax.bar(df['類別'], df['數值'])# 嘗試設置一個非常大的標題字體
ax.set_title('這是一個標題(fontsize=40)', fontsize=40, fontproperties=my_font)
ax.set_xlabel('類別', fontproperties=my_font, fontsize=12)
ax.set_ylabel('數值', fontproperties=my_font, fontsize=12)# 使用自動緊湊布局
plt.tight_layout()
plt.show()
- 預期結果:標題的字體設置為40,本應是一個標題占據圖表顯著高度、字體極大的圖像。
- 實際結果:在
plt.show()
窗口中,其視覺大小遠未達到fontsize=40
應有的效果,甚至很小。
2. 問題分析
這是matplotlib
頭文件的布局與渲染機制交互作用的結果。其核心原因可歸結為以下三點:
- 絕對字體大小:
fontsize
參數的單位是 points,是一個絕對度量單位。Matplotlib會根據該值計算標題所需的物理空間。 plt.tight_layout()
的動態調整:當tight_layout()
檢測到大尺寸標題時,為防止其與圖表主體(Axes)重疊,它會增加整個畫布(Figure)的理論高度,為標題分配空間。plt.show()
窗口的縮放行為:plt.show()
打開的交互式窗口大小受限于當前屏幕分辨率。當它需要展示一個被tight_layout()
“撐高”的畫布時,為將整個畫布完整地放入窗口內,它必須對整個圖像進行等比例縮小。
結論:預覽窗口的整體縮放,抵消了原始設置的巨大字體尺寸。雖然標題相對于圖表主體的比例確實變大了,但由于整體圖像被縮小,其在屏幕上的絕對視覺大小并未顯著增加。
3. 解決方案
方案一(推薦
):使用 fig.suptitle
結合 subplots_adjust
通過將標題從“子圖級別”(Axes)提升到“畫布級別”(Figure),并手動為其預留空間,從而繞開 tight_layout
的過度調整問題。
首先要明白 Matplotlib 的兩個核心層級:
- 畫布 (Figure):整個繪圖窗口,就像一張畫紙。
- 子圖 (Axes):畫紙上用來畫具體圖表(如條形圖)的矩形區域。
我們的策略分為兩步:
- 使用
fig.suptitle()
:與ax.set_title()
創建的是子圖內部的標題元素不同,fig.suptitle()
創建的是整個畫布(Figure)的全局標題 - 使用
tight_layout()
讓子圖內部的元素(坐標軸標簽等)自動排列整齊。 - 再用
fig.subplots_adjust(top=0.9)
手動將整個子圖區域在畫布內向下移動。比如top=0.90
的意思是“將所有子圖的頂部邊界向下移動,使其不超過畫布總高度的90%”。這就在畫布的頂部強制留出了10%的空白區域,專門用于容納suptitle
。
通過這個組合,我們既利用了 tight_layout
自動調整子圖內部元素的便利,又通過 subplots_adjust
精確地為全局標題提供了穩定、獨立的顯示空間,避免了整個畫布因標題過大而被縮放的問題。
- 解決方案代碼:
import matplotlib.pyplot as plt
import pandas as pd
import os
from matplotlib.font_manager import FontPropertiesdef get_chinese_font():"""一個輔助函數,用于獲取系統中可用的中文字體。"""font_path_msyh = r'C:\Windows\Fonts\msyh.ttc'font_path_deng = r'C:\Windows\Fonts\Deng.ttf'if os.path.exists(font_path_msyh):print("成功加載字體:微軟雅黑 (msyh.ttc)")return FontProperties(fname=font_path_msyh)elif os.path.exists(font_path_deng):print("注意: 未找到微軟雅黑,已加載備用字體:等線 (Deng.ttf)")return FontProperties(fname=font_path_deng)else:print("\033[91m錯誤: 微軟雅黑和等線字體均未找到!\033[0m")return FontProperties()# 獲取中文字體
my_font = get_chinese_font()# 準備數據
data = {'類別': ['A', 'B', 'C', 'D'], '數值': [10, 25, 18, 32]}
df = pd.DataFrame(data)
# ... (前面的數據準備和字體獲取代碼相同) ...# --- 推薦解決方案代碼 ---
fig, ax = plt.subplots(figsize=(10, 6))ax.bar(df['類別'], df['數值'])# 1. 使用 fig.suptitle() 設置Figure級標題
fig.suptitle('這是一個正確的標題(fontsize=24)', fontsize=24, # 使用一個更合理的字體大小fontweight='bold', fontproperties=my_font)ax.set_xlabel('類別', fontproperties=my_font, fontsize=12)
ax.set_ylabel('數值', fontproperties=my_font, fontsize=12)# 2. 調用 tight_layout() 進行初步布局
plt.tight_layout()# 3. 使用 subplots_adjust() 為 suptitle 預留空間,防止重疊
# top=0.9 表示將子圖的頂部邊界設置在畫布高度的90%處
fig.subplots_adjust(top=0.90)plt.show()
- 優點:
- 職責分離:
fig.suptitle()
負責全局標題,ax.set_title()
負責子圖標題,邏輯清晰。 - 布局穩定:通過
subplots_adjust()
為標題提供固定的、不受tight_layout()
過度干預的空間,避免了意外的畫布縮放。 - 所見即所得:
plt.show()
預覽窗口中的標題大小將更接近最終保存文件的效果。
- 職責分離:
方案二:以保存文件函數plt.savefig
為準
plt.show()
本質上是快速預覽工具,其渲染可能受GUI后端和屏幕尺寸影響。在學術或報告場景下,最終交付物是靜態圖像文件。可以嘗試使用一下plt.savefig函數
。
- 實踐:
- 在代碼中設置合理的字體大小(如22-26)。
- 執行代碼后,調用
plt.savefig('figure.png', dpi=300, bbox_inches='tight')
。 - 檢查生成的圖像文件,看生成的文件是否符合我們的最終效果。
- 優點:無需修改繪圖邏輯,簡單直接;確保了最終輸出文件的質量。
- 缺點:未改善交互式預覽的體驗。(而且有的時候我嘗試可能不起作用)
方案三:不使用 tight_layout
,完全手動布局
對于需要精確控制的復雜布局,可以不使用自動布局,轉而手動設置所有邊距。
- 實踐代碼:
fig, ax = plt.subplots(figsize=(10, 6))
ax.bar(df['類別'], df['數值'])
ax.set_title('手動布局下的標題(fontsize=24)', fontsize=24, fontproperties=my_font)
ax.set_xlabel('類別', fontproperties=my_font, fontsize=12)
ax.set_ylabel('數值', fontproperties=my_font, fontsize=12)# 不調用 plt.tight_layout()
# 手動設置所有邊距
fig.subplots_adjust(left=0.1, right=0.95, top=0.88, # 為大標題留出足夠空間bottom=0.1
)plt.show()
- 優點:提供對布局的完全、精確的控制。
- 缺點:過程繁瑣,需要為每個圖表手動調整參數,通用性差。通常只在
tight_layout
失效的極端情況下使用。
4. 總結與建議
plt.show()
中標題字體過小的問題,源于ax.set_title()
、plt.tight_layout()
及預覽窗口縮放機制的交互。
解決方案 | 優點 | 缺點 | 推薦指數 |
---|---|---|---|
1. fig.suptitle + subplots_adjust | 邏輯清晰,布局穩定,預覽效果好 | 需額外代碼 | ★★★★★ |
2. 以保存文件為準 | 簡單,保證最終輸出質量 | 無法直接預覽,有時不起作用 | ★★★☆☆ |
3. 手動布局 | 完全控制,精度高 | 繁瑣 | ★★☆☆☆ |