资讯详情

Matplotlib进阶教程:工具包

343f64ab75fb878dbcb21217ce2ac5b1.gif

回复后台【读书】

即可获取python相关电子书~

Hi,我是山月。

今天给大家介绍一下Matplotlib最后一个系列教程:介绍三个工具包。

今天的课程结束后,这个系列结束了。感兴趣的学生可以从零开始学习~

01

axes_grid1 工具包

mpl_toolkits.axes_grid1 是辅助类的集合,可以轻松使用matplotlib图像显示(多个)。

其中ImageGrid、RGB Axes 和 AxesDivider 是调整(多)Axes 位置辅助类。它们提供一个框架,可以在绘图时调整多个框架axes的位置。

ParasiteAxes 提供类似 twinx(或 twiny)这样你就可以拥有相同的功能 Axes 绘制不同的数据(例如,不同的数据) y 比例)。

AnchoredArtists 包括放置在固定位置的自定义artists,例如图例。

创建Axes网格的类。

在 matplotlib 中,Axes标准图形坐标中指定的位置(和大小)。这可能不理想图像需要以给定的纵横比显示。

例如,在 matplotlib 不能轻易显示相同大小的图像,并在它们之间设置一些固定的间距。在这种情况下可以使用 ImageGrid。

importmatplotlib.pyplotasplt frommpl_toolkits.axes_grid1importImageGrid importnumpyasnp  im1=np.arange(100).reshape((10,10)) im2=im1.T im3=np.flipud(im1) im4=np.fliplr(im2)  fig=plt.figure(figsize=(4.,4.)) grid=ImageGrid(fig,111,#类似于subplot(111) nrows_ncols=(2,2),#创建axes的2x2网格 axes_pad=0.1,#以英寸为单位axes填充距离。 )  forax,iminzip(grid,[im1,im2,im3,im4]): #迭代并返回网格Axes。 ax.imshow(im)  plt.show()

效果:

每个axes的位置会在绘图时确定,以便整个网格的大小适合给定的矩形。请注意,在此示例中,即使你更改了图形大小,axes间距也是固定的。

同一列中的axes宽度相同(在图形坐标中),在同一行中axes高度相同。在同一行(列)中axes宽度(高度)根据其视图限制(xlim 或 ylim)进行缩放。

importmatplotlib.pyplotasplt frommpl_toolkits.axes_grid1importImageGrid  defget_demo_image(): importnumpyasnp frommatplotlib.cbookimportget_sample_data f=get_sample_data("axes_grid/bivariate_normal.npy",asfileobj=False) z=np.load(f) #Z是15x15的numpy数组 returnz,(-3,4,-4,3)   fig=plt.figure(figsize=(5.5,3.5)) grid=ImageGrid(fig,111,#类似于subplot(111) nrows_ncols=(1,3), axes_pad=0.1, label_mode="L", )  Z,extent=get_demo_image()  im1=Z im2=Z[:,:10] im3=Z[:,10:] vmin,vmax=Z.min(),Z.max() forax,iminzip(grid,[im1,im2,im3]): ax.imshow(im,origin="lower",vmin=vmin,vmax=vmax, interpolation="nearest")  plt.show()

效果:

xaxis 在同一列中axes共享。yaxis 在同一行 axes之间共享。

因此,通过绘图命令或在交互式后端使用鼠标来更改 axes属性(视图限制、刻度位置等)会影响所有其他共享 axes。

初始化时,ImageGrid 会创建给定数量的 Axes 实例(如果 ngrids 为 None,则为 ngrids 或 ncols * nrows)。每个接口可以通过类似的序列访问 Axes 例如,grid[0] 是网格中的第一个 Axes)。

ImageGrid接受以下参数:

1)rect

指定网格的位置。可指定矩形坐标(例如,Axes中的 (0.1, 0.1, 0.8, 0.8))或类似子图的位置(例如,121)。

2)direction

表示axes数量的增加方向。

对行:

grid[0] grid[1]
grid[2] grid[3]

对于“列”:

grid[0] grid[2]
grid[1] grid[3]

3)aspect

默认情况下(False),网格中axes的宽度和高度是独立缩放的。如果为 True,它们将根据其数据限制进行缩放。

4)share_all如果为 True,则共享所有axes的 xaxis 和 yaxis。

你还可以创建一个(或多个)颜色条。并且可以为每个axes设置颜色条 (cbar_mode="each"),或为网格设置一个颜色条 (cbar_mode="single")。

颜色条可以放在你的右侧或顶部。每个颜色条的axes存储为 cbar_axes 属性。

下面的示例显示了你可以使用 ImageGrid 做什么。

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid

def get_demo_image():
    import numpy as np
    from matplotlib.cbook import get_sample_data
    f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
    z = np.load(f)
    # Z是15x15的numpy数组
    return z, (-3, 4, -4, 3)

