范围与比例;共享轴的图像中的方形像素

1 投票
1 回答
2588 浏览
提问于 2025-04-18 04:45

我现在遇到了一些复杂的问题。我正在用imshow()来绘制一些数据作为图像。不幸的是,我的代码比较长而且有点乱,所以很难给出一个能正常工作的例子,但我会展示关键步骤。这是我如何从一个更大的数组中获取图像数据的,数据是写在一个文件里的:

data = np.tril(np.loadtxt('IC-heatmap-20K.mtx'), 1)
#
#Here goes lot's of other stuff, where I define start and end
#
chrdata = data[start:end, start:end]
chrdata = ndimage.rotate(chrdata, 45, order=0, reshape=True, 
                         prefilter=False, cval=0)
ax1 = host_subplot(111) 
#I don't really need host_subplot() in this case, I could use something more common;
#It is just divider.append_axes("bottom", ...) is really convenient.
plt.imshow(chrdata, origin='lower', interpolation='none',
           extent=[0, length*resolution, 0, length*resolution]) #resolution=20000

我感兴趣的值都在一个三角形里,三角形的顶角在正方形的上边中间。同时,我在图像的底部附近绘制了一些数据(在这种情况下是很多彩色的线)。
带范围但无纵横比

乍一看,这似乎没问题,但实际上并不是:图像中的所有像素都不是正方形的,而是拉长的,高度比宽度大。这是我放大后看到的样子:
带范围但无纵横比的像素

如果我在调用imshow()时不设置范围,这种情况就不会发生,但我需要设置范围,以便图像中的坐标和其他图(在这种情况下是底部的彩色线)一致(见在matplotlib中转换图像坐标?)。我尝试用纵横比来修复这个问题。我这样做后,像素的形状确实修复了,但我得到了一个非常奇怪的图像:
范围和纵横比

问题是,在代码的后面,我明确设置了这个:

ax1.set_ylim(0*resolution, length*resolution) #resolution=20000

但是在设置了纵横比后,我得到了完全不同的y轴限制。最糟糕的是:ax1现在比底部另一个图的坐标轴宽,所以它们的坐标不再匹配了!我这样添加的:

axPlotx = divider.append_axes("bottom", size=0.1, pad=0, sharex=ax1)

我非常希望能得到帮助,解决这个问题:让像素变成正方形,确保两个(或更多,在其他情况下)图的坐标一致。我的理解是,图像的坐标轴需要变宽(就像纵横比那样),y轴限制应该适用,第二个坐标轴的宽度应该和图像的宽度相同。
感谢你阅读这个可能不太清楚的解释,如果有需要我进一步说明的地方,请告诉我。

更新

根据评论中的建议,我尝试使用

ax1.set(adjustable='box-forced')

这确实对图像本身有帮助,但导致两个坐标轴之间出现了空白。有没有办法让它们靠得更近一些?

范围、纵横比和强制框

1 个回答

2

我重新编辑了我的整个回答,因为我找到了你问题的解决办法。我是根据tcaswell的评论,使用了set_adjustable("box_forced")这个选项来解决的。

import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot, make_axes_locatable


#Calculate aspect ratio
def determine_aspect(shape, extent):
    dx = (extent[1] - extent[0]) / float(shape[1])
    dy = (extent[3] - extent[2]) / float(shape[0])
    return dx / dy

data = numpy.random.random((30,60))

shape = data.shape
extent = [-10, 10, -20, 20]
x_size, y_size = 6, 6

fig = plt.figure(figsize = (x_size, y_size))
ax = host_subplot(1, 1, 1)
ax.imshow(data, extent = extent, interpolation = "None", aspect = determine_aspect(shape, extent))

#Determine width and height of the subplot frame
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
width, height = bbox.width, bbox.height

#Calculate distance, the second plot needs to be elevated by
padding = (y_size - (height - width)) / float(1 / (2. * determine_aspect(shape, extent)))

#Create second image in subplot with shared x-axis
divider = make_axes_locatable(ax)
axPlotx = divider.append_axes("bottom", size = 0.1, pad = -padding, sharex = ax)

#Turn off yticks for axPlotx and xticks for ax 
axPlotx.set_yticks([])
plt.setp(ax.get_xticklabels(), visible=False)

#Make the plot obey the frame
ax.set_adjustable("box-forced")

fig.savefig("test.png", dpi=300, bbox_inches = "tight")

plt.show()

这样就得到了下面这张图,其中的x轴是共享的:

在这里输入图片描述

希望这对你有帮助!

撰写回答