axisartist 工具組#

警告

axisartist 使用自訂的 Axes 類別(衍生自 Matplotlib 原生的 Axes 類別)。副作用是,某些命令(主要與刻度相關)無法運作。

axisartist 包含一個自訂的 Axes 類別,旨在支援曲線網格(例如,天文學中的世界座標系統)。與 Matplotlib 原生的 Axes 類別使用 Axes.xaxis 和 Axes.yaxis 來繪製刻度、刻度線等不同,axisartist 使用特殊的藝術家 (AxisArtist) 來處理彎曲座標系統的刻度、刻度線等。

../../../_images/sphx_glr_demo_floating_axis_001.png

由於它使用特殊的藝術家,因此某些適用於 Axes.xaxis 和 Axes.yaxis 的 Matplotlib 命令可能無法運作。

axisartist#

axisartist 模組提供一個自訂(且非常實驗性)的 Axes 類別,其中每個軸(左、右、上和下)都有一個單獨的相關藝術家,負責繪製軸線、刻度、刻度標籤和標籤。您也可以建立自己的軸,該軸可以穿過軸座標中的固定位置,或資料座標中的固定位置(即,當視圖限制變更時,軸會浮動)。

預設情況下,軸類別的 xaxis 和 yaxis 為不可見,並且有 4 個額外的藝術家負責繪製「左」、「右」、「下」和「上」四個軸脊線。它們以 ax.axis["left"]、ax.axis["right"] 等方式存取,即 ax.axis 是一個包含藝術家的字典(請注意,ax.axis 仍然是一個可呼叫的方法,其行為與 Matplotlib 中的原始 Axes.axis 方法相同)。

若要建立 Axes,

import mpl_toolkits.axisartist as AA
fig = plt.figure()
fig.add_axes([0.1, 0.1, 0.8, 0.8], axes_class=AA.Axes)

或建立子圖

fig.add_subplot(111, axes_class=AA.Axes)
# Given that 111 is the default, one can also do
fig.add_subplot(axes_class=AA.Axes)

例如,您可以使用以下方式隱藏右側和頂部的脊線

ax.axis["right"].set_visible(False)
ax.axis["top"].set_visible(False)
../../../_images/sphx_glr_simple_axisline3_001.png

也可以新增水平軸。例如,您可以在 y=0 處有一個水平軸(在資料座標中)。

ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0)
../../../_images/sphx_glr_simple_axisartist1_001.png

或具有一些偏移的固定軸

# make new (right-side) yaxis, but with some offset
ax.axis["right2"] = ax.new_fixed_axis(loc="right", offset=(20, 0))

使用 ParasiteAxes 的 axisartist#

axes_grid1 工具組中的大多數命令都可以採用 axes_class 關鍵字引數,並且這些命令會建立給定類別的 Axes。例如,若要建立具有 axisartist.Axes 的主子圖,

import mpl_toolkits.axisartist as AA
from mpl_toolkits.axes_grid1 import host_subplot

host = host_subplot(111, axes_class=AA.Axes)

以下是一個使用 ParasiteAxes 的範例。

../../../_images/sphx_glr_demo_parasite_axes2_001.png

曲線網格#

AxisArtist 模組背後的動機是支援曲線網格和刻度。

../../../_images/sphx_glr_demo_curvelinear_grid_001.png

浮動軸#

AxisArtist 也支援外軸定義為浮動軸的浮動軸。

../../../_images/sphx_glr_demo_floating_axes_001.png

axisartist 名稱空間#

axisartist 名稱空間包含一個衍生的 Axes 實作。最大的差異在於,負責繪製軸線、刻度、刻度標籤和軸標籤的藝術家與 Matplotlib 的 Axis 類別分離,後者在原始的 Matplotlib 中不僅僅是藝術家。此變更主要是為了支援曲線網格。以下是 mpl_toolkits.axisartist.Axes 與 Matplotlib 原生 Axes 的幾個不同之處。

  • 軸元素(軸線(脊線)、刻度、刻度標籤和軸標籤)由 AxisArtist 實例繪製。與 Axis 不同,左軸、右軸、上軸和下軸由不同的藝術家繪製。而且它們每個都可能有不同的刻度位置和不同的刻度標籤。

  • 格線由 Gridlines 實例繪製。此變更的動機是,在曲線座標中,格線可能不會穿過軸線(即,沒有相關的刻度)。在原始的 Axes 類別中,格線會繫結至刻度。

  • 必要時可以旋轉刻度線(即,沿著格線)