def demo_simple_grid(fig):
    """
    一个2x2图像的网格,图像之间有0.05英寸的填充距,只有左下轴被标记。
    """
    grid = ImageGrid(fig, 141,  # 类似于 subplot(141)
                     nrows_ncols=(2, 2),
                     axes_pad=0.05,
                     label_mode="1",
                     )
    Z, extent = get_demo_image()
    for ax in grid:
        ax.imshow(Z, extent=extent, interpolation="nearest")
    # 这只影响第一列和第二行中的轴,因为share_all=False。
    grid.axes_llc.set_xticks([-2, 0, 2])
    grid.axes_llc.set_yticks([-2, 0, 2])


def demo_grid_with_single_cbar(fig):
    """
    带有单色条的2x2图像网格
    """
    grid = ImageGrid(fig, 142,  # 类似于 subplot(142)
                     nrows_ncols=(2, 2),
                     axes_pad=0.0,
                     share_all=True,
                     label_mode="L",
                     cbar_location="top",
                     cbar_mode="single",
                     )

    Z, extent = get_demo_image()
    for ax in grid:
        im = ax.imshow(Z, extent=extent, interpolation="nearest")
    grid.cbar_axes[0].colorbar(im)

    for cax in grid.cbar_axes:
        cax.toggle_label(False)

    # 这将影响所有轴,因为share_all = True。
    grid.axes_llc.set_xticks([-2, 0, 2])
    grid.axes_llc.set_yticks([-2, 0, 2])

def demo_grid_with_each_cbar(fig):
    """
    一个2x2图像的网格。每个图像都有自己的颜色条。
    """
    grid = ImageGrid(fig, 143,  # 类似于 subplot(143)
                     nrows_ncols=(2, 2),
                     axes_pad=0.1,
                     label_mode="1",
                     share_all=True,
                     cbar_location="top",
                     cbar_mode="each",
                     cbar_size="7%",
                     cbar_pad="2%",
                     )
    Z, extent = get_demo_image()
    for ax, cax in zip(grid, grid.cbar_axes):
        im = ax.imshow(Z, extent=extent, interpolation="nearest")
        cax.colorbar(im)
        cax.toggle_label(False)

    # 这影响了所有的轴,因为我们设置了 share_all = True.
    grid.axes_llc.set_xticks([-2, 0, 2])
    grid.axes_llc.set_yticks([-2, 0, 2])


def demo_grid_with_each_cbar_labelled(fig):
    """
    个2x2图像的网格。每个图像都有自己的颜色条。
    """
    grid = ImageGrid(fig, 144,  # 类似于 subplot(144)
                     nrows_ncols=(2, 2),
                     axes_pad=(0.45, 0.15),
                     label_mode="1",
                     share_all=True,
                     cbar_location="right",
                     cbar_mode="each",
                     cbar_size="7%",
                     cbar_pad="2%",
                     )
    Z, extent = get_demo_image()

    # 每次使用不同的颜色条范围
    limits = ((0, 1), (-2, 2), (-1.7, 1.4), (-1.5, 1))
    for ax, cax, vlim in zip(grid, grid.cbar_axes, limits):
        im = ax.imshow(Z, extent=extent, interpolation="nearest",
                       vmin=vlim[0], vmax=vlim[1])
        cb = cax.colorbar(im)
        cb.set_ticks((vlim[0], vlim[1]))

    # 这影响了所有的轴,因为我们设置了share_all = True.
    grid.axes_llc.set_xticks([-2, 0, 2])
    grid.axes_llc.set_yticks([-2, 0, 2])


fig = plt.figure(figsize=(10.5, 2.5))
fig.subplots_adjust(left=0.05, right=0.95)

demo_simple_grid(fig)
demo_grid_with_single_cbar(fig)
demo_grid_with_each_cbar(fig)
demo_grid_with_each_cbar_labelled(fig)

plt.show()

效果:

在幕后,ImageGrid 类和 RGBAxes 类利用了 AxesDivider 类,其作用是在绘制时计算axes的位置。但大多数用户都不需要直接使用 AxesDivider 类。

axes_divider 模块提供了一个辅助函数 make_axes_locatable,它采用现有的axes实例并为其创建分隔线。

ax = subplot(1, 1, 1)
divider = make_axes_locatable(ax)

make_axes_locatable 返回 AxesDivider 类的实例。它提供了一个 append_axes 方法,该方法在原始axes的给定侧(“top”、“right”、“bottom”和“left”)创建一个新axes。

高度(或宽度)与主axes同步的颜色条:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

ax = plt.subplot(111)
im = ax.imshow(np.arange(100).reshape((10, 10)))

#在ax的右侧创建一个坐标轴。cax的宽度为ax的5%,cax和ax之间的填充距固定为0.05英寸。
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

plt.colorbar(im, cax=cax)

plt.show()

效果:

可以使用 make_axes_locatable 重写带有直方图的散点图示例:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

# 为再现性固定随机状态
np.random.seed(19680801)

# 随机数据
x = np.random.randn(1000)
y = np.random.randn(1000)


fig, ax = plt.subplots(figsize=(5.5, 5.5))

# 散点图:
ax.scatter(x, y)

# 设置主axes的方向。
ax.set_aspect(1.)

# 在当前axes的右侧和顶部创建新的axes
divider = make_axes_locatable(ax)
# 高度和填充距的单位是英寸
ax_histx = divider.append_axes("top", 1.2, pad=0.1, sharex=ax)
ax_histy = divider.append_axes("right", 1.2, pad=0.1, sharey=ax)

