matplotlib基础:使用GridSpec自定义子图

2020-04-21 17:44:23 浏览数 (3)

GridSpec

指定绘制子图的网格形状,同时要设置绘制子图的行列数。当然也可以调整子图的布局(如 left,right等)。

SubplotSpec

确定由 GridSpec 指定的子图位置

subplot2grid

类似 pyplot.subplot 的非常有用的函数,但以 0 为起始

使用 subplot2grid 创建子图

使用 subplot2grid 时, 需要提供网格的几何形状子图在网格中的位置

先创建一个子图(即创建2行2列子图,并绘制第一个子图):

代码语言:javascript复制
ax = plt.subplot2grid((2,2),(0, 0))

等同于

代码语言:javascript复制
ax = plt.subplot(2,2,1)

注意: gridspec 的索引是以 0 为起始的,这一点和 subplot 不同。

下面创建含具有多个单元的子图:

完整代码:

代码语言:javascript复制
import matplotlib.pyplot as plt

def make_ticklabels_invisible(fig):
    for i, ax in enumerate(fig.axes):
        ax.text(0.5, 0.5, "ax%d" % (i 1), va="center", ha="center")
        for tl in ax.get_xticklabels()   ax.get_yticklabels():
            tl.set_visible(False)

plt.figure(0)
#创建3x3的子图,并且布局从第1行,第1列开始,占据3列,就是说整个第一行被我承包了
ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)
#创建3x3的子图,并且布局从第2行,第1列开始,占据2列
ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)
#创建3x3的子图,并且布局从第2行,第3列开始,占据2行
ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2)
#创建3x3的子图,并且布局从第3行,第1列开始,占据1行
ax4 = plt.subplot2grid((3,3), (2, 0))
#创建3x3的子图,并且布局从第3行,第2列开始,占据1行
ax5 = plt.subplot2grid((3,3), (2, 1))

plt.suptitle("subplot2grid")
make_ticklabels_invisible(plt.gcf())
plt.show()

GridSpec 和 SubplotSpec

当然也可以直接使用 GridSpec,然后创建子图

比如:

代码语言:javascript复制
ax = plt.subplot2grid((2,2),(0, 0))

相当于

代码语言:javascript复制
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
ax = plt.subplot(gs[0, 0])

gridspec 实例提供类数组操作,并且返回 SubplotSpec 实例。SubplotSpec 可以分隔多个单元:

比如:

代码语言:javascript复制
# 创建 3x3 的子图
gs = gridspec.GridSpec(3, 3)
# 承包整个第1行
ax1 = plt.subplot(gs[0, :])
# 承包第2行,前2列
ax2 = plt.subplot(gs[1,:-1])
# 承包2-3行,第3列
ax3 = plt.subplot(gs[1:, -1])
# 那我只能承包第3行第1列了,要不然 ax5 就没了
ax4 = plt.subplot(gs[-1,0])
# ...
ax5 = plt.subplot(gs[-1,-2])

完整代码如下:

代码语言:javascript复制
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

def make_ticklabels_invisible(fig):
    for i, ax in enumerate(fig.axes):
        ax.text(0.5, 0.5, "ax%d" % (i 1), va="center", ha="center")
        for tl in ax.get_xticklabels()   ax.get_yticklabels():
            tl.set_visible(False)

plt.figure()

gs = GridSpec(3, 3)
ax1 = plt.subplot(gs[0, :])
# 和 ax1 = plt.subplot(gs.new_subplotspec((0,0), colspan=3)) 相同
ax2 = plt.subplot(gs[1,:-1])
ax3 = plt.subplot(gs[1:, -1])
ax4 = plt.subplot(gs[-1,0])
ax5 = plt.subplot(gs[-1,-2])

plt.suptitle("GridSpec")
make_ticklabels_invisible(plt.gcf())

plt.show()

调整 GridSpec 布局

当直接使用 GridSpec 创建子图时,可以调整其布局参数创建更合适的子图(直接使用 update 方法更新)

代码语言:javascript复制
gs1 = gridspec.GridSpec(3, 3)
gs1.update(left=0.05, right=0.48, wspace=0.05)

