axisartist 工具包#
警告
axisartist 使用了一个自定义的 Axes 类(派生自 Matplotlib 的原始 Axes 类)。因此,一些命令(主要是与刻度相关的)可能无法正常工作。
The axisartist 包含一个自定义的 Axes 类,旨在支持曲线网格(例如,天文学中的世界坐标系)。与 Matplotlib 的原始 Axes 类使用 Axes.xaxis 和 Axes.yaxis 来绘制刻度、刻度线等不同,axisartist 使用一个特殊的艺术家(AxisArtist)来处理曲线坐标系统的刻度、刻度线等。
由于使用了特殊艺术家,一些在 Axes.xaxis 和 Axes.yaxis 上工作的 Matplotlib 命令可能无法正常工作。
axisartist#
axisartist 模块提供了一个自定义(且非常实验性的)Axes类,其中每个轴(左、右、上和下)都有一个单独关联的艺术家,负责绘制轴线、刻度、刻度标签和标签。您还可以创建自己的轴,它可以穿过轴坐标中的固定位置,或者数据坐标中的固定位置(即,当视图限制变化时,轴会浮动)。
轴类默认情况下,其 xaxis 和 yaxis 是不可见的,并且有 4 个额外的艺术家负责绘制 'left'、'right'、'bottom' 和 'top' 四个轴脊。它们可以通过 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)
也可以添加一个水平轴。例如,您可能在 y=0(数据坐标)处有一个水平轴。:
ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0)
或带有一定偏移的固定轴
# make new (right-side) yaxis, but with some offset
ax.axis["right2"] = ax.new_fixed_axis(loc="right", offset=(20, 0))
axisartist 与 ParasiteAxes#
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 的示例。
曲线网格#
AxisArtist 模块的动机是为了支持曲线网格和刻度。
浮动坐标轴#
AxisArtist 还支持外轴定义为浮动轴的浮动轴。
axisartist 命名空间#
The axisartist 命名空间包含一个派生的 Axes 实现。最大的不同在于,负责绘制轴线、刻度、刻度标签和轴标签的艺术家从 Matplotlib 的 Axis 类中分离出来,这些艺术家比原始 Matplotlib 中的艺术家要多得多。这一改变主要是为了支持曲线网格。以下是 mpl_toolkits.axisartist.Axes 与 Matplotlib 原始 Axes 的一些不同之处。
轴元素(轴线(脊柱)、刻度、刻度标签和轴标签)由一个 AxisArtist 实例绘制。与 Axis 不同,左、右、上和下轴由不同的艺术家绘制。并且它们中的每一个可能有不同的刻度位置和不同的刻度标签。
网格线由 Gridlines 实例绘制。这一改变的动机是,在曲线坐标系中,网格线可能不会穿过轴线(即,没有相关的刻度)。在原始的 Axes 类中,网格线与刻度绑定。
如果需要,刻度线可以旋转(即,沿着网格线)
总之,所有这些改变都是为了支持
a curvilinear grid.
浮动轴
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 的 xaxis 和 yaxis 的包装器,它的设计目的是以 Matplotlib 原始轴的工作方式工作。例如,使用 set_ticks 方法更改刻度位置等应按预期工作。但一般来说,艺术家属性的更改(例如,颜色)将不会生效,尽管已经做出了一些努力,使得一些经常更改的属性(颜色等)得到尊重。
AxisArtist#
AxisArtist 可以被视为一个包含以下属性的容器艺术家,这些属性将绘制刻度、标签等。
行
major_ticks, major_ticklabels
minor_ticks, minor_ticklabels
offsetText
标签
行#
源自 Line2D 类。负责绘制脊柱(?)线。
major_ticks, minor_ticks#
继承自 Line2D 类。注意,刻度是标记。
major_ticklabels, minor_ticklabels#
源自 Text。请注意,它不是一个 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")
更改所有轴的刻度颜色。
如何做#
更改刻度位置和标签。
与原始 Matplotlib 的轴相同:
ax.set_xticks([1, 2, 3])
更改轴属性,如颜色等。
更改适当艺术家的属性。例如,要更改刻度标签的颜色:
ax.axis["left"].major_ticklabels.set_color("r")
要更改多个轴的属性:
ax.axis["left", "bottom"].major_ticklabels.set_color("r")
或更改所有轴的属性:
ax.axis[:].major_ticklabels.set_color("r")
要更改刻度大小(长度),您需要使用 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")
set_axis_direction 的参数是以下之一:["left", "right", "bottom", "top"]。
你必须理解一些方向的基本概念。
存在一个参考方向,该方向定义为坐标增加的轴线方向。例如,左侧x轴的参考方向是从下到上。
刻度、刻度标签和轴标签的方向、文本角度和对齐方式是相对于参考方向确定的
label_direction 和 ticklabel_direction 要么是参考方向的右侧(+),要么是左侧(-)。
刻度线默认绘制在刻度标签的相反方向。
刻度标签和标签的文本旋转分别由 ticklabel_direction 或 label_direction 决定。刻度标签和标签的旋转是固定的。
另一方面,存在一个“轴方向”的概念。这是为每个“底部”、“左侧”、“顶部”和“右侧”轴的上述属性的默认设置。
参考方向 |
标签方向 |
标签旋转 |
水平对齐 |
垂直对齐 |
|---|---|---|---|---|
左 |
|
180 |
正确 |
中心 |
底部 |
'+' |
0 |
中心 |
顶部 |
正确 |
'+' |
0 |
正确 |
中心 |
顶部 |
|
180 |
中心 |
底部 |
参考方向 |
标签方向 |
标签旋转 |
水平对齐 |
垂直对齐 |
|---|---|---|---|---|
左 |
|
90 |
正确 |
中心 |
底部 |
'+' |
0 |
中心 |
基线 |
正确 |
'+' |
-90 |
正确 |
中心 |
顶部 |
|
180 |
中心 |
基线 |
并且,'set_axis_direction("top")' 意味着调整文本旋转等,以适应“顶部”轴的设置。轴方向的概念在曲线轴上可以更加清晰。
可以在 AxisArtist 级别或其子艺术家级别(即刻度、刻度标签和轴标签)调整 axis_direction。:
ax1.axis["left"].set_axis_direction("top")
更改与“左侧”轴关联的所有艺术家的轴方向,同时:
ax1.axis["left"].major_ticklabels.set_axis_direction("top")
仅更改 major_ticklabels 的 axis_direction。请注意,AxisArtist 级别的 set_axis_direction 会改变 ticklabel_direction 和 label_direction,而更改 ticks、ticklabels 和 axis-label 的 axis_direction 不会影响它们。
如果你想让刻度向外,刻度标签在坐标轴内,请使用 invert_ticklabel_direction 方法。:
ax.axis[:].invert_ticklabel_direction()
相关的方法是“set_tick_out”。它使刻度向外(实际上,它使刻度朝向与默认方向相反的方向)。:
ax.axis[:].major_ticks.set_tick_out(True)
所以,总之,
AxisArtist 的方法
set_axis_direction: "左", "右", "下", 或 "上"
set_ticklabel_direction: "+" 或 "-"
set_axislabel_direction: "+" 或 "-"
invert_ticklabel_direction
Ticks 的方法(major_ticks 和 minor_ticks)
set_tick_out: True 或 False
set_ticksize: 以点为单位的大小
TickLabels 的方法(major_ticklabels 和 minor_ticklabels)
set_axis_direction: "左", "右", "下", 或 "上"
set_rotation: 相对于参考方向的角度
set_ha 和 set_va: 见下文
AxisLabels 的方法 (标签)
set_axis_direction: "左", "右", "下", 或 "上"
set_rotation: 相对于参考方向的角度
set_ha 和 set_va
调整刻度标签对齐#
TickLabels 的对齐方式有特殊处理。见下文
调整垫片#
要更改刻度和刻度标签之间的填充
ax.axis["left"].major_ticklabels.set_pad(10)
或者刻度标签和轴标签
ax.axis["left"].label.set_pad(10)
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.
FloatingAxis#
浮动轴是一个数据坐标之一固定的轴,即其位置在Axes坐标中不是固定的,而是随着轴数据限制的变化而变化。浮动轴可以使用 new_floating_axis 方法创建。然而,确保生成的AxisArtist正确添加到轴中是你的责任。推荐的方法是将其作为Axes的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 轴浮动在 x = 0,但 y 轴仅从 0 到 1 之间。
FloatingAxis 的轴标签位置需要可选地以坐标值给出。例如,x=0 的浮动轴,标签位于 y=1。