# 使一些标签不可见
ax_histx.xaxis.set_tick_params(labelbottom=False)
ax_histy.yaxis.set_tick_params(labelleft=False)

# 手动确定极限:
binwidth = 0.25
xymax = max(np.max(np.abs(x)), np.max(np.abs(y)))
lim = (int(xymax/binwidth) + 1)*binwidth

bins = np.arange(-lim, lim + binwidth, binwidth)
ax_histx.hist(x, bins=bins)
ax_histy.hist(y, bins=bins, orientation='horizontal')

# ax_histx的x轴和ax_history的y轴与ax共用,因此不需要手动调整这些轴的xlim和ylim。

ax_histx.set_yticks([0, 50, 100])
ax_histy.set_xticks([0, 50, 100])

plt.show()

效果:

ParasiteAxes 是一个寄生axes,其位置与其宿主axes相同。该位置会在绘图时调整,因此即使宿主axes改变了位置,它也能工作。

创建一个宿主axes的方法:使用 host_subplot 或 host_axes 命令。

创建寄生axes的方法:twinx, twiny和 twin。

示例 1( twinx):

from mpl_toolkits.axes_grid1 import host_subplot
import matplotlib.pyplot as plt

host = host_subplot(111)

par = host.twinx()

host.set_xlabel("Distance")
host.set_ylabel("Density")
par.set_ylabel("Temperature")

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par.plot([0, 1, 2], [0, 3, 2], label="Temperature")

leg = plt.legend()

host.yaxis.get_label().set_color(p1.get_color())
leg.texts[0].set_color(p1.get_color())

par.yaxis.get_label().set_color(p2.get_color())
leg.texts[1].set_color(p2.get_color())

plt.show()

效果:

示例 2(twin):

如果没有transform参数,则假定寄生axes与宿主axes具有相同的数据转换。

这对设置顶部(或右侧)的轴与底部(或左侧)的轴具有不同的刻度位置、刻度标签很有用。

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot
import numpy as np

ax = host_subplot(111)
xx = np.arange(0, 2*np.pi, 0.01)
ax.plot(xx, np.sin(xx))

ax2 = ax.twin()  # ax2负责顶部轴和右侧轴
ax2.set_xticks([0., .5*np.pi, np.pi, 1.5*np.pi, 2*np.pi])
ax2.set_xticklabels(["$0$", r"$\frac{1}{2}\pi$",
                     r"$\pi$", r"$\frac{3}{2}\pi$", r"$2\pi$"])

ax2.axis["right"].major_ticklabels.set_visible(False)
ax2.axis["top"].major_ticklabels.set_visible(True)

plt.show()

效果:

下面是一个更复杂的使用twin的示例。请注意,如果更改宿主axes中的 x 限制,则寄生axes的 x 限制将相应更改。

import matplotlib.transforms as mtransforms
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.parasite_axes import SubplotHost

obs = [["01_S1", 3.88, 0.14, 1970, 63],
       ["01_S4", 5.6, 0.82, 1622, 150],
       ["02_S1", 2.4, 0.54, 1570, 40],
       ["03_S1", 4.1, 0.62, 2380, 170]]


fig = plt.figure()

ax_kms = SubplotHost(fig, 1, 1, 1, aspect=1.)

pm_to_kms = 1./206265.*2300*3.085e18/3.15e7/1.e5

aux_trans = mtransforms.Affine2D().scale(pm_to_kms, 1.)
ax_pm = ax_kms.twin(aux_trans)
ax_pm.set_viewlim_mode("transform")

fig.add_subplot(ax_kms)

for n, ds, dse, w, we in obs:
    time = ((2007 + (10. + 4/30.)/12) - 1988.5)
    v = ds / time * pm_to_kms
    ve = dse / time * pm_to_kms
    ax_kms.errorbar([v], [w], xerr=[ve], yerr=[we], color="k")


ax_kms.axis["bottom"].set_label("Linear velocity at 2.3 kpc [km/s]")
ax_kms.axis["left"].set_label("FWHM [km/s]")
ax_pm.axis["top"].set_label(r"Proper Motion [$''$/yr]")
ax_pm.axis["top"].label.set_visible(True)
ax_pm.axis["right"].major_ticklabels.set_visible(False)

ax_kms.set_xlim(950, 3700)
ax_kms.set_ylim(950, 3100)
# ax_pms的xlim和ylim将自动调整。

plt.show()

效果:

这是一个artist的集合,它们的位置像图例一样是固定在bbox上的。

它衍生于Matplotlib中的OffsetBox,并且需要在画布坐标中绘制artist。

import matplotlib.pyplot as plt

def draw_text(ax):
    """
    画两个文本框,分别固定在图的左上角。
    """
    from matplotlib.offsetbox import AnchoredText
    at = AnchoredText("Figure 1a",
                      loc='upper left', prop=dict(size=8), frameon=True,
                      )
    at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
    ax.add_artist(at)

    at2 = AnchoredText("Figure 1(b)",
                       loc='lower left', prop=dict(size=8), frameon=True,
                       bbox_to_anchor=(0., 1.),
                       bbox_transform=ax.transAxes
                       )
    at2.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
    ax.add_artist(at2)