總之,所有這些變更都是為了支援

  • 曲線網格。

  • 浮動軸

../../../_images/sphx_glr_demo_floating_axis_001.png

mpl_toolkits.axisartist.Axes 類別定義了 axis 屬性,該屬性是一個 AxisArtist 實例的字典。預設情況下,此字典有 4 個 AxisArtist 實例,負責繪製左軸、右軸、下軸和上軸。

xaxis 和 yaxis 屬性仍然可用,但它們設定為不可見。由於使用單獨的藝術家進行軸渲染,因此 Matplotlib 中某些與軸相關的方法可能沒有效果。除了 AxisArtist 實例之外,mpl_toolkits.axisartist.Axes 還會具有 gridlines 屬性 (Gridlines),該屬性顯然會繪製格線。

在 AxisArtist 和 Gridlines 中,刻度和格線位置的計算都會委派給 GridHelper 類別的實例。mpl_toolkits.axisartist.Axes 類別使用 GridHelperRectlinear 作為格線協助程式。GridHelperRectlinear 類別是 Matplotlib 原生 Axes 的 xaxisyaxis 的包裝函式,旨在以 Matplotlib 原生軸的方式運作。例如,使用 set_ticks 方法等方式變更刻度位置應如預期般運作。但是,藝術家屬性(例如,色彩)的變更通常不會生效,儘管已盡力確保會尊重一些經常變更的屬性(色彩等)。

AxisArtist#

AxisArtist 可以視為具有以下屬性的容器藝術家,這些屬性會繪製刻度、標籤等。

  • line

  • major_ticks, major_ticklabels

  • minor_ticks, minor_ticklabels

  • offsetText

  • label

line#

衍生自 Line2D 類別。負責繪製脊狀線。

major_ticks, minor_ticks#

衍生自 Line2D 類別。請注意,刻度是標記。

major_ticklabels, minor_ticklabels#

衍生自 Text。請注意,它不是 Text 藝術家的列表,而是一個單一的藝術家(類似於集合)。

axislabel#

衍生自 Text。

預設 AxisArtists#

預設情況下,會定義以下軸藝術家。

ax.axis["left"], ax.axis["bottom"], ax.axis["right"], ax.axis["top"]

頂部和右側軸的刻度標籤和軸標籤設定為不可見。

例如,如果您想要變更底部 x 軸的 major_ticklabels 的色彩屬性

ax.axis["bottom"].major_ticklabels.set_color("b")

同樣地,若要讓刻度標籤不可見

ax.axis["bottom"].major_ticklabels.set_visible(False)

AxisArtist 提供一個輔助方法來控制刻度、刻度標籤和標籤的可見性。若要讓刻度標籤不可見,

ax.axis["bottom"].toggle(ticklabels=False)

若要讓所有刻度、刻度標籤和(軸)標籤不可見

ax.axis["bottom"].toggle(all=False)

若要關閉所有項目但開啟刻度

ax.axis["bottom"].toggle(all=False, ticks=True)

若要開啟所有項目但關閉(軸)標籤

ax.axis["bottom"].toggle(all=True, label=False)

ax.axis 的 __getitem__ 方法可以採用多個軸名稱。例如,若要開啟「上」和「右」軸的刻度標籤,

ax.axis["top", "right"].toggle(ticklabels=True)

請注意,ax.axis["top", "right"] 會傳回一個簡單的 Proxy 物件,該物件會將以上程式碼轉譯為如下程式碼。

for n in ["top", "right"]:
    ax.axis[n].toggle(ticklabels=True)

因此,for 迴圈中的任何傳回值都會被忽略。您不應將它用於簡單方法以外的任何用途。

就像清單索引 ":" 表示所有項目一樣,即

ax.axis[:].major_ticks.set_color("r")

變更所有軸的刻度色彩。

如何做#

  1. 變更刻度位置和標籤。

    與原始 Matplotlib 的軸相同

    ax.set_xticks([1, 2, 3])
    
  2. 變更軸屬性,例如色彩等。

    變更適當藝術家的屬性。例如,若要變更刻度標籤的色彩

    ax.axis["left"].major_ticklabels.set_color("r")
    
  3. 若要變更多個軸的屬性

    ax.axis["left", "bottom"].major_ticklabels.set_color("r")
    

    或變更所有軸的屬性

    ax.axis[:].major_ticklabels.set_color("r")
    
  4. 若要變更刻度大小(長度),您需要使用 axis.major_ticks.set_ticksize 方法。若要變更刻度方向(刻度預設與刻度標籤方向相反),請使用 axis.major_ticks.set_tick_out 方法。

    若要變更刻度和刻度標籤之間的間距,請使用 axis.major_ticklabels.set_pad 方法。

    若要變更刻度標籤和軸標籤之間的間距,請使用 axis.label.set_pad 方法。

