我目前正在制作纸张图,如下所示:
以上内容非常接近我希望它的外观,但我有一种强烈的感觉,我不是以“正确的方式”做到这一点,因为生产非常繁琐,我的代码充满了所有各种魔术数字,我用手微调定位。因此,我的问题是,制作这样的情节的正确方法是什么?
以下是该剧情的重要特征,使其难以制作:
三个子图的纵横比由数据确定,但图像并非全部具有相同的分辨率。
我希望所有三个图都占据图的全部高度
我希望(a)和(b)靠近在一起,因为它们共用y轴,而(c)离得更远
理想情况下,我希望顶部颜色条的顶部与三个图像的顶部完全匹配,并且与底部颜色条的底部类似。 (实际上它们并不完全一致,因为我通过猜测数字和重新编译图像来做到这一点。)
在制作这个图时,我首先尝试使用GridSpec,但我无法控制三个主要子图之间的相对间距。然后我尝试了ImageGrid,它是AxisGrid toolkit的一部分,但是三个图像之间的不同分辨率导致它表现得很奇怪。深入研究AxesGrid,我能够使用mydomain/myservice/numbersnumbers
函数定位三个主要子图,但我仍然需要手动定位三个颜色栏。 (我手动创建了颜色栏。)
我宁愿不发布我现有的代码,因为它是一个可怕的黑客和魔法数字集合。相反我的问题是,在MatPlotLib中是否有任何方法只指定图形的逻辑布局(即上面的项目符号点的内容)并自动为我计算布局?
答案 0 :(得分:3)
这是一个可能的解决方案。您从图形宽度开始(在准备纸张时这是有意义的)并使用图中的方面计算您的方式,在子图和边距之间有一些任意的间距。公式类似于我在this answer中使用的公式。 GridSpec
width_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()