def draw_circle(ax):
    """
    在轴坐标上画一个圆
    """
    from mpl_toolkits.axes_grid1.anchored_artists import AnchoredDrawingArea
    from matplotlib.patches import Circle
    ada = AnchoredDrawingArea(20, 20, 0, 0,
                              loc='upper right', pad=0., frameon=False)
    p = Circle((10, 10), 10)
    ada.da.add_artist(p)
    ax.add_artist(ada)


def draw_ellipse(ax):
    """
    在数据坐标中绘制一个宽=0.1,高=0.15的椭圆
    """
    from mpl_toolkits.axes_grid1.anchored_artists import AnchoredEllipse
    ae = AnchoredEllipse(ax.transData, width=0.1, height=0.15, angle=0.,
                         loc='lower left', pad=0.5, borderpad=0.4,
                         frameon=True)
                         
    ax.add_artist(ae)


def draw_sizebar(ax):
    """
    在数据坐标中绘制一个长度为0.1的水平条,下面有一个固定的标签。
    """
    from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
    asb = AnchoredSizeBar(ax.transData,
                          0.1,
                          r"1$^{\prime}$",
                          loc='lower center',
                          pad=0.1, borderpad=0.5, sep=5,
                          frameon=False)
    ax.add_artist(asb)


ax = plt.gca()
ax.set_aspect(1.)

draw_text(ax)
draw_circle(ax)
draw_ellipse(ax)
draw_sizebar(ax)

plt.show()

效果:

mpl_toolkits.axes_grid1.inset_locator 提供了辅助类和函数来将(插入的)axes放置在父axes的固定位置,类似于 AnchoredArtist。

使用 mpl_toolkits.axes_grid1.inset_locator.inset_axes()可以拥有固定大小的插入axes,或固定比例的父axes。

示例:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

fig, (ax, ax2) = plt.subplots(1, 2, figsize=[5.5, 2.8])

#在默认的右上角位置创建宽度为1.3英寸,高度为0.9英寸的插入
axins = inset_axes(ax, width=1.3, height=0.9)

# 在左下角创建宽度为父axes边框的30%,高度为父axes边框的40%的插入(loc=3)
axins2 = inset_axes(ax, width="30%", height="40%", loc=3)

# 在第2个子图中创建混合插入;宽度为父axes边框的30%,左上角高度为1英寸(loc=2)
axins3 = inset_axes(ax2, width="30%", height=1., loc=2)

# 在右下角(loc=4)用borderpad=1创建一个插入
axins4 = inset_axes(ax2, width="20%", height="20%", loc=4, borderpad=1)

# 关闭插入的标记
for axi in [axins, axins2, axins3, axins4]:
    axi.tick_params(labelleft=False, labelbottom=False)

plt.show()

效果:

当你希望inset表示父axes中的一小部分的放大时,可以使用 zoomed_inset_axes()。

并且 inset_locator 提供了一个辅助函数 mark_inset() 来标记由 inset axes表示的区域位置。

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes, mark_inset
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
import numpy as np

def get_demo_image():
    from matplotlib.cbook import get_sample_data
    import numpy as np
    f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
    z = np.load(f)
    # Z是15x15的numpy数组
    return z, (-3, 4, -4, 3)

fig, (ax, ax2) = plt.subplots(ncols=2, figsize=[6, 3])


# 第一个子图,显示带有尺寸条的插入。
ax.set_aspect(1)

axins = zoomed_inset_axes(ax, zoom=0.5, loc='upper right')
# 固定插入axes的刻度数
axins.yaxis.get_major_locator().set_params(nbins=7)
axins.xaxis.get_major_locator().set_params(nbins=7)

plt.setp(axins.get_xticklabels(), visible=False)
plt.setp(axins.get_yticklabels(), visible=False)


def add_sizebar(ax, size):
    asb = AnchoredSizeBar(ax.transData,
                          size,
                          str(size),
                          loc=8,
                          pad=0.1, borderpad=0.5, sep=5,
                          frameon=False)
    ax.add_artist(asb)

add_sizebar(ax, 0.5)
add_sizebar(axins, 0.5)


# 第二个子图,显示带有插入缩放和标记插入的图像
Z, extent = get_demo_image()
Z2 = np.zeros([150, 150], dtype="d")
ny, nx = Z.shape
Z2[30:30 + ny, 30:30 + nx] = Z

# extent = [-3, 4, -4, 3]
ax2.imshow(Z2, extent=extent, interpolation="nearest",
          origin="lower")


axins2 = zoomed_inset_axes(ax2, 6, loc=1)  # zoom = 6
axins2.imshow(Z2, extent=extent, interpolation="nearest",
              origin="lower")

# 原始图像的子区域
x1, x2, y1, y2 = -1.5, -0.9, -2.5, -1.9
axins2.set_xlim(x1, x2)
axins2.set_ylim(y1, y2)
# 固定插入axes的刻度数
axins2.yaxis.get_major_locator().set_params(nbins=7)
axins2.xaxis.get_major_locator().set_params(nbins=7)

