seaborn繪製函數概觀#

您與seaborn的大部分互動都會透過一組繪製函數進行。其他章節的教學課程將探索每項功能提供的特定特點。在本章中,將介紹您將會遇到的不同種類函數(高階)。

相似功能,相似任務#

seaborn命名空間是平面的;所有功能都可以在頂層存取。但是,程式碼本身是階層化結構,具有功能模組透過不同方式達到相似的視覺化目標。大部分文件皆圍繞這些模組整理:您會看到像是「關係」、「分佈」以及「分類」等名稱。

例如,分佈模組定義專門用於表示資料點分佈函數。這包含了直方圖等常見的方法

penguins = sns.load_dataset("penguins")
sns.histplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
../_images/function_overview_3_0.png

以及類似但較不熟悉選項,例如核密度估計

sns.kdeplot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
../_images/function_overview_5_0.png

模組中的函數分享大量底層程式碼,並提供其他函式庫元件可能沒有的類似特點(例如上述範例中的multiple="stack")。它們設計用於切換不同的視覺化表示格式,因為在探索資料集時,不同的表示格式通常有互補的優缺點。

圖形級別 v.s. 軸級別函數#

除了各個模組外,seaborn 函式的分類方式還有橫切面的「座標軸層級」或「圖形層級」。上述範例都是座標軸層級函式。這些函式會將資料繪製到單一的 matplotlib.pyplot.Axes 物件,而此物件為函式的回傳值。

相對而言,圖形層級函式會透過 seaborn 物件,通常是 FacetGrid 來與 matplotlib 介接,而該物件會管理圖形。每個模組都只有一個圖形層級函式,其提供各個座標軸層級函式的一個統一介面。其組織概念大致如下

../_images/function_overview_8_0.png

例如,displot() 是分配模組的圖形層級函式。其預設行為是繪製直方圖,使用 histplot() 背後相同的程式碼

sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack")
../_images/function_overview_10_0.png

若要繪製核密度圖形,使用 kdeplot() 相同的程式碼,請使用 kind 參數來選取

sns.displot(data=penguins, x="flipper_length_mm", hue="species", multiple="stack", kind="kde")
../_images/function_overview_12_0.png

您會注意到圖形層級圖形看起來大致上與座標軸層級對應的圖形相同,但有一些差異。其中最顯著的是圖例放置在圖形外。其形狀也略有不同(稍後說明)。

圖形層級函式提供的最實用的功能是,它們可以輕鬆建立有多個子圖形的圖形。例如,我們可以改用依欄位排列的方式來「分面」繪製同一企鵝品種的 3 個分配,而非讓其堆疊在同一座標軸上

sns.displot(data=penguins, x="flipper_length_mm", hue="species", col="species")
../_images/function_overview_14_0.png

圖形層級函式會將其座標軸層級對應的函式包覆起來,並將類型特定的關鍵字參數(例如直方圖的 bin 大小)傳遞給基礎函式。這表示這些函式同樣具有彈性,但有一個缺點:特定類型的參數不會顯示在函式簽章或文件字串中。因此,某些功能可能會較難發現,而您可能需要查看文件中的兩個不同頁面,才能了解如何達成特定目標。

座標軸層級函式會建立獨立的圖形#

axes 層級函數撰寫為 drop-in 替換 matplotlib 函數使用。雖然這些函數會自動新增軸標籤和圖例,但在所繪製的軸之外,不會變更任何內容。代表這些函數可以結合在任意複雜的 matplotlib 圖形中,且具有可預測的結果。

axes 層級函數在內部會呼叫 matplotlib.pyplot.gca(),這會進入 matplotlib 狀態機介面,以便在「目前有效的」軸上繪製繪圖。但是,這些函數還接受 ax= 參數,這個參數整合到物件導向介面,讓您可以明確指定每一個繪圖的位置

f, axs = plt.subplots(1, 2, figsize=(8, 4), gridspec_kw=dict(width_ratios=[4, 3]))
sns.scatterplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species", ax=axs[0])
sns.histplot(data=penguins, x="species", hue="species", shrink=.8, alpha=.8, legend=False, ax=axs[1])
f.tight_layout()
../_images/function_overview_17_0.png

圖形層級函數擁有自己的圖形#

相對來說,圖形層級函數無法(輕鬆地)與其他繪圖結合。根據設計,這些函數「擁有」自己的圖形,包括其初始化,因此無法使用圖形層級函數來在現有軸上繪製繪圖。這個限制讓圖形層級函數可以實作一些功能,例如將圖例置於繪圖外。

儘管如此,您可以使用這些圖形層級函數回傳的物件存取 matplotlib 軸,再將其他元素新增至繪圖中,以此超越圖形層級函數所提供的功能

tips = sns.load_dataset("tips")
g = sns.relplot(data=tips, x="total_bill", y="tip")
g.ax.axline(xy1=(10, 2), slope=.2, color="b", dashes=(5, 2))
../_images/function_overview_19_0.png

