久久ER99热精品一区二区-久久精品99国产精品日本-久久精品免费一区二区三区-久久综合九色综合欧美狠狠

博客專欄

EEPW首頁 > 博客 > Matplotlib 可視化之圖例與標簽高級應用

Matplotlib 可視化之圖例與標簽高級應用

發布人:AI科技大本營 時間:2022-05-15 來源:工程師 發布文章

以下文章來源于數據STUDIO ,作者云朵君

作者 | 云朵君     

來源 | 數據STUDIO

裝飾物指的是你可以添加到一個圖形上的所有額外元素,以美化它或使它更清晰。裝飾物包括圖例、注釋、顏色條、文本等標準元素,但也可以專門設計自己的元素。今天一起繼續學習圖例與標簽元素的應用實例。

配置圖例

想在可視化圖形中使用圖例,可以為不同的圖形元素分配標簽。圖例非常容易使用,只要求用戶命名圖。Matplotlib將自動創建一個包含每個圖形元素的圖例。即使在大多數情況下,一個簡單的legend() 調用就足夠了,但圖例還是提供了幾個選項,允許我們自定義圖例的各個配置。如使用

ax.legend(loc='upper left',
          frameon=False,
          edgecolor="None")


完整代碼解析

上下滑動查看更多源碼
fig = plt.figure(figsize=(9.64))
ax = plt.subplot(
    xlim=[-np.pi, np.pi],
    xticks=[-np.pi, -np.pi / 20, np.pi / 2, np.pi],
    xticklabels=["$-\pi$""$-\pi/2$""0""$+\pi/2$""$+\pi$"],
    ylim=[-11],
    yticks=[-101],
    yticklabels=["-1""0""+1"],
)

X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C, S = np.cos(X), np.sin(X)
# 繪制兩條折線,顏色默認
ax.plot(X, C, label="$cos(x)$", clip_on=False)
ax.plot(X, S, label="$sin(x)$", clip_on=False)
# 隱藏上右邊的軸線
ax.spines["right"].set_visible(False)
ax.spines["top"].set_visible(False)
# 移動下左邊的軸線
ax.spines["left"].set_position(("data"-3.25))
ax.spines["bottom"].set_position(("data"-1.25))
ax.legend(edgecolor="None",loc=2,frameon=False)
然而,在某些情況下,用圖例來添加信息可能不是最合適的方式。例如,當你有多個圖表時,讀者在閱讀圖表,視線在圖表和圖例之間來回切換時,可能會覺得很乏味。另一種可以解決此類困惑的方法是在下圖所示的圖上直接添加信息。圖片

詳細代碼解析

上下滑動查看更多源碼
X = np.linspace(-np.pi, np.pi, 400, endpoint=True)
C, S = np.cos(X), np.sin(X)
plot1, plot2 = plot(ax) # 繪制折線圖的對象
# --------------------P1-------------------------
# 用小橫線標注在折線旁邊
ax.text(
    X[-1], C[-1],
    " — " + plot1.get_label(), # 從對象中獲取標簽   
    color=plot1.get_color(),   # 從對象中獲取線條顏色
    size="small", ha="left", va="center",)
# --------------------P2--------------------------
# 標注在對應折線上,且有透明邊框
ax.text(
    X[100], C[100],
    " " + plot1.get_label(),
    bbox=dict(facecolor="white", edgecolor="None", alpha=0.85),
    color=plot1.get_color(),
    ha="center", va="center", size="small",
    rotation=42.5,)
# --------------------P3--------------------------
# 使用箭頭
ax.annotate(
    "$cos(x)$",
    (X[100], C[100]),
    size="medium",
    color=plot1.get_color(),
    xytext=(-50, +10),
    textcoords="offset points",
    arrowprops=dict(
        arrowstyle="->", color=plot1.get_color(), 
        connectionstyle="arc3,rad=-0.3"),)
# --------------------P4--------------------------
# 圈點和注釋的組合
index = 10
ax.scatter(
    [X[index]], [C[index]],
    s=100, marker="o", zorder=10,     
    edgecolor=plot1.get_color(),
    facecolor="white", linewidth=1, clip_on=False,)
ax.text(
    X[index], 1.01 * C[index],
    "A",
    zorder=20,size="small",
    color=plot1.get_color(),
    ha="center", va="center", clip_on=False,)
當然,這里是沒有最好的選擇,因為它真的取決于數據。對于上述的sin / cos的示例(非常簡單),這四種解決方案都是合適的,但當有很多實際數據一起使用時,可能這種方法就失效了。此時我們可能需要尋求其他方式來標記數據,如將圖分成幾個圖分別展示。

標題和標簽