plt.setp(axins2.get_xticklabels(), visible=False)
plt.setp(axins2.get_yticklabels(), visible=False)

# 绘制父axes中插入axes所在区域的方框,以及方框与插入axes区域之间的连接线
mark_inset(ax2, axins2, loc1=2, loc2=4, fc="none", ec="0.5")

plt.show()

效果:

RGBAxes 是一个辅助类,用来显示 RGB 合成图像。

像 ImageGrid 一样,可以调整axes的位置,以便它们占据的区域适合给定的矩形。

此外,每个axes的 xaxis 和 yaxis 是共享的。

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes

def get_demo_image():
    import numpy as np
    from matplotlib.cbook import get_sample_data
    f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
    z = np.load(f)
    return z, (-3, 4, -4, 3)

def get_rgb():
    Z, extent = get_demo_image()

    Z[Z < 0] = 0.
    Z = Z / Z.max()

    R = Z[:13, :13]
    G = Z[2:, 2:]
    B = Z[:13, 2:]

    return R, G, B

fig = plt.figure()
ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8])

r, g, b = get_rgb() # r, g, b 是二维图像
kwargs = dict(origin="lower", interpolation="nearest")
ax.imshow_rgb(r, g, b, **kwargs)

ax.RGB.set_xlim(0., 9.5)
ax.RGB.set_ylim(0.9, 10.6)

plt.show()

效果:

mpl_toolkits.axes_grid1.axes_divider 模块提供了辅助类来在绘图时调整一组图像的axes位置。

  • axes_size 提供了一类单位,用于确定每个axes的大小,比如可以指定固定大小。

  • Divider 是计算axes位置的类。它将给定的矩形区域划分为几个区域,然后通过设置分隔符所基于的水平和垂直大小列表来初始化分隔符。最后使用 new_locator(),它会返回一个可调用对象,可用于设置axes的 axes_locator。

示例:

import mpl_toolkits.axes_grid1.axes_size as Size # mpl_toolkits.axes_grid1.axes_size 包含了几个可用于设置水平和垂直配置的类。
from mpl_toolkits.axes_grid1 import Divider
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(5.5, 4.))

# 当我们设置axes_locator时,rect参数将被忽略
rect = (0.1, 0.1, 0.8, 0.8) #  rect 是将被划分的方框的边界
ax = [fig.add_axes(rect, label="%d" % i) for i in range(4)]

horiz = [Size.Scaled(1.5), Size.Fixed(.5), Size.Scaled(1.),
         Size.Scaled(.5)]

vert = [Size.Scaled(1.), Size.Fixed(.5), Size.Scaled(1.5)]

# 将axes矩形划分为网格,网格的大小由水平*垂直指定
divider = Divider(fig, rect, horiz, vert, aspect=False)

ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0)) # 创建一个locator实例,该实例将提供给 axes对象
ax[1].set_axes_locator(divider.new_locator(nx=0, ny=2))
ax[2].set_axes_locator(divider.new_locator(nx=2, ny=2))
ax[3].set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0))

for ax1 in ax:
    ax1.tick_params(labelbottom=False, labelleft=False)

plt.show()

效果:

你也可以根据其 x 或 y 数据限制(AxesX 和 AxesY)调整每个轴的大小。

import mpl_toolkits.axes_grid1.axes_size as Size
from mpl_toolkits.axes_grid1 import Divider
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(5.5, 4))

# 当我们设置axes_locator时,rect参数将被忽略
rect = (0.1, 0.1, 0.8, 0.8)
ax = [fig.add_axes(rect, label="%d" % i) for i in range(4)]


horiz = [Size.AxesX(ax[0]), Size.Fixed(.5), Size.AxesX(ax[1])]
vert = [Size.AxesY(ax[0]), Size.Fixed(.5), Size.AxesY(ax[2])]

#  将axes矩形划分为网格,网格的大小由水平*垂直指定
divider = Divider(fig, rect, horiz, vert, aspect=False)


ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0))
ax[1].set_axes_locator(divider.new_locator(nx=2, ny=0))
ax[2].set_axes_locator(divider.new_locator(nx=0, ny=2))
ax[3].set_axes_locator(divider.new_locator(nx=2, ny=2))

ax[0].set_xlim(0, 2)
ax[1].set_xlim(0, 1)

ax[0].set_ylim(0, 1)
ax[2].set_ylim(0, 2)

divider.set_aspect(1.)

for ax1 in ax:
    ax1.tick_params(labelbottom=False, labelleft=False)

plt.show()

效果:

02

axisartist 工具包

axisartist 包含一个自定义 Axes 类,可以支持曲线网格(例如,天文学中的世界坐标系)。

与 Matplotlib 的原始 Axes 类使用 Axes.xaxis 和 Axes.yaxis 来绘制刻度线、刻度线等不同。

axisartist 使用了一个特殊的artist(AxisArtist)来处理曲线坐标系的刻度线、刻度线等。

注意:由于使用了特殊的artist,一些适用于 Axes.xaxis 和 Axes.yaxis 的 Matplotlib 命令可能不起作用。