自訂圖形層級函數的繪圖#

圖形層級函數會回傳 FacetGrid 實例,此實例提供一些方法,讓您可以自訂繪圖的屬性,並確保繪圖組織方式「智慧」。例如,您可以使用單一行程式碼變更外部軸上的標籤

g = sns.relplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", col="sex")
g.set_axis_labels("Flipper length (mm)", "Bill length (mm)")
../_images/function_overview_21_0.png

雖然如此便利,但這會帶來一些額外複雜性,因為您需要記住這個方法並非 matplotlib API 的一部分,且僅在使用圖形層級函數時才存在。

指定圖形大小#

若要增減 matplotlib 圖形的大小,要在 全域 rcParams 中設定整張圖形寬度與高度,或是在設定圖形時(例如使用 matplotlib.pyplot.subplots()figsize 參數)或呼叫圖形物件上的方法(例如 matplotlib.Figure.set_size_inches()),當在 seaborn 中使用軸級函數時,同樣的規則套用:圖形大小由它所在的圖形大小,與圖形中的軸配置決定。

當使用圖形級函數時,有幾個主要的差異。首先,函數本身有控制圖形大小的參數(雖然這些實際上是基礎 FacetGrid 函數的參數,用於管理圖形)。第二,這些參數,heightaspect,針對大小的參數化與 matplotlib 中的 widthheight 參數化稍微不同(使用 seaborn 參數,width = height * aspect)。最重要的,參數對應每個 子圖 的大小,而不是整體圖形的大小。

為了說明這些方法之間的差異,這是 matplotlib.pyplot.subplots() 的預設輸出,帶有一個子圖

f, ax = plt.subplots()
../_images/function_overview_24_0.png

有多個欄位的圖形會有相同的整體大小,但軸向會往水平擠壓以配合大小

f, ax = plt.subplots(1, 2, sharey=True)
../_images/function_overview_26_0.png

相較之下,由圖形級函數建立的圖形會是正方形。為了示範,我們直接使用 FacetGrid 設定空的圖形。這會在 relplot()displot()catplot() 檔中幕後產生

g = sns.FacetGrid(penguins)
../_images/function_overview_28_0.png

當新增其他欄時,圖形本身將會變得更寬,讓它的子繪圖具有相同的尺寸和形狀

g = sns.FacetGrid(penguins, col="sex")
../_images/function_overview_30_0.png

而且你可以調整每個子繪圖的大小和形狀,而不用考量圖形中的總列數和總欄數

g = sns.FacetGrid(penguins, col="sex", height=3.5, aspect=.75)
../_images/function_overview_32_0.png

重點是你可以指定分類變數,而不用停下來考慮你將如何調整總圖形的大小。一個缺點是當你真的想變更圖形大小時,你需要記住,在 matplotlib 中執行方式會有些不同。

圖形層級功能的相對優點#

以下是我們在上面所討論的優缺點摘要

優點

缺點

能輕易透過資料變數分類

許多參數不在函數簽署中

圖例預設在繪圖外側

不能成為較大型 matplotlib 圖形的一部分

能輕易自訂圖形層級

與 matplotlib 的 API 不同

圖形大小參數化不同

圖形大小參數化不同

整體而言,圖形層級功能會新增一些額外的複雜度,這可能會讓初學者感到更混亂,但它們的獨特特徵讓它們擁有更強大的功能。教學文件大多使用圖形層級功能,因為它們產生的繪圖會稍微簡潔一些,而且我們通常建議在大部分應用中使用它們。如果以下情況發生,這表示它們並非好的選擇:你需要製作一個複雜、獨立的圖形,而該圖形由多種不同的繪圖類型組成。在這種情況下,建議使用 matplotlib 直接設定圖形,並使用軸層級函數填入個別組成部分。

在資料中結合多重檢視#

在 seaborn 中有兩個重要的繪圖函數不完全符合上面所討論的分類配置。這些函數,jointplot()pairplot(),採用不同模組中多種不同类型的繪圖來在一個單一圖形中呈現資料集的多個面向。兩個繪圖都是圖形層級函數,而且預設會利用多個子繪圖來建立圖形。但它們會使用不同的物件來管理該圖形:JointGridPairGrid

jointplot() 繪製兩個變數的關係或聯合分佈,同時加入邊緣軸,用來分別顯示每個變數的單變數分佈

sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species")
../_images/function_overview_36_0.png

pairplot() 相似,它結合了聯合視圖和邊際視圖 - 但它並非著重於單一關係,而是同時視覺化了變數的每一對組合

sns.pairplot(data=penguins, hue="species")
../_images/function_overview_38_0.png

在幕後,這些函式正在使用您已經認識的軸層級函式 (scatterplot()kdeplot()),而它們也有 kind 參數,它讓您可以快速交換不同的表示法

sns.jointplot(data=penguins, x="flipper_length_mm", y="bill_length_mm", hue="species", kind="hist")
../_images/function_overview_40_0.png