刻度標籤的旋轉和對齊#

這也與標準 Matplotlib 非常不同,而且可能會造成混淆。當您想要旋轉刻度標籤時,請先考慮使用 "set_axis_direction" 方法。

ax1.axis["left"].major_ticklabels.set_axis_direction("top")
ax1.axis["right"].label.set_axis_direction("left")
../../../_images/sphx_glr_simple_axis_direction01_001.png

set_axis_direction 的參數是 ["left"、"right"、"bottom"、"top"] 其中之一。

您必須了解方向的一些基本概念。

  • 有一個參考方向,其定義為座標增加時軸線的方向。例如,左 x 軸的參考方向是從下到上。

    刻度、刻度標籤和軸標籤的方向、文字角度和對齊方式是根據參考方向來判斷的

  • label_directionticklabel_direction 是參考方向的右側 (+) 或左側 (-)。

  • 刻度預設會朝向與刻度標籤相反的方向繪製。

  • 刻度標籤和標籤的文字旋轉方向分別參考 ticklabel_directionlabel_direction 屬性決定。刻度標籤和標籤的旋轉是錨定的。

../../../_images/sphx_glr_axis_direction_001.png

另一方面,還有一個「axis_direction」的概念。這是針對每個「底部」、「左側」、「頂部」和「右側」軸的上述屬性的預設設定。

axislabel 屬性預設值#

參考方向

標籤方向

標籤旋轉

水平對齊

垂直對齊

'-'

180

置中

底部

'+'

0

置中

頂部

'+'

0

置中

頂部

'-'

180

置中

底部

ticklabel 屬性預設值#

參考方向

標籤方向

標籤旋轉

水平對齊

垂直對齊

'-'

90

置中

底部

'+'

0

置中

基準線

'+'

-90

置中

頂部

'-'

180

置中

基準線

並且,'set_axis_direction("top")' 表示調整文字旋轉等設定,使其適用於「頂部」軸。軸方向的概念在彎曲軸中會更為清晰。

../../../_images/sphx_glr_demo_axis_direction_001.png

axis_direction 可以在 AxisArtist 層級調整,也可以在其子繪圖物件(例如,刻度、刻度標籤和軸標籤)的層級調整。

ax1.axis["left"].set_axis_direction("top")

會變更與「左」軸相關的所有繪圖物件的 axis_direction,而

ax1.axis["left"].major_ticklabels.set_axis_direction("top")

只會變更主要刻度標籤的 axis_direction。請注意,在 AxisArtist 層級設定 set_axis_direction 會變更 ticklabel_direction 和 label_direction,而變更刻度、刻度標籤和軸標籤的 axis_direction 不會影響它們。

如果您想讓刻度向外,刻度標籤在軸內,請使用 invert_ticklabel_direction 方法。

ax.axis[:].invert_ticklabel_direction()

一個相關的方法是「set_tick_out」。它會讓刻度向外(事實上,它會讓刻度朝向與預設方向相反的方向)。

ax.axis[:].major_ticks.set_tick_out(True)
../../../_images/sphx_glr_simple_axis_direction03_001.png

總結來說,

  • AxisArtist 的方法

    • set_axis_direction:「左」、「右」、「底部」或「頂部」

    • set_ticklabel_direction:「+」或「-」

    • set_axislabel_direction:「+」或「-」

    • invert_ticklabel_direction

  • 刻度的方法(major_ticks 和 minor_ticks)

    • set_tick_out:True 或 False

    • set_ticksize:以點為單位的尺寸

  • 刻度標籤的方法(major_ticklabels 和 minor_ticklabels)

    • set_axis_direction:「左」、「右」、「底部」或「頂部」

    • set_rotation:相對於參考方向的角度

    • set_ha 和 set_va:請參閱下方

  • 軸標籤的方法(label)

    • set_axis_direction:「左」、「右」、「底部」或「頂部」

    • set_rotation:相對於參考方向的角度

    • set_ha 和 set_va

調整刻度標籤對齊方式#

刻度標籤的對齊方式會經過特殊處理。請參閱下方

../../../_images/sphx_glr_demo_ticklabel_alignment_001.png