axisartist 模块提供了一个自定义的Axes 类,其中每个轴(左、右、上和下)都有一个单独关联的artist负责绘制轴线、刻度、刻度标签和标签。

你还可以创建自己的轴,该轴可以穿过轴坐标中的固定位置,或数据坐标中的固定位置(即,当 viewlimit 变化时,轴会浮动)。

默认情况下,axis类的 xaxis 和 yaxis 是不可见的,并且有 4 个额外的artist负责绘制“left”、“right”、“bottom”和“top”中的 4 个轴。

它们以 ax.axis["left"]、ax.axis["right"] 等方式访问,即 ax.axis 是一个包含artist的字典(请注意,ax.axis 仍然是一个可调用的方法,它表现为 Matplotlib 中的原始 Axes.axis 方法)。

创建axes:

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

创建一个子图:

ax = AA.Subplot(fig, 111)
fig.add_subplot(ax)

示例:

import matplotlib.pyplot as plt
from mpl_toolkits.axisartist.axislines import Subplot

fig = plt.figure(figsize=(3, 3))

# 创建一个子图
ax = Subplot(fig, 111)
fig.add_subplot(ax)

# 隐藏右侧和顶部的坐标轴
ax.axis["right"].set_visible(False)
ax.axis["top"].set_visible(False)

plt.show()

效果:

在y=0处添加一个横轴(在数据坐标中):

import matplotlib.pyplot as plt
import mpl_toolkits.axisartist as AA

fig = plt.figure()
fig.subplots_adjust(right=0.85)
ax = AA.Subplot(fig, 1, 1, 1)
fig.add_subplot(ax)

# 使一些轴不可见
ax.axis["bottom", "top", "right"].set_visible(False)

# 沿着经过y=0的第一个轴(x轴)创建一个新轴。
ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0,
                                      axis_direction="bottom")
ax.axis["y=0"].toggle(all=True)
ax.axis["y=0"].label.set_text("y = 0")

ax.set_ylim(-2, 4)

plt.show()

效果:

或带有一些偏移的固定轴:

# 制作新的(右侧)yaxis,但有一些偏移
ax.axis["right2"] = ax.new_fixed_axis(loc="right",
              offset=(20, 0))

axes_grid1 工具包中的大多数命令都可以使用 axes_class 关键字参数,并且这些命令会创建给定类的axes。

示例:

from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import matplotlib.pyplot as plt

host = host_subplot(111, axes_class=AA.Axes)
plt.subplots_adjust(right=0.75)

par1 = host.twinx()
par2 = host.twinx()

offset = 60
new_fixed_axis = par2.get_grid_helper().new_fixed_axis
par2.axis["right"] = new_fixed_axis(loc="right",
                                    axes=par2,
                                    offset=(offset, 0))

par1.axis["right"].toggle(all=True)
par2.axis["right"].toggle(all=True)

host.set_xlim(0, 2)
host.set_ylim(0, 2)

host.set_xlabel("Distance")
host.set_ylabel("Density")
par1.set_ylabel("Temperature")
par2.set_ylabel("Velocity")

p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density")
p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature")
p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity")

par1.set_ylim(0, 4)
par2.set_ylim(1, 65)

host.legend()

host.axis["left"].label.set_color(p1.get_color())
par1.axis["right"].label.set_color(p2.get_color())
par2.axis["right"].label.set_color(p3.get_color())

plt.show()

效果:

AxisArtist模块背后的动机是支持曲线网格和刻度。

示例:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.projections import PolarAxes
from matplotlib.transforms import Affine2D

from mpl_toolkits.axisartist import (
    angle_helper, Subplot, SubplotHost, ParasiteAxesAuxTrans)
from mpl_toolkits.axisartist.grid_helper_curvelinear import (
    GridHelperCurveLinear)


def curvelinear_test1(fig):
    """用于自定义转换的网格。"""

    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y - x

    def inv_tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    # ax1将有一个刻度和网格线,由给定的transform (+ transData of the Axes)定义。注意,坐标轴本身的转换(即transData)不受给定转换的影响。

    fig.add_subplot(ax1)

    xx, yy = tr([3, 6], [5, 10])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1)
    ax1.set_xlim(0, 10)
    ax1.set_ylim(0, 10)

    ax1.axis["t"] = ax1.new_floating_axis(0, 3)
    ax1.axis["t2"] = ax1.new_floating_axis(1, 7)
    ax1.grid(True, zorder=0)