我們已經使用 set_titleset_xlabel 和 set_ylabel 方法操作了標題和標簽。當僅僅使用默認參數時,確實比較方便。并且它們的默認位置通常對大多數圖表都比較合適。盡管如此,仍然可以使用各種參數來定制和美化圖形。如下面兩個圖所示,對比觀察,可以明顯發現:上圖大部分使用了默認參數。而下圖中,用軸標簽替換軸刻度標簽,即在軸中間加上說明標簽,為了使其更靠近軸,刪除了可能與標簽碰撞的中心刻度。此外,將標題其向右移動,并相應地移動圖例框,將其放置在標題下方,并且使用一行兩列的排列方式。其實這里沒有做過復雜的操作,但我認為結果在視覺上更驚艷。圖片

完整代碼解析
ax.legend(
    edgecolor="None",
    ncol=2,
    loc="upper right",
    bbox_to_anchor=(1.011.225),   
    # 用于與loc一起定位圖例的框。(x, y, width, height)
    borderaxespad=1,                
    # 軸線和圖例邊框之間的填充,以字體大小為單位。
)
# 設置標題
ax.set_title("三角函數", x=1, y=1.2, ha="right",size=14)
# 設置x軸標簽
ax.set_xlabel("角度", va="center", weight="bold",size=12)
ax.xaxis.set_label_coords(0.5-0.25)
# 設置標簽的坐標。
# 默認情況下,y 標簽的 x 坐標和 x 標簽的 y 坐標由刻度標簽邊界框確定,
# 但是如果有多個軸,這可能會導致多個標簽對齊不良。
# 設置y軸標簽
ax.set_ylabel("值", ha="center", weight="bold",size=12)
ax.yaxis.set_label_coords(-0.0250.5)

在某些情況下(如會議海報),可能需要讓標題更吸引眼球,如下圖所示。這可以通過使用make_axes_locatable 方法來劃分每個軸,并為標題區域預留15%的高度。在這個圖中,還用Latex 插入了一個完全對齊的文本,它可以被看作是另一種形式或(高級)裝飾。圖片完整代碼參見latex-text-box[1]

注釋

在matplotlib中,注釋可能是最難處理的對象。原因是它包含的概念眾多,而這些概念又具有大量的參數。此外,由于注釋所涉及的文本大小是按點排列的,這無疑又是雪上加霜。此外可能需要混合使用像素、點、分數或數據單元中的絕對坐標或相對坐標。你可以這么認為,你可以對具有任何類型投影的任何軸進行注釋,那么你現在應該可以理解到為什么annotate方法提供這么多參數。

上面這段話比較抽象,接下來我們一起看下具體例子。注釋圖形最簡單的方法是在想要注釋的點附近添加標簽,如下圖所示。圖中,為了使得標簽獨立于數據分布保持可讀性,為標簽添加了一個白色的輪廓。然而,如果這樣的點過多,所有不同的標簽可能會使圖形變得混亂,并可能會掩蓋潛在的重要信息。

圖片

完整代碼解析

上下滑動查看更多源碼
import matplotlib.patheffects as path_effects
fig = plt.figure(figsize=(105))
ax = plt.subplot(121, xlim=[-1, +1], 
                 xticks=[], ylim=[-1, +1], 
                 yticks=[], aspect=1)
# --------------------------------------------- 
# 繪制散點圖
np.random.seed(123)
X = np.random.normal(00.351000)
Y = np.random.normal(00.351000)

ax.scatter(X, Y, edgecolor="None", s=60,
           facecolor="C1", alpha=0.5)

# 不重復采用:array([1, 4, 0, 3, 2])
I = np.random.choice(len(X), size=5
                     replace=False)
# 根據y值,從大到小排序
Px, Py = X[I], Y[I]
I = np.argsort(Y[I])[::-1]
Px, Py = Px[I], Py[I]
# 將隨機選取的五個點用黑色邊框框選出
ax.scatter(Px, Py, edgecolor="black", facecolor="white", zorder=20)
ax.scatter(Px, Py, edgecolor="None", facecolor="C1", alpha=0.5, zorder=30)

添加標簽注釋
for i in range(len(I)):
# 五個注釋是樣式是一樣的,可以使用循環添加
    text = ax.annotate(
        "Point " + chr(ord("A") + i),
        xy=(Px[i], Py[i]),
        xycoords="data",
        xytext=(018),
        textcoords="offset points",
        ha="center",
        size="medium",
        arrowprops=dict(
            arrowstyle="->", shrinkA=0, shrinkB=5, color="black", linewidth=0.75),
    )
    text.set_path_effects(
        [path_effects.Stroke(linewidth=2, foreground="white"), path_effects.Normal()]
    )
    text.arrow_patch.set_path_effects(
        [path_effects.Stroke(linewidth=2, foreground="white"), path_effects.Normal()]
    )

另一種方法是將標簽推到圖的一側,并使用虛線來建立點和標簽之間的鏈接,如下圖所示。圖片但這些形狀、位置、排列方式等樣式的設計并不是圖形自動的,為了繪制出該圖形,就必須計算幾乎所有的東西。首先,為了不讓線相互交叉,將目標標記的點排序:

