我有一个中等大小的数组(例如1500 x3000),我想按比例绘制,因为它是一个图像。然而,垂直和水平比例非常不同。为了简化,假设有一米/行和10/列。然后绘图应产生一个约为1500 x30000的图像。我使用kwarg范围作为比例和方面=无论是使用绘图窗口(QT 4)和imshow()还是使用savefig(),我都没有成功地以全分辨率和比例生成图像。
我已经研究了许多建议的解决方案,如here,here,或者here和there或there,以防它是一个bug。我已经改变了我的matplotlibrc,并将其放置在~/.config/matplotlib中,试图强制我的显示/保存选项,但无济于事。我也尝试了pcolormesh()但没有成功。我使用Python 2.7和matplotlib 1.3从Ubuntu 14.04的repo和QT 4Agg作为后端。我也尝试了TkAgg,但它很慢,并给出了相同的结果。我的印象是,在x轴的分辨率是正确的,但它肯定是在垂直方向下采样。这里是一个这段代码应该模拟我的问题。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
R, C = 1500, 3000
DATA = np.random.random((R, C))
DATA[::2, :] *= -1 # make every other line negative
Yi, Xi = 1, 10 # increment
CMP = 'seismic'
ImageFormat ='pdf'
Name = 'Image'
DataRange = (np.absolute(DATA)).max() # I want my data centred on 0
EXTENT = [0, Xi*C, 0 ,Yi*R]
NORM = matplotlib.colors.Normalize(vmin =-DataRange, vmax= DataRange, clip =True)
for i in range(1,4):
Fig=plt.figure(figsize=(45, 10), dpi = 100*i, tight_layout=True)
Fig.suptitle(Name+str(i)+'00DPI')
ax = Fig.add_subplot(1, 1, 1)
Plot = ax.imshow(DATA, cmap=plt.get_cmap(CMP), norm = NORM, extent = EXTENT, aspect = 1, interpolation='none')
ax.set_xlabel('metres')
ax.set_ylabel('metres')
Fig.savefig(Name+str(i)+'00DPI.'+ImageFormat, format = ImageFormat, dpi = Fig.dpi)
plt.close()
在imshow()中,插值= 'none'或'nearest'或'bilinear'不会因为某种原因改变分辨率,尽管我认为如果我使用show()而不是savefig(),它至少应该在Qt 4窗口中改变分辨率。请注意,无论您在plt.figure(dpi=)中设置什么,保存的图中的分辨率都是相同的。
我对这个系统的工作原理一无所知,也没有什么了解。任何帮助都是非常欢迎的。
先谢了。
3条答案
按热度按时间ylamdve61#
运行你的例子,在matplotlib中缩放后一切看起来都很好:无论分辨率如何,结果都是一样的,我看到每个轴单位一个像素。此外,尝试使用较小的数组,pdf(或其他格式)工作得很好。
这是我的解释:**当您设置图形dpi时,您正在设置整个图形的dpi(不仅仅是数据区域)。在我的系统上,这会导致绘图区域在垂直方向上占据整个图的20%左右。如果您设置300 dpi和10的高度,您将获得垂直数据轴的300x10x0.2=600像素,这不足以表示1500个点,这就解释了为什么输出必须被重新采样。**注意,有时候减小宽度也会起作用,因为它改变了数据图所占的图形比例。
然后你必须增加dpi,并设置插值='无'(如果分辨率设置得很完美,那应该没关系,但如果它足够接近,那就很重要了)。你也可以调整图的位置和大小,以获得更大的图的一部分,但回到最佳分辨率设置,理想情况下,你希望轴上的像素数是数据点的倍数,否则必须进行某种插值(想想如何在三个像素上绘制两个点,反之亦然)。
我不知道下面是不是最好的方法,matplotlib中可能有更合适的方法和属性,但我会尝试这样来计算最佳dpi:
然后你的代码(减少到第一个循环)变成:
这对我来说是合理的。
zzzyeukh2#
首先,当你保存为
.pdf
时,你隐含地使用了pdf后端,即使你可能在选项中指定了其他后端。这意味着你的图像是以矢量格式保存的,因此dpi是毫无意义的。在任何分辨率下,如果我在一个像样的浏览器中加载你的PDF,(我用的是inkscape,其他的都有),你可以清楚地看到条纹实际上,我发现如果将每隔一行设置为零,观察起来会更容易。当您指定figsize=(45, 10)
时,所有生成的PDF都建议显示大小为45英寸x 10英寸。如果我指定
png
作为图像类型,我会看到基于dpi
参数的文件大小的差异,我认为这是你所期望的。如果你看100 dpi的图像,它有4500000,200 dpi图像具有18000000像素(4倍)和300 dpi的图像有40500000(9倍)。你会注意到4500000 == 1500 x 3000,即原始数组的每个成员一个像素。因此,更大的dpi设置并不能真正获得任何进一步的定义-相反,你的条纹是2或3像素宽分别而不是1。我想你需要做的是有效地将每一列绘制10次,这样你就得到了一个1500 x 30000像素的图像。要做到这一点,使用所有你自己的代码,你可以使用
np.repeat
做如下事情:pdf
的矢量图形输出,您可以将ImageFormat
变量更改为png
我突然想到,你可能关心的另一件事是给予图片适当的宽高比(即宽高比的20倍)。这一点你已经在做了。所以,如果你看
pdf
中每个像素的表示,它们是矩形的(宽高比的10倍),而不是正方形。pprl5pva3#
如果你喜欢它作为一个功能:
这段代码是基于Jumenzooo的解决方案,但数学是为Python 3和matplotlib 3.7.2更新的。