def curvelinear_test2(fig):
    """
    极坐标投影,不过是在矩形框里
    """

    # PolarAxes.PolarTransform 采取弧度。但是,我们想要我们的坐标
    tr = Affine2D().scale(np.pi/180, 1) + PolarAxes.PolarTransform()
    # 极坐标投影,涉及周期,也有其坐标的限制,需要一个特殊的方法来找到极值(视图内坐标的最小值,最大值)。
    extreme_finder = angle_helper.ExtremeFinderCycle(
        nx=20, ny=20,  # 每个方向的采样点数。
        lon_cycle=360, lat_cycle=None,
        lon_minmax=None, lat_minmax=(0, np.inf),
    )
    # 找到适合坐标的网格值(度、分、秒)。
    grid_locator1 = angle_helper.LocatorDMS(12)
    # 使用适当的格式化程序。请注意,可接受的Locator和Formatter类与Matplotlib类略有不同,Matplotlib不能直接在这里使用。
    tick_formatter1 = angle_helper.FormatterDMS()

    grid_helper = GridHelperCurveLinear(
        tr, extreme_finder=extreme_finder,
        grid_locator1=grid_locator1, tick_formatter1=tick_formatter1)
    ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper)

    # 使右轴和顶轴的标记可见。
    ax1.axis["right"].major_ticklabels.set_visible(True)
    ax1.axis["top"].major_ticklabels.set_visible(True)
    # 让右轴显示第一个坐标(角度)的标签
    ax1.axis["right"].get_helper().nth_coord_ticks = 0
    # 让底部轴显示第二坐标(半径)的标签
    ax1.axis["bottom"].get_helper().nth_coord_ticks = 1

    fig.add_subplot(ax1)

    ax1.set_aspect(1)
    ax1.set_xlim(-5, 12)
    ax1.set_ylim(-5, 10)

    ax1.grid(True, zorder=0)

    # 寄生axes具有给定的变换
    ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal")
    # 请注意 ax2.transData == tr + ax1.transData。你在ax2中画的任何东西都将匹配ax1中的刻度和网格。
    ax1.parasites.append(ax2)
    ax2.plot(np.linspace(0, 30, 51), np.linspace(10, 10, 51), linewidth=2)


if __name__ == "__main__":
    fig = plt.figure(figsize=(7, 4))

    curvelinear_test1(fig)
    curvelinear_test2(fig)

    plt.show()

效果:

AxisArtister还支持一个浮动Axes,其外部轴定义为浮动轴。

示例:

from matplotlib.transforms import Affine2D
import mpl_toolkits.axisartist.floating_axes as floating_axes
import numpy as np
import mpl_toolkits.axisartist.angle_helper as angle_helper
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist.grid_finder import (FixedLocator, MaxNLocator,
                                                 DictFormatter)
import matplotlib.pyplot as plt

# 为再现性固定随机状态
np.random.seed(19680801)


def setup_axes1(fig, rect):

    tr = Affine2D().scale(2, 1).rotate_deg(30)

    grid_helper = floating_axes.GridHelperCurveLinear(
        tr, extremes=(-0.5, 3.5, 0, 4),
        grid_locator1=MaxNLocator(nbins=4),
        grid_locator2=MaxNLocator(nbins=4))

    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
    fig.add_subplot(ax1)

    aux_ax = ax1.get_aux_axes(tr)

    return ax1, aux_ax


def setup_axes2(fig, rect):
    """
    具有自定义定位器和格式化器。注意,极端值被交换了。
    """
    tr = PolarAxes.PolarTransform()

    pi = np.pi
    angle_ticks = [(0, r"$0$"),
                   (.25*pi, r"$\frac{1}{4}\pi$"),
                   (.5*pi, r"$\frac{1}{2}\pi$")]
    grid_locator1 = FixedLocator([v for v, s in angle_ticks])
    tick_formatter1 = DictFormatter(dict(angle_ticks))

    grid_locator2 = MaxNLocator(2)

    grid_helper = floating_axes.GridHelperCurveLinear(
        tr, extremes=(.5*pi, 0, 2, 1),
        grid_locator1=grid_locator1,
        grid_locator2=grid_locator2,
        tick_formatter1=tick_formatter1,
        tick_formatter2=None)

    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
    fig.add_subplot(ax1)

    # 创建一个寄生轴,其transData在RA,cz中
    aux_ax = ax1.get_aux_axes(tr)

    aux_ax.patch = ax1.patch  # 让aux_ax具有与ax中相同的剪辑路径
    ax1.patch.zorder = 0.9  # 但这有一个副作用:补丁绘制两次,可能超过其他artists。因此,我们降低了zorder来防止这种情况。

    return ax1, aux_ax


def setup_axes3(fig, rect):
    """
   有时候,需要对axis_direction之类的东西进行调整。
    """

    # 旋转一些以获得更好的方向
    tr_rotate = Affine2D().translate(-95, 0)

    # 将度数缩放为弧度
    tr_scale = Affine2D().scale(np.pi/180., 1.)

    tr = tr_rotate + tr_scale + PolarAxes.PolarTransform()

    grid_locator1 = angle_helper.LocatorHMS(4)
    tick_formatter1 = angle_helper.FormatterHMS()

    grid_locator2 = MaxNLocator(3)

    # 以度为单位指定 theta 限制
    ra0, ra1 = 8.*15, 14.*15
    # 指定径向限制
    cz0, cz1 = 0, 14000
    grid_helper = floating_axes.GridHelperCurveLinear(
        tr, extremes=(ra0, ra1, cz0, cz1),
        grid_locator1=grid_locator1,
        grid_locator2=grid_locator2,
        tick_formatter1=tick_formatter1,
        tick_formatter2=None)

    ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
    fig.add_subplot(ax1)

    # 调整轴
    ax1.axis["left"].set_axis_direction("bottom")
    ax1.axis["right"].set_axis_direction("top")

    ax1.axis["bottom"].set_visible(False)
    ax1.axis["top"].set_axis_direction("bottom")
    ax1.axis["top"].toggle(ticklabels=True, label=True)
    ax1.axis["top"].major_ticklabels.set_axis_direction("top")
    ax1.axis["top"].label.set_axis_direction("top")

    ax1.axis["left"].label.set_text(r"cz [km$^{-1}$]")
    ax1.axis["top"].label.set_text(r"$\alpha_{1950}$")

    # 创建一个寄生轴,其 transData 在 RA, cz
    aux_ax = ax1.get_aux_axes(tr)

    aux_ax.patch = ax1.patch  # 让 aux_ax 具有与 ax 中一样的剪辑路径
    ax1.patch.zorder = 0.9  # 但这有一个副作用:补丁绘制两次,可能超过其他artists。因此,我们降低了zorder来防止这种情况。

    return ax1, aux_ax