X = np.random.normal(0.351000
Y = np.random.normal(0.351000)
ax.scatter(X, Y, edgecolor="None"
           facecolor="C1", alpha=0.5)
I = np.random.choice(len(X), size=5, replace=False)
Px, Py = X[I], Y[I]
I = np.argsort(Y[I])[::-1]
Px, Py = Px[I], Py[I]

從這些點開始,使用一個相當復雜的連接樣式來注釋它們:

上下滑動查看更多源碼
y, dy = 0.250.125
style = "arc,angleA=-0,angleB=0,armA=-100,armB=0,rad=0"
for i in range(len(I)):
    text = ax2.annotate(
        "Point " + chr(ord("A") + i),
        xy=(Px[i], Py[i]),
        xycoords="data",
        xytext=(1.25, y - i * dy),
        textcoords="data",
        arrowprops=dict(
            arrowstyle="->",
            color="black",
            linewidth=0.75,
            shrinkA=20,
            shrinkB=5,
            patchA=None,
            patchB=None,
            connectionstyle=style,
        ),
    )
    text.arrow_patch.set_path_effects(
        [path_effects.Stroke(linewidth=2, foreground="white"), path_effects.Normal()]
    )
也可以使用連接補片的方式在軸外來注釋的目標對象,如下圖所示。
圖片該圖中,創建了幾個矩形,在一些點周圍顯示感興趣的區域,并創建了與相應的縮放軸的連接。注意連接開始在外面的矩形,這是一個不錯的功能提供的注釋:可以指定對象的性質要注釋(通過提供一個patche)和matplotlib會照顧的連接邊界的起源的patche。

完整代碼解析

上下滑動查看更多源碼
from matplotlib.gridspec import GridSpec
from matplotlib.patches import Rectangle, ConnectionPatch
# 設置畫布
fig = plt.figure(figsize=(65))
n = 5
gs = GridSpec(n, n + 1)
ax = plt.subplot( gs[:n, :n], 
          xlim=[-1, +1], xticks=[], 
          ylim=[-1, +1], yticks=[], aspect=1)

# 繪制散點圖略(見上面代碼)
dx, dy = 0.0750.075
for i, (x, y) in enumerate(zip(Px, Py)):
# 設置子畫布
    sax = plt.subplot(
        gs[i, n],
        xlim=[x - dx, x + dx],
        xticks=[],
        ylim=[y - dy, y + dy],
        yticks=[],
        aspect=1,)
# 在子畫布上繪制散點
    sax.scatter(X, Y, edgecolor="None"
                facecolor="C1", alpha=0.5,s=60)
    sax.scatter(Px, Py, edgecolor="black"
                facecolor="None", linewidth=0.75,s=60)
# 加上注釋
    sax.text(
        1.10.5,
        "Point " + chr(ord("A") + i),
        rotation=90, size=8, ha="left", va="center",
        transform=sax.transAxes, )
# 繪制矩形
    rect = Rectangle(
        (x - dx, y - dy),
        2 * dx, 2 * dy,
        edgecolor="black", facecolor="None",
        linestyle="--", linewidth=0.75, )
    ax.add_patch(rect)
# 繪制連接補丁Patch
    con = ConnectionPatch(
        xyA=(x, y), coordsA=ax.transData,
        xyB=(00.5), coordsB=sax.transAxes,
        linestyle="--", linewidth=0.75,
        patchA=rect, arrowstyle="->", )
    fig.add_artist(con)
GridSpec:指定子圖將放置的網格的幾何位置。需要設置網格的行數和列數。子圖布局參數(例如,左,右等)可以選擇性調整。
ConnectionPatch:用于在兩點之間建立連接線。
上下滑動查看更多參數
參數:xyA: 它是x-y圖上也稱為點A的連接線的起點。xyB: 它是x-y圖上連接線的起點,也稱為點B。coordsA: A點的坐標。coordsB: B點的坐標。axesA: 它是x-y圖上連接軸的起點。axesB: 它是x-y圖上連接軸的終點。arrowstyle: 用于設置連接箭頭的樣式。其默認類型為“-”。arrow_transmuter: 用于忽略連接線。connectionstyle: 它描述了posA和posB的連接方式。它可以是ConnectionStyle類的實例,也可以是connectionstyle名稱的字符串,它具有可選的逗號分隔屬性。connector: 通常忽略它,并決定忽略哪個連接器。patchA: 用于在A點添加補丁。patchB: 用于在B點添加補丁shrinkA: 用于在A點收縮連接器。shrinkB: 用于在B點收縮連接器。mutation_scale: 箭頭樣式的屬性(例如head_length)的縮放比例值。mutation_aspect: 變異前,矩形的高度將被該值擠壓,變異框將被其倒數拉伸。clip_on: 設置藝術家是否使用剪輯。dpi_cor: dpi_cor當前用于linewidth-related事物和收縮因子。突變規模受此影響。

參考資料[1]

latex-text-box: https://github.com/rougier/scientific-visualization-book/blob/master/code/ornaments/latex-text-box.py

[2]

Scientific Visualisation-Python & Matplotlib



*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



關鍵詞: AI

相關推薦

技術專區

關閉