【发布时间】:2021-05-06 00:56:27
【问题描述】:
我正在尝试在 imshow 图的顶部添加一个条形图,并在右侧添加另一个条形图,条形图与 imshow“单元格”对齐。
我已尝试使用此示例中使用的方法adding histograms at the margins of a scatterplot) 和make_axes_locatable。
我得到的结果如图所示。有两个问题我无法解决:
-
imshow图的实际大小小于我在其中绘制它的轴的大小,因为我想保持矩阵纵横比,因此实际图将严格包含在轴中 - 即使这不是问题(参见上图),条形也不会与
imshow单元格对齐。
这是我的代码
# from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.style.use('dark_background')
m = np.random.rand(25, 200)
# definitions for the axes
left, width = 0.1, 0.65
bottom, height = 0.1, 0.65
spacing = 0.005
rect0 = [left, bottom, width, height]
rect1 = [left, bottom + height + spacing, width, 0.2]
rect2 = [left + width + spacing, bottom, 0.2, height]
# start with a rectangular Figure
fig = plt.figure(figsize=(20, 8))
ax0 = plt.axes(rect0)
ax0.tick_params(direction='in', top=True, right=True)
ax1 = plt.axes(rect1)
ax1.tick_params(direction='in', labelbottom=False)
ax2 = plt.axes(rect2)
ax2.tick_params(direction='in', labelleft=False)
ax0.matshow(m, norm=matplotlib.colors.LogNorm())
# divider = make_axes_locatable(ax)
# cax = divider.append_axes('right', size='95%', pad=0)
ax1.bar(np.arange(m.shape[1]), np.apply_along_axis(scipy.stats.entropy, 0, m))
# divider = make_axes_locatable(ax)
# cax = divider.append_axes('bottom', size='95%', pad=0)
ax2.barh(np.arange(m.shape[0]), np.apply_along_axis(scipy.stats.entropy, 1, m), orientation='horizontal')
plt.savefig('/data/l989o/a/so.png')
plt.style.use('default')
编辑 尝试向情节添加细节,如轴标签或 colobar,我发现一般情况可能更加复杂。我为添加其他绘图元素的更一般情况添加了代码,以及代码。
注意,我注意到我必须反转右侧的条形图,因为在使用orientation=horizontal 时,条形图的顺序与图像的其中一行相反。
# from mpl_toolkits.axes_grid1 import make_axes_locatable
import functools
plt.style.use('dark_background')
m = np.random.rand(58, 226) * 20
# definitions for the axes
left, width = 0.1, 0.65
bottom, height = 0.1, 0.65
spacing = 0.005
rect0 = [left, bottom, width, height]
rect1 = [left, bottom + height + spacing, width, 0.2]
rect2 = [left + width + spacing, bottom, 0.2, height]
# start with a rectangular Figure
fig = plt.figure(figsize=(20, 8))
ax0 = plt.axes(rect0)
ax0.tick_params(direction='in', top=True, right=True)
ax1 = plt.axes(rect1)
ax1.tick_params(direction='in', labelbottom=False)
ax2 = plt.axes(rect2)
ax2.tick_params(direction='in', labelleft=False)
t = 10
n = 2
cmap = matplotlib.colors.LinearSegmentedColormap.from_list(None, plt.cm.Set1(range(0, n)), n)
im = ax0.imshow(m > t, cmap=cmap)
ax0.set_xlabel('image')
ax0.set_ylabel('cluster label')
divider = make_axes_locatable(ax0)
cax = divider.append_axes('left', size='1%', pad=1)
cbar = fig.colorbar(im, ticks=range(n), cax=cax)
# cbar.set_lim(-0.5, n - 0.5)
cbar.ax.tick_params(length=0)
cbar.set_ticks([0.25, 0.75])
cbar.set_ticklabels([f'<= {t}', f'> {t}'])
cbar.ax.set_title('# cells')
# divider = make_axes_locatable(ax)
# cax = divider.append_axes('right', size='95%', pad=0)
def sum_treshold(v, threshold):
return np.sum(v > threshold)
ax1.bar(np.arange(m.shape[1]), np.apply_along_axis(functools.partial(sum_treshold, threshold=t), 0, m))
ax1.set_xlim([0, m.shape[1]])
# divider = make_axes_locatable(ax)
# cax = divider.append_axes('bottom', size='95%', pad=0)
ax2.barh(np.arange(m.shape[0])[::-1], np.apply_along_axis(functools.partial(sum_treshold, threshold=t), 1, m), orientation='horizontal')
ax2.set_ylim([0, m.shape[0]])
plt.savefig('/data/l989o/a/so.png')
plt.style.use('default')
编辑 2 这是最终输出应该是什么样子的示例。为了获得这一点,我进行了疯狂的二进制搜索并设置了硬编码坐标(这当然只适用于我拥有的特定数据矩阵,而不是一般情况下)。
【问题讨论】:
-
你考虑过使用gridspec吗? matplotlib.org/3.3.3/tutorials/intermediate/gridspec.html
-
设置
ax0.aspect('auto')并通过ax1.get_shared_x_axes().join(ax1, ax0); ax2.get_shared_y_axes().join(ax2, ax0)加入各个轴似乎有效。要获得“相等”的纵横比,您可能可以更改图形尺寸。顺便说一句,在imshow()中,您可以将origin='lower'设置为具有“常规”y 轴。您可以将颜色条设置在右上角以避免移动其他子图。
标签: python matplotlib axes imshow