fig = plt.figure(figsize=(8, 4))
fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95)

ax1, aux_ax1 = setup_axes1(fig, 131)
aux_ax1.bar([0, 1, 2, 3], [3, 2, 1, 3])

ax2, aux_ax2 = setup_axes2(fig, 132)
theta = np.random.rand(10)*.5*np.pi
radius = np.random.rand(10) + 1.
aux_ax2.scatter(theta, radius)

ax3, aux_ax3 = setup_axes3(fig, 133)

theta = (8 + np.random.rand(10)*(14 - 8))*15.  # 度数
radius = np.random.rand(10)*14000.
aux_ax3.scatter(theta, radius)

plt.show()

效果:

axisartist 命名空间包含了一个衍生的 Axes 实现。

最大的不同是,负责绘制轴线、刻度、刻度标签和轴标签的artists从 Matplotlib 的 Axis 类中分离出来。

这比原始 Matplotlib 中的artists要多得多,这种改变是为了支持曲线网格。

以下是 mpl_toolkits.axisartist.Axes 与来自 Matplotlib 的原始 Axes 的一些不同之处。

  • 轴元素(轴线(spine)、刻度、刻度标签和轴标签)由 AxisArtist 实例绘制。与 Axis 不同,左轴、右轴、顶轴、底轴是由不同的artists绘制的。它们中的每一个都可能有不同的刻度位置和不同的刻度标签。

  • 网格线由 Gridlines 实例绘制。这种变化的原因是在曲线坐标中,网格线不能与轴线相交(即没有相关的刻度)。在原始 Axes 类中,网格线与刻度线相关联。

  • 如有必要,可以旋转刻度线(即沿网格线)。

总之,所有这些变化都是为了支持:

  • 一个曲线网格

  • 一个浮动轴

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axisartist.angle_helper as angle_helper
from matplotlib.projections import PolarAxes
from matplotlib.transforms import Affine2D
from mpl_toolkits.axisartist import SubplotHost
from mpl_toolkits.axisartist import GridHelperCurveLinear


def curvelinear_test2(fig):
    """极坐标投影,不过是在矩形框里。"""
    tr = Affine2D().scale(np.pi / 180., 1.) + PolarAxes.PolarTransform()

    extreme_finder = angle_helper.ExtremeFinderCycle(20,
                                                     20,
                                                     lon_cycle=360,
                                                     lat_cycle=None,
                                                     lon_minmax=None,
                                                     lat_minmax=(0,
                                                                 np.inf),
                                                     )

    grid_locator1 = angle_helper.LocatorDMS(12)

    tick_formatter1 = angle_helper.FormatterDMS()

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

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

    fig.add_subplot(ax1)

    # 现在创建浮动轴

    # 第一个坐标(theta)固定为60的浮动轴
    ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 60)
    axis.label.set_text(r"$\theta = 60^{\circ}$")
    axis.label.set_visible(True)

    # 第二坐标(r)固定为6的浮动轴
    ax1.axis["lon"] = axis = ax1.new_floating_axis(1, 6)
    axis.label.set_text(r"$r = 6$")

    ax1.set_aspect(1.)
    ax1.set_xlim(-5, 12)
    ax1.set_ylim(-5, 10)

    ax1.grid(True)


fig = plt.figure(figsize=(5, 5))
curvelinear_test2(fig)
plt.show()

效果:

mpl_toolkits.axisartist.Axes 类定义了一个axis属性,它是一个 AxisArtist 实例的字典。

默认情况下,字典有 4 个 AxisArtist 实例,负责绘制左、右、下、上轴。

xaxis 和 yaxis 属性仍然可用,但是它们被设置为不可见。由于是单独使用artists来绘制轴,所以Matplotlib 中一些与轴相关的方法可能没有效果。

除了 AxisArtist 实例之外,mpl_toolkits.axisartist.Axes 还会有网格线属性(Gridlines),可以绘制网格线。

在 AxisArtist 和 Gridlines 中,刻度和网格位置的计算都委托给 GridHelper 类的实例。

mpl_toolkits.axisar

标签: j30j矩形连接器ada102p3p间距连接器16zs矩形连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台