調整間距#

要變更刻度和刻度標籤之間的間距

ax.axis["left"].major_ticklabels.set_pad(10)

或刻度標籤和軸標籤之間的間距

ax.axis["left"].label.set_pad(10)
../../../_images/sphx_glr_simple_axis_pad_001.png

GridHelper#

要實際定義曲線座標,您必須使用自己的網格輔助器。提供了一個通用版本的網格輔助器類別,此類別應足以應付大多數情況。使用者可以提供兩個函數,定義從曲線座標到(直線)圖像座標的轉換(及其反向配對)。請注意,雖然刻度和網格是針對曲線座標繪製的,但軸本身的資料轉換 (ax.transData) 仍然是直線(圖像)座標。

from mpl_toolkits.axisartist.grid_helper_curvelinear \
     import GridHelperCurveLinear
from mpl_toolkits.axisartist import Axes

# from curved coordinate to rectlinear coordinate.
def tr(x, y):
    x, y = np.asarray(x), np.asarray(y)
    return x, y-x

# from rectlinear coordinate to curved coordinate.
def inv_tr(x, y):
    x, y = np.asarray(x), np.asarray(y)
    return x, y+x

grid_helper = GridHelperCurveLinear((tr, inv_tr))

fig.add_subplot(axes_class=Axes, grid_helper=grid_helper)

您可以使用 Matplotlib 的 Transform 實例來代替(但必須定義反向轉換)。通常,曲線座標系統中的座標範圍可能有限,或可能有循環。在這些情況下,需要更客製化的網格輔助器版本。

import mpl_toolkits.axisartist.angle_helper as angle_helper

# PolarAxes.PolarTransform takes radian. However, we want our coordinate
# system in degree
tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()

# extreme finder: find a range of coordinate.
# 20, 20: number of sampling points along x, y direction
# The first coordinate (longitude, but theta in polar)
#   has a cycle of 360 degree.
# The second coordinate (latitude, but radius in polar)  has a minimum of 0
extreme_finder = angle_helper.ExtremeFinderCycle(20, 20,
                                                 lon_cycle=360,
                                                 lat_cycle=None,
                                                 lon_minmax=None,
                                                 lat_minmax=(0, np.inf),
                                                 )

# Find a grid values appropriate for the coordinate (degree,
# minute, second). The argument is a approximate number of grids.
grid_locator1 = angle_helper.LocatorDMS(12)

# And also uses an appropriate formatter.  Note that the acceptable Locator
# and Formatter classes are different than that of Matplotlib's, and you
# cannot directly use Matplotlib's Locator and Formatter here (but may be
# possible in the future).
tick_formatter1 = angle_helper.FormatterDMS()

grid_helper = GridHelperCurveLinear(tr,
                                    extreme_finder=extreme_finder,
                                    grid_locator1=grid_locator1,
                                    tick_formatter1=tick_formatter1
                                    )

同樣地,軸的 *transData* 仍然是直線座標(圖像座標)。您可以手動執行兩個座標之間的轉換,也可以為了方便起見而使用 Parasite Axes。

ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper)

# A parasite axes with given transform
ax2 = ax1.get_aux_axes(tr, "equal")
# note that ax2.transData == tr + ax1.transData
# Anything you draw in ax2 will match the ticks and grids of ax1.
../../../_images/sphx_glr_demo_curvelinear_grid_001.png

FloatingAxis#

浮動軸是指其中一個資料座標固定的軸,也就是說,它的位置不是固定在 Axes 座標中,而是隨著軸的資料限制變更而變更。可以使用 *new_floating_axis* 方法建立浮動軸。但是,您有責任將產生的 AxisArtist 正確新增至軸。建議的方法是將其作為軸的 axis 屬性的項目新增。

# floating axis whose first (index starts from 0) coordinate
# (theta) is fixed at 60

ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 60)
axis.label.set_text(r"$\theta = 60^{\circ}$")
axis.label.set_visible(True)

請參閱此頁的第一個範例。

目前限制和待辦事項#

程式碼需要更多精煉。以下是不完整的問題和待辦事項清單

  • 沒有簡單的方法來支援使用者客製化的刻度位置(針對曲線網格)。需要建立新的 Locator 類別。

  • FloatingAxis 可能有座標限制,例如,x = 0 的浮動軸,但 y 僅從 0 跨越到 1。

  • FloatingAxis 的軸標籤位置需要選擇性地以座標值給定。例如,x=0 的浮動軸,標籤在 y=1