类似 subplots_adjust() ,但是仅能作用于 GridSpec 创建的子图。

代码语言:javascript复制
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

# demo 3 : gridspec with subplotpars set.
f = plt.figure()

plt.suptitle("GridSpec w/ different subplotpars")

gs1 = GridSpec(3, 3)
gs1.update(left=0.05, right=0.48, wspace=0.05)
ax1 = plt.subplot(gs1[:-1, :])
ax2 = plt.subplot(gs1[-1, :-1])
ax3 = plt.subplot(gs1[-1, -1])

gs2 = GridSpec(3, 3)
gs2.update(left=0.55, right=0.98, hspace=0.05)
ax4 = plt.subplot(gs2[:, :-1])
ax5 = plt.subplot(gs2[:-1, -1])
ax6 = plt.subplot(gs2[-1, -1])

make_ticklabels_invisible(plt.gcf())

plt.show()
代码语言:javascript复制

使用 SubplotSpec

也可以通过 SubplotSpec 创建子图。这时候其布局参数将设置为 SubplotSpec 给定的位置。

代码语言:javascript复制
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# gridspec 嵌套 gridspec
f = plt.figure()

gs0 = gridspec.GridSpec(1, 2)

gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0])

ax1 = plt.Subplot(f, gs00[:-1, :])
f.add_subplot(ax1)
ax2 = plt.Subplot(f, gs00[-1, :-1])
f.add_subplot(ax2)
ax3 = plt.Subplot(f, gs00[-1, -1])
f.add_subplot(ax3)

gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1])

ax4 = plt.Subplot(f, gs01[:, :-1])
f.add_subplot(ax4)
ax5 = plt.Subplot(f, gs01[:-1, -1])
f.add_subplot(ax5)
ax6 = plt.Subplot(f, gs01[-1, -1])
f.add_subplot(ax6)

plt.suptitle("GirdSpec Inside GridSpec")
make_ticklabels_invisible(plt.gcf())

plt.show()

使用 SubplotSpec 嵌套 GridSpec

下面给出一个更复杂的子图示例,最外围是 4x4 的子图,每个图中又含有 3x3 的子图,但3X3的子图的 spine 被隐藏了

代码语言:javascript复制
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

try:
    from itertools import product
except ImportError:
    def product(*args, **kwds):
        pools = map(tuple, args) * kwds.get('repeat', 1)
        result = [[]]
        for pool in pools:
            result = [x [y] for x in result for y in pool]
        for prod in result:
            yield tuple(prod)


def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)):
    return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d)

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

# gridspec 嵌套 gridspec
outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0)

for i in range(16):
    inner_grid = gridspec.GridSpecFromSubplotSpec(3, 3,
            subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0)
    a, b = int(i/4) 1,i%4 1
    for j, (c, d) in enumerate(product(range(1, 4), repeat=2)):
        ax = plt.Subplot(fig, inner_grid[j])
        ax.plot(*squiggle_xy(a, b, c, d))
        ax.set_xticks([])
        ax.set_yticks([])
        fig.add_subplot(ax)
plt.show()        

如果再添加下面的语句

代码语言:javascript复制
for ax in all_axes:
    for sp in ax.spines.values():
        sp.set_visible(False)
    if ax.is_first_row():
        ax.spines['top'].set_visible(True)
    if ax.is_last_row():
        ax.spines['bottom'].set_visible(True)
    if ax.is_first_col():
        ax.spines['left'].set_visible(True)
    if ax.is_last_col():
        ax.spines['right'].set_visible(True)

plt.show()

使用 GridSpec 绘制不同尺寸的子图

代码语言:javascript复制
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

f = plt.figure()

gs = gridspec.GridSpec(2, 2,
                       width_ratios=[1,2],
                       height_ratios=[4,1]
                       )

ax1 = plt.subplot(gs[0])
ax2 = plt.subplot(gs[1])
ax3 = plt.subplot(gs[2])
ax4 = plt.subplot(gs[3])

make_ticklabels_invisible(f)
plt.show()

0 人点赞