【问题标题】:Precise control over subplot locations in matplotlib精确控制 matplotlib 中的子图位置
【发布时间】:2017-08-19 18:49:51
【问题描述】:

我目前正在为一篇论文制作一个图形,如下所示:

上面的内容非常接近我想要的样子,但我有一种强烈的感觉,我没有以“正确的方式”做这件事,因为它的制作真的很繁琐,而且我的代码充满了所有我手动微调定位的各种神奇数字。因此我的问题是,产生这样的情节的正确方法是什么?

以下是该情节难以制作的重要特征:

  • 三个子图的纵横比是由数据固定的,但图像的分辨率并不相同。

  • 我希望所有三个地块都占据图的整个高度

  • 我希望 (a) 和 (b) 靠得很近,因为它们共享 y 轴,而 (c) 更远

  • 理想情况下,我希望顶部颜色条的顶部与三个图像的顶部完全匹配,并且与下部颜色条的底部类似。 (实际上它们并没有完全对齐,因为我是通过猜测数字和重新编译图像来做到这一点的。)

在制作这个图时,我首先尝试使用GridSpec,但我无法控制三个主要子图之间的相对间距。然后我尝试了 ImageGrid,它是 AxisGrid toolkit 的一部分,但是三个图像之间的不同分辨率导致它的行为很奇怪。深入研究 AxesGrid,我能够使用 append_axes 函数定位三个主要子图,但我仍然必须手动定位三个颜色条。 (我手动创建了颜色条。)

我宁愿不发布我现有的代码,因为它是黑客和神奇数字的可怕集合。而我的问题是,MatPlotLib 中是否有任何方法可以指定图形的逻辑布局(即上面的项目符号的内容)并自动为我计算布局?

【问题讨论】:

  • 这清楚地表明 matplotlib 不是一个好的库。在一个好的库中,应该能够在画布的任意位置绘制绘图。

标签: python matplotlib


【解决方案1】:

这是一个可能的解决方案。您将从图形宽度开始(这在准备论文时是有意义的)并使用图形的各个方面计算您的方式,子图和边距之间的一些任意间距。这些公式类似于我在this answer 中使用的公式。不平等方面由GridSpecwidth_ratios 论点处理。 然后你最终得到一个图形高度,使得子图的高度相等。

所以你不能避免输入一些数字,但它们不是“魔法”。所有这些都与可访问量有关,例如图形大小的分数或平均子图大小的分数。由于系统是封闭的,改变任何数字只会产生不同的图形高度,但不会破坏布局。

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np; np.random.seed(42)

imgs = []
shapes = [(550,200), ( 550,205), (1100,274) ]
for shape in shapes:
    imgs.append(np.random.random(shape))

# calculate inverse aspect(width/height) for all images
inva = np.array([ img.shape[1]/float(img.shape[0]) for img in imgs])
# set width of empty column used to stretch layout
emptycol = 0.02
r = np.array([inva[0],inva[1], emptycol, inva[2], 3*emptycol, emptycol])
# set a figure width in inch
figw = 8
# border, can be set independently of all other quantities
left = 0.1; right=1-left
bottom=0.1; top=1-bottom
# wspace (=average relative space between subplots)
wspace = 0.1
#calculate scale
s = figw*(right-left)/(len(r)+(len(r)-1)*wspace) 
# mean aspect
masp = len(r)/np.sum(r)
#calculate figheight
figh = s*masp/float(top-bottom)


gs = gridspec.GridSpec(3,len(r), width_ratios=r)

fig = plt.figure(figsize=(figw,figh))
plt.subplots_adjust(left, bottom, right, top, wspace)

ax1 = plt.subplot(gs[:,0])
ax2 = plt.subplot(gs[:,1])
ax2.set_yticks([])

ax3 = plt.subplot(gs[:,3])
ax3.yaxis.tick_right()
ax3.yaxis.set_label_position("right")

cax1 = plt.subplot(gs[0,5])
cax2 = plt.subplot(gs[1,5])
cax3 = plt.subplot(gs[2,5])


im1 = ax1.imshow(imgs[0], cmap="viridis")
im2 = ax2.imshow(imgs[1], cmap="plasma")
im3 = ax3.imshow(imgs[2], cmap="RdBu")

fig.colorbar(im1, ax=ax1, cax=cax1)
fig.colorbar(im2, ax=ax2, cax=cax2)
fig.colorbar(im3, ax=ax3, cax=cax3)

ax1.set_title("image title")
ax1.set_xlabel("xlabel")
ax1.set_ylabel("ylabel")

plt.show()

【讨论】:

  • 所以这不能回答问题吗?
猜你喜欢
  • 1970-01-01
  • 2019-07-10
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多