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 类,其中每个轴(左、右、上、下)都有一个单独的关联艺术家,负责绘制轴线、刻度线、刻度标签和标签。您还可以创建自己的轴,它可以穿过轴坐标中的固定位置,或穿过数据坐标中的固定位置(即,当 viewlimit 更改时,轴会浮动)。

默认情况下,axes 类使其 xaxis 和 yaxis 不可见,并有 4 个额外的艺术家负责绘制“左”、“右”、“下”和“上”的 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 类分离,而 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"] 返回一个简单的代理对象,该对象将上面的代码转换为类似于下面的代码。

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”的概念。这是每个“bottom”、“left”、“top”和“right”轴的上述属性的默认设置。

axislabel 属性默认值#

参考方向

标签方向

标签旋转

水平对齐

垂直对齐

'-'

180

中心

底部

'+'

0

中心

顶部

'+'

0

中心

顶部

'-'

180

中心

底部

ticklabel 属性默认值#

参考方向

标签方向

标签旋转

水平对齐

垂直对齐

'-'

90

中心

底部

'+'

0

中心

基线

'+'

-90

中心

顶部

'-'

180

中心

基线

并且,'set_axis_direction("top")' 表示调整文本旋转等设置,使其适合 "top" 轴。 轴方向的概念在弯曲轴上会更清晰。

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

轴方向可以在 AxisArtist 级别调整,也可以在其子艺术家(即刻度、刻度标签和轴标签)的级别调整。

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

更改与 "left" 轴关联的所有艺术家的 axis_direction,而

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

仅更改 major_ticklabels 的 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: "left", "right", "bottom", 或 "top"

    • 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: "left", "right", "bottom", 或 "top"

    • set_rotation: 相对于参考方向的角度

    • set_ha 和 set_va: 请参见下文

  • 轴标签的方法 (label)

    • set_axis_direction: "left", "right", "bottom", 或 "top"

    • 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 仍然是直线坐标(图像坐标)。您可以手动在两个坐标之间进行转换,或者可以使用寄生轴来方便操作。

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#

浮动轴是其中一个数据坐标固定的轴,即它的位置不是固定在轴坐标系中,而是随着轴数据限制的更改而更改。可以使用 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。